mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2025-02-18 02:05:39 +00:00
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:
parent
041e6659b3
commit
65536fd0fe
|
@ -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
|
||||||
}
|
}
|
|
@ -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
|
Loading…
Reference in a new issue