mirror of
https://github.com/AppleWin/AppleWin.git
synced 2025-01-03 11:30:22 +00:00
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:
parent
adfb48c6ab
commit
3d6c10bad9
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
@ -8490,27 +8525,81 @@ void DebugContinueStepping ()
|
||||
}
|
||||
|
||||
if (g_nDebugSteps)
|
||||
{
|
||||
bool bDoSingleStep = true;
|
||||
|
||||
if (bForceSingleStepNext)
|
||||
{
|
||||
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();
|
||||
|
||||
// Update profiling stats
|
||||
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);
|
||||
int nOpmode = g_aOpcodes[ nOpcode ].nAddressMode;
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
if (bDoSingleStep)
|
||||
{
|
||||
SingleStep(g_bGoCmd_ReinitFlag);
|
||||
g_bGoCmd_ReinitFlag = false;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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 );
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user