Changes to debugger classes:

- updated debugger classes to compile again with all recent changes.
- improved debugger classes to allow them to work in multi-threaded emulator and be able to handle CPUs on different threads.
- added debug classes for new Z80 and Musashi 68K CPU cores.
- added logging of cycle counts and frames.
- moved all Supermodel specific code & configuration to CSupermodelDebugger.
- added all Model 3 CPUs (PPC, sound board 68K, DSB 68K/Z80 and drive board Z80) to CSupermodelDebugger.
- added persisting of custom entry points in saved debug state to CCodeAnalyser.
- fixed bug with listing I/O ports in CConsoleDebugger and added displaying of cycle counts and CPU speeds when listing CPUs.
This commit is contained in:
Nik Henson 2011-09-18 21:59:23 +00:00
parent b9430cd988
commit e8e02ba685
20 changed files with 1822 additions and 281 deletions

View file

@ -5,9 +5,12 @@
#include <string.h>
#include <ctype.h>
#define M68KSPECIAL_SP 0
#define M68KSPECIAL_SR 1
namespace Debugger
{
C68KDebug::C68KDebug() : CCPUDebug("68K", 2, 10, true, 24, 7)
C68KDebug::C68KDebug(const char *name) : CCPUDebug("68K", name, 2, 10, true, 24, 7)
{
// Exceptions
AddException("BUS", 2, "Bus Error");
@ -47,39 +50,6 @@ namespace Debugger
AddInterrupt("AUTO5", 4, "Level 5 Interrupt Autovector");
AddInterrupt("AUTO6", 5, "Level 6 Interrupt Autovector");
AddInterrupt("AUTO7", 6, "Level 7 Interrupt Autovector");
// TODO - following Model3-specific stuff should be moved to SupermodelDebugger
// Regions
AddRegion(0x000000, 0x0FFFFF, true, false, "SCSP1 RAM");
AddRegion(0x200000, 0x2FFFFF, true, false, "SCSP2 RAM");
AddRegion(0x600000, 0x67FFFF, true, true, "Program ROM");
AddRegion(0x800000, 0x9FFFFF, false, true, "Sample ROM (low 2 MB)");
AddRegion(0xA00000, 0xDFFFFF, false, true, "Sample ROM (bank)");
AddRegion(0xE00000, 0xFFFFFF, false, true, "Sample ROM (bank)");
AddRegion(0x100000, 0x10FFFF, false, false, "SCSP Master");
AddRegion(0x300000, 0x30FFFF, false, false, "SCSP Slave");
// Mapped I/O
for (unsigned slot = 0; slot < 32; slot++)
{
sprintf(m_mSlotStr[slot], "SCSP Master Slot %02X", slot);
for (unsigned reg = 0; reg < 16; reg++)
{
UINT32 addr = 0x100000 + slot * 0x20 + reg * 0x02;
sprintf(m_regStr[reg], "Register %u", reg);
AddMappedIO(addr, 2, m_regStr[reg], m_mSlotStr[slot]);
}
}
for (unsigned slot = 0; slot < 32; slot++)
{
sprintf(m_sSlotStr[slot], "SCSP Slave Slot %02X", slot);
for (unsigned reg = 0; reg < 16; reg++)
{
UINT32 addr = 0x300000 + slot * 0x20 + reg * 0x02;
AddMappedIO(addr, 2, m_regStr[reg], m_sSlotStr[slot]);
}
}
}
static const char *opATable0004[] = { "movep.w [DW3](A0),D0","movep.w [DW3](A1),D0","movep.w [DW3](A2),D0",
@ -1245,7 +1215,7 @@ namespace Debugger
int C68KDebug::Disassemble(UINT32 addr, char *mnemonic, char *operands)
{
// Read opcode head word
UINT16 opcode = (UINT16)ReadMem(addr, 16);
UINT16 opcode = (UINT16)ReadMem(addr, 2);
int offset = 2;
const char *instr;
@ -2204,7 +2174,7 @@ namespace Debugger
if (opcode != 0x4E74 && opcode != 0x4E75 && opcode != 0x4E73)
return false;
// Return address will be at top of stack for rts and stack + 2 for rtr or rte
UINT32 sp = 0; // TODO GetSP(); //(UINT32)turbo68kcontext_68000.a[7];
UINT32 sp = GetSP();
if (opcode == 0x4E75)
retAddr = (UINT32)ReadMem(sp, 4);
else

View file

@ -4,14 +4,6 @@
#include "Debugger/CPUDebug.h"
#include "Types.h"
#include "CPU/68K/Turbo68K/Turbo68K.h"
#define M68KSPECIAL_SP 0
#define M68KSPECIAL_SR 1
#define USE_NATIVE_READ 0
#define USE_NATIVE_WRITE 0
namespace Debugger
{
@ -21,20 +13,13 @@ namespace Debugger
class C68KDebug : public CCPUDebug
{
private:
char m_drNames[8][3];
char m_arNames[8][3];
char m_mSlotStr[32][20];
char m_sSlotStr[32][20];
char m_regStr[16][12];
bool FormatAddrMode(UINT32 addr, UINT32 opcode, int &offset, UINT8 addrMode, char sizeC, char *dest);
protected:
virtual UINT32 GetSP() = 0;
public:
C68KDebug();
C68KDebug(const char *name);
// CCPUDebug methods

View file

@ -0,0 +1,178 @@
#ifdef SUPERMODEL_DEBUGGER
#include "Musashi68KDebug.h"
#include <string.h>
#include <ctype.h>
//namespace Debugger
//{
UINT32 CMusashi68KDebug::GetReg(CCPUDebug *cpu, unsigned id)
{
CMusashi68KDebug *m68K = (CMusashi68KDebug*)cpu;
return M68KGetRegister(m68K->m_ctx, id);
}
bool CMusashi68KDebug::SetReg(CCPUDebug *cpu, unsigned id, UINT32 data)
{
CMusashi68KDebug *m68K = (CMusashi68KDebug*)cpu;
m68K->SetM68KContext();
bool okay = M68KSetRegister(m68K->m_ctx, id, data);
m68K->RestoreM68KContext();
return okay;
}
static const char *srGroup = "Special Registers";
static const char *drGroup = "Data Registers";
static const char *arGroup = "Address Regsters";
CMusashi68KDebug::CMusashi68KDebug(const char *name, M68KCtx *ctx) : C68KDebug(name), m_ctx(ctx), m_resetAddr(0)
{
// Special registers
AddPCRegister ("PC", srGroup);
AddAddrRegister ("SP", srGroup, DBG68K_REG_SP, GetReg, SetReg);
AddStatus32Register("SR", srGroup, DBG68K_REG_SR, "TtSM.210...XNZVC", GetReg, SetReg);
// Data registers
AddInt32Register("D0", drGroup, DBG68K_REG_D0, GetReg, SetReg);
AddInt32Register("D1", drGroup, DBG68K_REG_D1, GetReg, SetReg);
AddInt32Register("D2", drGroup, DBG68K_REG_D2, GetReg, SetReg);
AddInt32Register("D3", drGroup, DBG68K_REG_D3, GetReg, SetReg);
AddInt32Register("D4", drGroup, DBG68K_REG_D4, GetReg, SetReg);
AddInt32Register("D5", drGroup, DBG68K_REG_D5, GetReg, SetReg);
AddInt32Register("D6", drGroup, DBG68K_REG_D6, GetReg, SetReg);
AddInt32Register("D7", drGroup, DBG68K_REG_D7, GetReg, SetReg);
// Address registers
AddInt32Register("A0", arGroup, DBG68K_REG_A0, GetReg, SetReg);
AddInt32Register("A1", arGroup, DBG68K_REG_A1, GetReg, SetReg);
AddInt32Register("A2", arGroup, DBG68K_REG_A2, GetReg, SetReg);
AddInt32Register("A3", arGroup, DBG68K_REG_A3, GetReg, SetReg);
AddInt32Register("A4", arGroup, DBG68K_REG_A4, GetReg, SetReg);
AddInt32Register("A5", arGroup, DBG68K_REG_A5, GetReg, SetReg);
AddInt32Register("A6", arGroup, DBG68K_REG_A6, GetReg, SetReg);
AddInt32Register("A7", arGroup, DBG68K_REG_A7, GetReg, SetReg);
}
CMusashi68KDebug::~CMusashi68KDebug()
{
DetachFromCPU();
}
UINT32 CMusashi68KDebug::GetSP()
{
return M68KGetRegister(m_ctx, DBG68K_REG_SP);
}
void CMusashi68KDebug::AttachToCPU()
{
if (m_ctx->Debug != NULL)
DetachFromCPU();
m_ctx->Debug = this;
m_bus = m_ctx->Bus;
m_ctx->Bus = this;
// Reset address is held at 0x000004
m_resetAddr = m_bus->Read32(0x000004);
}
void CMusashi68KDebug::DetachFromCPU()
{
if (m_ctx->Debug == NULL)
return;
m_ctx->Bus = m_bus;
m_bus = NULL;
m_ctx->Debug = NULL;
}
UINT32 CMusashi68KDebug::GetResetAddr()
{
return m_resetAddr;
}
bool CMusashi68KDebug::UpdatePC(UINT32 newPC)
{
// TODO
return false;
}
bool CMusashi68KDebug::ForceException(CException *ex)
{
// TODO
return false;
}
bool CMusashi68KDebug::ForceInterrupt(CInterrupt *in)
{
if (in->code > 6)
return false;
M68KSetIRQ(in->code + 1);
return true;
}
UINT64 CMusashi68KDebug::ReadMem(UINT32 addr, unsigned dataSize)
{
switch (dataSize)
{
case 1: return (UINT64)m_bus->Read8(addr);
case 2: return (UINT64)m_bus->Read16(addr);
case 4: return (UINT64)m_bus->Read32(addr);
default: return CCPUDebug::ReadMem(addr, dataSize);
}
}
bool CMusashi68KDebug::WriteMem(UINT32 addr, unsigned dataSize, UINT64 data)
{
switch (dataSize)
{
case 1: m_bus->Write8(addr, (UINT8)data); return true;
case 2: m_bus->Write16(addr, (UINT16)data); return true;
case 4: m_bus->Write32(addr, (UINT32)data); return true;
case 8: return CCPUDebug::WriteMem(addr, dataSize, data);
default: return false;
}
}
// CBus methods
UINT8 CMusashi68KDebug::Read8(UINT32 addr)
{
UINT8 data = m_bus->Read8(addr);
CheckRead8(addr, data);
return data;
}
void CMusashi68KDebug::Write8(UINT32 addr, UINT8 data)
{
m_bus->Write8(addr, data);
CheckWrite8(addr, data);
}
UINT16 CMusashi68KDebug::Read16(UINT32 addr)
{
UINT16 data = m_bus->Read16(addr);
CheckRead16(addr, data);
return data;
}
void CMusashi68KDebug::Write16(UINT32 addr, UINT16 data)
{
m_bus->Write16(addr, data);
CheckWrite16(addr, data);
}
UINT32 CMusashi68KDebug::Read32(UINT32 addr)
{
UINT32 data = m_bus->Read32(addr);
CheckRead32(addr, data);
return data;
}
void CMusashi68KDebug::Write32(UINT32 addr, UINT32 data)
{
m_bus->Write32(addr, data);
CheckWrite32(addr, data);
}
//}
#endif // SUPERMODEL_DEBUGGER

View file

@ -0,0 +1,100 @@
#ifdef SUPERMODEL_DEBUGGER
#ifndef INCLUDED_MUSASHI68KDEBUG_H
#define INCLUDED_MUSASHI68KDEBUG_H
#include "68KDebug.h"
#include "CPU/Bus.h"
#include "CPU/68K/68K.h"
#include "Types.h"
using namespace Debugger;
// TODO - can't get this namespace to work with 68K.h for some reason - strange Visual Studio errors
//namespace Debugger
//{
/*
* CCPUDebug implementation for the Musashi Motorola 68000 emulator.
*/
class CMusashi68KDebug : public C68KDebug, public ::CBus
{
private:
static UINT32 GetReg(CCPUDebug *cpu, unsigned id);
static bool SetReg(CCPUDebug *cpu, unsigned id, UINT32 data);
M68KCtx *m_ctx;
UINT32 m_resetAddr;
M68KCtx m_savedCtx;
::CBus *m_bus;
void SetM68KContext();
void UpdateM68KContext(M68KCtx *ctx);
void RestoreM68KContext();
protected:
UINT32 GetSP();
public:
CMusashi68KDebug(const char *name, M68KCtx *m68K);
virtual ~CMusashi68KDebug();
// CCPUDebug methods
void AttachToCPU();
void DetachFromCPU();
UINT32 GetResetAddr();
bool UpdatePC(UINT32 pc);
bool ForceException(CException *ex);
bool ForceInterrupt(CInterrupt *in);
UINT64 ReadMem(UINT32 addr, unsigned dataSize);
bool WriteMem(UINT32 addr, unsigned dataSize, UINT64 data);
// CBus methods
UINT8 Read8(UINT32 addr);
void Write8(UINT32 addr, UINT8 data);
UINT16 Read16(UINT32 addr);
void Write16(UINT32 addr, UINT16 data);
UINT32 Read32(UINT32 addr);
void Write32(UINT32 addr, UINT32 data);
};
// Inlined methods
inline void CMusashi68KDebug::SetM68KContext()
{
M68KGetContext(&m_savedCtx);
if (m_savedCtx.Debug != this)
M68KSetContext(m_ctx);
}
inline void CMusashi68KDebug::UpdateM68KContext(M68KCtx *ctx)
{
m_ctx = ctx;
}
inline void CMusashi68KDebug::RestoreM68KContext()
{
if (m_savedCtx.Debug != this)
M68KSetContext(&m_savedCtx);
}
//}
#endif // INCLUDED_MUSASHI68KDEBUG_H
#endif // SUPERMODEL_DEBUGGER

View file

@ -85,10 +85,8 @@ namespace Debugger
static const char *crGroup = "Condition Registers";
static const char *grGroup = "GPR Registers";
static const char *frGroup = "FPR Registers";
static const char *giGroup = "Game Inputs";
static const char *sbGroup = "Sound Board";
CPPCDebug::CPPCDebug() : CCPUDebug("PPC", 4, 4, true, 32, 7), m_irqState(0)
CPPCDebug::CPPCDebug(const char *name) : CCPUDebug("PPC", name, 4, 4, true, 32, 7), m_irqState(0)
{
// PC & Link registers
AddPCRegister ("pc", srGroup);
@ -131,69 +129,6 @@ namespace Debugger
AddException("SMI", EXCEPTION_SMI, "SMI");
AddException("DSI", EXCEPTION_DSI, "DSI");
AddException("ISI", EXCEPTION_ISI, "ISI");
// TODO - following Model3-specific stuff should be moved to SupermodelDebugger
// Interrupts
AddInterrupt("VD0", 0, "Unknown video-related");
AddInterrupt("VBL", 1, "VBlank start");
AddInterrupt("VD2", 2, "Unknown video-related");
AddInterrupt("VD3", 3, "Unknown video-related");
AddInterrupt("NET", 4, "Network");
AddInterrupt("UN5", 5, "Unknown");
AddInterrupt("SND", 6, "SCSP (sound)");
AddInterrupt("UN7", 7, "Unknown");
// Memory regions
AddRegion(0x00000000, 0x007FFFFF, true, false, "RAM");
AddRegion(0x84000000, 0x8400003F, false, false, "Real3D Status Registers");
AddRegion(0x88000000, 0x88000007, false, false, "Real3D Command Port");
AddRegion(0x8C000000, 0x8C3FFFFF, false, false, "Real3D Culling RAM (Low)");
AddRegion(0x8E000000, 0x8E0FFFFF, false, false, "Real3D Culling RAM (High)");
AddRegion(0x90000000, 0x9000000B, false, false, "Real3D VROM Texture Port");
AddRegion(0x94000000, 0x940FFFFF, false, false, "Real3D Texture FIFO");
AddRegion(0x98000000, 0x980FFFFF, false, false, "Real3D Polygon RAM");
AddRegion(0xC0000000, 0xC00000FF, false, false, "SCSI (Step 1.x)");
AddRegion(0xC1000000, 0xC10000FF, false, false, "SCSI (Step 1.x) (Lost World expects it here)");
AddRegion(0xC2000000, 0xC20000FF, false, false, "Real3D DMA (Step 2.x)");
AddRegion(0xF0040000, 0xF004003F, false, false, "Input (Controls) Registers");
AddRegion(0xF0080000, 0xF0080007, false, false, "Sound Board Registers");
AddRegion(0xF00C0000, 0xF00DFFFF, false, false, "Backup RAM");
AddRegion(0xF0100000, 0xF010003F, false, false, "System Registers");
AddRegion(0xF0140000, 0xF014003F, false, false, "Real, 0xTime Clock");
AddRegion(0xF0180000, 0xF019FFFF, false, false, "Security Board RAM");
AddRegion(0xF01A0000, 0xF01A003F, false, false, "Security Board Registers");
AddRegion(0xF0800CF8, 0xF0800CFF, false, false, "MPC105 CONFIG_ADDR (Step 1.x)");
AddRegion(0xF0C00CF8, 0xF0C00CFF, false, false, "MPC105 CONFIG_DATA (Step 1.x)");
AddRegion(0xF1000000, 0xF10F7FFF, false, false, "Tile Generator Pattern Table");
AddRegion(0xF10F8000, 0xF10FFFFF, false, false, "Tile Generator Name Table");
AddRegion(0xF1100000, 0xF111FFFF, false, false, "Tile Generator Palette");
AddRegion(0xF1180000, 0xF11800FF, false, false, "Tile Generator Registers");
AddRegion(0xF8FFF000, 0xF8FFF0FF, false, false, "MPC105 (Step 1.x) or MPC106 (Step 2.x) Registers");
AddRegion(0xF9000000, 0xF90000FF, false, false, "NCR 53C810 Registers (Step 1.x?)");
AddRegion(0xFE040000, 0xFE04003F, false, false, "Mirrored Input Registers");
AddRegion(0xFEC00000, 0xFEDFFFFF, false, false, "MPC106 CONFIG_ADDR (Step 2.x)");
AddRegion(0xFEE00000, 0xFEFFFFFF, false, false, "MPC106 CONFIG_DATA (Step 2.x)");
AddRegion(0xFF000000, 0xFF7FFFFF, true, true, "Banked CROM (CROMxx)");
AddRegion(0xFF800000, 0xFFFFFFFF, true, true, "Fixed CROM");
// Memory-mapped IO
AddMappedIO(0xF0040000, 1, "Input Bank Select", giGroup);
AddMappedIO(0xF0040004, 1, "Current Input Bank", giGroup);
AddMappedIO(0xF0040008, 1, "Game Specific Inputs 1", giGroup);
AddMappedIO(0xF004000C, 1, "Game Specific Inputs 2", giGroup);
AddMappedIO(0xF0040010, 1, "Drive Board", giGroup);
AddMappedIO(0xF0040014, 1, "LED Outputs?", giGroup);
AddMappedIO(0xF0040018, 1, "Unknown?", giGroup);
AddMappedIO(0xF0040024, 1, "Serial FIFO 1 Control", giGroup);
AddMappedIO(0xF0040028, 1, "Serial FIFO 2 Control", giGroup);
AddMappedIO(0xF004002C, 1, "Serial FIFO 1", giGroup);
AddMappedIO(0xF0040030, 1, "Serial FIFO 2", giGroup);
AddMappedIO(0xF0040034, 1, "Serial FIFO Flags", giGroup);
AddMappedIO(0xF004003C, 1, "ADC", giGroup);
AddMappedIO(0xF0080000, 1, "MIDI", sbGroup);
AddMappedIO(0xF0080004, 1, "Control", sbGroup);
}
CPPCDebug::~CPPCDebug()
@ -278,7 +213,7 @@ namespace Debugger
void CPPCDebug::CheckException(UINT16 exCode)
{
CCPUDebug::CheckException(exCode);
CCPUDebug::CPUException(exCode);
if (exCode == EXCEPTION_IRQ)
{
@ -288,7 +223,7 @@ namespace Debugger
for (int intCode = 0; newIRQs && intCode < 8; intCode++)
{
if (newIRQs&0x01)
CheckInterrupt(intCode);
CPUInterrupt(intCode);
newIRQs >>= 1;
}
m_irqState = irqState;
@ -350,7 +285,6 @@ namespace Debugger
return 4;
}
else
return -4;
}

View file

@ -35,7 +35,7 @@ namespace Debugger
UINT8 m_irqState;
public:
CPPCDebug();
CPPCDebug(const char *name);
virtual ~CPPCDebug();

View file

@ -11,9 +11,9 @@ namespace Debugger
{
switch (id)
{
case M68KSPECIAL_SP: return (UINT32)turbo68kcontext_68000.a[7];
case M68KSPECIAL_SR: return (UINT32)turbo68kcontext_68000.sr;
default: return 0;
case TBO68K_REG_SP: return (UINT32)turbo68kcontext_68000.a[7];
case TBO68K_REG_SR: return (UINT32)turbo68kcontext_68000.sr;
default: return 0;
}
}
@ -21,9 +21,9 @@ namespace Debugger
{
switch (id)
{
case M68KSPECIAL_SP: turbo68kcontext_68000.a[7] = data; return true;
case M68KSPECIAL_SR: turbo68kcontext_68000.sr = data; return true;
default: return false;
case TBO68K_REG_SP: turbo68kcontext_68000.a[7] = data; return true;
case TBO68K_REG_SR: turbo68kcontext_68000.sr = data; return true;
default: return false;
}
}
@ -53,12 +53,12 @@ namespace Debugger
static const char *drGroup = "Data Registers";
static const char *arGroup = "Address Regsters";
CTurbo68KDebug::CTurbo68KDebug() : C68KDebug(), m_resetAddr(0)
CTurbo68KDebug::CTurbo68KDebug(const char *name) : C68KDebug(name), m_resetAddr(0)
{
// Special registers
AddPCRegister ("PC", srGroup);
AddAddrRegister ("SP", srGroup, M68KSPECIAL_SP, GetSpecialReg, SetSpecialReg);
AddStatus32Register("SR", srGroup, M68KSPECIAL_SR, "TtSM.210...XNZVC", GetSpecialReg, SetSpecialReg);
AddAddrRegister ("SP", srGroup, TBO68K_REG_SP, GetSpecialReg, SetSpecialReg);
AddStatus32Register("SR", srGroup, TBO68K_REG_SR, "TtSM.210...XNZVC", GetSpecialReg, SetSpecialReg);
// Data registers
for (unsigned id = 0; id < 8; id++)
@ -73,39 +73,6 @@ namespace Debugger
sprintf(m_arNames[id], "A%u", id);
AddInt32Register(m_arNames[id], arGroup, id, GetAddressReg, SetAddressReg);
}
// TODO - following Model3-specific stuff should be moved to SupermodelDebugger
// Regions
AddRegion(0x000000, 0x0FFFFF, true, false, "SCSP1 RAM");
AddRegion(0x200000, 0x2FFFFF, true, false, "SCSP2 RAM");
AddRegion(0x600000, 0x67FFFF, true, true, "Program ROM");
AddRegion(0x800000, 0x9FFFFF, false, true, "Sample ROM (low 2 MB)");
AddRegion(0xA00000, 0xDFFFFF, false, true, "Sample ROM (bank)");
AddRegion(0xE00000, 0xFFFFFF, false, true, "Sample ROM (bank)");
AddRegion(0x100000, 0x10FFFF, false, false, "SCSP Master");
AddRegion(0x300000, 0x30FFFF, false, false, "SCSP Slave");
// Mapped I/O
for (unsigned slot = 0; slot < 32; slot++)
{
sprintf(m_mSlotStr[slot], "SCSP Master Slot %02X", slot);
for (unsigned reg = 0; reg < 16; reg++)
{
UINT32 addr = 0x100000 + slot * 0x20 + reg * 0x02;
sprintf(m_regStr[reg], "Register %u", reg);
AddMappedIO(addr, 2, m_regStr[reg], m_mSlotStr[slot]);
}
}
for (unsigned slot = 0; slot < 32; slot++)
{
sprintf(m_sSlotStr[slot], "SCSP Slave Slot %02X", slot);
for (unsigned reg = 0; reg < 16; reg++)
{
UINT32 addr = 0x300000 + slot * 0x20 + reg * 0x02;
AddMappedIO(addr, 2, m_regStr[reg], m_sSlotStr[slot]);
}
}
}
CTurbo68KDebug::~CTurbo68KDebug()
@ -116,7 +83,7 @@ namespace Debugger
bool __cdecl DebugHandler(TURBO68K_INT32 pc, TURBO68K_INT32 opcode)
{
// Return true to let Turbo68K know if PC was changed by user
return debug->CheckExecution((UINT32)pc, (UINT32)opcode);
return debug->CPUExecute((UINT32)pc, (UINT32)opcode, 1); // TODO - lastCycles
}
void __cdecl InterruptHandler(TURBO68K_UINT32 intVec)
@ -126,11 +93,11 @@ namespace Debugger
return;
else if (intVec >= 25 || intVec < 32)
{
debug->CheckException(25);
debug->CheckInterrupt((UINT16)intVec - 25);
debug->CPUException(25);
debug->CPUInterrupt((UINT16)intVec - 25);
}
else
debug->CheckException((UINT16)intVec);
debug->CPUException((UINT16)intVec);
if (origIntAckPtr != NULL)
origIntAckPtr(intVec);

View file

@ -7,8 +7,8 @@
#include "CPU/68K/Turbo68K/Turbo68K.h"
#define M68KSPECIAL_SP 0
#define M68KSPECIAL_SR 1
#define TBO68K_REG_SP 0
#define TBO68K_REG_SR 1
#define USE_NATIVE_READ 0
#define USE_NATIVE_WRITE 0
@ -93,14 +93,13 @@ namespace Debugger
char m_drNames[8][3];
char m_arNames[8][3];
char m_mSlotStr[32][20];
char m_sSlotStr[32][20];
char m_regStr[16][12];
UINT32 m_resetAddr;
protected:
UINT32 GetSP();
public:
CTurbo68KDebug();
CTurbo68KDebug(const char *name);
virtual ~CTurbo68KDebug();
@ -112,8 +111,6 @@ namespace Debugger
UINT32 GetResetAddr();
UINT32 GetSP();
bool UpdatePC(UINT32 pc);
bool ForceException(CException *ex);

702
Src/Debugger/CPU/Z80Debug.cpp Executable file
View file

@ -0,0 +1,702 @@
#ifdef SUPERMODEL_DEBUGGER
#include "Z80Debug.h"
#include "CPU/Z80/Z80.h"
#include <string.h>
namespace Debugger
{
// Instruction templates
static char *templates[5][256] = {
{
// Table 0: single byte instructions
"NOP","LD BC,@a","LD (BC),A","INC BC","INC B","DEC B","LD B,@d","RLCA",
"EX AF,AF'","ADD HL,BC","LD A,(BC)","DEC BC","INC C","DEC C","LD C,@d","RRCA",
"DJNZ @b","LD DE,@a","LD (DE),A","INC DE","INC D","DEC D","LD D,@d","RLA",
"JR @b","ADD HL,DE","LD A,(DE)","DEC DE","INC E","DEC E","LD E,@d","RRA",
"JR NZ,@b","LD HL,@a","LD (@a),HL","INC HL","INC H","DEC H","LD H,@d","DAA",
"JR Z,@b","ADD HL,HL","LD HL,(@a)","DEC HL","INC L","DEC L","LD L,@d","CPL",
"JR NC,@b","LD SP,@a","LD (@a),A","INC SP","INC (HL)","DEC (HL)","LD (HL),@d","SCF",
"JR C,@b","ADD HL,SP","LD A,(@a)","DEC SP","INC A","DEC A","LD A,@d","CCF",
"LD B,B","LD B,C","LD B,D","LD B,E","LD B,H","LD B,L","LD B,(HL)","LD B,A",
"LD C,B","LD C,C","LD C,D","LD C,E","LD C,H","LD C,L","LD C,(HL)","LD C,A",
"LD D,B","LD D,C","LD D,D","LD D,E","LD D,H","LD D,L","LD D,(HL)","LD D,A",
"LD E,B","LD E,C","LD E,D","LD E,E","LD E,H","LD E,L","LD E,(HL)","LD E,A",
"LD H,B","LD H,C","LD H,D","LD H,E","LD H,H","LD H,L","LD H,(HL)","LD H,A",
"LD L,B","LD L,C","LD L,D","LD L,E","LD L,H","LD L,L","LD L,(HL)","LD L,A",
"LD (HL),B","LD (HL),C","LD (HL),D","LD (HL),E","LD (HL),H","LD (HL),L","HALT","LD (HL),A",
"LD A,B","LD A,C","LD A,D","LD A,E","LD A,H","LD A,L","LD A,(HL)","LD A,A",
"ADD B","ADD C","ADD D","ADD E","ADD H","ADD L","ADD (HL)","ADD A",
"ADC B","ADC C","ADC D","ADC E","ADC H","ADC L","ADC (HL)","ADC A",
"SUB B","SUB C","SUB D","SUB E","SUB H","SUB L","SUB (HL)","SUB A",
"SBC B","SBC C","SBC D","SBC E","SBC H","SBC L","SBC (HL)","SBC A",
"AND B","AND C","AND D","AND E","AND H","AND L","AND (HL)","AND A",
"XOR B","XOR C","XOR D","XOR E","XOR H","XOR L","XOR (HL)","XOR A",
"OR B","OR C","OR D","OR E","OR H","OR L","OR (HL)","OR A",
"CP B","CP C","CP D","CP E","CP H","CP L","CP (HL)","CP A",
"RET NZ","POP BC","JP NZ,@j","JP @j","CALL NZ,@j","PUSH BC","ADD @d","RST 00h",
"RET Z","RET","JP Z,@j","PFX_CB","CALL Z,@j","CALL @j","ADC @d","RST 08h",
"RET NC","POP DE","JP NC,@j","OUTA (@p)","CALL NC,@j","PUSH DE","SUB @d","RST 10h",
"RET C","EXX","JP C,@j","INA (@p)","CALL C,@j","PFX_DD","SBC @d","RST 18h",
"RET PO","POP HL","JP PO,@j","EX HL,(SP)","CALL PO,@j","PUSH HL","AND @d","RST 20h",
"RET PE","LD PC,HL","JP PE,@j","EX DE,HL","CALL PE,@j","PFX_ED","XOR @d","RST 28h",
"RET P","POP AF","JP P,@j","DI","CALL P,@j","PUSH AF","OR @d","RST 30h",
"RET M","LD SP,HL","JP M,@j","EI","CALL M,@j","PFX_FD","CP @d","RST 38h"
}, {
// Table 1: two byte instructions of form CB-XX
"RLC B","RLC C","RLC D","RLC E","RLC H","RLC L","RLC (HL)","RLC A",
"RRC B","RRC C","RRC D","RRC E","RRC H","RRC L","RRC (HL)","RRC A",
"RL B","RL C","RL D","RL E","RL H","RL L","RL (HL)","RL A",
"RR B","RR C","RR D","RR E","RR H","RR L","RR (HL)","RR A",
"SLA B","SLA C","SLA D","SLA E","SLA H","SLA L","SLA (HL)","SLA A",
"SRA B","SRA C","SRA D","SRA E","SRA H","SRA L","SRA (HL)","SRA A",
"SLL B","SLL C","SLL D","SLL E","SLL H","SLL L","SLL (HL)","SLL A",
"SRL B","SRL C","SRL D","SRL E","SRL H","SRL L","SRL (HL)","SRL A",
"BIT 0,B","BIT 0,C","BIT 0,D","BIT 0,E","BIT 0,H","BIT 0,L","BIT 0,(HL)","BIT 0,A",
"BIT 1,B","BIT 1,C","BIT 1,D","BIT 1,E","BIT 1,H","BIT 1,L","BIT 1,(HL)","BIT 1,A",
"BIT 2,B","BIT 2,C","BIT 2,D","BIT 2,E","BIT 2,H","BIT 2,L","BIT 2,(HL)","BIT 2,A",
"BIT 3,B","BIT 3,C","BIT 3,D","BIT 3,E","BIT 3,H","BIT 3,L","BIT 3,(HL)","BIT 3,A",
"BIT 4,B","BIT 4,C","BIT 4,D","BIT 4,E","BIT 4,H","BIT 4,L","BIT 4,(HL)","BIT 4,A",
"BIT 5,B","BIT 5,C","BIT 5,D","BIT 5,E","BIT 5,H","BIT 5,L","BIT 5,(HL)","BIT 5,A",
"BIT 6,B","BIT 6,C","BIT 6,D","BIT 6,E","BIT 6,H","BIT 6,L","BIT 6,(HL)","BIT 6,A",
"BIT 7,B","BIT 7,C","BIT 7,D","BIT 7,E","BIT 7,H","BIT 7,L","BIT 7,(HL)","BIT 7,A",
"RES 0,B","RES 0,C","RES 0,D","RES 0,E","RES 0,H","RES 0,L","RES 0,(HL)","RES 0,A",
"RES 1,B","RES 1,C","RES 1,D","RES 1,E","RES 1,H","RES 1,L","RES 1,(HL)","RES 1,A",
"RES 2,B","RES 2,C","RES 2,D","RES 2,E","RES 2,H","RES 2,L","RES 2,(HL)","RES 2,A",
"RES 3,B","RES 3,C","RES 3,D","RES 3,E","RES 3,H","RES 3,L","RES 3,(HL)","RES 3,A",
"RES 4,B","RES 4,C","RES 4,D","RES 4,E","RES 4,H","RES 4,L","RES 4,(HL)","RES 4,A",
"RES 5,B","RES 5,C","RES 5,D","RES 5,E","RES 5,H","RES 5,L","RES 5,(HL)","RES 5,A",
"RES 6,B","RES 6,C","RES 6,D","RES 6,E","RES 6,H","RES 6,L","RES 6,(HL)","RES 6,A",
"RES 7,B","RES 7,C","RES 7,D","RES 7,E","RES 7,H","RES 7,L","RES 7,(HL)","RES 7,A",
"SET 0,B","SET 0,C","SET 0,D","SET 0,E","SET 0,H","SET 0,L","SET 0,(HL)","SET 0,A",
"SET 1,B","SET 1,C","SET 1,D","SET 1,E","SET 1,H","SET 1,L","SET 1,(HL)","SET 1,A",
"SET 2,B","SET 2,C","SET 2,D","SET 2,E","SET 2,H","SET 2,L","SET 2,(HL)","SET 2,A",
"SET 3,B","SET 3,C","SET 3,D","SET 3,E","SET 3,H","SET 3,L","SET 3,(HL)","SET 3,A",
"SET 4,B","SET 4,C","SET 4,D","SET 4,E","SET 4,H","SET 4,L","SET 4,(HL)","SET 4,A",
"SET 5,B","SET 5,C","SET 5,D","SET 5,E","SET 5,H","SET 5,L","SET 5,(HL)","SET 5,A",
"SET 6,B","SET 6,C","SET 6,D","SET 6,E","SET 6,H","SET 6,L","SET 6,(HL)","SET 6,A",
"SET 7,B","SET 7,C","SET 7,D","SET 7,E","SET 7,H","SET 7,L","SET 7,(HL)","SET 7,A"
}, {
// Table 2: two byte instructions of form ED-XX
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
"IN B,(C)","OUT (C),B","SBC HL,BC","LD (@a),BC","NEG","RETN","IM 0","LD I,A",
"IN C,(C)","OUT (C),C","ADC HL,BC","LD BC,(@a)",NULL,"RETI",NULL,"LD R,A",
"IN D,(C)","OUT (C),D","SBC HL,DE","LD (@a),DE",NULL,NULL,"IM 1","LD A,I",
"IN E,(C)","OUT (C),E","ADC HL,DE","LD DE,(@a)",NULL,NULL,"IM 2","LD A,R",
"IN H,(C)","OUT (C),H","SBC HL,HL","LD (@a),HL",NULL,NULL,NULL,"RRD",
"IN L,(C)","OUT (C),L","ADC HL,HL","LD HL,(@a)",NULL,NULL,NULL,"RLD",
"IN F,(C)",NULL,"SBC HL,SP","LD (@a),SP",NULL,NULL,NULL,NULL,
"IN A,(C)","OUT (C),A","ADC HL,SP","LD SP,(@a)",NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
"LDI","CPI","INI","OUTI",NULL,NULL,NULL,NULL,
"LDD","CPD","IND","OUTD",NULL,NULL,NULL,NULL,
"LDIR","CPIR","INIR","OTIR",NULL,NULL,NULL,NULL,
"LDDR","CPDR","INDR","OTDR",NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL
}, {
// Table 3: two byte instructions of form DD-XX or FD-XX
"NOP","LD BC,@a","LD (BC),A","INC BC","INC B","DEC B","LD B,@d","RLCA",
"EX AF,AF'","ADD I?,BC","LD A,(BC)","DEC BC","INC C","DEC C","LD C,@d","RRCA",
"DJNZ @b","LD DE,@a","LD (DE),A","INC DE","INC D","DEC D","LD D,@d","RLA",
"JR @b","ADD I?,DE","LD A,(DE)","DEC DE","INC E","DEC E","LD E,@d","RRA",
"JR NZ,@b","LD I?,@a","LD (@a),I?","INC I?","INC I?h","DEC I?h","LD I?h,@d","DAA",
"JR Z,@b","ADD I?,I?","LD I?,(@a)","DEC I?","INC I?l","DEC I?l","LD I?l,@d","CPL",
"JR NC,@b","LD SP,@a","LD (@a),A","INC SP","INC (I?+@d)","DEC (I?+@d)","LD (I?+@d),@d","SCF",
"JR C,@b","ADD I?,SP","LD A,(@a)","DEC SP","INC A","DEC A","LD A,@d","CCF",
"LD B,B","LD B,C","LD B,D","LD B,E","LD B,I?h","LD B,I?l","LD B,(I?+@d)","LD B,A",
"LD C,B","LD C,C","LD C,D","LD C,E","LD C,I?h","LD C,I?l","LD C,(I?+@d)","LD C,A",
"LD D,B","LD D,C","LD D,D","LD D,E","LD D,I?h","LD D,I?l","LD D,(I?+@d)","LD D,A",
"LD E,B","LD E,C","LD E,D","LD E,E","LD E,I?h","LD E,I?l","LD E,(I?+@d)","LD E,A",
"LD I?h,B","LD I?h,C","LD I?h,D","LD I?h,E","LD I?h,I?h","LD I?h,I?l","LD H,(I?+@d)","LD I?h,A",
"LD I?l,B","LD I?l,C","LD I?l,D","LD I?l,E","LD I?l,I?h","LD I?l,I?l","LD L,(I?+@d)","LD I?l,A",
"LD (I?+@d),B","LD (I?+@d),C","LD (I?+@d),D","LD (I?+@d),E","LD (I?+@d),H","LD (I?+@d),L","HALT","LD (I?+@d),A",
"LD A,B","LD A,C","LD A,D","LD A,E","LD A,I?h","LD A,I?l","LD A,(I?+@d)","LD A,A",
"ADD B","ADD C","ADD D","ADD E","ADD I?h","ADD I?l","ADD (I?+@d)","ADD A",
"ADC B","ADC C","ADC D","ADC E","ADC I?h","ADC I?l","ADC (I?+@d)","ADC,A",
"SUB B","SUB C","SUB D","SUB E","SUB I?h","SUB I?l","SUB (I?+@d)","SUB A",
"SBC B","SBC C","SBC D","SBC E","SBC I?h","SBC I?l","SBC (I?+@d)","SBC A",
"AND B","AND C","AND D","AND E","AND I?h","AND I?l","AND (I?+@d)","AND A",
"XOR B","XOR C","XOR D","XOR E","XOR I?h","XOR I?l","XOR (I?+@d)","XOR A",
"OR B","OR C","OR D","OR E","OR I?h","OR I?l","OR (I?+@d)","OR A",
"CP B","CP C","CP D","CP E","CP I?h","CP I?l","CP (I?+@d)","CP A",
"RET NZ","POP BC","JP NZ,@a","JP @a","CALL NZ,@a","PUSH BC","ADD @d","RST 00h",
"RET Z","RET","JP Z,@a","PFX_CB","CALL Z,@a","CALL @a","ADC @d","RST 08h",
"RET NC","POP DE","JP NC,@a","OUTA (@p)","CALL NC,@a","PUSH DE","SUB @d","RST 10h",
"RET C","EXX","JP C,@a","INA (@p)","CALL C,@a","PFX_DD","SBC @d","RST 18h",
"RET PO","POP I?","JP PO,@a","EX I?,(SP)","CALL PO,@a","PUSH I?","AND @d","RST 20h",
"RET PE","LD PC,I?","JP PE,@a","EX DE,I?","CALL PE,@a","PFX_ED","XOR @d","RST 28h",
"RET P","POP AF","JP P,@a","DI","CALL P,@a","PUSH AF","OR @d","RST 30h",
"RET M","LD SP,I?","JP M,@a","EI","CALL M,@a","PFX_FD","CP @d","RST 38h"
}, {
// Table 4: three byte instructions of form DD-CB-XX or FD-CB-XX
"RLC B","RLC C","RLC D","RLC E","RLC H","RLC L","RLC (I?@o)","RLC A",
"RRC B","RRC C","RRC D","RRC E","RRC H","RRC L","RRC (I?@o)","RRC A",
"RL B","RL C","RL D","RL E","RL H","RL L","RL (I?@o)","RL A",
"RR B","RR C","RR D","RR E","RR H","RR L","RR (I?@o)","RR A",
"SLA B","SLA C","SLA D","SLA E","SLA H","SLA L","SLA (I?@o)","SLA A",
"SRA B","SRA C","SRA D","SRA E","SRA H","SRA L","SRA (I?@o)","SRA A",
"SLL B","SLL C","SLL D","SLL E","SLL H","SLL L","SLL (I?@o)","SLL A",
"SRL B","SRL C","SRL D","SRL E","SRL H","SRL L","SRL (I?@o)","SRL A",
"BIT 0,B","BIT 0,C","BIT 0,D","BIT 0,E","BIT 0,H","BIT 0,L","BIT 0,(I?@o)","BIT 0,A",
"BIT 1,B","BIT 1,C","BIT 1,D","BIT 1,E","BIT 1,H","BIT 1,L","BIT 1,(I?@o)","BIT 1,A",
"BIT 2,B","BIT 2,C","BIT 2,D","BIT 2,E","BIT 2,H","BIT 2,L","BIT 2,(I?@o)","BIT 2,A",
"BIT 3,B","BIT 3,C","BIT 3,D","BIT 3,E","BIT 3,H","BIT 3,L","BIT 3,(I?@o)","BIT 3,A",
"BIT 4,B","BIT 4,C","BIT 4,D","BIT 4,E","BIT 4,H","BIT 4,L","BIT 4,(I?@o)","BIT 4,A",
"BIT 5,B","BIT 5,C","BIT 5,D","BIT 5,E","BIT 5,H","BIT 5,L","BIT 5,(I?@o)","BIT 5,A",
"BIT 6,B","BIT 6,C","BIT 6,D","BIT 6,E","BIT 6,H","BIT 6,L","BIT 6,(I?@o)","BIT 6,A",
"BIT 7,B","BIT 7,C","BIT 7,D","BIT 7,E","BIT 7,H","BIT 7,L","BIT 7,(I?@o)","BIT 7,A",
"RES 0,B","RES 0,C","RES 0,D","RES 0,E","RES 0,H","RES 0,L","RES 0,(I?@o)","RES 0,A",
"RES 1,B","RES 1,C","RES 1,D","RES 1,E","RES 1,H","RES 1,L","RES 1,(I?@o)","RES 1,A",
"RES 2,B","RES 2,C","RES 2,D","RES 2,E","RES 2,H","RES 2,L","RES 2,(I?@o)","RES 2,A",
"RES 3,B","RES 3,C","RES 3,D","RES 3,E","RES 3,H","RES 3,L","RES 3,(I?@o)","RES 3,A",
"RES 4,B","RES 4,C","RES 4,D","RES 4,E","RES 4,H","RES 4,L","RES 4,(I?@o)","RES 4,A",
"RES 5,B","RES 5,C","RES 5,D","RES 5,E","RES 5,H","RES 5,L","RES 5,(I?@o)","RES 5,A",
"RES 6,B","RES 6,C","RES 6,D","RES 6,E","RES 6,H","RES 6,L","RES 6,(I?@o)","RES 6,A",
"RES 7,B","RES 7,C","RES 7,D","RES 7,E","RES 7,H","RES 7,L","RES 7,(I?@o)","RES 7,A",
"SET 0,B","SET 0,C","SET 0,D","SET 0,E","SET 0,H","SET 0,L","SET 0,(I?@o)","SET 0,A",
"SET 1,B","SET 1,C","SET 1,D","SET 1,E","SET 1,H","SET 1,L","SET 1,(I?@o)","SET 1,A",
"SET 2,B","SET 2,C","SET 2,D","SET 2,E","SET 2,H","SET 2,L","SET 2,(I?@o)","SET 2,A",
"SET 3,B","SET 3,C","SET 3,D","SET 3,E","SET 3,H","SET 3,L","SET 3,(I?@o)","SET 3,A",
"SET 4,B","SET 4,C","SET 4,D","SET 4,E","SET 4,H","SET 4,L","SET 4,(I?@o)","SET 4,A",
"SET 5,B","SET 5,C","SET 5,D","SET 5,E","SET 5,H","SET 5,L","SET 5,(I?@o)","SET 5,A",
"SET 6,B","SET 6,C","SET 6,D","SET 6,E","SET 6,H","SET 6,L","SET 6,(I?@o)","SET 6,A",
"SET 7,B","SET 7,C","SET 7,D","SET 7,E","SET 7,H","SET 7,L","SET 7,(I?@o)","SET 7,A"
}
};
UINT8 CZ80Debug::ReadReg8(CCPUDebug *cpu, unsigned reg8)
{
return ((CZ80Debug*)cpu)->m_z80->GetReg8(reg8);
}
bool CZ80Debug::WriteReg8(CCPUDebug *cpu, unsigned reg8, UINT8 value)
{
return ((CZ80Debug*)cpu)->m_z80->SetReg8(reg8, value);
}
UINT16 CZ80Debug::ReadReg16(CCPUDebug *cpu, unsigned reg16)
{
return ((CZ80Debug*)cpu)->m_z80->GetReg16(reg16);
}
bool CZ80Debug::WriteReg16(CCPUDebug *cpu, unsigned reg16, UINT16 value)
{
return ((CZ80Debug*)cpu)->m_z80->SetReg16(reg16, value);
}
static const char *crGroup = "Control Regs";
static const char *irGroup = "Int/Refresh Regs";
static const char *r8Group = "8-Bit Regs";
static const char *r16Group = "16-Bit Regs";
static const char *srGroup = "Shadow Regs";
CZ80Debug::CZ80Debug(const char *name, CZ80 *z80) : CCPUDebug("Z80", name, 1, 4, false, 16, 4), m_z80(z80)
{
// Main registers
AddPCRegister ("PC", crGroup);
AddInt16Register ("SP", crGroup, Z80_REG16_SP, ReadReg16, WriteReg16);
AddStatus8Register("F", crGroup, Z80_REG8_F, "SZ.HPVNC", ReadReg8, WriteReg8);
AddStatus8Register("IFF", irGroup, Z80_REG8_IFF, "H.E.G21F", ReadReg8, WriteReg8);
AddInt8Register ("I", irGroup, Z80_REG8_I, ReadReg8, WriteReg8);
AddInt8Register ("R", irGroup, Z80_REG8_R, ReadReg8, WriteReg8);
AddInt8Register("A", r8Group, Z80_REG8_A, ReadReg8, WriteReg8);
AddInt8Register("B", r8Group, Z80_REG8_B, ReadReg8, WriteReg8);
AddInt8Register("C", r8Group, Z80_REG8_C, ReadReg8, WriteReg8);
AddInt8Register("D", r8Group, Z80_REG8_D, ReadReg8, WriteReg8);
AddInt8Register("E", r8Group, Z80_REG8_E, ReadReg8, WriteReg8);
AddInt16Register("AF", r16Group, Z80_REG16_AF, ReadReg16, WriteReg16);
AddInt16Register("BC", r16Group, Z80_REG16_BC, ReadReg16, WriteReg16);
AddInt16Register("DE", r16Group, Z80_REG16_DE, ReadReg16, WriteReg16);
AddInt16Register("HL", r16Group, Z80_REG16_HL, ReadReg16, WriteReg16);
AddInt16Register("IX", r16Group, Z80_REG16_IX, ReadReg16, WriteReg16);
AddInt16Register("IY", r16Group, Z80_REG16_IY, ReadReg16, WriteReg16);
AddInt16Register("AF'", srGroup, Z80_REG16_AF_, ReadReg16, WriteReg16);
AddInt16Register("BC'", srGroup, Z80_REG16_BC_, ReadReg16, WriteReg16);
AddInt16Register("DE'", srGroup, Z80_REG16_DE_, ReadReg16, WriteReg16);
AddInt16Register("HL'", srGroup, Z80_REG16_HL_, ReadReg16, WriteReg16);
// Exceptions
AddException("NMI", Z80_EX_NMI, "Non-Maskable Interrupt");
AddException("RST00", Z80_INT_RST_00, "RST 00h (IM0)");
AddException("RST08", Z80_INT_RST_08, "RST 08h (IM0)");
AddException("RST10", Z80_INT_RST_10, "RST 10h (IM0)");
AddException("RST18", Z80_INT_RST_18, "RST 18h (IM0)");
AddException("RST20", Z80_INT_RST_20, "RST 20h (IM0)");
AddException("RST28", Z80_INT_RST_28, "RST 28h (IM0)");
AddException("RST30", Z80_INT_RST_30, "RST 30h (IM0)");
AddException("RST38", Z80_INT_RST_38, "RST 38h (IM0)");
AddException("IRQ", Z80_IM1_IRQ, "Hardwired IRQ (IM1)");
AddException("VECTOR", Z80_IM2_VECTOR, "Interrupt Vectors (IM2)");
// Interrupts
for (unsigned vecNum = 0; vecNum < 256; vecNum++)
{
sprintf(m_vecIds[vecNum], "V%u", vecNum + 1);
sprintf(m_vecNames[vecNum], "Interrupt Vector #%u", vecNum + 1);
AddInterrupt(m_vecIds[vecNum], vecNum, m_vecNames[vecNum]);
}
// I/O ports
for (unsigned portNum = 0; portNum < 256; portNum++)
{
sprintf(m_portNames[portNum], "Port #%u", portNum);
AddPortIO(portNum, 1, m_portNames[portNum], "I/O Ports");
}
}
CZ80Debug::~CZ80Debug()
{
DetachFromCPU();
}
void CZ80Debug::AttachToCPU()
{
m_z80->AttachDebugger(this);
}
::CBus *CZ80Debug::AttachBus(::CBus *bus)
{
m_bus = bus;
return this;
}
void CZ80Debug::DetachFromCPU()
{
m_z80->DetachDebugger();
}
::CBus *CZ80Debug::DetachBus()
{
::CBus *bus = m_bus;
m_bus = NULL;
return bus;
}
UINT32 CZ80Debug::GetResetAddr()
{
return 0x0000;
}
bool CZ80Debug::UpdatePC(UINT32 pc)
{
return m_z80->SetReg16(Z80_REG16_PC, pc);
}
bool CZ80Debug::ForceException(CException *ex)
{
if (ex->code != Z80_EX_NMI)
{
// TODO
return false;
}
m_z80->TriggerNMI();
return true;
}
bool CZ80Debug::ForceInterrupt(CInterrupt *in)
{
// TODO
return false;
}
UINT64 CZ80Debug::ReadMem(UINT32 addr, unsigned dataSize)
{
if (dataSize == 1)
return m_bus->Read8(addr);
// TODO - byte swapping
return CCPUDebug::ReadMem(addr, dataSize);
}
bool CZ80Debug::WriteMem(UINT32 addr, unsigned dataSize, UINT64 data)
{
if (dataSize == 1)
{
m_bus->Write8(addr, (UINT8)data);
return true;
}
// TODO - byte swapping
return CCPUDebug::WriteMem(addr, dataSize, data);
}
UINT64 CZ80Debug::ReadPort(UINT16 portNum)
{
return m_bus->IORead8(portNum);
}
bool CZ80Debug::WritePort(UINT16 portNum, UINT64 data)
{
m_bus->IOWrite8(portNum, (UINT8)data);
return true;
}
int CZ80Debug::Disassemble(UINT32 addr, char *mnemonic, char *operands)
{
char tmpStr[128], valStr[50], *templ, *pos;
INT8 offs;
EOpFlags opFlags;
UINT16 dAddr = addr;
UINT16 tAddr;
char xyChr = '\0';
bool notJump = false;
// Get instruction template from opcode
UINT8 opcode = m_bus->Read8(dAddr++);
UINT8 nextCode;
switch (opcode)
{
case 0xCB:
templ = templates[1][m_bus->Read8(dAddr++)];
break;
case 0xED:
templ = templates[2][m_bus->Read8(dAddr++)];
break;
case 0xDD:
xyChr = 'X';
nextCode = m_bus->Read8(dAddr++);
if (nextCode == 0xCB)
{
offs = m_bus->Read8(dAddr++);
notJump = true;
templ = templates[4][m_bus->Read8(dAddr++)];
}
else
templ = templates[3][nextCode];
break;
case 0xFD:
xyChr = 'Y';
nextCode = m_bus->Read8(dAddr++);
if (nextCode == 0xCB)
{
offs = m_bus->Read8(dAddr++);
notJump = true;
templ = templates[4][m_bus->Read8(dAddr++)];
}
else
templ = templates[3][nextCode];
break;
default:
templ = templates[0][opcode];
break;
}
// If no template found, then instruction is invalid
if (templ == NULL)
return -1;
// See if instruction has any operands
if (pos = strchr(templ, ' '))
{
// If so, substitute all @ parameters in template operand
strncpy(mnemonic, templ, pos - templ);
mnemonic[pos - templ] = '\0';
operands[0] = '\0';
char *opPos = operands;
templ = pos + 1;
for (;;)
{
if (pos = strchr(templ, '@'))
{
strncpy(opPos, templ, pos - templ);
opPos[pos - templ] = '\0';
// Format data for parameter
switch (*(pos + 1))
{
case 'd': // ^h or *h
FormatData(valStr, 1, m_bus->Read8(dAddr++));
break;
case 'p': // *p
FormatPortNum(valStr, m_bus->Read8(dAddr++), true);
break;
case 'b': // @H
offs = m_bus->Read8(dAddr++);
tAddr = dAddr + offs;
opFlags = GetOpFlags(addr, opcode);
FormatJumpAddress(valStr, tAddr, opFlags);
break;
case 'o': // @h
if (notJump)
{
// Keep argument as +/-offs
strcat(operands, (offs&0x80 ? "-" : "+"));
FormatData(valStr, 1, (offs&0x80 ? 256 - offs : offs));
}
else
{
offs = m_bus->Read8(dAddr++);
tAddr = dAddr + offs;
FormatAddress(valStr, tAddr, true);
}
break;
case 'j': // #H
tAddr = m_bus->Read8(dAddr++) + (m_bus->Read8(dAddr++)<<8);
opFlags = GetOpFlags(addr, opcode);
FormatJumpAddress(valStr, tAddr, opFlags);
break;
case 'a': // #h
tAddr = m_bus->Read8(dAddr++) + (m_bus->Read8(dAddr++)<<8);
FormatAddress(valStr, tAddr, true);
break;
}
// Append formatted data and loop again to process any more @ parameters
strcat(opPos, valStr);
templ = pos + 2;
opPos += strlen(opPos);
}
else
{
// No more @ parameters found so append remainder of template operand and exit loop
strcat(opPos, templ);
break;
}
}
// Finally substitute ? parameter (X or Y)
if (pos = strchr(operands, '?'))
*pos = xyChr;
}
else
{
// Instruction has no operands
strcpy(mnemonic, templ);
operands[0] = '\0';
}
// Return instruction size
return dAddr - addr;
}
//int CZ80Debug::GetOpLength(UINT32 addr)
//{
// // Get instruction template from opcode
// UINT32 dAddr = addr;
// UINT8 opcode = m_bus->Read8(dAddr++);
// const char *templ;
// switch (opcode)
// {
// case 0xCB:
// templ = templates[1][m_bus->Read8(dAddr++)];
// break;
// case 0xED:
// templ = templates[2][m_bus->Read8(dAddr++)];
// break;
// case 0xDD:
// opcode = m_bus->Read8(dAddr++);
// if (opcode == 0xCB)
// {
// dAddr++;
// templ = templates[4][m_bus->Read8(dAddr++)];
// }
// else
// templ = templates[3][opcode];
// break;
// case 0xFD:
// opcode = m_bus->Read8(dAddr++);
// if (opcode == 0xCB)
// {
// dAddr++;
// templ = templates[4][m_bus->Read8(dAddr++)];
// }
// else
// templ = templates[3][opcode];
// break;
// default:
// templ = templates[0][opcode];
// break;
// }
//
// // If no template found, then instruction is invalid
// if (templ == NULL)
// return -1;
//
// // Return instruction size
// return dAddr - addr;
//}
EOpFlags CZ80Debug::GetOpFlags(UINT32 addr, UINT32 opcode)
{
if (opcode == 0xC3)
return JumpSimple; // JP
else if (opcode == 0xC2 || opcode == 0xCA || opcode == 0xD2 || opcode == 0xDA ||
opcode == 0xE2 || opcode == 0xEA || opcode == 0xF2 || opcode == 0xFA)
return (EOpFlags)(JumpSimple | Conditional); // JP NZ, JP Z, JP NC, JP C, JP PO, JP PE, JP P, JP M
else if (opcode == 0x18)
return (EOpFlags)(JumpSimple | Relative); // JR
else if (opcode == 0x20 || opcode == 0x28 || opcode == 0x30 || opcode == 0x38)
return (EOpFlags)(JumpSimple | Relative | Conditional); // JR NZ, JR Z, JR NC, JR C
else if (opcode == 0x10)
return (EOpFlags)(JumpLoop | Relative | Conditional); // DJNZ
else if (opcode == 0xCD)
return JumpSub; // CALL
else if (opcode == 0xC4 || opcode == 0xCC || opcode == 0xD4 || opcode == 0xDC ||
opcode == 0xE4 || opcode == 0xEC || opcode == 0xF4 || opcode == 0xFC)
return (EOpFlags)(JumpSub | Conditional); // CALL NZ, CALL Z, CALL NC, CALL C, CALL PO, CALL PE, CALL P, CALL M
else if (opcode == 0xC9)
return ReturnSub; // RET
else if (opcode == 0xC0 || opcode == 0xC8 || opcode == 0xD0 || opcode == 0xD8 ||
opcode == 0xE0 || opcode == 0xE8 || opcode == 0xF0 || opcode == 0xF8)
return (EOpFlags)(ReturnSub | Conditional); // RET NZ, RET Z, RET NC, RET C, RET PO, RET PE, RET P, RET M
else if (opcode == 0xC7 || opcode == 0xCF || opcode == 0xD7 || opcode == 0xD7 ||
opcode == 0xE7 || opcode == 0xEF || opcode == 0xF7 || opcode == 0xFF)
return (EOpFlags)(JumpEx | NotFixed); // RST 0, RST 8, RST 10H, RST 18H, RST 20H, RST 28H, RST 30H, RST 38H
else if (opcode == 0xED)
{
UINT8 nextCode = m_bus->Read8(addr + 1);
if (nextCode == 0x4D || nextCode == 0x45)
return ReturnEx; // RETI, RETN
}
else if (opcode == 0xE9 ||
opcode == 0xDD && m_bus->Read8(addr + 1) == 0xE9 ||
opcode == 0xFD && m_bus->Read8(addr + 1) == 0xE9)
return (EOpFlags)(JumpSimple | NotFixed); // JR (HL), JR (IX) or JR (IY)
return NormalOp;
}
bool CZ80Debug::GetJumpAddr(UINT32 addr, UINT32 opcode, UINT32 &jumpAddr)
{
if (opcode == 0xC3 ||
opcode == 0xC2 || opcode == 0xCA || opcode == 0xD2 || opcode == 0xDA ||
opcode == 0xE2 || opcode == 0xEA || opcode == 0xF2 || opcode == 0xFA ||
opcode == 0xCD ||
opcode == 0xC4 || opcode == 0xCC || opcode == 0xD4 || opcode == 0xDC ||
opcode == 0xE4 || opcode == 0xEC || opcode == 0xF4 || opcode == 0xFC)
{
// JP, JP NZ, JP Z, JP NC, JP C, JP PO, JP PE, JP P, JP M,
// CALL, CALL NZ, CALL Z, CALL NC, CALL C, CALL PO, CALL PE, CALL P, CALL M
jumpAddr = (UINT32)(m_bus->Read8(addr + 1) + (m_bus->Read8(addr + 2)<<8));
return true;
}
else if (opcode == 0x18 || opcode == 0x20 || opcode == 0x28 || opcode == 0x30 || opcode == 0x38 || opcode == 0x10)
{
// JR, JR NZ, JR NC, JR C, DJNZ
INT8 offs = m_bus->Read8(addr + 1);
jumpAddr = addr + 2 + offs;
return true;
}
return false;
}
bool CZ80Debug::GetJumpRetAddr(UINT32 addr, UINT32 opcode, UINT32 &retAddr)
{
if (opcode == 0xCD ||
opcode == 0xC4 || opcode == 0xCC || opcode == 0xD4 || opcode == 0xDC ||
opcode == 0xE4 || opcode == 0xEC || opcode == 0xF4 || opcode == 0xFC)
{
// CALL, CALL NZ, CALL Z, CALL NC, CALL C, CALL PO, CALL PE, CALL P, CALL M
retAddr = addr + 3;
return true;
}
else if (opcode == 0xC7 || opcode == 0xCF || opcode == 0xD7 || opcode == 0xD7 ||
opcode == 0xE7 || opcode == 0xEF || opcode == 0xF7 || opcode == 0xFF)
{
// RST 0, RST 8, RST 10H, RST 18H, RST 20H, RST 28H, RST 30H, RST 38H
retAddr = addr + 1;
}
return false;
}
bool CZ80Debug::GetReturnAddr(UINT32 addr, UINT32 opcode, UINT32 &retAddr)
{
if (opcode == 0xC9 ||
opcode == 0xC0 || opcode == 0xC8 || opcode == 0xD0 || opcode == 0xD8 ||
opcode == 0xE0 || opcode == 0xE8 || opcode == 0xF0 || opcode == 0xF8)
{
// RET, RET NZ, RET Z, RET NC, RET C, RET PO, RET PE, RET P, RET M
UINT16 sp = m_z80->GetReg16(Z80_REG16_SP);
retAddr = (UINT32)m_bus->Read8(sp) + (((UINT32)m_bus->Read8(sp + 1))<<8);
return true;
}
else if (opcode == 0xED)
{
UINT8 nextCode = m_bus->Read8(addr + 1);
if (nextCode == 0x4D || nextCode == 0x45)
{
// RETI, RETN
UINT16 sp = m_z80->GetReg16(Z80_REG16_SP);
retAddr = (UINT32)m_bus->Read8(sp) + (((UINT32)m_bus->Read8(sp + 1))<<8);
return true;
}
}
return false;
}
bool CZ80Debug::GetHandlerAddr(CException *ex, UINT32 &handlerAddr)
{
switch (ex->code)
{
case Z80_EX_NMI: handlerAddr = 0x0066; return true; // Hardwired NMI vector
case Z80_INT_RST_00: handlerAddr = 0x0000; return true; // RST 0h
case Z80_INT_RST_08: handlerAddr = 0x0008; return true; // RST 8h
case Z80_INT_RST_10: handlerAddr = 0x0010; return true; // RST 10h
case Z80_INT_RST_18: handlerAddr = 0x0018; return true; // RST 18h
case Z80_INT_RST_20: handlerAddr = 0x0020; return true; // RST 20h
case Z80_INT_RST_28: handlerAddr = 0x0028; return true; // RST 28h
case Z80_INT_RST_30: handlerAddr = 0x0030; return true; // RST 30h
case Z80_INT_RST_38: handlerAddr = 0x0038; return true; // RST 38h
case Z80_IM1_IRQ: handlerAddr = 0x0038; return true; // Hardwired IRQ vector
default: return false;
}
}
bool CZ80Debug::GetHandlerAddr(CInterrupt *in, UINT32 &handlerAddr)
{
UINT8 iff = m_z80->GetReg8(Z80_REG8_IFF);
if (!(iff&0x04)) // IM2 mode
return false;
UINT8 i = m_z80->GetReg8(Z80_REG8_I);
handlerAddr = (((UINT32)i)<<8)|(((UINT32)in->code)&0xFF);
return true;
}
// CBus methods
UINT8 CZ80Debug::Read8(UINT32 addr)
{
UINT8 data = m_bus->Read8(addr);
CheckRead8(addr, data);
return data;
}
void CZ80Debug::Write8(UINT32 addr, UINT8 data)
{
m_bus->Write8(addr, data);
CheckWrite8(addr, data);
}
UINT8 CZ80Debug::IORead8(UINT32 portNum)
{
UINT8 data = m_bus->IORead8(portNum);
CheckPortInput(portNum, data);
return data;
}
void CZ80Debug::IOWrite8(UINT32 portNum, UINT8 data)
{
m_bus->IOWrite8(portNum, data);
CheckPortOutput(portNum, data);
}
}
#endif // SUPERMODEL_DEBUGGER

94
Src/Debugger/CPU/Z80Debug.h Executable file
View file

@ -0,0 +1,94 @@
#ifdef SUPERMODEL_DEBUGGER
#ifndef INCLUDED_Z80DEBUG_H
#define INCLUDED_Z80DEBUG_H
#include "Debugger/CPUDebug.h"
#include "CPU/Bus.h"
#include "Types.h"
class CZ80;
namespace Debugger
{
/*
* CCPUDebug implementation for the Zilog Z80 emulator.
*/
class CZ80Debug : public CCPUDebug, public ::CBus
{
private:
static UINT8 ReadReg8(CCPUDebug *cpu, unsigned reg8);
static bool WriteReg8(CCPUDebug *cpu, unsigned reg8, UINT8 value);
static UINT16 ReadReg16(CCPUDebug *cpu, unsigned reg16);
static bool WriteReg16(CCPUDebug *cpu, unsigned reg16, UINT16 value);
CZ80 *m_z80;
::CBus *m_bus;
char m_vecIds[256][5];
char m_vecNames[256][22];
char m_portNames[256][10];
public:
CZ80Debug(const char *name, CZ80 *z80);
virtual ~CZ80Debug();
// CZ80Debug methods
void AttachToCPU();
::CBus *AttachBus(::CBus *bus);
void DetachFromCPU();
::CBus *DetachBus();
UINT32 GetResetAddr();
bool UpdatePC(UINT32 pc);
bool ForceException(CException *ex);
bool ForceInterrupt(CInterrupt *in);
UINT64 ReadMem(UINT32 addr, unsigned dataSize);
bool WriteMem(UINT32 addr, unsigned dataSize, UINT64 data);
UINT64 ReadPort(UINT16 portNum);
bool WritePort(UINT16 portNum, UINT64 data);
int Disassemble(UINT32 addr, char *mnemonic, char *operands);
//int GetOpLength(UINT32 addr);
EOpFlags GetOpFlags(UINT32 addr, UINT32 opcode);
bool GetJumpAddr(UINT32 addr, UINT32 opcode, UINT32 &jumpAddr);
bool GetJumpRetAddr(UINT32 addr, UINT32 opcode, UINT32 &retAddr);
bool GetReturnAddr(UINT32 addr, UINT32 opcode, UINT32 &retAddr);
bool GetHandlerAddr(CException *ex, UINT32 &handlerAddr);
bool GetHandlerAddr(CInterrupt *in, UINT32 &handlerAddr);
// CBus methods
UINT8 Read8(UINT32 addr);
void Write8(UINT32 addr, UINT8 data);
UINT8 IORead8(UINT32 portNum);
void IOWrite8(UINT32 portNum, UINT8 data);
};
}
#endif // INCLUDED_Z80DEBUG_H
#endif // SUPERMODEL_DEBUGGER

View file

@ -9,19 +9,27 @@
namespace Debugger
{
CCPUDebug::CCPUDebug(const char *cpuName, UINT8 cpuMinInstrLen, UINT8 cpuMaxInstrLen, bool cpuBigEndian, UINT8 cpuMemBusWidth, UINT8 cpuMaxMnemLen) :
name(cpuName), minInstrLen(cpuMinInstrLen), maxInstrLen(cpuMaxInstrLen),
CCPUDebug::CCPUDebug(const char *cpuType, const char *cpuName,
UINT8 cpuMinInstrLen, UINT8 cpuMaxInstrLen, bool cpuBigEndian, UINT8 cpuMemBusWidth, UINT8 cpuMaxMnemLen) :
type(cpuType), name(cpuName), minInstrLen(cpuMinInstrLen), maxInstrLen(cpuMaxInstrLen),
bigEndian(cpuBigEndian), memBusWidth(cpuMemBusWidth), maxMnemLen(cpuMaxMnemLen),
enabled(true), addrFmt(HexDollar), portFmt(Decimal), dataFmt(HexDollar), debugger(NULL),
numExCodes(0), numIntCodes(0), numPorts(0), memSize(0), instrCount(0), pc(0), opcode(0),
m_break(false), m_userBreak(false), m_step(false), m_steppingOver(false), m_steppingOut(false), m_count(0), m_until(false), m_untilAddr(0),
numExCodes(0), numIntCodes(0), numPorts(0), memSize(0), active(false), instrCount(0), totalCycles(0), cyclesPerPoll(0), pc(0), opcode(0),
m_break(false), m_breakUser(false), m_halted(false), m_step(false), m_steppingOver(false), m_steppingOut(false),
m_count(0), m_until(false), m_untilAddr(0),
m_mappedIOTable(NULL), m_memWatchTable(NULL), m_bpTable(NULL), m_numRegMons(0), m_regMonArray(NULL),
m_analyser(NULL), m_stateUpdated(false), m_exRaised(NULL), m_exTrapped(NULL), m_intRaised(NULL), m_intTrapped(NULL), m_bpReached(NULL),
m_memWatchTriggered(NULL), m_ioWatchTriggered(NULL), m_regMonTriggered(NULL)
m_memWatchTriggered(NULL), m_ioWatchTriggered(NULL), m_regMonTriggered(NULL), m_prevTotalCycles(0)
{
memset(m_exArray, NULL, sizeof(m_exArray));
memset(m_intArray, NULL, sizeof(m_intArray));
memset(m_portArray, NULL, sizeof(m_portArray));
#ifdef DEBUGGER_HASTHREAD
m_breakWait = false;
m_mutex = CThread::CreateMutex();
m_condVar = CThread::CreateCondVar();
#endif // DEBUGGER_HASTHREAD
}
CCPUDebug::~CCPUDebug()
@ -377,14 +385,17 @@ namespace Debugger
void CCPUDebug::ForceBreak(bool user)
{
m_breakUser |= user;
m_break = true;
m_userBreak |= user;
}
void CCPUDebug::ClearBreak()
{
#ifdef DEBUGGER_HASTHREAD
m_breakWait = false;
#endif // DEBUGGER_HASTHREAD
m_breakUser = false;
m_break = false;
m_userBreak = false;
}
void CCPUDebug::SetContinue()
@ -1145,6 +1156,11 @@ namespace Debugger
}
}
// Load analyser state
CCodeAnalyser *analyser = GetCodeAnalyser();
if (!analyser->LoadState(state))
return false;
// TODO - load breakpoints, watches, exception/interrupt traps and register monitors
return true;
@ -1191,13 +1207,17 @@ namespace Debugger
state->Write(str, strLen * sizeof(char));
}
// Save analyser state, if available
if (m_analyser != NULL && !m_analyser->SaveState(state))
return false;
// TODO - save breakpoints, watches, exception/interrupt traps and register monitors
return true;
}
#endif // DEBUGGER_HASBLOCKFILE
void CCPUDebug::CheckException(UINT16 exCode)
void CCPUDebug::CPUException(UINT16 exCode)
{
if (exCode >= numExCodes)
return;
@ -1215,7 +1235,7 @@ namespace Debugger
m_break = true;
}
void CCPUDebug::CheckInterrupt(UINT16 intCode)
void CCPUDebug::CPUInterrupt(UINT16 intCode)
{
if (intCode >= numIntCodes)
return;
@ -1233,6 +1253,106 @@ namespace Debugger
m_break = true;
}
void CCPUDebug::CPUActive()
{
#ifdef DEBUGGER_HASTHREAD
m_mutex->Lock();
active = true;
m_condVar->Signal();
m_mutex->Unlock();
#else
active = true;
#endif // DEBUGGER_HASTHREAD
}
void CCPUDebug::CPUInactive()
{
#ifdef DEBUGGER_HASTHREAD
m_mutex->Lock();
active = false;
m_condVar->Signal();
m_mutex->Unlock();
#else
active = false;
#endif // DEBUGGER_HASTHREAD
}
void CCPUDebug::WaitCommand(EHaltReason reason)
{
#ifdef DEBUGGER_HASTHREAD
m_mutex->Lock();
m_halted = true;
m_condVar->Signal();
if (debugger->MakePrimary(this))
{
if (reason != HaltNone)
debugger->ExecutionHalted(this, reason);
debugger->WaitCommand(this);
if (!m_stateUpdated)
debugger->ReleasePrimary();
}
else
{
if (reason != HaltNone)
debugger->ExecutionHalted(this, reason);
while (m_breakWait)
m_condVar->Wait(m_mutex);
}
m_halted = false;
m_condVar->Signal();
m_mutex->Unlock();
#else
if (reason != HaltNone)
debugger->ExecutionHalted(this, reason);
debugger->WaitCommand(this);
debugger->ClearBreak();
#endif // DEBUGGER_HASTHREAD
}
#ifdef DEBUGGER_HASTHREAD
void CCPUDebug::ForceWait()
{
m_mutex->Lock();
m_breakWait = true;
m_break = true;
m_condVar->Signal();
m_mutex->Unlock();
}
void CCPUDebug::WaitForHalt()
{
m_mutex->Lock();
// Wait for CPU to become inactive or halt
while (active && !m_halted)
m_condVar->Wait(m_mutex);
m_mutex->Unlock();
}
void CCPUDebug::ClearWait()
{
m_mutex->Lock();
ClearBreak();
m_condVar->Signal();
m_mutex->Unlock();
}
#endif // DEBUGGER_HASTHREAD
void CCPUDebug::DebuggerReset()
{
instrCount = 0;
@ -1244,6 +1364,12 @@ namespace Debugger
m_analyser->Reset();
}
void CCPUDebug::DebuggerPolled()
{
cyclesPerPoll = totalCycles - m_prevTotalCycles;
m_prevTotalCycles = totalCycles;
}
UINT64 CCPUDebug::ReadMem(UINT32 addr, unsigned dataSize)
{
// TODO - currently assumes big-endian - should act according to this.bigEndian

View file

@ -23,6 +23,10 @@ using namespace std;
#include "BlockFile.h"
#endif // DEBUGGER_HASBLOCKFILE
#ifdef DEBUGGER_HASTHREAD
#include "Thread.h"
#endif // DEBUGGER_HASTHREAD
#define MAX_EXCEPTIONS 255
#define MAX_INTERRUPTS 255
#define MAX_IOPORTS 255
@ -66,7 +70,11 @@ namespace Debugger
private:
bool m_break;
bool m_userBreak;
#ifdef DEBUGGER_HASTHREAD
bool m_breakWait;
#endif // DEBUGGER_HASTHREAD
bool m_breakUser;
bool m_halted;
bool m_step;
EStepMode m_stepMode;
bool m_stepBreak;
@ -78,6 +86,11 @@ namespace Debugger
bool m_until;
UINT32 m_untilAddr;
#ifdef DEBUGGER_HASTHREAD
CMutex *m_mutex;
CCondVar *m_condVar;
#endif // DEBUGGER_HASTHREAD
CException *m_exArray[MAX_EXCEPTIONS];
CInterrupt *m_intArray[MAX_INTERRUPTS];
CPortIO *m_portArray[MAX_IOPORTS];
@ -116,12 +129,68 @@ namespace Debugger
CWatch *m_ioWatchTriggered;
CRegMonitor *m_regMonTriggered;
CCPUDebug(const char *cpuName, UINT8 cpuMinInstrLen, UINT8 cpuMaxInstrLen, bool cpuBigEndian, UINT8 cpuMemBusWidth, UINT8 cpuMaxMnemLen);
UINT64 m_prevTotalCycles;
CCPUDebug(const char *cpuType, const char *cpuName,
UINT8 cpuMinInstrLen, UINT8 cpuMaxInstrLen, bool cpuBigEndian, UINT8 cpuMemBusWidth, UINT8 cpuMaxMnemLen);
//
// Methods to define CPU features, such as registers, exceptions and interrupts
// Protected virtual methods for sub-class to implement
//
virtual bool UpdatePC(UINT32 pc) = 0;
virtual bool ForceException(CException *ex) = 0;
virtual bool ForceInterrupt(CInterrupt *in) = 0;
public:
const char *type;
const char *name;
const UINT8 minInstrLen;
const UINT8 maxInstrLen;
const bool bigEndian;
const UINT8 memBusWidth;
const UINT8 maxMnemLen;
bool enabled;
EFormat addrFmt;
EFormat portFmt;
EFormat dataFmt;
CDebugger *debugger;
UINT16 numExCodes;
UINT16 numIntCodes;
UINT16 numPorts;
UINT32 memSize;
bool active;
UINT64 instrCount;
UINT64 totalCycles;
UINT64 cyclesPerPoll;
UINT32 pc;
UINT32 opcode;
vector<CRegister*> regs;
vector<CException*> exceps;
vector<CInterrupt*> inters;
vector<CIO*> ios;
// TODO - should use map<UINT32,T*> for T=CRegion,CLabel&CComment so that look-ups via address are faster
vector<CRegion*> regions;
vector<CLabel*> labels;
vector<CComment*> comments;
vector<CWatch*> memWatches;
vector<CWatch*> ioWatches;
vector<CBreakpoint*> bps;
vector<CRegMonitor*> regMons;
virtual ~CCPUDebug();
//
// Methods to define CPU registers (must be called before attached to debugger)
CPCRegister *AddPCRegister(const char *name, const char *group);
CAddrRegister *AddAddrRegister(const char *name, const char *group, unsigned id, GetInt32FPtr getFunc, SetInt32FPtr setFunc = NULL);
@ -142,60 +211,14 @@ namespace Debugger
CFPointRegister *AddFPointRegister(const char *name, const char *group, unsigned id, GetFPointFPtr getFunc, SetFPointFPtr setFunc = NULL);
//
// Methods to add exceptions and interrupts (must be called before attached to debugger)
//
CException *AddException(const char *id, UINT16 code, const char *name);
CInterrupt *AddInterrupt(const char *id, UINT16 code, const char *name);
//
// Protected virtual methods for sub-class to implement
//
virtual bool UpdatePC(UINT32 pc) = 0;
virtual bool ForceException(CException *ex) = 0;
virtual bool ForceInterrupt(CInterrupt *in) = 0;
public:
const char *name;
const UINT8 minInstrLen;
const UINT8 maxInstrLen;
const bool bigEndian;
const UINT8 memBusWidth;
const UINT8 maxMnemLen;
bool enabled;
EFormat addrFmt;
EFormat portFmt;
EFormat dataFmt;
CDebugger *debugger;
UINT16 numExCodes;
UINT16 numIntCodes;
UINT16 numPorts;
UINT32 memSize;
UINT64 instrCount;
UINT32 pc;
UINT32 opcode;
vector<CRegister*> regs;
vector<CException*> exceps;
vector<CInterrupt*> inters;
vector<CIO*> ios;
// TODO - should use map<UINT32,T*> for T=CRegion,CLabel&CComment so that look-ups via address are faster
vector<CRegion*> regions;
vector<CLabel*> labels;
vector<CComment*> comments;
vector<CWatch*> memWatches;
vector<CWatch*> ioWatches;
vector<CBreakpoint*> bps;
vector<CRegMonitor*> regMons;
virtual ~CCPUDebug();
//
// Methods to define memory layout (must be called before attached to debugger)
//
@ -279,21 +302,43 @@ namespace Debugger
void CheckPortOutput(UINT16 portNum, UINT64 data);
/*
* Should be called before every instruction.
* Should be called by CPU when it becomes active and starts executing an instruction loop.
* This call is needed so that the debugger can handle multi-threading of CPUs.
*/
void CPUActive();
/*
* Should be called by CPU when it becomes inactive after having finished executing an instruction loop.
* This call is needed so that the debugger can handle multi-threading of CPUs.
*/
void CPUInactive();
/*
* Should be called by CPU before every instruction.
* If returns true, then PC may have been changed by user and/or an exception/interrupt may have forced, so CPU core should
* check for this and handle appropriately. Otherwise, it can continue to execute as normal.
*/
bool CheckExecution(UINT32 newPC, UINT32 newOpcode);
bool CPUExecute(UINT32 newPC, UINT32 newOpcode, UINT32 lastCycles);
/*
* Should be called whenever a CPU exception is raised (and before the exception handler is executed).
* Should be called by CPU whenever a CPU exception is raised (and before the exception handler is executed).
*/
virtual void CheckException(UINT16 exCode);
virtual void CPUException(UINT16 exCode);
/*
* Should be called whenever a CPU interrupt is raised (and before the interrupt handler is executed).
* Should be called by CPU whenever a CPU interrupt is raised (and before the interrupt handler is executed).
*/
virtual void CheckInterrupt(UINT16 intCode);
virtual void CPUInterrupt(UINT16 intCode);
void WaitCommand(EHaltReason reason);
#ifdef DEBUGGER_HASTHREAD
void ForceWait();
void WaitForHalt();
void ClearWait();
#endif // DEBUGGER_HASTHREAD
//
// Execution control
@ -489,6 +534,8 @@ namespace Debugger
virtual void DebuggerReset();
virtual void DebuggerPolled();
virtual UINT32 GetResetAddr() = 0;
virtual UINT64 ReadMem(UINT32 addr, unsigned dataSize);
@ -754,13 +801,14 @@ namespace Debugger
IOWatchTriggered(port->watch, port, data, false);
}
inline bool CCPUDebug::CheckExecution(UINT32 newPC, UINT32 newOpcode)
inline bool CCPUDebug::CPUExecute(UINT32 newPC, UINT32 newOpcode, UINT32 lastCycles)
{
// Check if debugging is enabled for this CPU
if (!enabled)
{
// If not, update instruction count, pc and opcode but don't allow any execution control
// If not, update instruction count, total cycles counts, pc and opcode but don't allow any execution control
instrCount++;
totalCycles += lastCycles;
pc = newPC;
opcode = newOpcode;
return false;
@ -786,8 +834,9 @@ namespace Debugger
}
}
// Now update instruction count, pc and opcode
// Now update instruction count, total cycles count, pc and opcode
instrCount++;
totalCycles += lastCycles;
pc = newPC;
opcode = newOpcode;
@ -862,17 +911,13 @@ namespace Debugger
if (m_break || m_stateUpdated || stepBreak || countBreak || untilBreak)
{
// See if execution halt was caused by user manually breaking execution in some manner
if (m_stateUpdated || m_userBreak || stepBreak || countBreak || untilBreak)
{
EHaltReason reason = HaltNone;
if (m_stateUpdated) reason = (EHaltReason)(reason | HaltState);
if (m_userBreak) reason = (EHaltReason)(reason | HaltUser);
if (stepBreak) reason = (EHaltReason)(reason | HaltStep);
if (countBreak) reason = (EHaltReason)(reason | HaltCount);
if (untilBreak) reason = (EHaltReason)(reason | HaltUntil);
debugger->ExecutionHalted(this, reason);
}
EHaltReason reason = HaltNone;
if (m_stateUpdated) reason = (EHaltReason)(reason | HaltState);
if (m_breakUser) reason = (EHaltReason)(reason | HaltUser);
if (stepBreak) reason = (EHaltReason)(reason | HaltStep);
if (countBreak) reason = (EHaltReason)(reason | HaltCount);
if (untilBreak) reason = (EHaltReason)(reason | HaltUntil);
// Keep hold of breakpoint, if any, and its address so that can reset it later
UINT32 bpAddr = 0;
CBreakpoint *bpToReset = NULL;
@ -883,7 +928,6 @@ namespace Debugger
}
// Reset all control flags
debugger->ClearBreak();
m_stateUpdated = false;
m_step = false;
m_steppingOver = false;
@ -898,9 +942,9 @@ namespace Debugger
m_memWatchTriggered = NULL;
m_ioWatchTriggered = NULL;
m_regMonTriggered = NULL;
// Wait for instruction from user
debugger->WaitCommand(this);
WaitCommand(reason);
// Reset breakpoint, if any
if (bpToReset != NULL && m_bpTable != NULL)

View file

@ -461,7 +461,7 @@ namespace Debugger
unsigned i = 0;
for (vector<UINT32>::iterator it = m_customEntryAddrs.begin(); it != m_customEntryAddrs.end(); it++)
{
sprintf(labelStr, "Custom%s", i++);
sprintf(labelStr, "Custom%u", i++);
AddEntryPoint(entryPoints, *it, LFEntryPoint, labelStr);
}
@ -651,6 +651,11 @@ namespace Debugger
{
m_abortAnalysis = true;
}
void CCodeAnalyser::ClearCustomEntryAddrs()
{
m_customEntryAddrs.clear();
}
void CCodeAnalyser::AddCustomEntryAddr(UINT32 entryAddr)
{
@ -666,6 +671,43 @@ namespace Debugger
m_customEntryAddrs.erase(it);
return true;
}
}
#ifdef DEBUGGER_HASBLOCKFILE
bool CCodeAnalyser::LoadState(CBlockFile *state)
{
// Load custom entry addresses
char blockStr[255];
sprintf(blockStr, "%s.entryaddrs", cpu->name);
if (state->FindBlock(blockStr) == OKAY)
{
m_customEntryAddrs.clear();
UINT32 numAddrs;
state->Read(&numAddrs, sizeof(numAddrs));
for (UINT32 i = 0; i < numAddrs; i++)
{
UINT32 addr;
state->Read(&addr, sizeof(addr));
m_customEntryAddrs.push_back(addr);
}
}
return true;
}
bool CCodeAnalyser::SaveState(CBlockFile *state)
{
// Save custom entry addresses
char blockStr[255];
sprintf(blockStr, "%s.entryaddrs", cpu->name);
state->NewBlock(blockStr, __FILE__);
UINT32 numAddrs = m_customEntryAddrs.size();
state->Write(&numAddrs, sizeof(numAddrs));
for (UINT32 i = 0; i < numAddrs; i++)
{
UINT32 addr = m_customEntryAddrs[i];
state->Write(&addr, sizeof(addr));
}
return true;
}
#endif // DEBUGGER_HASBLOCKFILE
}
#endif // SUPERMODEL_DEBUGGER

View file

@ -11,8 +11,13 @@ using namespace std;
#include "Types.h"
#include "Debugger.h"
#include "AddressTable.h"
#ifdef DEBUGGER_HASBLOCKFILE
#include "BlockFile.h"
#endif // DEBUGGER_HASBLOCKFILE
namespace Debugger
{
class CCPUDebug;
@ -202,15 +207,31 @@ namespace Debugger
bool GetIndexOfAddr(UINT32 addr, unsigned &index);
//
// Methods to check, run or abort analysis
//
bool NeedsAnalysis();
bool AnalyseCode();
void AbortAnalysis();
//
// Methods to manipulate custom entry addresses
//
void ClearCustomEntryAddrs();
void AddCustomEntryAddr(UINT32 entryAddr);
bool RemoveCustomEntryAddr(UINT32 entryAddr);
#ifdef DEBUGGER_HASBLOCKFILE
bool LoadState(CBlockFile *state);
bool SaveState(CBlockFile *state);
#endif // DEBUGGER_HASBLOCKFILE
};
}

View file

@ -1661,7 +1661,7 @@ namespace Debugger
modifier[modSize] = '\0';
char actual[255];
size_t actSize = min(pos - token - 1, 254);
size_t actSize = min<size_t>(pos - token - 1, 254);
strncpy(actual, token, actSize);
actual[actSize] = '\0';
return CheckToken(actual, simple, full);
@ -1932,16 +1932,30 @@ namespace Debugger
return;
}
Print(" %-3s %-12s %-9s %12s\n", "Num", "CPU", "Debugging", "Instr Count");
Print(" %-3s %-9s %-6s %-9s %-7s %-12s %-12s %-9s\n", "Num", "Name", "Type", "Debugging", "State", "Instr Count", "Total Cycles", "Frequency");
unsigned num = 0;
double freq;
char onCPU;
const char *debugStr;
const char *stateStr;
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
{
stateStr = ((*it)->enabled ? "Enabled" : "Disabled");
onCPU = (*it == m_cpu ? '*': ' ');
debugStr = ((*it)->enabled ? "Enabled" : "Disabled");
stateStr = ((*it)->active ? "Running" : "Waiting");
if ((*it)->instrCount > 0)
Print(" %-3u %-12s %-9s %12llu\n", num++, (*it)->name, stateStr, (*it)->instrCount - 1);
{
if (frameCount > 0)
{
freq = ((*it)->cyclesPerPoll * 60.0) / 1000000.0;
Print("%c%-3u %-9s %-6s %-9s %-7s %12llu %12llu %6.1fMHz\n", onCPU, num++, (*it)->name, (*it)->type, debugStr, stateStr, (*it)->instrCount - 1, (*it)->totalCycles, freq);
}
else
Print("%c%-3u %-9s %-6s %-9s %-7s %12llu %12llu %9s\n", onCPU, num++, (*it)->name, (*it)->type, debugStr, stateStr, (*it)->instrCount - 1, (*it)->totalCycles, "-");
}
else
Print(" %-3u %-12s %-9s -\n", num++, (*it)->name, stateStr);
Print("%c%-3u %-9s %-6s %-9s %-7s %12s %12s %9s\n", onCPU, num++, (*it)->name, (*it)->type, debugStr, stateStr, "-", "-", "-");
}
}
@ -2097,7 +2111,7 @@ namespace Debugger
dirChar = ((*it)->last == &(*it)->lastIn ? '<' : '>');
else
dirChar = ' ';
// Formatt last input
// Format last input
if ((*it)->inCount > 0)
m_cpu->FormatData(inStr, (*it)->dataSize, (*it)->lastIn);
else
@ -2109,7 +2123,7 @@ namespace Debugger
int inLPad = 5 - (int)inLen / 2;
int inRPad = 5 - (int)inLen + (int)inLen / 2;
// Format last output
if ((*it)->inCount > 0)
if ((*it)->outCount > 0)
m_cpu->FormatData(outStr, (*it)->dataSize, (*it)->lastOut);
else
{
@ -2402,7 +2416,8 @@ namespace Debugger
// In the absence of code analyser, try to align code with current PC address
if (m_cpu->instrCount > 0 && pc >= start && pc <= end)
{
while (start < end)
unsigned count = m_cpu->instrCount;
while (start < end && count-- > 0)
{
bool okay = false;
addr = start;

View file

@ -101,21 +101,33 @@ namespace Debugger
return sscanf(str, "%d", val) == 1;
}
CDebugger::CDebugger() : m_exit(false), m_pause(false), frameCount(0), logDebug(true), logInfo(true), logError(true)
CDebugger::CDebugger() : m_exit(false), m_pause(false), m_break(false), m_breakUser(false),
frameCount(0), logDebug(true), logInfo(true), logError(true)
{
//
#ifdef DEBUGGER_HASTHREAD
m_mutex = CThread::CreateMutex();
m_primaryCPU = NULL;
#endif // DEBUGGER_HASTHREAD
}
CDebugger::~CDebugger()
{
DeleteCPUs();
}
void CDebugger::DeleteCPUs()
{
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
delete *it;
cpus.clear();
}
void CDebugger::AddCPU(CCPUDebug *cpu)
{
cpu->AttachToDebugger(this);
cpus.push_back(cpu);
if (m_break)
cpu->ForceBreak(m_breakUser);
}
void CDebugger::RemoveCPU(CCPUDebug *cpu)
@ -158,24 +170,70 @@ namespace Debugger
void CDebugger::ForceBreak(bool user)
{
m_break = true;
m_breakUser = user;
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
(*it)->ForceBreak(user);
}
void CDebugger::ClearBreak()
{
m_break = false;
m_breakUser = false;
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
(*it)->ClearBreak();
}
void CDebugger::SetContinue()
#ifdef DEBUGGER_HASTHREAD
bool CDebugger::MakePrimary(CCPUDebug *cpu)
{
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
(*it)->SetContinue();
m_mutex->Lock();
bool isPrimary = m_primaryCPU == NULL || m_primaryCPU == cpu;
if (isPrimary)
m_primaryCPU = cpu;
m_mutex->Unlock();
if (isPrimary)
{
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
{
if ((*it) != m_primaryCPU)
(*it)->ForceWait();
}
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
{
if ((*it) != m_primaryCPU)
(*it)->WaitForHalt();
}
}
return isPrimary;
}
void CDebugger::ReleasePrimary()
{
m_mutex->Lock();
m_primaryCPU = NULL;
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
{
if ((*it) == m_primaryCPU)
(*it)->ClearBreak();
else
(*it)->ClearWait();
}
m_mutex->Unlock();
}
#endif // DEBUGGER_HASTHREAD
void CDebugger::Attach()
{
AddCPUs();
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
(*it)->AttachToCPU();
}
@ -184,6 +242,8 @@ namespace Debugger
{
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
(*it)->DetachFromCPU();
DeleteCPUs();
}
void CDebugger::Reset()
@ -196,6 +256,8 @@ namespace Debugger
void CDebugger::Poll()
{
frameCount++;
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
(*it)->DebuggerPolled();
}
void CDebugger::PrintEvent(CCPUDebug *cpu, const char *fmt, ...)

View file

@ -13,6 +13,7 @@ using namespace std;
#if defined(SUPERMODEL_WIN32) || defined(SUPERMODEL_UNIX) || defined(SUPERMODEL_OSX)
#define DEBUGGER_HASBLOCKFILE
#define DEBUGGER_HASLOGGER
#define DEBUGGER_HASTHREAD
#endif
#define DEBUGGER_STATEFILE_VERSION 0
@ -22,9 +23,16 @@ using namespace std;
#endif // DEBUGGER_HASBLOCKFILE
#ifdef DEBUGGER_HASLOGGER
#ifndef SUPERMODEL_VERSION
#define SUPERMODEL_VERSION ""
#endif // SUPERMODEL_VERSEION
#include "Logger.h"
#endif // DEBUGGER_HASLOGGER
#ifdef DEBUGGER_HASTHREAD
#include "Thread.h"
#endif // DEBUGGER_HASTHREAD
#ifndef stricmp
#ifdef _MSC_VER // MS VisualC++
#define stricmp _stricmp
@ -83,8 +91,19 @@ namespace Debugger
private:
bool m_exit;
bool m_pause;
bool m_break;
bool m_breakUser;
#ifdef DEBUGGER_HASTHREAD
CMutex *m_mutex;
CCPUDebug *m_primaryCPU;
#endif
protected:
virtual void AddCPUs() = 0;
virtual void DeleteCPUs();
#ifdef DEBUGGER_HASBLOCKFILE
virtual bool LoadState(CBlockFile *state);
@ -154,12 +173,16 @@ namespace Debugger
void ClearBreak();
void SetContinue();
bool CheckExit();
bool CheckPause();
#ifdef DEBUGGER_HASTHREAD
bool MakePrimary(CCPUDebug *cpu);
void ReleasePrimary();
#endif // DEBUGGER_HASTHREAD
//
// Printing/logging
//

View file

@ -92,7 +92,7 @@ namespace Debugger
void CPortIO::GetLocation(char *str)
{
if (name != NULL)
sprintf(str, "port %s", name);
strcpy(str, name);
else
sprintf(str, "port %u", portNum);
}

View file

@ -11,20 +11,291 @@
namespace Debugger
{
static const char *s_giGroup = "Game Inputs";
static const char *s_gmGroup = "Game Inputs (Mirrored)";
static const char *s_sbGroup = "Sound Board";
static char s_mSlotStr[32][20];
static char s_sSlotStr[32][20];
CCPUDebug *CSupermodelDebugger::CreateMainBoardCPUDebug(::CModel3 *model3)
{
CPPCDebug *cpu = new CPPCDebug("MainPPC");
// Interrupts
cpu->AddInterrupt("VD0", 0, "Unknown video-related");
cpu->AddInterrupt("VBL", 1, "VBlank start");
cpu->AddInterrupt("VD2", 2, "Unknown video-related");
cpu->AddInterrupt("VD3", 3, "Unknown video-related");
cpu->AddInterrupt("NET", 4, "Network");
cpu->AddInterrupt("UN5", 5, "Unknown");
cpu->AddInterrupt("SND", 6, "SCSP (sound)");
cpu->AddInterrupt("UN7", 7, "Unknown");
// Memory regions
cpu->AddRegion(0x00000000, 0x007FFFFF, true, false, "RAM");
cpu->AddRegion(0x84000000, 0x8400003F, false, false, "Real3D Status Registers");
cpu->AddRegion(0x88000000, 0x88000007, false, false, "Real3D Command Port");
cpu->AddRegion(0x8C000000, 0x8C3FFFFF, false, false, "Real3D Culling RAM (Low)");
cpu->AddRegion(0x8E000000, 0x8E0FFFFF, false, false, "Real3D Culling RAM (High)");
cpu->AddRegion(0x90000000, 0x9000000B, false, false, "Real3D VROM Texture Port");
cpu->AddRegion(0x94000000, 0x940FFFFF, false, false, "Real3D Texture FIFO");
cpu->AddRegion(0x98000000, 0x980FFFFF, false, false, "Real3D Polygon RAM");
cpu->AddRegion(0xC0000000, 0xC00000FF, false, false, "SCSI (Step 1.x)");
cpu->AddRegion(0xC1000000, 0xC10000FF, false, false, "SCSI (Step 1.x) (Lost World expects it here)");
cpu->AddRegion(0xC2000000, 0xC20000FF, false, false, "Real3D DMA (Step 2.x)");
cpu->AddRegion(0xF0040000, 0xF004003F, false, false, "Input (Controls) Registers");
cpu->AddRegion(0xF0080000, 0xF0080007, false, false, "Sound Board Registers");
cpu->AddRegion(0xF00C0000, 0xF00DFFFF, false, false, "Backup RAM");
cpu->AddRegion(0xF0100000, 0xF010003F, false, false, "System Registers");
cpu->AddRegion(0xF0140000, 0xF014003F, false, false, "Real, 0xTime Clock");
cpu->AddRegion(0xF0180000, 0xF019FFFF, false, false, "Security Board RAM");
cpu->AddRegion(0xF01A0000, 0xF01A003F, false, false, "Security Board Registers");
cpu->AddRegion(0xF0800CF8, 0xF0800CFF, false, false, "MPC105 CONFIG_cpu->AddR (Step 1.x)");
cpu->AddRegion(0xF0C00CF8, 0xF0C00CFF, false, false, "MPC105 CONFIG_DATA (Step 1.x)");
cpu->AddRegion(0xF1000000, 0xF10F7FFF, false, false, "Tile Generator Pattern Table");
cpu->AddRegion(0xF10F8000, 0xF10FFFFF, false, false, "Tile Generator Name Table");
cpu->AddRegion(0xF1100000, 0xF111FFFF, false, false, "Tile Generator Palette");
cpu->AddRegion(0xF1180000, 0xF11800FF, false, false, "Tile Generator Registers");
cpu->AddRegion(0xF8FFF000, 0xF8FFF0FF, false, false, "MPC105 (Step 1.x) or MPC106 (Step 2.x) Registers");
cpu->AddRegion(0xF9000000, 0xF90000FF, false, false, "NCR 53C810 Registers (Step 1.x?)");
cpu->AddRegion(0xFE040000, 0xFE04003F, false, false, "Mirrored Input Registers");
cpu->AddRegion(0xFEC00000, 0xFEDFFFFF, false, false, "MPC106 CONFIG_cpu->AddR (Step 2.x)");
cpu->AddRegion(0xFEE00000, 0xFEFFFFFF, false, false, "MPC106 CONFIG_DATA (Step 2.x)");
cpu->AddRegion(0xFF000000, 0xFF7FFFFF, true, true, "Banked CROM (CROMxx)");
cpu->AddRegion(0xFF800000, 0xFFFFFFFF, true, true, "Fixed CROM");
// Memory-mapped IO
cpu->AddMappedIO(0xF0040000, 1, "Input Bank Select", s_giGroup);
cpu->AddMappedIO(0xF0040004, 1, "Current Input Bank", s_giGroup);
cpu->AddMappedIO(0xF0040008, 1, "Game Specific Inputs 1", s_giGroup);
cpu->AddMappedIO(0xF004000C, 1, "Game Specific Inputs 2", s_giGroup);
cpu->AddMappedIO(0xF0040010, 1, "Drive Board", s_giGroup);
cpu->AddMappedIO(0xF0040014, 1, "LED Outputs?", s_giGroup);
cpu->AddMappedIO(0xF0040018, 1, "Unknown?", s_giGroup);
cpu->AddMappedIO(0xF0040024, 1, "Serial FIFO 1 Control", s_giGroup);
cpu->AddMappedIO(0xF0040028, 1, "Serial FIFO 2 Control", s_giGroup);
cpu->AddMappedIO(0xF004002C, 1, "Serial FIFO 1", s_giGroup);
cpu->AddMappedIO(0xF0040030, 1, "Serial FIFO 2", s_giGroup);
cpu->AddMappedIO(0xF0040034, 1, "Serial FIFO Flags", s_giGroup);
cpu->AddMappedIO(0xF004003C, 1, "ADC", s_giGroup);
cpu->AddMappedIO(0xFE040000, 1, "Input Bank Select", s_gmGroup);
cpu->AddMappedIO(0xFE040004, 1, "Current Input Bank", s_gmGroup);
cpu->AddMappedIO(0xFE040008, 1, "Game Specific Inputs 1", s_gmGroup);
cpu->AddMappedIO(0xFE04000C, 1, "Game Specific Inputs 2", s_gmGroup);
cpu->AddMappedIO(0xFE040010, 1, "Drive Board", s_gmGroup);
cpu->AddMappedIO(0xFE040014, 1, "LED Outputs?", s_gmGroup);
cpu->AddMappedIO(0xFE040018, 1, "Unknown?", s_gmGroup);
cpu->AddMappedIO(0xFE040024, 1, "Serial FIFO 1 Control", s_gmGroup);
cpu->AddMappedIO(0xFE040028, 1, "Serial FIFO 2 Control", s_gmGroup);
cpu->AddMappedIO(0xFE04002C, 1, "Serial FIFO 1", s_gmGroup);
cpu->AddMappedIO(0xFE040030, 1, "Serial FIFO 2", s_gmGroup);
cpu->AddMappedIO(0xFE040034, 1, "Serial FIFO Flags", s_gmGroup);
cpu->AddMappedIO(0xFE04003C, 1, "ADC", s_gmGroup);
cpu->AddMappedIO(0xF0080000, 1, "MIDI", s_sbGroup);
cpu->AddMappedIO(0xF0080004, 1, "Control", s_sbGroup);
return cpu;
}
CCPUDebug *CSupermodelDebugger::CreateSoundBoardCPUDebug(::CModel3 *model3)
{
CSoundBoard *sndBrd = model3->GetSoundBoard();
CMusashi68KDebug *cpu = new CMusashi68KDebug("Snd68K", sndBrd->GetM68K());
// Regions
cpu->AddRegion(0x000000, 0x0FFFFF, true, false, "SCSP1 RAM");
cpu->AddRegion(0x200000, 0x2FFFFF, true, false, "SCSP2 RAM");
cpu->AddRegion(0x600000, 0x67FFFF, true, true, "Program ROM");
cpu->AddRegion(0x800000, 0x9FFFFF, false, true, "Sample ROM (low 2 MB)");
cpu->AddRegion(0xA00000, 0xDFFFFF, false, true, "Sample ROM (bank)");
cpu->AddRegion(0xE00000, 0xFFFFFF, false, true, "Sample ROM (bank)");
cpu->AddRegion(0x100000, 0x10FFFF, false, false, "SCSP Master");
cpu->AddRegion(0x300000, 0x30FFFF, false, false, "SCSP Slave");
// Mapped I/O
// SCSP Master 32 slots
for (unsigned slot = 0; slot < 32; slot++)
{
sprintf(s_mSlotStr[slot], "SCSP Master Slot %02X", slot);
UINT32 addr = 0x100000 + slot * 0x20;
cpu->AddMappedIO(addr + 0x00, 2, "KYONX,KYONB,SBCTL,SSCTL,LPCTL,PCM8B,SA", s_mSlotStr[slot]);
cpu->AddMappedIO(addr + 0x02, 2, "SA", s_mSlotStr[slot]);
cpu->AddMappedIO(addr + 0x04, 2, "LSA", s_mSlotStr[slot]);
cpu->AddMappedIO(addr + 0x06, 2, "LEA", s_mSlotStr[slot]);
cpu->AddMappedIO(addr + 0x08, 2, "D2R,D1R,EGHOLD,AR", s_mSlotStr[slot]);
cpu->AddMappedIO(addr + 0x0A, 2, "LPSLNK,KRS,DL,RR", s_mSlotStr[slot]);
cpu->AddMappedIO(addr + 0x0C, 1, "STWINH", s_mSlotStr[slot]);
cpu->AddMappedIO(addr + 0x0D, 1, "SDIR,TL", s_mSlotStr[slot]);
cpu->AddMappedIO(addr + 0x0E, 2, "MDL,MDXSL,MDYSL", s_mSlotStr[slot]);
cpu->AddMappedIO(addr + 0x10, 2, "OCT,FNS", s_mSlotStr[slot]);
cpu->AddMappedIO(addr + 0x12, 1, "LFORE,LFOF,PLFOWS", s_mSlotStr[slot]);
cpu->AddMappedIO(addr + 0x13, 1, "PLFOS,ALFOWS,ALFOS", s_mSlotStr[slot]);
cpu->AddMappedIO(addr + 0x15, 1, "ISEL,OMXL", s_mSlotStr[slot]);
cpu->AddMappedIO(addr + 0x16, 1, "DISDL,DIPAN", s_mSlotStr[slot]);
cpu->AddMappedIO(addr + 0x17, 1, "EFSDL,EFPAN", s_mSlotStr[slot]);
}
// SCSP Master control registers
const char *masterCtl = "SCSP Master Control Registers";
cpu->AddMappedIO(0x100400, 1, "MEM4MB,DAC18B", masterCtl);
cpu->AddMappedIO(0x100401, 1, "VER,MVOL", masterCtl);
cpu->AddMappedIO(0x100402, 2, "RBL,RBP", masterCtl);
cpu->AddMappedIO(0x100404, 1, "MOFULL,MOEMP,MIOVF,MIFULL,MIEMP", masterCtl);
cpu->AddMappedIO(0x100405, 1, "MIBUF", masterCtl);
cpu->AddMappedIO(0x100407, 1, "MOBUF", masterCtl);
cpu->AddMappedIO(0x100408, 2, "MSLC,CA", masterCtl);
cpu->AddMappedIO(0x100412, 2, "DMEAL", masterCtl);
cpu->AddMappedIO(0x100414, 2, "DMEAH,DRGA", masterCtl);
cpu->AddMappedIO(0x100416, 2, "DGATE,DDIR,DEXE,DTLG", masterCtl);
cpu->AddMappedIO(0x100418, 1, "TACTL", masterCtl);
cpu->AddMappedIO(0x100419, 1, "TIMA", masterCtl);
cpu->AddMappedIO(0x10041A, 1, "TBCTL", masterCtl);
cpu->AddMappedIO(0x10041B, 1, "TIMB", masterCtl);
cpu->AddMappedIO(0x10041C, 1, "TCCTL", masterCtl);
cpu->AddMappedIO(0x10041D, 1, "TIMC", masterCtl);
cpu->AddMappedIO(0x10041E, 2, "SCIEB", masterCtl);
cpu->AddMappedIO(0x100420, 2, "SCIPD", masterCtl);
cpu->AddMappedIO(0x100422, 2, "SCIRE", masterCtl);
cpu->AddMappedIO(0x100425, 1, "SCILV0", masterCtl);
cpu->AddMappedIO(0x100427, 1, "SCILV1", masterCtl);
cpu->AddMappedIO(0x100429, 1, "SCILV2", masterCtl);
cpu->AddMappedIO(0x10042A, 2, "MCIEB", masterCtl);
cpu->AddMappedIO(0x10042C, 2, "MCIPD", masterCtl);
cpu->AddMappedIO(0x10042E, 2, "MCIRE", masterCtl);
// SCSP Slave 32 slots
for (unsigned slot = 0; slot < 32; slot++)
{
sprintf(s_sSlotStr[slot], "SCSP Slave Slot %02X", slot);
UINT32 addr = 0x300000 + slot * 0x20;
cpu->AddMappedIO(addr + 0x00, 2, "KYONX,KYONB,SBCTL,SSCTL,LPCTL,PCM8B,SA", s_sSlotStr[slot]);
cpu->AddMappedIO(addr + 0x02, 2, "SA", s_sSlotStr[slot]);
cpu->AddMappedIO(addr + 0x04, 2, "LSA", s_sSlotStr[slot]);
cpu->AddMappedIO(addr + 0x06, 2, "LEA", s_sSlotStr[slot]);
cpu->AddMappedIO(addr + 0x08, 2, "D2R,D1R,EGHOLD,AR", s_sSlotStr[slot]);
cpu->AddMappedIO(addr + 0x0A, 2, "LPSLNK,KRS,DL,RR", s_sSlotStr[slot]);
cpu->AddMappedIO(addr + 0x0C, 1, "STWINH", s_sSlotStr[slot]);
cpu->AddMappedIO(addr + 0x0D, 1, "SDIR,TL", s_sSlotStr[slot]);
cpu->AddMappedIO(addr + 0x0E, 2, "MDL,MDXSL,MDYSL", s_sSlotStr[slot]);
cpu->AddMappedIO(addr + 0x10, 2, "OCT,FNS", s_sSlotStr[slot]);
cpu->AddMappedIO(addr + 0x12, 1, "LFORE,LFOF,PLFOWS", s_sSlotStr[slot]);
cpu->AddMappedIO(addr + 0x13, 1, "PLFOS,ALFOWS,ALFOS", s_sSlotStr[slot]);
cpu->AddMappedIO(addr + 0x15, 1, "ISEL,OMXL", s_sSlotStr[slot]);
cpu->AddMappedIO(addr + 0x16, 1, "DISDL,DIPAN", s_sSlotStr[slot]);
cpu->AddMappedIO(addr + 0x17, 1, "EFSDL,EFPAN", s_sSlotStr[slot]);
}
// SCSP Master control registers
const char *slaveCtl = "SCSP Slave Control Registers";
cpu->AddMappedIO(0x300400, 1, "MEM4MB,DAC18B", slaveCtl);
cpu->AddMappedIO(0x300401, 1, "VER,MVOL", slaveCtl);
cpu->AddMappedIO(0x300402, 2, "RBL,RBP", slaveCtl);
cpu->AddMappedIO(0x300404, 1, "MOFULL,MOEMP,MIOVF,MIFULL,MIEMP", slaveCtl);
cpu->AddMappedIO(0x300405, 1, "MIBUF", slaveCtl);
cpu->AddMappedIO(0x300407, 1, "MOBUF", slaveCtl);
cpu->AddMappedIO(0x300408, 2, "MSLC,CA", slaveCtl);
cpu->AddMappedIO(0x300412, 2, "DMEAL", slaveCtl);
cpu->AddMappedIO(0x300414, 2, "DMEAH,DRGA", slaveCtl);
cpu->AddMappedIO(0x300416, 2, "DGATE,DDIR,DEXE,DTLG", slaveCtl);
cpu->AddMappedIO(0x300418, 1, "TACTL", slaveCtl);
cpu->AddMappedIO(0x300419, 1, "TIMA", slaveCtl);
cpu->AddMappedIO(0x30041A, 1, "TBCTL", slaveCtl);
cpu->AddMappedIO(0x30041B, 1, "TIMB", slaveCtl);
cpu->AddMappedIO(0x30041C, 1, "TCCTL", slaveCtl);
cpu->AddMappedIO(0x30041D, 1, "TIMC", slaveCtl);
cpu->AddMappedIO(0x30041E, 2, "SCIEB", slaveCtl);
cpu->AddMappedIO(0x300420, 2, "SCIPD", slaveCtl);
cpu->AddMappedIO(0x300422, 2, "SCIRE", slaveCtl);
cpu->AddMappedIO(0x300425, 1, "SCILV0", slaveCtl);
cpu->AddMappedIO(0x300427, 1, "SCILV1", slaveCtl);
cpu->AddMappedIO(0x300429, 1, "SCILV2", slaveCtl);
cpu->AddMappedIO(0x30042A, 2, "MCIEB", slaveCtl);
cpu->AddMappedIO(0x30042C, 2, "MCIPD", slaveCtl);
cpu->AddMappedIO(0x30042E, 2, "MCIRE", slaveCtl);
return cpu;
}
CCPUDebug *CSupermodelDebugger::CreateDSBCPUDebug(::CModel3 *model3)
{
CSoundBoard *sndBrd = model3->GetSoundBoard();
CDSB *dsb = sndBrd->GetDSB();
CDSB1 *dsb1 = dynamic_cast<CDSB1*>(dsb);
if (dsb1 != NULL)
{
CZ80Debug *cpu = new CZ80Debug("DSBZ80", dsb1->GetZ80());
// TODO
return cpu;
}
CDSB2 *dsb2 = dynamic_cast<CDSB2*>(dsb);
if (dsb2 != NULL)
{
CMusashi68KDebug *cpu = new CMusashi68KDebug("DSB68K", dsb2->GetM68K());
// TODO
return cpu;
}
return NULL;
}
CCPUDebug *CSupermodelDebugger::CreateDriveBoardCPUDebug(::CModel3 *model3)
{
CDriveBoard *drvBrd = model3->GetDriveBoard();
if (!drvBrd->IsAttached())
return NULL;
CZ80Debug *cpu = new CZ80Debug("DrvZ80", drvBrd->GetZ80());
// Regions
cpu->AddRegion(0x0000, 0x7FFF, true, true, "ROM");
cpu->AddRegion(0xE000, 0xFFFF, false, false, "RAM");
// TODO - rename some I/O ports
return cpu;
}
CSupermodelDebugger::CSupermodelDebugger(::CModel3 *model3, ::CInputs *inputs, ::CLogger *logger) :
CConsoleDebugger(), m_model3(model3), m_inputs(inputs), m_logger(logger),
m_loadEmuState(false), m_saveEmuState(false), m_resetEmu(false)
{
AddCPU(new CPPCDebug());
//
}
void CSupermodelDebugger::AddCPUs()
{
CCPUDebug *cpu;
// Add main board CPU
cpu = CreateMainBoardCPUDebug(m_model3);
if (cpu) AddCPU(cpu);
// Add sound board CPU (if attached)
cpu = CreateSoundBoardCPUDebug(m_model3);
if (cpu) AddCPU(cpu);
// Add sound daughter board CPU (if attached)
cpu = CreateDSBCPUDebug(m_model3);
if (cpu) AddCPU(cpu);
// Add drive board CPU (if attached)
cpu = CreateDriveBoardCPUDebug(m_model3);
if (cpu) AddCPU(cpu);
}
void CSupermodelDebugger::WaitCommand(CCPUDebug *cpu)
{
// Ungrab mouse and disable audio
m_inputs->GetInputSystem()->UngrabMouse();
SetAudioEnabled(false);
CConsoleDebugger::WaitCommand(cpu);
m_inputs->GetInputSystem()->GrabMouse();
SetAudioEnabled(true);
}
bool CSupermodelDebugger::ProcessToken(const char *token, const char *cmd)

View file

@ -36,6 +36,8 @@ namespace Debugger
void ListInputs();
protected:
void AddCPUs();
void WaitCommand(CCPUDebug *cpu);
bool ProcessToken(const char *token, const char *cmd);
@ -45,6 +47,14 @@ namespace Debugger
void Detaching();
public:
static CCPUDebug *CreateMainBoardCPUDebug(::CModel3 *model3);
static CCPUDebug *CreateSoundBoardCPUDebug(::CModel3 *model3);
static CCPUDebug *CreateDSBCPUDebug(::CModel3 *model3);
static CCPUDebug *CreateDriveBoardCPUDebug(::CModel3 *model3);
CSupermodelDebugger(::CModel3 *model3, ::CInputs *inputs, ::CLogger *logger);
void Poll();