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