From 3d6c10bad988df838787829f826796ead52133ba Mon Sep 17 00:00:00 2001 From: tomcw Date: Tue, 7 Mar 2017 21:35:38 +0000 Subject: [PATCH] Debugger: . Move the BRK and invalid opcodes checks out of main emulation's Fetch() and into DebugContinueStepping() . Added a new break condition: when PC reads floating bus or I/O memory . On a break condition, output a 'Stop Reason' message to the console --- source/CPU.cpp | 28 +------- source/CPU/cpu6502.h | 11 +-- source/CPU/cpu65C02.h | 11 +-- source/CPU/cpu65d02.h | 11 +-- source/Debugger/Debug.cpp | 119 +++++++++++++++++++++++++++---- source/Debugger/Debug.h | 52 +------------- source/Frame.cpp | 1 - test/TestCPU6502/TestCPU6502.cpp | 28 -------- 8 files changed, 117 insertions(+), 144 deletions(-) diff --git a/source/CPU.cpp b/source/CPU.cpp index 104ce158..402ca743 100644 --- a/source/CPU.cpp +++ b/source/CPU.cpp @@ -102,7 +102,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Z80VICE\z80.h" #include "Z80VICE\z80mem.h" -#include "Debugger\Debug.h" #include "YamlHelper.h" // 6502 Accumulator Bit Flags @@ -200,26 +199,9 @@ void SetActiveCpu(eCpuType cpu) #include "cpu/cpu_instructions.inl" -void RequestDebugger() -{ - // BUG: This causes DebugBegin to constantly be called. - // It's as if the WM_KEYUP are auto-repeating? - // FrameWndProc() - // ProcessButtonClick() - // DebugBegin() - // PostMessage( g_hFrameWindow, WM_KEYDOWN, DEBUG_TOGGLE_KEY, 0 ); - // PostMessage( g_hFrameWindow, WM_KEYUP , DEBUG_TOGGLE_KEY, 0 ); - - // Not a valid solution, since hitting F7 (to exit) debugger gets the debugger out of sync - // due to EnterMessageLoop() calling ContinueExecution() after the mode has changed to DEBUG. - // DebugBegin(); - - FrameWndProc( g_hFrameWindow, WM_KEYDOWN, DEBUG_TOGGLE_KEY, 0 ); - FrameWndProc( g_hFrameWindow, WM_KEYUP , DEBUG_TOGGLE_KEY, 0 ); -} - // Break into debugger on invalid opcodes -#define INV IsDebugBreakOnInvalid(AM_1); +//#define INV IsDebugBreakOnInvalid(AM_1); +#define INV /**************************************************************************** * @@ -373,7 +355,7 @@ static void DebugHddEntrypoint(const USHORT PC) } #endif -static __forceinline int Fetch(BYTE& iOpcode, ULONG uExecutedCycles) +static __forceinline void Fetch(BYTE& iOpcode, ULONG uExecutedCycles) { const USHORT PC = regs.pc; @@ -385,16 +367,12 @@ static __forceinline int Fetch(BYTE& iOpcode, ULONG uExecutedCycles) ? IORead[(PC>>4) & 0xFF](PC,PC,0,0,uExecutedCycles) // Fetch opcode from I/O memory, but params are still from mem[] : *(mem+PC); - if (IsDebugBreakOpcode( iOpcode )) - return 0; - #ifdef USE_SPEECH_API if (PC == COUT && g_Speech.IsEnabled() && !g_bFullSpeed) CaptureCOUT(); #endif regs.pc++; - return 1; } //#define ENABLE_NMI_SUPPORT // Not used - so don't enable diff --git a/source/CPU/cpu6502.h b/source/CPU/cpu6502.h index 6451c1cf..a9b87701 100644 --- a/source/CPU/cpu6502.h +++ b/source/CPU/cpu6502.h @@ -36,7 +36,6 @@ static DWORD Cpu6502(DWORD uTotalCycles, const bool bVideoUpdate) AF_TO_EF ULONG uExecutedCycles = 0; WORD base; - g_bDebugBreakpointHit = 0; do { @@ -53,10 +52,10 @@ static DWORD Cpu6502(DWORD uTotalCycles, const bool bVideoUpdate) } else { - if (!Fetch(iOpcode, uExecutedCycles)) - break; + Fetch(iOpcode, uExecutedCycles); -#define $ INV // INV = Invalid -> Debugger Break +//#define $ INV // INV = Invalid -> Debugger Break +#define $ switch (iOpcode) { case 0x00: BRK CYC(7) break; @@ -335,10 +334,6 @@ static DWORD Cpu6502(DWORD uTotalCycles, const bool bVideoUpdate) EF_TO_AF - if( g_bDebugBreakpointHit ) - if ((g_nAppMode != MODE_DEBUG) && (g_nAppMode != MODE_STEPPING)) // Running at full speed? (debugger not running) - RequestDebugger(); - return uExecutedCycles; } diff --git a/source/CPU/cpu65C02.h b/source/CPU/cpu65C02.h index 92106513..67279db3 100644 --- a/source/CPU/cpu65C02.h +++ b/source/CPU/cpu65C02.h @@ -39,7 +39,6 @@ static DWORD Cpu65C02(DWORD uTotalCycles, const bool bVideoUpdate) AF_TO_EF ULONG uExecutedCycles = 0; WORD base; - g_bDebugBreakpointHit = 0; do { @@ -56,10 +55,10 @@ static DWORD Cpu65C02(DWORD uTotalCycles, const bool bVideoUpdate) } else { - if (!Fetch(iOpcode, uExecutedCycles)) - break; + Fetch(iOpcode, uExecutedCycles); -#define $ INV // INV = Invalid -> Debugger Break +//#define $ INV // INV = Invalid -> Debugger Break +#define $ switch (iOpcode) { case 0x00: BRK CYC(7) break; @@ -338,10 +337,6 @@ static DWORD Cpu65C02(DWORD uTotalCycles, const bool bVideoUpdate) EF_TO_AF // Emulator Flags to Apple Flags - if( g_bDebugBreakpointHit ) - if ((g_nAppMode != MODE_DEBUG) && (g_nAppMode != MODE_STEPPING)) // Running at full speed? (debugger not running) - RequestDebugger(); - return uExecutedCycles; } diff --git a/source/CPU/cpu65d02.h b/source/CPU/cpu65d02.h index 9f83f88c..7161f824 100644 --- a/source/CPU/cpu65d02.h +++ b/source/CPU/cpu65d02.h @@ -113,7 +113,6 @@ static DWORD Cpu65D02(DWORD uTotalCycles, const bool bVideoUpdate) AF_TO_EF ULONG uExecutedCycles = 0; WORD base; - g_bDebugBreakpointHit = 0; do { @@ -132,15 +131,15 @@ static DWORD Cpu65D02(DWORD uTotalCycles, const bool bVideoUpdate) HEATMAP_X( regs.pc ); - if (!Fetch(iOpcode, uExecutedCycles)) - break; + Fetch(iOpcode, uExecutedCycles); // INV = Invalid -> Debugger Break // MSVC C PreProcessor is BROKEN... #define @ INV //#define # INV //#define @ Read() //#define $ Store() -#define $ INV +//#define $ INV // INV = Invalid -> Debugger Break +#define $ switch (iOpcode) { @@ -423,9 +422,5 @@ static DWORD Cpu65D02(DWORD uTotalCycles, const bool bVideoUpdate) EF_TO_AF // Emulator Flags to Apple Flags - if( g_bDebugBreakpointHit ) - if ((g_nAppMode != MODE_DEBUG) && (g_nAppMode != MODE_STEPPING)) // // Running at full speed? (debugger not running) - RequestDebugger(); - return uExecutedCycles; } diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index bc9e00d6..68e47cfe 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -67,8 +67,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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_bDebugBreakDelayCheck = false; // If exiting the debugger, allow at least one instruction to execute so we don't trigger on the same invalid opcode - int g_bDebugBreakpointHit = 0; // See: BreakpointHit_t + static int g_bDebugBreakpointHit = 0; // See: BreakpointHit_t int g_nBreakpoints = 0; Breakpoint_t g_aBreakpoints[ MAX_BREAKPOINTS ]; @@ -868,6 +867,24 @@ _Help: //=========================================================================== + +// iOpcodeType = AM_IMPLIED (BRK), AM_1, AM_2, AM_3 +static int IsDebugBreakOnInvalid( int iOpcodeType ) +{ + g_bDebugBreakpointHit |= ((g_nDebugBreakOnInvalid >> iOpcodeType) & 1) ? BP_HIT_INVALID : 0; + return g_bDebugBreakpointHit; +} + +// iOpcodeType = AM_IMPLIED (BRK), AM_1, AM_2, AM_3 +static void SetDebugBreakOnInvalid( int iOpcodeType, int nValue ) +{ + if (iOpcodeType <= AM_3) + { + g_nDebugBreakOnInvalid &= ~ ( 1 << iOpcodeType); + g_nDebugBreakOnInvalid |= ((nValue & 1) << iOpcodeType); + } +} + Update_t CmdBreakInvalid (int nArgs) // Breakpoint IFF Full-speed! { if (nArgs > 2) // || (nArgs == 0)) @@ -8469,9 +8486,27 @@ void DebugExitDebugger () } //=========================================================================== + +static void CheckBreakOpcode( int iOpcode ) +{ + if (iOpcode == 0x00) // BRK + IsDebugBreakOnInvalid( AM_IMPLIED ); + + if (g_aOpcodes[iOpcode].sMnemonic[0] >= 'a') // All 6502/65C02 undocumented opcodes mnemonics are lowercase strings! + { + // TODO: Translate g_aOpcodes[iOpcode].nAddressMode into {AM_1, AM_2, AM_3} + IsDebugBreakOnInvalid( AM_1 ); + } + + // User wants to enter debugger on specific opcode? (NB. Can't be BRK) + if (g_iDebugBreakOnOpcode && g_iDebugBreakOnOpcode == iOpcode) + g_bDebugBreakpointHit |= BP_HIT_OPCODE; +} + void DebugContinueStepping () { static unsigned nStepsTaken = 0; + static bool bForceSingleStepNext = false; // Allow at least one instruction to execute so we don't trigger on the same invalid opcode if (g_nDebugSkipLen > 0) { @@ -8491,26 +8526,80 @@ void DebugContinueStepping () if (g_nDebugSteps) { - if (g_hTraceFile) - OutputTraceLine(); + bool bDoSingleStep = true; - // Update profiling stats + if (bForceSingleStepNext) { - BYTE nOpcode = *(mem+regs.pc); - int nOpmode = g_aOpcodes[ nOpcode ].nAddressMode; + bForceSingleStepNext = false; + g_bDebugBreakpointHit = BP_HIT_NONE; // Don't show 'Stop Reason' msg a 2nd time + } + else if (GetActiveCpu() != CPU_Z80) + { + if (g_hTraceFile) + OutputTraceLine(); - g_aProfileOpcodes[ nOpcode ].m_nCount++; - g_aProfileOpmodes[ nOpmode ].m_nCount++; + g_bDebugBreakpointHit = BP_HIT_NONE; + + bool bPCIsFloatBusOrIO = (regs.pc >= 0xC000 && regs.pc <= 0xC0FF); // TODO: Determine $C100..CFFF - assume executable + + if (!bPCIsFloatBusOrIO) + { + BYTE nOpcode = *(mem+regs.pc); + + // Update profiling stats + int nOpmode = g_aOpcodes[ nOpcode ].nAddressMode; + g_aProfileOpcodes[ nOpcode ].m_nCount++; + g_aProfileOpmodes[ nOpmode ].m_nCount++; + + CheckBreakOpcode( nOpcode ); // Can set g_bDebugBreakpointHit + } + else + { + g_bDebugBreakpointHit = BP_HIT_PC_READ_FLOATING_BUS_OR_IO_REG; + } + + if (g_bDebugBreakpointHit) + { + bDoSingleStep = false; + bForceSingleStepNext = true; // Allow next single-step (after this) to execute + } } - SingleStep(g_bGoCmd_ReinitFlag); - g_bGoCmd_ReinitFlag = false; + if (bDoSingleStep) + { + SingleStep(g_bGoCmd_ReinitFlag); + g_bGoCmd_ReinitFlag = false; - g_bDebugBreakpointHit |= CheckBreakpointsIO() || CheckBreakpointsReg(); + g_bDebugBreakpointHit |= CheckBreakpointsIO() || CheckBreakpointsReg(); + } + + if (regs.pc == g_nDebugStepUntil || g_bDebugBreakpointHit) + { + TCHAR sText[ CONSOLE_WIDTH ]; + char* pszStopReason = NULL; + + if (regs.pc == g_nDebugStepUntil) + pszStopReason = TEXT("PC matches 'Go until' address"); + else if (g_bDebugBreakpointHit & BP_HIT_INVALID) + pszStopReason = TEXT("Invalid opcode"); + else if (g_bDebugBreakpointHit & BP_HIT_OPCODE) + pszStopReason = TEXT("Opcode match"); + else if (g_bDebugBreakpointHit & BP_HIT_REG) + pszStopReason = TEXT("Register matches value"); + else if (g_bDebugBreakpointHit & BP_HIT_MEM) + pszStopReason = TEXT("Memory accessed"); + else if (g_bDebugBreakpointHit & BP_HIT_PC_READ_FLOATING_BUS_OR_IO_REG) + pszStopReason = TEXT("PC reads from floating bus or I/O register"); + else + pszStopReason = TEXT("Unknown!"); + + ConsoleBufferPushFormat( sText, TEXT("Stop reason: %s"), pszStopReason ); + ConsoleUpdate(); - if ((regs.pc == g_nDebugStepUntil) || g_bDebugBreakpointHit) g_nDebugSteps = 0; - else if (g_nDebugSteps > 0) + } + + if (g_nDebugSteps > 0) g_nDebugSteps--; } @@ -8525,7 +8614,7 @@ void DebugContinueStepping () DisasmCalcTopBotAddress(); Update_t bUpdate = UPDATE_ALL; - UpdateDisplay( bUpdate ); // nStepsTaken >= 0x10000); + UpdateDisplay( bUpdate ); nStepsTaken = 0; } } diff --git a/source/Debugger/Debug.h b/source/Debugger/Debug.h index db9e6c21..e40e89d5 100644 --- a/source/Debugger/Debug.h +++ b/source/Debugger/Debug.h @@ -34,6 +34,7 @@ ,BP_HIT_OPCODE = (1 << 1) ,BP_HIT_REG = (1 << 2) ,BP_HIT_MEM = (1 << 3) + ,BP_HIT_PC_READ_FLOATING_BUS_OR_IO_REG = (1 << 4) }; extern int g_nBreakpoints; @@ -42,14 +43,9 @@ extern const char *g_aBreakpointSource [ NUM_BREAKPOINT_SOURCES ]; extern const TCHAR *g_aBreakpointSymbols[ NUM_BREAKPOINT_OPERATORS ]; - // Any Speed Breakpoints extern int g_nDebugBreakOnInvalid ; extern int g_iDebugBreakOnOpcode ; - // Breakpoint Status - extern bool g_bDebugBreakDelayCheck; - extern int g_bDebugBreakpointHit ; - // Commands void VerifyDebuggerCommandTable(); @@ -144,52 +140,6 @@ bool GetBreakpointInfo ( WORD nOffset, bool & bBreakpointActive_, bool & bBreakpointEnable_ ); - inline int _IsDebugBreakOnOpcode( int iOpcode ) - { - if (g_iDebugBreakOnOpcode == iOpcode) - g_bDebugBreakpointHit |= BP_HIT_OPCODE; - return g_bDebugBreakpointHit; - } - - // iOpcodeType = AM_IMPLIED (BRK), AM_1, AM_2, AM_3 - inline int IsDebugBreakOnInvalid( int iOpcodeType ) - { - g_bDebugBreakpointHit |= ((g_nDebugBreakOnInvalid >> iOpcodeType) & 1) ? BP_HIT_INVALID : 0; - return g_bDebugBreakpointHit; - } - - // iOpcodeType = AM_IMPLIED (BRK), AM_1, AM_2, AM_3 - inline void SetDebugBreakOnInvalid( int iOpcodeType, int nValue ) - { - if (iOpcodeType <= AM_3) - { - g_nDebugBreakOnInvalid &= ~ ( 1 << iOpcodeType); - g_nDebugBreakOnInvalid |= ((nValue & 1) << iOpcodeType); - } - } - - // - // CPU checks the Debugger breakpoints - // a) at opcode fetch - // b) after opcode execution - // - inline int IsDebugBreakOpcode( int iOpcode ) - { - if (g_bDebugBreakDelayCheck) - { - g_bDebugBreakDelayCheck = false; - return false; - } - - if (! iOpcode ) - IsDebugBreakOnInvalid( AM_IMPLIED ); - - if (g_iDebugBreakOnOpcode ) // User wants to enter debugger on specific opcode? - _IsDebugBreakOnOpcode(iOpcode); - - return g_bDebugBreakpointHit; - } - // Source Level Debugging int FindSourceLine( WORD nAddress ); const char* FormatAddress( WORD nAddress, int nBytes ); diff --git a/source/Frame.cpp b/source/Frame.cpp index eaa313f2..ae804e17 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -1898,7 +1898,6 @@ static void ProcessButtonClick(int button, bool bFromButtonUI /*=false*/) else if (g_nAppMode == MODE_DEBUG) { - g_bDebugBreakDelayCheck = true; ProcessButtonClick(BTN_RUN); // Exit debugger, switch to MODE_RUNNING or MODE_STEPPING } else diff --git a/test/TestCPU6502/TestCPU6502.cpp b/test/TestCPU6502/TestCPU6502.cpp index 8514f1a7..996cee35 100644 --- a/test/TestCPU6502/TestCPU6502.cpp +++ b/test/TestCPU6502/TestCPU6502.cpp @@ -14,15 +14,6 @@ LPBYTE memdirty = NULL; // TODO: Init iofunction IORead[256] = {0}; // TODO: Init iofunction IOWrite[256] = {0}; // TODO: Init -// From Debugger_Types.h - enum AddressingMode_e // ADDRESSING_MODES_e - { - AM_IMPLIED // Note: SetDebugBreakOnInvalid() assumes this order of first 4 entries - , AM_1 // Invalid 1 Byte - , AM_2 // Invalid 2 Bytes - , AM_3 // Invalid 3 Bytes - }; - // From CPU.cpp #define AF_SIGN 0x80 #define AF_OVERFLOW 0x40 @@ -58,12 +49,6 @@ static __forceinline int Fetch(BYTE& iOpcode, ULONG uExecutedCycles) return 1; } -#define INV IsDebugBreakOnInvalid(AM_1); -inline int IsDebugBreakOnInvalid( int iOpcodeType ) -{ - return 0; -} - static __forceinline void DoIrqProfiling(DWORD uCycles) { } @@ -80,19 +65,6 @@ static __forceinline void IRQ(ULONG& uExecutedCycles, BOOL& flagc, BOOL& flagn, { } -void RequestDebugger() -{ -} - -// From Debug.h -inline int IsDebugBreakpointHit() -{ - return 0; -} - -// From Debug.cpp -int g_bDebugBreakpointHit = 0; - // From z80.cpp DWORD z80_mainloop(ULONG uTotalCycles, ULONG uExecutedCycles) {