Changes to allow debugging of Z80 core:

- added methods to attach/detach debugger.
- added hooks into CZ80Debug to allow debugger to control execution.
- added methods to allow reading/writing of Z80 registers.
This commit is contained in:
Nik Henson 2011-09-18 22:21:14 +00:00
parent 041e6659b3
commit 65536fd0fe
2 changed files with 285 additions and 25 deletions

View file

@ -30,8 +30,8 @@
*/ */
#include <cstdio> // for NULL #include <cstdio> // for NULL
#include "Z80.h" // must include this first to define CZ80
#include "Supermodel.h" #include "Supermodel.h"
#include "Z80.h" // must include this first to define CZ80
/****************************************************************************** /******************************************************************************
@ -228,16 +228,6 @@ static const unsigned char cycleTables[5][256] = {
pc += 2; \ pc += 2; \
} }
// Save local copies of Z80 registers back to context
#define SAVE_TO_CONTEXT() \
af[af_sel] = AF; \
regs[regs_sel].bc = BC; \
regs[regs_sel].de = DE; \
regs[regs_sel].hl = HL; \
ix = IX; \
iy = IY; \
sp = SP
/******************************************************************************* /*******************************************************************************
Functions Functions
@ -245,6 +235,16 @@ static const unsigned char cycleTables[5][256] = {
int CZ80::Run(int numCycles) int CZ80::Run(int numCycles)
{ {
#ifdef SUPERMODEL_DEBUGGER
// If debugging enabled, don't optimize access to registers as they need to be accesible to debugger during execution
#define AF af[af_sel]
#define BC regs[regs_sel].bc
#define DE regs[regs_sel].de
#define HL regs[regs_sel].hl
#define SP sp
#define IX ix
#define IY iy
#else
// Optimization: copy registers into native word-sized local variables // Optimization: copy registers into native word-sized local variables
unsigned int AF = af[af_sel]; unsigned int AF = af[af_sel];
unsigned int BC = regs[regs_sel].bc; unsigned int BC = regs[regs_sel].bc;
@ -253,13 +253,31 @@ int CZ80::Run(int numCycles)
unsigned int SP = sp; unsigned int SP = sp;
unsigned int IX = ix; unsigned int IX = ix;
unsigned int IY = iy; unsigned int IY = iy;
#endif
unsigned int temp, acu, sum, cbits; unsigned int temp, acu, sum, cbits;
unsigned int op, adr; unsigned int op, adr;
int cycles = numCycles; int cycles = numCycles;
#ifdef SUPERMODEL_DEBUGGER
if (Debug != NULL)
{
Debug->CPUActive();
lastCycles += numCycles;
}
#endif // SUPERMODEL_DEBUGGER
while (cycles > 0) while (cycles > 0)
{ {
op = GetBYTE_pp(pc); op = GetBYTE_pp(pc);
#ifdef SUPERMODEL_DEBUGGER
if (Debug != NULL)
{
while (Debug->CPUExecute(pc - 1, op, lastCycles - cycles))
op = GetBYTE_pp(pc);
lastCycles = cycles;
}
#endif // SUPERMODEL_DEBUGGER
switch(op) { switch(op) {
case 0x00: /* NOP */ case 0x00: /* NOP */
cycles -= cycleTables[0][0x00]; cycles -= cycleTables[0][0x00];
@ -3617,6 +3635,12 @@ int CZ80::Run(int numCycles)
* - Clear IFF1 (disable interrupts) * - Clear IFF1 (disable interrupts)
* - Un-halt CPU (if in HALT state) * - Un-halt CPU (if in HALT state)
*/ */
#ifdef SUPERMODEL_DEBUGGER
if (Debug != NULL)
Debug->CPUException(Z80_EX_NMI);
#endif // SUPERMODEL_DEBUGGER
PUSH(pc); PUSH(pc);
pc = 0x0066; pc = 0x0066;
iff = (iff&~2) | ((iff&1)<<1); iff = (iff&~2) | ((iff&1)<<1);
@ -3658,6 +3682,11 @@ int CZ80::Run(int numCycles)
{ {
v = INTCallback(this); v = INTCallback(this);
#ifdef SUPERMODEL_DEBUGGER
if (Debug != NULL)
Debug->CPUException(v);
#endif // SUPERMODEL_DEBUGGER
switch (v) switch (v)
{ {
case Z80_INT_RST_00: v = 0x0000; break; case Z80_INT_RST_00: v = 0x0000; break;
@ -3687,6 +3716,12 @@ int CZ80::Run(int numCycles)
* *
* Vector is 0x0038. * Vector is 0x0038.
*/ */
#ifdef SUPERMODEL_DEBUGGER
if (Debug != NULL)
Debug->CPUException(Z80_IM1_IRQ);
#endif // SUPERMODEL_DEBUGGER
PUSH(pc); PUSH(pc);
pc = 0x0038; pc = 0x0038;
iff = 0; iff = 0;
@ -3703,6 +3738,12 @@ int CZ80::Run(int numCycles)
* and 8 bits read from the bus (with bit 0 cleared). The final * and 8 bits read from the bus (with bit 0 cleared). The final
* 16-bit vector is read from this address. * 16-bit vector is read from this address.
*/ */
#ifdef SUPERMODEL_DEBUGGER
if (Debug != NULL)
Debug->CPUException(Z80_IM2_VECTOR);
#endif // SUPERMODEL_DEBUGGER
if (NULL != INTCallback) if (NULL != INTCallback)
{ {
v = INTCallback(this); v = INTCallback(this);
@ -3726,7 +3767,22 @@ int CZ80::Run(int numCycles)
// write registers back to context // write registers back to context
HALTExit: HALTExit:
SAVE_TO_CONTEXT(); #ifdef SUPERMODEL_DEBUGGER
if (Debug != NULL)
{
Debug->CPUInactive();
lastCycles = lastCycles - cycles;
}
#else
// Save local copies of Z80 registers back to context
af[af_sel] = AF;
regs[regs_sel].bc = BC;
regs[regs_sel].de = DE;
regs[regs_sel].hl = HL;
ix = IX;
iy = IY;
sp = SP;
#endif // SUPERMODEL_DEBUGGER
// Return number of cycles actually executed // Return number of cycles actually executed
return numCycles - cycles; return numCycles - cycles;
@ -3747,6 +3803,90 @@ UINT16 CZ80::GetPC(void)
return pc; return pc;
} }
#ifdef SUPERMODEL_DEBUGGER
UINT8 CZ80::GetReg8(unsigned reg8)
{
switch (reg8)
{
case Z80_REG8_IFF: return iff;
case Z80_REG8_IM: return im;
case Z80_REG8_I: return ir>>8;
case Z80_REG8_R: return ir&0xFF;
case Z80_REG8_A: return af[0]>>8;
case Z80_REG8_F: return af[0]&0xFF;
case Z80_REG8_B: return regs[0].bc>>8;
case Z80_REG8_C: return regs[0].bc&0xFF;
case Z80_REG8_D: return regs[0].de>>8;
case Z80_REG8_E: return regs[0].de&0xFF;
case Z80_REG8_H: return regs[0].hl>>8;
case Z80_REG8_L: return regs[0].hl&0xFF;
default: return 0;
}
}
bool CZ80::SetReg8(unsigned reg8, UINT8 value)
{
switch (reg8)
{
case Z80_REG8_IFF: iff = value; return true;
case Z80_REG8_IM: im = value; return true;
case Z80_REG8_I: ir |= value<<8; return true;
case Z80_REG8_R: ir |= value; return true;
case Z80_REG8_A: af[0] |= value<<8; return true;
case Z80_REG8_F: af[0] |= value; return true;
case Z80_REG8_B: regs[0].bc |= value<<8; return true;
case Z80_REG8_C: regs[0].bc |= value; return true;
case Z80_REG8_D: regs[0].de |= value<<8; return true;
case Z80_REG8_E: regs[0].de |= value; return true;
case Z80_REG8_H: regs[0].hl |= value<<8; return true;
case Z80_REG8_L: regs[0].hl |= value; return true;
default: return false;
}
}
UINT16 CZ80::GetReg16(unsigned reg16)
{
switch (reg16)
{
case Z80_REG16_SP: return sp;
case Z80_REG16_PC: return pc;
case Z80_REG16_IR: return ir;
case Z80_REG16_AF: return af[0];
case Z80_REG16_BC: return regs[0].bc;
case Z80_REG16_DE: return regs[0].de;
case Z80_REG16_HL: return regs[0].hl;
case Z80_REG16_IX: return ix;
case Z80_REG16_IY: return iy;
case Z80_REG16_AF_: return af[1];
case Z80_REG16_BC_: return regs[1].bc;
case Z80_REG16_DE_: return regs[1].de;
case Z80_REG16_HL_: return regs[1].hl;
default: return 0;
}
}
bool CZ80::SetReg16(unsigned reg16, UINT16 value)
{
switch (reg16)
{
case Z80_REG16_SP: sp = value; return true;
case Z80_REG16_PC: pc = value; return true;
case Z80_REG16_IR: ir = value; return true;
case Z80_REG16_AF: af[0] = value; return true;
case Z80_REG16_BC: regs[0].bc = value; return true;
case Z80_REG16_DE: regs[0].de = value; return true;
case Z80_REG16_HL: regs[0].hl = value; return true;
case Z80_REG16_IX: ix = value; return true;
case Z80_REG16_IY: iy = value; return true;
case Z80_REG16_AF_: af[1] = value; return true;
case Z80_REG16_BC_: regs[1].bc = value; return true;
case Z80_REG16_DE_: regs[1].de = value; return true;
case Z80_REG16_HL_: regs[1].hl = value; return true;
default: return false;
}
}
#endif // SUPERMODEL_DEBUGGER
void CZ80::Reset(void) void CZ80::Reset(void)
{ {
pc = 0x0000; pc = 0x0000;
@ -3770,6 +3910,10 @@ void CZ80::Reset(void)
intLine = false; intLine = false;
nmiTrigger = false; nmiTrigger = false;
#ifdef SUPERMODEL_DEBUGGER
lastCycles = 0;
#endif // SUPERMODEL_DEBUGGER
} }
void CZ80::SaveState(CBlockFile *StateFile, const char *name) void CZ80::SaveState(CBlockFile *StateFile, const char *name)
@ -3832,14 +3976,41 @@ void CZ80::Init(CBus *BusPtr, int (*INTF)(CZ80 *Z80))
INTCallback = INTF; INTCallback = INTF;
} }
#ifdef SUPERMODEL_DEBUGGER
void CZ80::AttachDebugger(Debugger::CZ80Debug *DebugPtr)
{
if (Debug != NULL)
DetachDebugger();
Debug = DebugPtr;
Bus = Debug->AttachBus(Bus);
}
void CZ80::DetachDebugger()
{
if (Debug == NULL)
return;
Bus = Debug->DetachBus();
Debug = NULL;
}
#endif //SUPERMODEL_DEBUGGER
CZ80::CZ80(void) CZ80::CZ80(void)
{ {
INTCallback = NULL; // so we can later check to see if one has been installed INTCallback = NULL; // so we can later check to see if one has been installed
Bus = NULL; Bus = NULL;
#ifdef SUPERMODEL_DEBUGGER
Debug = NULL;
#endif //SUPERMODEL_DEBUGGER
} }
CZ80::~CZ80(void) CZ80::~CZ80(void)
{ {
INTCallback = NULL; INTCallback = NULL;
Bus = NULL; Bus = NULL;
#ifdef SUPERMODEL_DEBUGGER
Debug = NULL;
#endif //SUPERMODEL_DEBUGGER
} }

View file

@ -64,6 +64,44 @@
#define Z80_INT_RST_30 0xF7 // RST 0x30 #define Z80_INT_RST_30 0xF7 // RST 0x30
#define Z80_INT_RST_38 0xFF // RST 0x38 #define Z80_INT_RST_38 0xFF // RST 0x38
#ifdef SUPERMODEL_DEBUGGER
// Extra interrupt types
#define Z80_EX_NMI 0
#define Z80_IM1_IRQ 1
#define Z80_IM2_VECTOR 2
// 8-bit registers
#define Z80_REG8_IFF 0
#define Z80_REG8_IM 1
#define Z80_REG8_I 2
#define Z80_REG8_R 3
#define Z80_REG8_A 4
#define Z80_REG8_F 5
#define Z80_REG8_B 6
#define Z80_REG8_C 7
#define Z80_REG8_D 8
#define Z80_REG8_E 9
#define Z80_REG8_H 10
#define Z80_REG8_L 11
// 16-bit registers
#define Z80_REG16_SP 0
#define Z80_REG16_PC 1
#define Z80_REG16_IR 2
#define Z80_REG16_AF 3
#define Z80_REG16_BC 4
#define Z80_REG16_DE 5
#define Z80_REG16_HL 6
#define Z80_REG16_IX 7
#define Z80_REG16_IY 8
#define Z80_REG16_AF_ 9
#define Z80_REG16_BC_ 10
#define Z80_REG16_DE_ 11
#define Z80_REG16_HL_ 12
class Debugger::CZ80Debug;
#endif // SUPERMODEL_DEBUGGER
/* /*
* CZ80: * CZ80:
* *
@ -103,8 +141,8 @@ public:
* callbacks to clear interrupts. * callbacks to clear interrupts.
* *
* Parameters: * Parameters:
* state If true, this is equivalent to /INT being asserted on the * state If TRUE, this is equivalent to /INT being asserted on the
* Z80 (INT line low, which triggers an interrupt). If false, * Z80 (INT line low, which triggers an interrupt). If FALSE,
* this deasserts /INT (INT line high, no interrupt pending). * this deasserts /INT (INT line high, no interrupt pending).
*/ */
void SetINT(bool state); void SetINT(bool state);
@ -119,6 +157,36 @@ public:
*/ */
UINT16 GetPC(void); UINT16 GetPC(void);
#ifdef SUPERMODEL_DEBUGGER
/*
* GetReg8(state):
*
* Returns value of given 8-bit register.
*/
UINT8 GetReg8(unsigned reg8);
/*
* SetReg8(state):
*
* Sets value of given 8-bit register.
*/
bool SetReg8(unsigned reg8, UINT8 value);
/*
* GetReg16(state):
*
* Returns value of given 16-bit register.
*/
UINT16 GetReg16(unsigned reg16);
/*
* SetReg16(state):
*
* Sets value of given 16-bit register.
*/
bool SetReg16(unsigned reg16, UINT16 value);
#endif // SUPERMODEL_DEBUGGER
/* /*
* Reset(void): * Reset(void):
* *
@ -161,7 +229,7 @@ public:
* *
* An interrupt callback, which is called each time an interrupt occurs, * An interrupt callback, which is called each time an interrupt occurs,
* should also be supplied. The interrupt callback should explicitly clear * should also be supplied. The interrupt callback should explicitly clear
* the INT status (using SetINT(false)) and then return the appropriate * the INT status (using SetINT(FALSE)) and then return the appropriate
* vector depending on the interrupt mode that is used by the system. * vector depending on the interrupt mode that is used by the system.
* *
* For mode 0, only Z80_INT_RST_* values are acceptable. For mode 1, the * For mode 0, only Z80_INT_RST_* values are acceptable. For mode 1, the
@ -183,6 +251,22 @@ public:
*/ */
void Init(CBus *BusPtr, int (*INTF)(CZ80 *Z80)); void Init(CBus *BusPtr, int (*INTF)(CZ80 *Z80));
#ifdef SUPERMODEL_DEBUGGER
/*
* AttachDebugger(DebugPtr):
*
* Attaches debugger to CPU.
*/
void AttachDebugger(Debugger::CZ80Debug *DebugPtr);
/*
* DetachDebugger():
*
* Detaches debugger from CPU.
*/
void DetachDebugger();
#endif // SUPERMODEL_DEBUGGER
/* /*
* CZ80(void): * CZ80(void):
* ~CZ80(void): * ~CZ80(void):
@ -217,7 +301,12 @@ private:
bool nmiTrigger; bool nmiTrigger;
bool intLine; bool intLine;
int (*INTCallback)(CZ80 *Z80); int (*INTCallback)(CZ80 *Z80);
#ifdef SUPERMODEL_DEBUGGER
int lastCycles;
Debugger::CZ80Debug *Debug;
#endif // SUPERMODEL_DEBUGGER
}; };
#endif // INCLUDED_Z80_H #endif // INCLUDED_Z80_H