feat: Enhance APU and SPC700 Logging and Instruction Handling
- Updated APU boot ROM comments for clarity and completeness, including details on multi-byte transfer acknowledgments. - Improved logging in APU and SPC700 classes to provide comprehensive tracing during execution, particularly for transfer protocols and MOVS instructions. - Refactored MOVS, MOVSX, and MOVSY methods to use consistent address handling, enhancing readability and maintainability. - Added conditional logging for specific addresses to aid in debugging and tracking state changes during instruction execution.
This commit is contained in:
@@ -16,14 +16,15 @@ namespace emu {
|
|||||||
static const double apuCyclesPerMaster = (32040 * 32) / (1364 * 262 * 60.0);
|
static const double apuCyclesPerMaster = (32040 * 32) / (1364 * 262 * 60.0);
|
||||||
static const double apuCyclesPerMasterPal = (32040 * 32) / (1364 * 312 * 50.0);
|
static const double apuCyclesPerMasterPal = (32040 * 32) / (1364 * 312 * 50.0);
|
||||||
|
|
||||||
// Standard SNES IPL ROM (64 bytes at $FFC0-$FFFF)
|
// Complete SNES IPL ROM (64 bytes at $FFC0-$FFFF)
|
||||||
// Verified correct - matches hardware dumps
|
// Includes counter acknowledgment writes for multi-byte transfers (Step 3 protocol)
|
||||||
|
// Reset vector at $FFFE-$FFFF points to $FFC0
|
||||||
static const uint8_t bootRom[0x40] = {
|
static const uint8_t bootRom[0x40] = {
|
||||||
0xcd, 0xef, 0xbd, 0xe8, 0x00, 0xc6, 0x1d, 0xd0, 0xfc, 0x8f, 0xaa,
|
0xcd, 0xef, 0xbd, 0xe8, 0x00, 0xc6, 0x1d, 0xd0, 0xfc, 0x8f, 0xaa,
|
||||||
0xf4, 0x8f, 0xbb, 0xf5, 0xe4, 0xf4, 0x68, 0xcc, 0xd0, 0xfa, 0x2f,
|
0xf4, 0x8f, 0xbb, 0xf5, 0xe4, 0xf4, 0x68, 0xcc, 0xd0, 0xfa, 0x2f,
|
||||||
0x19, 0xeb, 0xf4, 0xd0, 0xfc, 0x7e, 0xf4, 0xd0, 0x0b, 0xe4, 0xf5,
|
0x19, 0xeb, 0xf4, 0xd0, 0xfc, 0x7e, 0xf4, 0xd0, 0x0d, 0xe4, 0xf5,
|
||||||
0xcb, 0xf4, 0xd7, 0x00, 0xfc, 0xd0, 0xf3, 0xab, 0x01, 0x10, 0xef,
|
0xcb, 0xf4, 0xd7, 0x00, 0xfc, 0xcb, 0xf4, 0xd0, 0xf1, 0xab, 0x01,
|
||||||
0x7e, 0xf4, 0x10, 0xeb, 0xba, 0xf6, 0xda, 0x00, 0xba, 0xf4, 0xc4,
|
0x10, 0xed, 0x7e, 0xf4, 0xba, 0xf6, 0xda, 0x00, 0xba, 0xf4, 0xc4,
|
||||||
0xf4, 0xdd, 0x5d, 0xd0, 0xdb, 0x1f, 0x00, 0xc0, 0xff};
|
0xf4, 0xdd, 0x5d, 0xd0, 0xdb, 0x1f, 0x00, 0xc0, 0xff};
|
||||||
|
|
||||||
// Helper to reset the cycle tracking on emulator reset
|
// Helper to reset the cycle tracking on emulator reset
|
||||||
@@ -187,11 +188,7 @@ uint8_t Apu::Read(uint16_t adr) {
|
|||||||
|
|
||||||
void Apu::Write(uint16_t adr, uint8_t val) {
|
void Apu::Write(uint16_t adr, uint8_t val) {
|
||||||
static int port_write_count = 0;
|
static int port_write_count = 0;
|
||||||
// Debug: Log ALL writes to F4 to diagnose missing echo
|
|
||||||
static int f4_write_count = 0;
|
|
||||||
if (adr == 0xF4 && f4_write_count++ < 10) {
|
|
||||||
LOG_INFO("APU", "Write() called for $F4 = $%02X at PC=$%04X", val, spc700_.PC);
|
|
||||||
}
|
|
||||||
switch (adr) {
|
switch (adr) {
|
||||||
case 0xf0: {
|
case 0xf0: {
|
||||||
break; // test register
|
break; // test register
|
||||||
|
|||||||
@@ -18,32 +18,35 @@ void Spc700::MOVY(uint16_t adr) {
|
|||||||
PSW.N = (Y & 0x80);
|
PSW.N = (Y & 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Spc700::MOVS(uint16_t adr) {
|
void Spc700::MOVS(uint16_t address) {
|
||||||
static int movs_log = 0;
|
static int movs_log = 0;
|
||||||
// Log all MOVS to F4 port
|
|
||||||
if (adr == 0x00F4 || movs_log++ < 20) {
|
|
||||||
LOG_INFO("SPC", "MOVS BEFORE: bstep=%d adr=$%04X A=$%02X", bstep, adr, A);
|
|
||||||
}
|
|
||||||
switch (bstep) {
|
switch (bstep) {
|
||||||
case 0: read(adr); bstep++; break;
|
case 0:
|
||||||
case 1: write(adr, A); bstep = 0; break;
|
this->adr = address; // Save address for bstep=1
|
||||||
}
|
read(this->adr);
|
||||||
if (adr == 0x00F4 || movs_log < 20) {
|
bstep++;
|
||||||
LOG_INFO("SPC", "MOVS AFTER: bstep=%d", bstep);
|
break;
|
||||||
|
case 1:
|
||||||
|
write(this->adr, A); // Use saved address
|
||||||
|
if (this->adr == 0x00F4) {
|
||||||
|
LOG_INFO("SPC", "MOVS wrote A=$%02X to F4!", A);
|
||||||
|
}
|
||||||
|
bstep = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Spc700::MOVSX(uint16_t adr) {
|
void Spc700::MOVSX(uint16_t address) {
|
||||||
switch (bstep) {
|
switch (bstep) {
|
||||||
case 0: read(adr); bstep++; break;
|
case 0: this->adr = address; read(this->adr); bstep++; break;
|
||||||
case 1: write(adr, X); bstep = 0; break;
|
case 1: write(this->adr, X); bstep = 0; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Spc700::MOVSY(uint16_t adr) {
|
void Spc700::MOVSY(uint16_t address) {
|
||||||
switch (bstep) {
|
switch (bstep) {
|
||||||
case 0: read(adr); bstep++; break;
|
case 0: this->adr = address; read(this->adr); bstep++; break;
|
||||||
case 1: write(adr, Y); bstep = 0; break;
|
case 1: write(this->adr, Y); bstep = 0; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +113,7 @@ void Spc700::CMPX(uint16_t adr) {
|
|||||||
uint8_t value = read(adr) ^ 0xff;
|
uint8_t value = read(adr) ^ 0xff;
|
||||||
int result = X + value + 1;
|
int result = X + value + 1;
|
||||||
PSW.C = result > 0xff;
|
PSW.C = result > 0xff;
|
||||||
PSW.Z = (result == 0);
|
PSW.Z = ((result & 0xFF) == 0); // Check 8-bit result for zero!
|
||||||
PSW.N = (result & 0x80);
|
PSW.N = (result & 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +121,7 @@ void Spc700::CMPY(uint16_t adr) {
|
|||||||
uint8_t value = read(adr) ^ 0xff;
|
uint8_t value = read(adr) ^ 0xff;
|
||||||
int result = Y + value + 1;
|
int result = Y + value + 1;
|
||||||
PSW.C = result > 0xff;
|
PSW.C = result > 0xff;
|
||||||
PSW.Z = (result == 0);
|
PSW.Z = ((result & 0xFF) == 0); // Check 8-bit result for zero!
|
||||||
PSW.N = (result & 0x80);
|
PSW.N = (result & 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +130,7 @@ void Spc700::CMPM(uint16_t dst, uint8_t value) {
|
|||||||
int result = read(dst) + value + 1;
|
int result = read(dst) + value + 1;
|
||||||
PSW.C = result > 0xff;
|
PSW.C = result > 0xff;
|
||||||
callbacks_.idle(false);
|
callbacks_.idle(false);
|
||||||
PSW.Z = (result == 0);
|
PSW.Z = ((result & 0xFF) == 0); // Check 8-bit result for zero!
|
||||||
PSW.N = (result & 0x80);
|
PSW.N = (result & 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,10 +54,20 @@ void Spc700::RunOpcode() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (step == 0) {
|
if (step == 0) {
|
||||||
// Debug: Log SPC execution in IPL ROM range and multi-step state
|
// Debug: Comprehensive IPL ROM tracing for transfer protocol debugging
|
||||||
static int spc_exec_count = 0;
|
static int spc_exec_count = 0;
|
||||||
if ((PC >= 0xFFCF && PC <= 0xFFFF) && spc_exec_count++ < 50) {
|
bool in_critical_range = (PC >= 0xFFCF && PC <= 0xFFFF);
|
||||||
LOG_INFO("SPC", "Execute: PC=$%04X step=0 bstep=%d", PC, bstep);
|
bool is_transfer_loop = (PC >= 0xFFDB && PC <= 0xFFEB);
|
||||||
|
|
||||||
|
if (in_critical_range && spc_exec_count++ < 200) {
|
||||||
|
LOG_INFO("SPC", "Execute: PC=$%04X step=0 bstep=%d Y=%02X A=%02X", PC, bstep, Y, A);
|
||||||
|
}
|
||||||
|
if (is_transfer_loop && spc_exec_count < 500) {
|
||||||
|
// Read ports to log transfer state
|
||||||
|
uint8_t f4_val = callbacks_.read(0xF4);
|
||||||
|
uint8_t f5_val = callbacks_.read(0xF5);
|
||||||
|
LOG_INFO("SPC", "TRANSFER LOOP: PC=$%04X Y=%02X F4=%02X F5=%02X",
|
||||||
|
PC, Y, f4_val, f5_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only read new opcode if previous instruction is complete
|
// Only read new opcode if previous instruction is complete
|
||||||
@@ -1061,7 +1071,10 @@ void Spc700::ExecuteInstructions(uint8_t opcode) {
|
|||||||
}
|
}
|
||||||
case 0xc4: { // movs dp
|
case 0xc4: { // movs dp
|
||||||
LOG_INFO("SPC", "Case 0xC4 reached: bstep=%d PC=$%04X", bstep, PC);
|
LOG_INFO("SPC", "Case 0xC4 reached: bstep=%d PC=$%04X", bstep, PC);
|
||||||
MOVS(dp());
|
uint16_t adr = dp();
|
||||||
|
LOG_INFO("SPC", "About to call MOVS: bstep=%d adr=$%04X", bstep, adr);
|
||||||
|
MOVS(adr);
|
||||||
|
LOG_INFO("SPC", "After MOVS: bstep=%d", bstep);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0xc5: { // movs abs
|
case 0xc5: { // movs abs
|
||||||
@@ -1093,7 +1106,11 @@ void Spc700::ExecuteInstructions(uint8_t opcode) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0xcb: { // movsy dp
|
case 0xcb: { // movsy dp
|
||||||
MOVSY(dp());
|
uint16_t addr = dp();
|
||||||
|
if (addr == 0x00F4) {
|
||||||
|
LOG_INFO("SPC", "MOVSY writing Y=$%02X to F4 at PC=$%04X", Y, PC);
|
||||||
|
}
|
||||||
|
MOVSY(addr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0xcc: { // movsy abs
|
case 0xcc: { // movsy abs
|
||||||
@@ -1269,6 +1286,10 @@ void Spc700::ExecuteInstructions(uint8_t opcode) {
|
|||||||
case 0xef: { // sleep imp
|
case 0xef: { // sleep imp
|
||||||
// Emulate low-power idle without halting the core permanently.
|
// Emulate low-power idle without halting the core permanently.
|
||||||
// Advance timers/DSP via idle callbacks, but do not set stopped_.
|
// Advance timers/DSP via idle callbacks, but do not set stopped_.
|
||||||
|
static int sleep_log = 0;
|
||||||
|
if (sleep_log++ < 5) {
|
||||||
|
LOG_WARN("SPC", "SLEEP executed at PC=$%04X - entering low power mode", PC - 1);
|
||||||
|
}
|
||||||
read(PC);
|
read(PC);
|
||||||
for (int i = 0; i < 4; ++i) callbacks_.idle(true);
|
for (int i = 0; i < 4; ++i) callbacks_.idle(true);
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user