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
This commit is contained in:
tomcw 2017-03-07 21:35:38 +00:00
parent adfb48c6ab
commit 3d6c10bad9
8 changed files with 117 additions and 144 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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 );

View File

@ -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

View File

@ -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)
{