mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-25 15:15:40 +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 "Z80.h" // must include this first to define CZ80
|
||||
#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; \
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -245,6 +235,16 @@ static const unsigned char cycleTables[5][256] = {
|
|||
|
||||
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
|
||||
unsigned int AF = af[af_sel];
|
||||
unsigned int BC = regs[regs_sel].bc;
|
||||
|
@ -253,13 +253,31 @@ int CZ80::Run(int numCycles)
|
|||
unsigned int SP = sp;
|
||||
unsigned int IX = ix;
|
||||
unsigned int IY = iy;
|
||||
#endif
|
||||
unsigned int temp, acu, sum, cbits;
|
||||
unsigned int op, adr;
|
||||
|
||||
int cycles = numCycles;
|
||||
|
||||
#ifdef SUPERMODEL_DEBUGGER
|
||||
if (Debug != NULL)
|
||||
{
|
||||
Debug->CPUActive();
|
||||
lastCycles += numCycles;
|
||||
}
|
||||
#endif // SUPERMODEL_DEBUGGER
|
||||
|
||||
while (cycles > 0)
|
||||
{
|
||||
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) {
|
||||
case 0x00: /* NOP */
|
||||
cycles -= cycleTables[0][0x00];
|
||||
|
@ -3617,6 +3635,12 @@ int CZ80::Run(int numCycles)
|
|||
* - Clear IFF1 (disable interrupts)
|
||||
* - Un-halt CPU (if in HALT state)
|
||||
*/
|
||||
|
||||
#ifdef SUPERMODEL_DEBUGGER
|
||||
if (Debug != NULL)
|
||||
Debug->CPUException(Z80_EX_NMI);
|
||||
#endif // SUPERMODEL_DEBUGGER
|
||||
|
||||
PUSH(pc);
|
||||
pc = 0x0066;
|
||||
iff = (iff&~2) | ((iff&1)<<1);
|
||||
|
@ -3658,6 +3682,11 @@ int CZ80::Run(int numCycles)
|
|||
{
|
||||
v = INTCallback(this);
|
||||
|
||||
#ifdef SUPERMODEL_DEBUGGER
|
||||
if (Debug != NULL)
|
||||
Debug->CPUException(v);
|
||||
#endif // SUPERMODEL_DEBUGGER
|
||||
|
||||
switch (v)
|
||||
{
|
||||
case Z80_INT_RST_00: v = 0x0000; break;
|
||||
|
@ -3687,6 +3716,12 @@ int CZ80::Run(int numCycles)
|
|||
*
|
||||
* Vector is 0x0038.
|
||||
*/
|
||||
|
||||
#ifdef SUPERMODEL_DEBUGGER
|
||||
if (Debug != NULL)
|
||||
Debug->CPUException(Z80_IM1_IRQ);
|
||||
#endif // SUPERMODEL_DEBUGGER
|
||||
|
||||
PUSH(pc);
|
||||
pc = 0x0038;
|
||||
iff = 0;
|
||||
|
@ -3703,6 +3738,12 @@ int CZ80::Run(int numCycles)
|
|||
* and 8 bits read from the bus (with bit 0 cleared). The final
|
||||
* 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)
|
||||
{
|
||||
v = INTCallback(this);
|
||||
|
@ -3726,7 +3767,22 @@ int CZ80::Run(int numCycles)
|
|||
|
||||
// write registers back to context
|
||||
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 numCycles - cycles;
|
||||
|
@ -3747,6 +3803,90 @@ UINT16 CZ80::GetPC(void)
|
|||
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)
|
||||
{
|
||||
pc = 0x0000;
|
||||
|
@ -3770,6 +3910,10 @@ void CZ80::Reset(void)
|
|||
|
||||
intLine = false;
|
||||
nmiTrigger = false;
|
||||
|
||||
#ifdef SUPERMODEL_DEBUGGER
|
||||
lastCycles = 0;
|
||||
#endif // SUPERMODEL_DEBUGGER
|
||||
}
|
||||
|
||||
void CZ80::SaveState(CBlockFile *StateFile, const char *name)
|
||||
|
@ -3832,14 +3976,41 @@ void CZ80::Init(CBus *BusPtr, int (*INTF)(CZ80 *Z80))
|
|||
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)
|
||||
{
|
||||
INTCallback = NULL; // so we can later check to see if one has been installed
|
||||
Bus = NULL;
|
||||
|
||||
#ifdef SUPERMODEL_DEBUGGER
|
||||
Debug = NULL;
|
||||
#endif //SUPERMODEL_DEBUGGER
|
||||
}
|
||||
|
||||
CZ80::~CZ80(void)
|
||||
{
|
||||
INTCallback = 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_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:
|
||||
*
|
||||
|
@ -103,8 +141,8 @@ public:
|
|||
* callbacks to clear interrupts.
|
||||
*
|
||||
* Parameters:
|
||||
* state If true, this is equivalent to /INT being asserted on the
|
||||
* Z80 (INT line low, which triggers an interrupt). If false,
|
||||
* state If TRUE, this is equivalent to /INT being asserted on the
|
||||
* Z80 (INT line low, which triggers an interrupt). If FALSE,
|
||||
* this deasserts /INT (INT line high, no interrupt pending).
|
||||
*/
|
||||
void SetINT(bool state);
|
||||
|
@ -119,6 +157,36 @@ public:
|
|||
*/
|
||||
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):
|
||||
*
|
||||
|
@ -161,7 +229,7 @@ public:
|
|||
*
|
||||
* An interrupt callback, which is called each time an interrupt occurs,
|
||||
* 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.
|
||||
*
|
||||
* 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));
|
||||
|
||||
#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):
|
||||
|
@ -217,7 +301,12 @@ private:
|
|||
bool nmiTrigger;
|
||||
bool intLine;
|
||||
int (*INTCallback)(CZ80 *Z80);
|
||||
|
||||
#ifdef SUPERMODEL_DEBUGGER
|
||||
int lastCycles;
|
||||
|
||||
Debugger::CZ80Debug *Debug;
|
||||
#endif // SUPERMODEL_DEBUGGER
|
||||
};
|
||||
|
||||
|
||||
#endif // INCLUDED_Z80_H
|
Loading…
Reference in a new issue