diff --git a/help/dbg-breakpoints.html b/help/dbg-breakpoints.html index d8287f4c..4acb47e5 100644 --- a/help/dbg-breakpoints.html +++ b/help/dbg-breakpoints.html @@ -51,13 +51,9 @@ BPX address[,len]
BPX [op] symbol

-

Add -Breakpoint trigger to stop executing when the PC is within the range of -the Address, Symbol, or Expression. i.e. Range is: [addr,addr+len)
- +

Add Breakpoint trigger to stop executing when the PC is within the range of the Address, Symbol, or Expression. i.e. Range is: [addr,addr+len)
Default length is 1.
- -Default comparision operator is equal ‘=’

+Default comparison operator is equal ‘=’

@@ -65,52 +61,40 @@ Default comparision operator is equal

BP

-

Currently -an Alias for BPX.
- -(In a future version, will also support Loading and Saving of -breakpoints.)

+

Currently an Alias for BPX.
+(In a future version, will also support Loading and Saving of breakpoints.)

-

BPM -address[,len]

+

BPM address[,len]

-

Add -Breakpoint trigger when memory is accessed by 6502.

+

Add Breakpoint trigger when memory is accessed by 6502.

-

BPMR -address[,len]

+

BPMR address[,len]

-

Add -Breakpoint trigger when memory is read by 6502.

+

Add Breakpoint trigger when memory is read by 6502.

-

BPMW -address[,len]

+

BPMW address[,len]

-

Add -Breakpoint trigger when memory is written by 6502.

+

Add Breakpoint trigger when memory is written by 6502.

-

BPR -reg [op] value

+

BPR reg [op] value

-

Add -Breakpoint trigger when Register’s ‘reg’ -value is compared to the Value.

+

Add Breakpoint trigger when Register’s ‘reg’ value is compared to the Value.

@@ -118,8 +102,7 @@ value is compared to the Value.

BPD

-

Disable -Breakpoint (grayed out).

+

Disable Breakpoint (grayed out).

@@ -127,21 +110,16 @@ Breakpoint (grayed out).

BPE

-

Enable -Breakpoint (colored red).

+

Enable Breakpoint (colored red).

-

BPC -#

+

BPC #

-

Clear -specified Breakpoint.
- -Note: The asterisk ‘*’ may be used to clear all -breakpoints.

+

Clear specified Breakpoint.
+Note: The asterisk ‘*’ may be used to clear all breakpoints.

@@ -149,8 +127,7 @@ breakpoints.

BPL

-

List -Breakpoints.

+

List Breakpoints.

@@ -158,8 +135,7 @@ Breakpoints.

BPIO

-

(In -a future version, will add Breakpoint trigger on memory read or write.)

+

(In a future version, will add Breakpoint trigger on memory read or write.)

@@ -167,9 +143,31 @@ a future version, will add Breakpoint trigger on memory read or write.)BPP

-

(In -a future version, will add Breakpoint trigger on specific flag cleared -or set.)

+

(In a future version, will add Breakpoint trigger on specific flag cleared or set.)

+ + + + +

BRK [1|2|3] [on|off]

+ + +

Break on BRK or Invalid 1-3 byte opcodes

+ + + + +

BRKOP [opcode]

+ + +

Break on Opcode

+ + + + +

BRKINT [0|1]

+ + +

Break on Interrupt

@@ -379,8 +377,7 @@ or set.)

-

BPR -A 0

+

BPR A 0

Adds Breakpoint when Accumulator is zero.

@@ -388,8 +385,7 @@ A 0

-

BPR -A ! 0

+

BPR A ! 0

Adds Breakpoint when Accumulator is not zero.

@@ -397,13 +393,36 @@ A ! 0

-

BPR -S < 1FF

+

BPR S < 1FF

Adds Breakpoint when Stack has had something pushed onto it.

+ + +

BRK ON

+ + +

Adds Breakpoint to break when the opcode to be executed is $00 or BRK.

+ + + + +

BRKOP 6C

+ + +

Adds Breakpoint to break when the opcode to be executed is $6C or JMP (ABS).

+ + + + +

BRKINT 1

+ + +

Adds Breakpoint to break just after an interrupt occurs.

+ +
diff --git a/source/CPU.cpp b/source/CPU.cpp index 1319be8e..865710a3 100644 --- a/source/CPU.cpp +++ b/source/CPU.cpp @@ -137,6 +137,7 @@ static volatile UINT32 g_bmNMI = 0; static volatile BOOL g_bNmiFlank = FALSE; // Positive going flank on NMI line static bool g_irqDefer1Opcode = false; +static bool g_interruptInLastExecutionBatch = false; // Last batch of executed cycles included an interrupt (IRQ/NMI) // @@ -198,6 +199,11 @@ void ResetCyclesExecutedForDebugger(void) g_nCyclesExecuted = 0; } +bool IsInterruptInLastExecution(void) +{ + return g_interruptInLastExecutionBatch; +} + // #include "CPU/cpu_general.inl" @@ -369,25 +375,29 @@ static __forceinline void Fetch(BYTE& iOpcode, ULONG uExecutedCycles) } //#define ENABLE_NMI_SUPPORT // Not used - so don't enable -static __forceinline void NMI(ULONG& uExecutedCycles, BOOL& flagc, BOOL& flagn, BOOL& flagv, BOOL& flagz) +static __forceinline bool NMI(ULONG& uExecutedCycles, BOOL& flagc, BOOL& flagn, BOOL& flagv, BOOL& flagz) { #ifdef ENABLE_NMI_SUPPORT - if(g_bNmiFlank) - { - // NMI signals are only serviced once - g_bNmiFlank = FALSE; + if (!g_bNmiFlank) + return false; + + // NMI signals are only serviced once + g_bNmiFlank = FALSE; #ifdef _DEBUG - g_nCycleIrqStart = g_nCumulativeCycles + uExecutedCycles; + g_nCycleIrqStart = g_nCumulativeCycles + uExecutedCycles; #endif - PUSH(regs.pc >> 8) - PUSH(regs.pc & 0xFF) - EF_TO_AF - PUSH(regs.ps & ~AF_BREAK) - regs.ps = regs.ps | AF_INTERRUPT & ~AF_DECIMAL; - regs.pc = * (WORD*) (mem+0xFFFA); - UINT uExtraCycles = 0; // Needed for CYC(a) macro - CYC(7) - } + PUSH(regs.pc >> 8) + PUSH(regs.pc & 0xFF) + EF_TO_AF + PUSH(regs.ps & ~AF_BREAK) + regs.ps = regs.ps | AF_INTERRUPT & ~AF_DECIMAL; + regs.pc = * (WORD*) (mem+0xFFFA); + UINT uExtraCycles = 0; // Needed for CYC(a) macro + CYC(7); + g_interruptInLastExecutionBatch = true; + return true; +#else + return false; #endif } @@ -399,16 +409,18 @@ static __forceinline void CheckSynchronousInterruptSources(UINT cycles, ULONG uE // NB. No need to save to save-state, as IRQ() follows CheckSynchronousInterruptSources(), and IRQ() always sets it to false. bool g_irqOnLastOpcodeCycle = false; -static __forceinline void IRQ(ULONG& uExecutedCycles, BOOL& flagc, BOOL& flagn, BOOL& flagv, BOOL& flagz) +static __forceinline bool IRQ(ULONG& uExecutedCycles, BOOL& flagc, BOOL& flagn, BOOL& flagv, BOOL& flagz) { - if(g_bmIRQ && !(regs.ps & AF_INTERRUPT)) + bool irqTaken = false; + + if (g_bmIRQ && !(regs.ps & AF_INTERRUPT)) { - // if 6522 interrupt occurs on opcode's last cycle, then defer IRQ by 1 opcode + // if interrupt (eg. from 6522) occurs on opcode's last cycle, then defer IRQ by 1 opcode if (g_irqOnLastOpcodeCycle && !g_irqDefer1Opcode) { g_irqOnLastOpcodeCycle = false; g_irqDefer1Opcode = true; // if INT occurs again on next opcode, then do NOT defer - return; + return false; } g_irqDefer1Opcode = false; @@ -424,7 +436,7 @@ static __forceinline void IRQ(ULONG& uExecutedCycles, BOOL& flagc, BOOL& flagn, regs.ps = (regs.ps | AF_INTERRUPT) & (~AF_DECIMAL); regs.pc = * (WORD*) (mem+0xFFFE); UINT uExtraCycles = 0; // Needed for CYC(a) macro - CYC(7) + CYC(7); #if defined(_DEBUG) && LOG_IRQ_TAKEN_AND_RTI std::string irq6522; MB_Get6522IrqDescription(irq6522); @@ -435,9 +447,12 @@ static __forceinline void IRQ(ULONG& uExecutedCycles, BOOL& flagc, BOOL& flagn, LogOutput("IRQ (%08X) (%s)\n", (UINT)g_nCycleIrqStart, pSrc); #endif CheckSynchronousInterruptSources(7, uExecutedCycles); + g_interruptInLastExecutionBatch = true; + irqTaken = true; } g_irqOnLastOpcodeCycle = false; + return irqTaken; } //=========================================================================== @@ -606,6 +621,7 @@ DWORD CpuExecute(const DWORD uCycles, const bool bVideoUpdate) #endif g_nCyclesExecuted = 0; + g_interruptInLastExecutionBatch = false; #ifdef _DEBUG MB_CheckCumulativeCycles(); diff --git a/source/CPU.h b/source/CPU.h index e04ba508..fdf282d3 100644 --- a/source/CPU.h +++ b/source/CPU.h @@ -59,3 +59,4 @@ void SetActiveCpu(eCpuType cpu); bool IsIrqAsserted(void); bool Is6502InterruptEnabled(void); void ResetCyclesExecutedForDebugger(void); +bool IsInterruptInLastExecution(void); diff --git a/source/CPU/cpu6502.h b/source/CPU/cpu6502.h index d7d036ff..96c7a58d 100644 --- a/source/CPU/cpu6502.h +++ b/source/CPU/cpu6502.h @@ -52,6 +52,16 @@ static DWORD Cpu6502(DWORD uTotalCycles, const bool bVideoUpdate) } else { + if (IRQ(uExecutedCycles, flagc, flagn, flagv, flagz) || NMI(uExecutedCycles, flagc, flagn, flagv, flagz)) + { + if (bVideoUpdate) + { + ULONG uElapsedCycles = uExecutedCycles - uPreviousCycles; + NTSC_VideoUpdateCycles(uElapsedCycles); + } + continue; // Allow AppleWin debugger's single-stepping to just step the pending IRQ + } + HEATMAP_X( regs.pc ); Fetch(iOpcode, uExecutedCycles); @@ -318,8 +328,6 @@ static DWORD Cpu6502(DWORD uTotalCycles, const bool bVideoUpdate) } CheckSynchronousInterruptSources(uExecutedCycles - uPreviousCycles, uExecutedCycles); - NMI(uExecutedCycles, flagc, flagn, flagv, flagz); - IRQ(uExecutedCycles, flagc, flagn, flagv, flagz); // NTSC_BEGIN if (bVideoUpdate) diff --git a/source/CPU/cpu65C02.h b/source/CPU/cpu65C02.h index 425a0b6c..fa1b4ff7 100644 --- a/source/CPU/cpu65C02.h +++ b/source/CPU/cpu65C02.h @@ -52,6 +52,16 @@ static DWORD Cpu65C02(DWORD uTotalCycles, const bool bVideoUpdate) } else { + if (IRQ(uExecutedCycles, flagc, flagn, flagv, flagz) || NMI(uExecutedCycles, flagc, flagn, flagv, flagz)) + { + if (bVideoUpdate) + { + ULONG uElapsedCycles = uExecutedCycles - uPreviousCycles; + NTSC_VideoUpdateCycles(uElapsedCycles); + } + continue; // Allow AppleWin debugger's single-stepping to just step the pending IRQ + } + HEATMAP_X( regs.pc ); Fetch(iOpcode, uExecutedCycles); @@ -318,8 +328,6 @@ static DWORD Cpu65C02(DWORD uTotalCycles, const bool bVideoUpdate) } CheckSynchronousInterruptSources(uExecutedCycles - uPreviousCycles, uExecutedCycles); - NMI(uExecutedCycles, flagc, flagn, flagv, flagz); - IRQ(uExecutedCycles, flagc, flagn, flagv, flagz); // NTSC_BEGIN if ( bVideoUpdate ) diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index 4a3cc4c8..dfd657f0 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -67,6 +67,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Any Speed Breakpoints int g_nDebugBreakOnInvalid = 0; // Bit Flags of Invalid Opcode to break on: // iOpcodeType = AM_IMPLIED (BRK), AM_1, AM_2, AM_3 int g_iDebugBreakOnOpcode = 0; + bool g_bDebugBreakOnInterrupt = false; static int g_bDebugBreakpointHit = 0; // See: BreakpointHit_t @@ -989,6 +990,32 @@ Update_t CmdBreakOpcode (int nArgs) // Breakpoint IFF Full-speed! } +//=========================================================================== +Update_t CmdBreakOnInterrupt(int nArgs) +{ + TCHAR sText[CONSOLE_WIDTH]; + + if (nArgs > 1) + return HelpLastCommand(); + + TCHAR sAction[CONSOLE_WIDTH] = TEXT("Current"); // default to display + + if (nArgs == 1) + { + g_bDebugBreakOnInterrupt = g_aArgs[1].nValue ? true : false; + _tcscpy(sAction, TEXT("Setting")); + } + + // Show what the current break opcode is + ConsoleBufferPushFormat(sText, TEXT("%s Break on Interrupt: %s") + , sAction + , g_bDebugBreakOnInterrupt ? "Enabled" : "Disabled" + ); + + return ConsoleUpdate(); +} + + // bool bBP = g_nBreakpoints && CheckBreakpoint(nOffset,nOffset == regs.pc); //=========================================================================== bool GetBreakpointInfo ( WORD nOffset, bool & bBreakpointActive_, bool & bBreakpointEnable_ ) @@ -8249,10 +8276,18 @@ void DebugContinueStepping(const bool bCallerWillUpdateDisplay/*=false*/) if (bDoSingleStep) { UpdateLBR(); + const WORD oldPC = regs.pc; SingleStep(g_bGoCmd_ReinitFlag); g_bGoCmd_ReinitFlag = false; + if (IsInterruptInLastExecution()) + { + g_LBR = oldPC; + if (g_bDebugBreakOnInterrupt) + g_bDebugBreakpointHit |= BP_HIT_INTERRUPT; + } + g_bDebugBreakpointHit |= CheckBreakpointsIO() | CheckBreakpointsReg(); } @@ -8278,6 +8313,8 @@ void DebugContinueStepping(const bool bCallerWillUpdateDisplay/*=false*/) sprintf_s(szStopMessage, sizeof(szStopMessage), "Read access at $%04X", g_uBreakMemoryAddress); else if (g_bDebugBreakpointHit & BP_HIT_PC_READ_FLOATING_BUS_OR_IO_MEM) pszStopReason = TEXT("PC reads from floating bus or I/O memory"); + else if (g_bDebugBreakpointHit & BP_HIT_INTERRUPT) + sprintf_s(szStopMessage, sizeof(szStopMessage), "Interrupt occurred at $%04X", g_LBR); else pszStopReason = TEXT("Unknown!"); diff --git a/source/Debugger/Debug.h b/source/Debugger/Debug.h index 0558b90b..5ff94c1f 100644 --- a/source/Debugger/Debug.h +++ b/source/Debugger/Debug.h @@ -38,6 +38,7 @@ , BP_HIT_MEMR = (1 << 4) , BP_HIT_MEMW = (1 << 5) , BP_HIT_PC_READ_FLOATING_BUS_OR_IO_MEM = (1 << 6) + , BP_HIT_INTERRUPT = (1 << 7) }; extern int g_nBreakpoints; diff --git a/source/Debugger/Debugger_Commands.cpp b/source/Debugger/Debugger_Commands.cpp index 456ae7c4..ac056080 100644 --- a/source/Debugger/Debugger_Commands.cpp +++ b/source/Debugger/Debugger_Commands.cpp @@ -80,6 +80,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Breakpoints {TEXT("BRK") , CmdBreakInvalid , CMD_BREAK_INVALID , "Enter debugger on BRK or INVALID" }, {TEXT("BRKOP") , CmdBreakOpcode , CMD_BREAK_OPCODE , "Enter debugger on opcode" }, + {TEXT("BRKINT") , CmdBreakOnInterrupt , CMD_BREAK_ON_INTERRUPT , "Enter debugger on interrupt" }, {TEXT("BP") , CmdBreakpoint , CMD_BREAKPOINT , "Alias for BPR (Breakpoint Register Add)" }, {TEXT("BPA") , CmdBreakpointAddSmart, CMD_BREAKPOINT_ADD_SMART , "Add (smart) breakpoint" }, // {TEXT("BPP") , CmdBreakpointAddFlag , CMD_BREAKPOINT_ADD_FLAG , "Add breakpoint on flags" }, diff --git a/source/Debugger/Debugger_Types.h b/source/Debugger/Debugger_Types.h index dc27a878..8ac67eb2 100644 --- a/source/Debugger/Debugger_Types.h +++ b/source/Debugger/Debugger_Types.h @@ -323,6 +323,7 @@ // Breakpoints , CMD_BREAK_INVALID , CMD_BREAK_OPCODE + , CMD_BREAK_ON_INTERRUPT , CMD_BREAKPOINT , CMD_BREAKPOINT_ADD_SMART // smart breakpoint , CMD_BREAKPOINT_ADD_REG // break on: PC == Address (fetch/execute) @@ -599,6 +600,7 @@ Update_t CmdCursorSetPC (int nArgs); Update_t CmdBreakInvalid (int nArgs); // Breakpoint IFF Full-speed! Update_t CmdBreakOpcode (int nArgs); // Breakpoint IFF Full-speed! + Update_t CmdBreakOnInterrupt (int nArgs); Update_t CmdGoNormalSpeed (int nArgs); Update_t CmdGoFullSpeed (int nArgs); Update_t CmdIn (int nArgs); diff --git a/test/TestCPU6502/TestCPU6502.cpp b/test/TestCPU6502/TestCPU6502.cpp index 7eafbd69..2258d80c 100644 --- a/test/TestCPU6502/TestCPU6502.cpp +++ b/test/TestCPU6502/TestCPU6502.cpp @@ -54,12 +54,14 @@ static __forceinline void CheckSynchronousInterruptSources(UINT cycles, ULONG uE { } -static __forceinline void NMI(ULONG& uExecutedCycles, BOOL& flagc, BOOL& flagn, BOOL& flagv, BOOL& flagz) +static __forceinline bool NMI(ULONG& uExecutedCycles, BOOL& flagc, BOOL& flagn, BOOL& flagv, BOOL& flagz) { + return false; } -static __forceinline void IRQ(ULONG& uExecutedCycles, BOOL& flagc, BOOL& flagn, BOOL& flagv, BOOL& flagz) +static __forceinline bool IRQ(ULONG& uExecutedCycles, BOOL& flagc, BOOL& flagn, BOOL& flagv, BOOL& flagz) { + return false; } // From z80.cpp