diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index f4205905..ddf916b3 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -1127,11 +1127,11 @@ int CheckBreakpointsIO () int iTarget; int nAddress; - // bIgnoreNextOpcodeAddress = true: + // bIncludeNextOpcodeAddress == false: // . JSR addr16: ignore addr16 as a target - // . RTS/RTI : ignore return as a target - _6502_GetTargets( regs.pc, &aTarget[0], &aTarget[1], &aTarget[2], &nBytes, true, true, true ); - + // . BRK/RTS/RTI: ignore return (or vector) addr16 as a target + _6502_GetTargets( regs.pc, &aTarget[0], &aTarget[1], &aTarget[2], &nBytes, true, true, false ); + if (nBytes) { for (iTarget = 0; iTarget < NUM_TARGETS; iTarget++ ) diff --git a/source/Debugger/Debugger_Assembler.cpp b/source/Debugger/Debugger_Assembler.cpp index 2a292e66..5639ecaf 100644 --- a/source/Debugger/Debugger_Assembler.cpp +++ b/source/Debugger/Debugger_Assembler.cpp @@ -42,7 +42,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Addressing _____________________________________________________________________________________ AddressingMode_t g_aOpmodes[ NUM_ADDRESSING_MODES ] = - { // Outut, but eventually used for Input when Assembler is working. + { // Output, but eventually used for Input when Assembler is working. {TEXT("") , 1 , "(implied)" }, // (implied) {TEXT("") , 1 , "n/a 1" }, // INVALID1 {TEXT("") , 2 , "n/a 2" }, // INVALID2 @@ -584,7 +584,7 @@ bool _6502_GetStackReturnAddress ( WORD & nAddress_ ) //=========================================================================== bool _6502_GetTargets ( WORD nAddress, int *pTargetPartial_, int *pTargetPartial2_, int *pTargetPointer_, int * pTargetBytes_, - bool bIgnoreJSRJMP /*= true*/, bool bIgnoreBranch /*= true*/, bool bIgnoreNextOpcodeAddress /*= false*/ ) + bool bIgnoreJSRJMP /*= true*/, bool bIgnoreBranch /*= true*/, bool bIncludeNextOpcodeAddress /*= true*/ ) { bool bStatus = false; @@ -657,29 +657,35 @@ bool _6502_GetTargets ( WORD nAddress, int *pTargetPartial_, int *pTargetPartial nTarget16 = _6502_STACK_BEGIN + ((regs.sp+1) & 0xFF); } - *pTargetPointer_ = nTarget16; + if (bIncludeNextOpcodeAddress || (nOpcode != OPCODE_RTI && nOpcode != OPCODE_RTS && nOpcode != OPCODE_BRK)) + *pTargetPointer_ = nTarget16; if (pTargetBytes_) *pTargetBytes_ = 1; } break; - case AM_A: // $Absolute + case AM_A: // Absolute if (nOpcode == OPCODE_JSR) // JSR? { *pTargetPartial_ = _6502_STACK_BEGIN + ((regs.sp+0) & 0xFF); *pTargetPartial2_ = _6502_STACK_BEGIN + ((regs.sp-1) & 0xFF); } - *pTargetPointer_ = nTarget16; + if (bIncludeNextOpcodeAddress || (nOpcode != OPCODE_JSR)) + *pTargetPointer_ = nTarget16; + if (pTargetBytes_) *pTargetBytes_ = 2; break; - case AM_IAX: // Indexed (Absolute) Indirect + case AM_IAX: // Indexed (Absolute) Indirect - ie. JMP (abs,x) + _ASSERT(nOpcode == OPCODE_JMP_IAX); nTarget16 += regs.x; *pTargetPartial_ = nTarget16; - *pTargetPointer_ = *(LPWORD)(mem + nTarget16); + *pTargetPartial2_ = nTarget16+1; + if (bIncludeNextOpcodeAddress) + *pTargetPointer_ = *(LPWORD)(mem + nTarget16); if (pTargetBytes_) *pTargetBytes_ = 2; break; @@ -698,9 +704,12 @@ bool _6502_GetTargets ( WORD nAddress, int *pTargetPartial_, int *pTargetPartial *pTargetBytes_ = 2; break; - case AM_NA: // Indirect (Absolute) i.e. JMP + case AM_NA: // Indirect (Absolute) - ie. JMP (abs) + _ASSERT(nOpcode == OPCODE_JMP_NA); *pTargetPartial_ = nTarget16; - *pTargetPointer_ = *(LPWORD)(mem + nTarget16); + *pTargetPartial2_ = nTarget16+1; + if (bIncludeNextOpcodeAddress) + *pTargetPointer_ = *(LPWORD)(mem + nTarget16); if (pTargetBytes_) *pTargetBytes_ = 2; break; @@ -728,7 +737,7 @@ bool _6502_GetTargets ( WORD nAddress, int *pTargetPartial_, int *pTargetPartial break; case AM_R: - if (! bIgnoreBranch) + if (!bIgnoreBranch) { *pTargetPartial_ = nTarget8; *pTargetPointer_ = nAddress + 2; @@ -784,13 +793,6 @@ bool _6502_GetTargets ( WORD nAddress, int *pTargetPartial_, int *pTargetPartial } } - if (bIgnoreNextOpcodeAddress) - { - *pTargetPointer_ = NO_6502_TARGET; - if (pTargetBytes_) - *pTargetBytes_ = 0; - } - return bStatus; } diff --git a/source/Debugger/Debugger_Assembler.h b/source/Debugger/Debugger_Assembler.h index c4976d1b..4a78ff14 100644 --- a/source/Debugger/Debugger_Assembler.h +++ b/source/Debugger/Debugger_Assembler.h @@ -194,7 +194,7 @@ extern int g_aAssemblerFirstDirective[ NUM_ASSEMBLERS ]; void _6502_GetOpcodeOpmodeOpbyte( int & iOpcode_, int & iOpmode_, int & nOpbytes_ ); bool _6502_GetStackReturnAddress( WORD & nAddress_ ); bool _6502_GetTargets( WORD nAddress, int *pTargetPartial_, int *pTargetPartial2_, int *pTargetPointer_, int * pBytes_ - , const bool bIgnoreJSRJMP = true, bool bIgnoreBranch = true, bool bIgnoreNextOpcodeAddress = false ); + , const bool bIgnoreJSRJMP = true, bool bIgnoreBranch = true, bool bIncludeNextOpcodeAddress = true ); bool _6502_GetTargetAddress( const WORD & nAddress, WORD & nTarget_ ); bool _6502_IsOpcodeBranch( int nOpcode ); bool _6502_IsOpcodeValid( int nOpcode ); diff --git a/source/Debugger/Debugger_Types.h b/source/Debugger/Debugger_Types.h index 952b7ab9..7e5a8a34 100644 --- a/source/Debugger/Debugger_Types.h +++ b/source/Debugger/Debugger_Types.h @@ -1069,6 +1069,7 @@ const DisasmData_t* pDisasmData; // If != NULL then bytes are marked up as data OPCODE_RTS = 0x60, OPCODE_JMP_NA = 0x6C, // Indirect Absolute OPCODE_JMP_IAX = 0x7C, // Indexed (Absolute Indirect, X) + OPCODE_LDA_A = 0xAD, // Absolute OPCODE_NOP = 0xEA, // No operation }; diff --git a/test/TestDebugger/TestDebugger.cpp b/test/TestDebugger/TestDebugger.cpp index dfc1e7e9..a212cffc 100644 --- a/test/TestDebugger/TestDebugger.cpp +++ b/test/TestDebugger/TestDebugger.cpp @@ -128,12 +128,14 @@ int GH445_test_PLn(BYTE op) return 0; } -int GH445_test_abs(BYTE op, WORD target2) +int GH445_test_abs(BYTE op) { bool bRes; int TargetAddr[3]; int TargetBytes; + const WORD target2 = 0x1234; + mem[regs.pc] = op; mem[(regs.pc+1)&0xFFFF] = (BYTE) (target2&0xff); mem[(regs.pc+2)&0xFFFF] = (BYTE) ((target2>>8)&0xff); @@ -143,46 +145,153 @@ int GH445_test_abs(BYTE op, WORD target2) return 0; } +// NB. bIgnoreJSRJMP == false, ie. TargetAddr[2] gets set int GH445_test_jsr(void) { bool bRes; int TargetAddr[3]; int TargetBytes; - mem[regs.pc] = 0x20; + WORD target2 = 0x1234; + + mem[regs.pc] = OPCODE_JSR; + mem[(regs.pc+1)&0xFFFF] = (BYTE) (target2&0xff); + mem[(regs.pc+2)&0xFFFF] = (BYTE) ((target2>>8)&0xff); regs.sp = 0x1FF; bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, false); - if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != regs.sp-1) return 1; + if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != regs.sp-1 || TargetAddr[2] != target2) return 1; regs.sp = 0x100; bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, false); - if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != 0x1FF) return 1; + if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != 0x1FF || TargetAddr[2] != target2) return 1; regs.sp = 0x101; bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, false); - if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != regs.sp-1) return 1; + if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != regs.sp-1 || TargetAddr[2] != target2) return 1; return 0; } -int GH445_test_rts(WORD sp) +int GH445_test_brk(void) { bool bRes; int TargetAddr[3]; int TargetBytes; - mem[regs.pc] = 0x60; + mem[regs.pc] = OPCODE_BRK; + regs.sp = 0x1FF; + bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes); + if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != regs.sp-1) return 1; + + regs.sp = 0x100; + bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes); + if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != 0x1FF) return 1; + + regs.sp = 0x101; + bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes); + if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != regs.sp-1) return 1; + + return 0; +} + +int GH445_test_rti_rts(WORD sp, const bool isRTI) +{ + bool bRes; + int TargetAddr[3]; + int TargetBytes; + + mem[regs.pc] = isRTI ? OPCODE_RTI : OPCODE_RTS; regs.sp = sp; - WORD sp_addr_l = 0x100 + ((regs.sp+1)&0xFF); - WORD sp_addr_h = 0x100 + ((regs.sp+2)&0xFF); - WORD rts_addr = 0x1234; - mem[sp_addr_l] = (BYTE) (rts_addr&0xFF); - mem[sp_addr_h] = (BYTE) ((rts_addr>>8)&0xFF); - rts_addr++; // NB. return addr from stack is incremented before being transferred to PC + + WORD sp_addr_p=0, sp_addr_l=0, sp_addr_h=0; + if (isRTI) + { + sp_addr_p = 0x100 + ((regs.sp+1)&0xFF); + sp_addr_l = 0x100 + ((regs.sp+2)&0xFF); + sp_addr_h = 0x100 + ((regs.sp+3)&0xFF); + mem[sp_addr_p] = 0xEA; + } + else + { + sp_addr_l = 0x100 + ((regs.sp+1)&0xFF); + sp_addr_h = 0x100 + ((regs.sp+2)&0xFF); + } + + WORD ret_addr = 0x1234; + mem[sp_addr_l] = (BYTE) (ret_addr&0xFF); + mem[sp_addr_h] = (BYTE) ((ret_addr>>8)&0xFF); + + if (!isRTI) + ret_addr++; // NB. return addr from stack is incremented before being transferred to PC + + bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes); + if (!bRes || TargetAddr[0] != sp_addr_l || TargetAddr[1] != sp_addr_h || TargetAddr[2] != ret_addr) return 1; + + return 0; +} + +// NB. bIgnoreJSRJMP == false, ie. TargetAddr[2] gets set +int GH445_test_jmp(BYTE op) +{ + bool bRes; + int TargetAddr[3]; + int TargetBytes; + + const WORD target16 = 0x1234; + + int target0, target1, target2; + if (op == OPCODE_JMP_A) + { + target0 = NO_6502_TARGET; + target1 = NO_6502_TARGET; + target2 = target16; + } + else if (op == OPCODE_JMP_NA) + { + target0 = target16; + target1 = (target16+1)&0xffff; + target2 = 0x5678; + mem[target0] = target2 & 0xff; + mem[target1] = (target2>>8) & 0xff; + } + else if (op == OPCODE_JMP_IAX) + { + target0 = (target16+regs.x)&0xffff; + target1 = (target16+regs.x+1)&0xffff; + target2 = 0xABCD; + mem[target0] = target2 & 0xff; + mem[target1] = (target2>>8) & 0xff; + } + + mem[regs.pc] = op; + mem[(regs.pc+1)&0xFFFF] = (BYTE) (target16&0xff); + mem[(regs.pc+2)&0xFFFF] = (BYTE) ((target16>>8)&0xff); bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, false); - if (!bRes || TargetAddr[0] != sp_addr_l || TargetAddr[1] != sp_addr_h || TargetAddr[2] != rts_addr) return 1; + if (!bRes || TargetAddr[0] != target0 || TargetAddr[1] != target1 || TargetAddr[2] != target2) return 1; + + return 0; +} + +// bIgnoreBranch == true (default) +int GH445_test_Bcc(void) +{ + bool bRes; + int TargetAddr[3]; + int TargetBytes; + + mem[regs.pc] = 0x10; // BPL next-op + mem[regs.pc+1] = 0; + + bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes); + if (!bRes || TargetAddr[0] != NO_6502_TARGET || TargetAddr[1] != NO_6502_TARGET || TargetAddr[2] != NO_6502_TARGET) return 1; + + mem[regs.pc] = 0x10; // BPL this-op + mem[regs.pc+1] = 0xfe; + + bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes); + if (!bRes || TargetAddr[0] != NO_6502_TARGET || TargetAddr[1] != NO_6502_TARGET || TargetAddr[2] != NO_6502_TARGET) return 1; return 0; } @@ -197,11 +306,11 @@ int GH445_test_sub(bool bIs65C02) mem[0x200] = 0xDD; // Bad data if SP wrap not working mem[0x201] = 0xDD; + regs.pc = 0x300; + // // PHn/PLn - regs.pc = 0x300; - res = GH445_test_PHn(0x08); // PHP if (res) return res; res = GH445_test_PHn(0x48); // PHA @@ -231,34 +340,76 @@ int GH445_test_sub(bool bIs65C02) } // - // ABS + // LDA abs regs.pc = 0xFFFD; - res = GH445_test_abs(0xAD, 0x1234); // LDA ABS + res = GH445_test_abs(OPCODE_LDA_A); // LDA ABS if (res) return res; regs.pc = 0xFFFE; - res = GH445_test_abs(0xAD, 0x1234); // LDA ABS + res = GH445_test_abs(OPCODE_LDA_A); // LDA ABS if (res) return res; regs.pc = 0xFFFF; - res = GH445_test_abs(0xAD, 0x1234); // LDA ABS + res = GH445_test_abs(OPCODE_LDA_A); // LDA ABS if (res) return res; // - // JSR ABS + // JSR abs res = GH445_test_jsr(); if (res) return res; + // + // BRK + + mem[_6502_BRK_VECTOR+0] = 0x40; // BRK vector: $FA40 + mem[_6502_BRK_VECTOR+1] = 0xFA; + + regs.pc = 0x300; + res = GH445_test_brk(); + if (res) return res; + + // + // RTI + + res = GH445_test_rti_rts(0x1FE, true); + if (res) return res; + res = GH445_test_rti_rts(0x1FF, true); + if (res) return res; + res = GH445_test_rti_rts(0x100, true); + if (res) return res; + // // RTS - res = GH445_test_rts(0x1FE); + res = GH445_test_rti_rts(0x1FE, false); if (res) return res; - res = GH445_test_rts(0x1FF); + res = GH445_test_rti_rts(0x1FF, false); if (res) return res; - res = GH445_test_rts(0x100); + res = GH445_test_rti_rts(0x100, false); + if (res) return res; + + // + // JMP + + res = GH445_test_jmp(OPCODE_JMP_A); // JMP abs + if (res) return res; + + res = GH445_test_jmp(OPCODE_JMP_NA); // JMP (abs) + if (res) return res; + + if (bIs65C02) + { + regs.x = 0xff; + res = GH445_test_jmp(OPCODE_JMP_IAX); // JMP (abs,x) + if (res) return res; + } + + // + // Bcc + + res = GH445_test_Bcc(); if (res) return res; return 0; @@ -280,6 +431,264 @@ int GH445_test(void) //------------------------------------- +// +// bIncludeNextOpcodeAddress == false, check that: +// . TargetAddr[2] gets set, eg. for LDA abs +// . TargetAddr[2] == NO_6502_TARGET for control flow instructions, eg. BRK,RTI,RTS,JSR,JMP,Bcc +// + +int GH451_test_abs(BYTE op) +{ + bool bRes; + int TargetAddr[3]; + int TargetBytes; + + const WORD target2 = 0x1234; + + mem[regs.pc] = op; + mem[(regs.pc+1)&0xFFFF] = (BYTE) (target2&0xff); + mem[(regs.pc+2)&0xFFFF] = (BYTE) ((target2>>8)&0xff); + bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, true, true, false); + if (!bRes || TargetAddr[2] != target2) return 1; + + return 0; +} + +int GH451_test_jsr(void) +{ + bool bRes; + int TargetAddr[3]; + int TargetBytes; + + mem[regs.pc] = OPCODE_JSR; + + regs.sp = 0x1FF; + bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, true, true, false); + if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != regs.sp-1 || TargetAddr[2] != NO_6502_TARGET) return 1; + + regs.sp = 0x100; + bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, true, true, false); + if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != 0x1FF || TargetAddr[2] != NO_6502_TARGET) return 1; + + regs.sp = 0x101; + bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, true, true, false); + if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != regs.sp-1 || TargetAddr[2] != NO_6502_TARGET) return 1; + + return 0; +} + +int GH451_test_brk(void) +{ + bool bRes; + int TargetAddr[3]; + int TargetBytes; + + mem[regs.pc] = OPCODE_BRK; + + regs.sp = 0x1FF; + bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, true, true, false); + if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != regs.sp-1 || TargetAddr[2] != NO_6502_TARGET) return 1; + + regs.sp = 0x100; + bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, true, true, false); + if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != 0x1FF || TargetAddr[2] != NO_6502_TARGET) return 1; + + regs.sp = 0x101; + bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, true, true, false); + if (!bRes || TargetAddr[0] != regs.sp || TargetAddr[1] != regs.sp-1 || TargetAddr[2] != NO_6502_TARGET) return 1; + + return 0; +} + +int GH451_test_rti_rts(WORD sp, const bool isRTI) +{ + bool bRes; + int TargetAddr[3]; + int TargetBytes; + + mem[regs.pc] = isRTI ? OPCODE_RTI : OPCODE_RTS; + regs.sp = sp; + + WORD sp_addr_p=0, sp_addr_l=0, sp_addr_h=0; + if (isRTI) + { + sp_addr_p = 0x100 + ((regs.sp+1)&0xFF); + sp_addr_l = 0x100 + ((regs.sp+2)&0xFF); + sp_addr_h = 0x100 + ((regs.sp+3)&0xFF); + mem[sp_addr_p] = 0xEA; + } + else + { + sp_addr_l = 0x100 + ((regs.sp+1)&0xFF); + sp_addr_h = 0x100 + ((regs.sp+2)&0xFF); + } + + WORD ret_addr = 0x1234; + mem[sp_addr_l] = (BYTE) (ret_addr&0xFF); + mem[sp_addr_h] = (BYTE) ((ret_addr>>8)&0xFF); + + if (!isRTI) + ret_addr++; // NB. return addr from stack is incremented before being transferred to PC + + bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, true, true, false); + if (!bRes || TargetAddr[0] != sp_addr_l || TargetAddr[1] != sp_addr_h || TargetAddr[2] != NO_6502_TARGET) return 1; + + return 0; +} + +// bIgnoreJSRJMP == true +int GH451_test_jmp(BYTE op) +{ + bool bRes; + int TargetAddr[3]; + int TargetBytes; + + const WORD target16 = 0x1234; + + int target0, target1; + if (op == OPCODE_JMP_A) + { + target0 = NO_6502_TARGET; + target1 = NO_6502_TARGET; + } + else if (op == OPCODE_JMP_NA) + { + target0 = target16; + target1 = (target16+1)&0xffff; + } + else if (op == OPCODE_JMP_IAX) + { + target0 = (target16+regs.x)&0xffff; + target1 = (target16+regs.x+1)&0xffff; + } + + mem[regs.pc] = op; + mem[(regs.pc+1)&0xFFFF] = (BYTE) (target16&0xff); + mem[(regs.pc+2)&0xFFFF] = (BYTE) ((target16>>8)&0xff); + bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, true, true, false); + if (!bRes || TargetAddr[0] != target0 || TargetAddr[1] != target1 || TargetAddr[2] != NO_6502_TARGET) return 1; + + return 0; +} + +// bIgnoreBranch == true +int GH451_test_Bcc(void) +{ + bool bRes; + int TargetAddr[3]; + int TargetBytes; + + mem[regs.pc] = 0x10; // BPL next-op + mem[regs.pc+1] = 0; + + bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, true, true, false); + if (!bRes || TargetAddr[0] != NO_6502_TARGET || TargetAddr[1] != NO_6502_TARGET || TargetAddr[2] != NO_6502_TARGET) return 1; + + mem[regs.pc] = 0x10; // BPL this-op + mem[regs.pc+1] = 0xfe; + + bRes = _6502_GetTargets(regs.pc, &TargetAddr[0], &TargetAddr[1], &TargetAddr[2], &TargetBytes, true, true, false); + if (!bRes || TargetAddr[0] != NO_6502_TARGET || TargetAddr[1] != NO_6502_TARGET || TargetAddr[2] != NO_6502_TARGET) return 1; + + return 0; +} + +int GH451_test_sub(bool bIs65C02) +{ + int res; + + mem[0x10000] = 0xDD; // Bad data if 64K wrap not working + mem[0x10001] = 0xDD; + + mem[0x200] = 0xDD; // Bad data if SP wrap not working + mem[0x201] = 0xDD; + + regs.pc = 0x300; + + // + // LDA abs + + res = GH451_test_abs(OPCODE_LDA_A); + if (res) return res; + + // + // JSR abs + + res = GH451_test_jsr(); + if (res) return res; + + // + // BRK + + mem[_6502_BRK_VECTOR+0] = 0x40; // BRK vector: $FA40 + mem[_6502_BRK_VECTOR+1] = 0xFA; + + res = GH451_test_brk(); + if (res) return res; + + // + // RTI + + res = GH451_test_rti_rts(0x1FE, true); + if (res) return res; + res = GH451_test_rti_rts(0x1FF, true); + if (res) return res; + res = GH451_test_rti_rts(0x100, true); + if (res) return res; + + // + // RTS + + res = GH451_test_rti_rts(0x1FE, false); + if (res) return res; + res = GH451_test_rti_rts(0x1FF, false); + if (res) return res; + res = GH451_test_rti_rts(0x100, false); + if (res) return res; + + // + // JMP + + res = GH451_test_jmp(OPCODE_JMP_A); // JMP abs + if (res) return res; + + res = GH451_test_jmp(OPCODE_JMP_NA); // JMP (abs) + if (res) return res; + + if (bIs65C02) + { + regs.x = 0xff; + res = GH451_test_jmp(OPCODE_JMP_IAX); // JMP (abs),x + if (res) return res; + } + + // + // Bcc + + res = GH451_test_Bcc(); + if (res) return res; + + return 0; +} + +// debugger command 'bpm[r|w] addr16': JSR abs should not trigger a breakpoint at addr16 +// . similarly for all other control flow opcodes (eg. Bcc, BRK, JMP, RTI, RTS) +int GH451_test(void) +{ + int res; + + g_aOpcodes = g_aOpcodes65C02; + res = GH451_test_sub(true); + if (res) return res; + + g_aOpcodes = g_aOpcodes6502; + res = GH451_test_sub(false); + + return res; +} + +//------------------------------------- + int _tmain(int argc, _TCHAR* argv[]) { int res = 1; @@ -289,5 +698,8 @@ int _tmain(int argc, _TCHAR* argv[]) res = GH445_test(); if (res) return res; + res = GH451_test(); + if (res) return res; + return 0; }