mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2025-02-16 17:35:39 +00:00
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:
parent
b9430cd988
commit
e8e02ba685
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
178
Src/Debugger/CPU/Musashi68KDebug.cpp
Executable file
178
Src/Debugger/CPU/Musashi68KDebug.cpp
Executable 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
|
100
Src/Debugger/CPU/Musashi68KDebug.h
Executable file
100
Src/Debugger/CPU/Musashi68KDebug.h
Executable 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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ namespace Debugger
|
|||
UINT8 m_irqState;
|
||||
|
||||
public:
|
||||
CPPCDebug();
|
||||
CPPCDebug(const char *name);
|
||||
|
||||
virtual ~CPPCDebug();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
702
Src/Debugger/CPU/Z80Debug.cpp
Executable 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
94
Src/Debugger/CPU/Z80Debug.h
Executable 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
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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, ...)
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue