feat(apu): add atomic Step() function for cycle-accurate SPC700 execution

- Add Step() method that executes one complete instruction atomically
- Returns exact cycle count consumed by the instruction
- Handles reset and stopped states explicitly
- Uses cycle lookup table from spc700_cycles.h
- Maintains compatibility with existing RunOpcode() for gradual migration

This implements the LakeSnes-inspired atomic execution model while
adding explicit cycle return for better testability.
This commit is contained in:
scawful
2025-10-10 17:29:42 -04:00
parent b5cecedbb0
commit f8c6536f40
2 changed files with 42 additions and 1 deletions

View File

@@ -27,6 +27,43 @@ void Spc700::Reset(bool hard) {
reset_wanted_ = true;
}
int Spc700::Step() {
// Handle reset sequence (based on 6502, brk without writes)
if (reset_wanted_) {
reset_wanted_ = false;
read(PC);
read(PC);
read(0x100 | SP--);
read(0x100 | SP--);
read(0x100 | SP--);
callbacks_.idle(false);
PSW.I = false;
PC = read_word(0xfffe);
last_opcode_cycles_ = 8;
return 8;
}
// Handle stopped state (SLEEP/STOP instructions)
if (stopped_) {
callbacks_.idle(true);
last_opcode_cycles_ = 2;
return 2;
}
// Fetch and execute one complete instruction
uint8_t opcode = ReadOpcode();
// Set base cycle count from lookup table
// This will be the return value; callbacks during execution will advance APU cycles
last_opcode_cycles_ = spc700_cycles[opcode];
// Execute the instruction completely (atomic execution)
ExecuteInstructions(opcode);
// Return the number of cycles this instruction consumed
return last_opcode_cycles_;
}
void Spc700::RunOpcode() {
static int entry_log = 0;
if ((PC >= 0xFFF0 && PC <= 0xFFFF) && entry_log++ < 5) {

View File

@@ -138,7 +138,11 @@ class Spc700 {
void Reset(bool hard = false);
void RunOpcode();
// New atomic step function - executes one complete instruction and returns cycles consumed
// This is the preferred method for cycle-accurate emulation
int Step();
// Get the number of cycles consumed by the last opcode execution
int GetLastOpcodeCycles() const { return last_opcode_cycles_; }