mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2025-04-10 19:15:14 +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 <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#define M68KSPECIAL_SP 0
|
||||||
|
#define M68KSPECIAL_SR 1
|
||||||
|
|
||||||
namespace Debugger
|
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
|
// Exceptions
|
||||||
AddException("BUS", 2, "Bus Error");
|
AddException("BUS", 2, "Bus Error");
|
||||||
|
@ -47,39 +50,6 @@ namespace Debugger
|
||||||
AddInterrupt("AUTO5", 4, "Level 5 Interrupt Autovector");
|
AddInterrupt("AUTO5", 4, "Level 5 Interrupt Autovector");
|
||||||
AddInterrupt("AUTO6", 5, "Level 6 Interrupt Autovector");
|
AddInterrupt("AUTO6", 5, "Level 6 Interrupt Autovector");
|
||||||
AddInterrupt("AUTO7", 6, "Level 7 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",
|
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)
|
int C68KDebug::Disassemble(UINT32 addr, char *mnemonic, char *operands)
|
||||||
{
|
{
|
||||||
// Read opcode head word
|
// Read opcode head word
|
||||||
UINT16 opcode = (UINT16)ReadMem(addr, 16);
|
UINT16 opcode = (UINT16)ReadMem(addr, 2);
|
||||||
int offset = 2;
|
int offset = 2;
|
||||||
|
|
||||||
const char *instr;
|
const char *instr;
|
||||||
|
@ -2204,7 +2174,7 @@ namespace Debugger
|
||||||
if (opcode != 0x4E74 && opcode != 0x4E75 && opcode != 0x4E73)
|
if (opcode != 0x4E74 && opcode != 0x4E75 && opcode != 0x4E73)
|
||||||
return false;
|
return false;
|
||||||
// Return address will be at top of stack for rts and stack + 2 for rtr or rte
|
// 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)
|
if (opcode == 0x4E75)
|
||||||
retAddr = (UINT32)ReadMem(sp, 4);
|
retAddr = (UINT32)ReadMem(sp, 4);
|
||||||
else
|
else
|
||||||
|
|
|
@ -5,14 +5,6 @@
|
||||||
#include "Debugger/CPUDebug.h"
|
#include "Debugger/CPUDebug.h"
|
||||||
#include "Types.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
|
namespace Debugger
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -21,20 +13,13 @@ namespace Debugger
|
||||||
class C68KDebug : public CCPUDebug
|
class C68KDebug : public CCPUDebug
|
||||||
{
|
{
|
||||||
private:
|
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);
|
bool FormatAddrMode(UINT32 addr, UINT32 opcode, int &offset, UINT8 addrMode, char sizeC, char *dest);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual UINT32 GetSP() = 0;
|
virtual UINT32 GetSP() = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
C68KDebug();
|
C68KDebug(const char *name);
|
||||||
|
|
||||||
// CCPUDebug methods
|
// 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 *crGroup = "Condition Registers";
|
||||||
static const char *grGroup = "GPR Registers";
|
static const char *grGroup = "GPR Registers";
|
||||||
static const char *frGroup = "FPR 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
|
// PC & Link registers
|
||||||
AddPCRegister ("pc", srGroup);
|
AddPCRegister ("pc", srGroup);
|
||||||
|
@ -131,69 +129,6 @@ namespace Debugger
|
||||||
AddException("SMI", EXCEPTION_SMI, "SMI");
|
AddException("SMI", EXCEPTION_SMI, "SMI");
|
||||||
AddException("DSI", EXCEPTION_DSI, "DSI");
|
AddException("DSI", EXCEPTION_DSI, "DSI");
|
||||||
AddException("ISI", EXCEPTION_ISI, "ISI");
|
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()
|
CPPCDebug::~CPPCDebug()
|
||||||
|
@ -278,7 +213,7 @@ namespace Debugger
|
||||||
|
|
||||||
void CPPCDebug::CheckException(UINT16 exCode)
|
void CPPCDebug::CheckException(UINT16 exCode)
|
||||||
{
|
{
|
||||||
CCPUDebug::CheckException(exCode);
|
CCPUDebug::CPUException(exCode);
|
||||||
|
|
||||||
if (exCode == EXCEPTION_IRQ)
|
if (exCode == EXCEPTION_IRQ)
|
||||||
{
|
{
|
||||||
|
@ -288,7 +223,7 @@ namespace Debugger
|
||||||
for (int intCode = 0; newIRQs && intCode < 8; intCode++)
|
for (int intCode = 0; newIRQs && intCode < 8; intCode++)
|
||||||
{
|
{
|
||||||
if (newIRQs&0x01)
|
if (newIRQs&0x01)
|
||||||
CheckInterrupt(intCode);
|
CPUInterrupt(intCode);
|
||||||
newIRQs >>= 1;
|
newIRQs >>= 1;
|
||||||
}
|
}
|
||||||
m_irqState = irqState;
|
m_irqState = irqState;
|
||||||
|
@ -350,7 +285,6 @@ namespace Debugger
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
||||||
return -4;
|
return -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ namespace Debugger
|
||||||
UINT8 m_irqState;
|
UINT8 m_irqState;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CPPCDebug();
|
CPPCDebug(const char *name);
|
||||||
|
|
||||||
virtual ~CPPCDebug();
|
virtual ~CPPCDebug();
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,9 @@ namespace Debugger
|
||||||
{
|
{
|
||||||
switch (id)
|
switch (id)
|
||||||
{
|
{
|
||||||
case M68KSPECIAL_SP: return (UINT32)turbo68kcontext_68000.a[7];
|
case TBO68K_REG_SP: return (UINT32)turbo68kcontext_68000.a[7];
|
||||||
case M68KSPECIAL_SR: return (UINT32)turbo68kcontext_68000.sr;
|
case TBO68K_REG_SR: return (UINT32)turbo68kcontext_68000.sr;
|
||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,9 +21,9 @@ namespace Debugger
|
||||||
{
|
{
|
||||||
switch (id)
|
switch (id)
|
||||||
{
|
{
|
||||||
case M68KSPECIAL_SP: turbo68kcontext_68000.a[7] = data; return true;
|
case TBO68K_REG_SP: turbo68kcontext_68000.a[7] = data; return true;
|
||||||
case M68KSPECIAL_SR: turbo68kcontext_68000.sr = data; return true;
|
case TBO68K_REG_SR: turbo68kcontext_68000.sr = data; return true;
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,12 +53,12 @@ namespace Debugger
|
||||||
static const char *drGroup = "Data Registers";
|
static const char *drGroup = "Data Registers";
|
||||||
static const char *arGroup = "Address Regsters";
|
static const char *arGroup = "Address Regsters";
|
||||||
|
|
||||||
CTurbo68KDebug::CTurbo68KDebug() : C68KDebug(), m_resetAddr(0)
|
CTurbo68KDebug::CTurbo68KDebug(const char *name) : C68KDebug(name), m_resetAddr(0)
|
||||||
{
|
{
|
||||||
// Special registers
|
// Special registers
|
||||||
AddPCRegister ("PC", srGroup);
|
AddPCRegister ("PC", srGroup);
|
||||||
AddAddrRegister ("SP", srGroup, M68KSPECIAL_SP, GetSpecialReg, SetSpecialReg);
|
AddAddrRegister ("SP", srGroup, TBO68K_REG_SP, GetSpecialReg, SetSpecialReg);
|
||||||
AddStatus32Register("SR", srGroup, M68KSPECIAL_SR, "TtSM.210...XNZVC", GetSpecialReg, SetSpecialReg);
|
AddStatus32Register("SR", srGroup, TBO68K_REG_SR, "TtSM.210...XNZVC", GetSpecialReg, SetSpecialReg);
|
||||||
|
|
||||||
// Data registers
|
// Data registers
|
||||||
for (unsigned id = 0; id < 8; id++)
|
for (unsigned id = 0; id < 8; id++)
|
||||||
|
@ -73,39 +73,6 @@ namespace Debugger
|
||||||
sprintf(m_arNames[id], "A%u", id);
|
sprintf(m_arNames[id], "A%u", id);
|
||||||
AddInt32Register(m_arNames[id], arGroup, id, GetAddressReg, SetAddressReg);
|
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()
|
CTurbo68KDebug::~CTurbo68KDebug()
|
||||||
|
@ -116,7 +83,7 @@ namespace Debugger
|
||||||
bool __cdecl DebugHandler(TURBO68K_INT32 pc, TURBO68K_INT32 opcode)
|
bool __cdecl DebugHandler(TURBO68K_INT32 pc, TURBO68K_INT32 opcode)
|
||||||
{
|
{
|
||||||
// Return true to let Turbo68K know if PC was changed by user
|
// 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)
|
void __cdecl InterruptHandler(TURBO68K_UINT32 intVec)
|
||||||
|
@ -126,11 +93,11 @@ namespace Debugger
|
||||||
return;
|
return;
|
||||||
else if (intVec >= 25 || intVec < 32)
|
else if (intVec >= 25 || intVec < 32)
|
||||||
{
|
{
|
||||||
debug->CheckException(25);
|
debug->CPUException(25);
|
||||||
debug->CheckInterrupt((UINT16)intVec - 25);
|
debug->CPUInterrupt((UINT16)intVec - 25);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
debug->CheckException((UINT16)intVec);
|
debug->CPUException((UINT16)intVec);
|
||||||
|
|
||||||
if (origIntAckPtr != NULL)
|
if (origIntAckPtr != NULL)
|
||||||
origIntAckPtr(intVec);
|
origIntAckPtr(intVec);
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
|
|
||||||
#include "CPU/68K/Turbo68K/Turbo68K.h"
|
#include "CPU/68K/Turbo68K/Turbo68K.h"
|
||||||
|
|
||||||
#define M68KSPECIAL_SP 0
|
#define TBO68K_REG_SP 0
|
||||||
#define M68KSPECIAL_SR 1
|
#define TBO68K_REG_SR 1
|
||||||
|
|
||||||
#define USE_NATIVE_READ 0
|
#define USE_NATIVE_READ 0
|
||||||
#define USE_NATIVE_WRITE 0
|
#define USE_NATIVE_WRITE 0
|
||||||
|
@ -93,14 +93,13 @@ namespace Debugger
|
||||||
char m_drNames[8][3];
|
char m_drNames[8][3];
|
||||||
char m_arNames[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;
|
UINT32 m_resetAddr;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
UINT32 GetSP();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CTurbo68KDebug();
|
CTurbo68KDebug(const char *name);
|
||||||
|
|
||||||
virtual ~CTurbo68KDebug();
|
virtual ~CTurbo68KDebug();
|
||||||
|
|
||||||
|
@ -112,8 +111,6 @@ namespace Debugger
|
||||||
|
|
||||||
UINT32 GetResetAddr();
|
UINT32 GetResetAddr();
|
||||||
|
|
||||||
UINT32 GetSP();
|
|
||||||
|
|
||||||
bool UpdatePC(UINT32 pc);
|
bool UpdatePC(UINT32 pc);
|
||||||
|
|
||||||
bool ForceException(CException *ex);
|
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
|
namespace Debugger
|
||||||
{
|
{
|
||||||
CCPUDebug::CCPUDebug(const char *cpuName, UINT8 cpuMinInstrLen, UINT8 cpuMaxInstrLen, bool cpuBigEndian, UINT8 cpuMemBusWidth, UINT8 cpuMaxMnemLen) :
|
CCPUDebug::CCPUDebug(const char *cpuType, const char *cpuName,
|
||||||
name(cpuName), minInstrLen(cpuMinInstrLen), maxInstrLen(cpuMaxInstrLen),
|
UINT8 cpuMinInstrLen, UINT8 cpuMaxInstrLen, bool cpuBigEndian, UINT8 cpuMemBusWidth, UINT8 cpuMaxMnemLen) :
|
||||||
|
type(cpuType), name(cpuName), minInstrLen(cpuMinInstrLen), maxInstrLen(cpuMaxInstrLen),
|
||||||
bigEndian(cpuBigEndian), memBusWidth(cpuMemBusWidth), maxMnemLen(cpuMaxMnemLen),
|
bigEndian(cpuBigEndian), memBusWidth(cpuMemBusWidth), maxMnemLen(cpuMaxMnemLen),
|
||||||
enabled(true), addrFmt(HexDollar), portFmt(Decimal), dataFmt(HexDollar), debugger(NULL),
|
enabled(true), addrFmt(HexDollar), portFmt(Decimal), dataFmt(HexDollar), debugger(NULL),
|
||||||
numExCodes(0), numIntCodes(0), numPorts(0), memSize(0), instrCount(0), pc(0), opcode(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_userBreak(false), m_step(false), m_steppingOver(false), m_steppingOut(false), m_count(0), m_until(false), m_untilAddr(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_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_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_exArray, NULL, sizeof(m_exArray));
|
||||||
memset(m_intArray, NULL, sizeof(m_intArray));
|
memset(m_intArray, NULL, sizeof(m_intArray));
|
||||||
memset(m_portArray, NULL, sizeof(m_portArray));
|
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()
|
CCPUDebug::~CCPUDebug()
|
||||||
|
@ -377,14 +385,17 @@ namespace Debugger
|
||||||
|
|
||||||
void CCPUDebug::ForceBreak(bool user)
|
void CCPUDebug::ForceBreak(bool user)
|
||||||
{
|
{
|
||||||
|
m_breakUser |= user;
|
||||||
m_break = true;
|
m_break = true;
|
||||||
m_userBreak |= user;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCPUDebug::ClearBreak()
|
void CCPUDebug::ClearBreak()
|
||||||
{
|
{
|
||||||
|
#ifdef DEBUGGER_HASTHREAD
|
||||||
|
m_breakWait = false;
|
||||||
|
#endif // DEBUGGER_HASTHREAD
|
||||||
|
m_breakUser = false;
|
||||||
m_break = false;
|
m_break = false;
|
||||||
m_userBreak = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCPUDebug::SetContinue()
|
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
|
// TODO - load breakpoints, watches, exception/interrupt traps and register monitors
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1191,13 +1207,17 @@ namespace Debugger
|
||||||
state->Write(str, strLen * sizeof(char));
|
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
|
// TODO - save breakpoints, watches, exception/interrupt traps and register monitors
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif // DEBUGGER_HASBLOCKFILE
|
#endif // DEBUGGER_HASBLOCKFILE
|
||||||
|
|
||||||
void CCPUDebug::CheckException(UINT16 exCode)
|
void CCPUDebug::CPUException(UINT16 exCode)
|
||||||
{
|
{
|
||||||
if (exCode >= numExCodes)
|
if (exCode >= numExCodes)
|
||||||
return;
|
return;
|
||||||
|
@ -1215,7 +1235,7 @@ namespace Debugger
|
||||||
m_break = true;
|
m_break = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCPUDebug::CheckInterrupt(UINT16 intCode)
|
void CCPUDebug::CPUInterrupt(UINT16 intCode)
|
||||||
{
|
{
|
||||||
if (intCode >= numIntCodes)
|
if (intCode >= numIntCodes)
|
||||||
return;
|
return;
|
||||||
|
@ -1233,6 +1253,106 @@ namespace Debugger
|
||||||
m_break = true;
|
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()
|
void CCPUDebug::DebuggerReset()
|
||||||
{
|
{
|
||||||
instrCount = 0;
|
instrCount = 0;
|
||||||
|
@ -1244,6 +1364,12 @@ namespace Debugger
|
||||||
m_analyser->Reset();
|
m_analyser->Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CCPUDebug::DebuggerPolled()
|
||||||
|
{
|
||||||
|
cyclesPerPoll = totalCycles - m_prevTotalCycles;
|
||||||
|
m_prevTotalCycles = totalCycles;
|
||||||
|
}
|
||||||
|
|
||||||
UINT64 CCPUDebug::ReadMem(UINT32 addr, unsigned dataSize)
|
UINT64 CCPUDebug::ReadMem(UINT32 addr, unsigned dataSize)
|
||||||
{
|
{
|
||||||
// TODO - currently assumes big-endian - should act according to this.bigEndian
|
// TODO - currently assumes big-endian - should act according to this.bigEndian
|
||||||
|
|
|
@ -23,6 +23,10 @@ using namespace std;
|
||||||
#include "BlockFile.h"
|
#include "BlockFile.h"
|
||||||
#endif // DEBUGGER_HASBLOCKFILE
|
#endif // DEBUGGER_HASBLOCKFILE
|
||||||
|
|
||||||
|
#ifdef DEBUGGER_HASTHREAD
|
||||||
|
#include "Thread.h"
|
||||||
|
#endif // DEBUGGER_HASTHREAD
|
||||||
|
|
||||||
#define MAX_EXCEPTIONS 255
|
#define MAX_EXCEPTIONS 255
|
||||||
#define MAX_INTERRUPTS 255
|
#define MAX_INTERRUPTS 255
|
||||||
#define MAX_IOPORTS 255
|
#define MAX_IOPORTS 255
|
||||||
|
@ -66,7 +70,11 @@ namespace Debugger
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_break;
|
bool m_break;
|
||||||
bool m_userBreak;
|
#ifdef DEBUGGER_HASTHREAD
|
||||||
|
bool m_breakWait;
|
||||||
|
#endif // DEBUGGER_HASTHREAD
|
||||||
|
bool m_breakUser;
|
||||||
|
bool m_halted;
|
||||||
bool m_step;
|
bool m_step;
|
||||||
EStepMode m_stepMode;
|
EStepMode m_stepMode;
|
||||||
bool m_stepBreak;
|
bool m_stepBreak;
|
||||||
|
@ -78,6 +86,11 @@ namespace Debugger
|
||||||
bool m_until;
|
bool m_until;
|
||||||
UINT32 m_untilAddr;
|
UINT32 m_untilAddr;
|
||||||
|
|
||||||
|
#ifdef DEBUGGER_HASTHREAD
|
||||||
|
CMutex *m_mutex;
|
||||||
|
CCondVar *m_condVar;
|
||||||
|
#endif // DEBUGGER_HASTHREAD
|
||||||
|
|
||||||
CException *m_exArray[MAX_EXCEPTIONS];
|
CException *m_exArray[MAX_EXCEPTIONS];
|
||||||
CInterrupt *m_intArray[MAX_INTERRUPTS];
|
CInterrupt *m_intArray[MAX_INTERRUPTS];
|
||||||
CPortIO *m_portArray[MAX_IOPORTS];
|
CPortIO *m_portArray[MAX_IOPORTS];
|
||||||
|
@ -116,12 +129,68 @@ namespace Debugger
|
||||||
CWatch *m_ioWatchTriggered;
|
CWatch *m_ioWatchTriggered;
|
||||||
CRegMonitor *m_regMonTriggered;
|
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);
|
CPCRegister *AddPCRegister(const char *name, const char *group);
|
||||||
|
|
||||||
CAddrRegister *AddAddrRegister(const char *name, const char *group, unsigned id, GetInt32FPtr getFunc, SetInt32FPtr setFunc = NULL);
|
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);
|
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);
|
CException *AddException(const char *id, UINT16 code, const char *name);
|
||||||
|
|
||||||
CInterrupt *AddInterrupt(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)
|
// Methods to define memory layout (must be called before attached to debugger)
|
||||||
//
|
//
|
||||||
|
@ -279,21 +302,43 @@ namespace Debugger
|
||||||
void CheckPortOutput(UINT16 portNum, UINT64 data);
|
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
|
* 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.
|
* 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
|
// Execution control
|
||||||
|
@ -489,6 +534,8 @@ namespace Debugger
|
||||||
|
|
||||||
virtual void DebuggerReset();
|
virtual void DebuggerReset();
|
||||||
|
|
||||||
|
virtual void DebuggerPolled();
|
||||||
|
|
||||||
virtual UINT32 GetResetAddr() = 0;
|
virtual UINT32 GetResetAddr() = 0;
|
||||||
|
|
||||||
virtual UINT64 ReadMem(UINT32 addr, unsigned dataSize);
|
virtual UINT64 ReadMem(UINT32 addr, unsigned dataSize);
|
||||||
|
@ -754,13 +801,14 @@ namespace Debugger
|
||||||
IOWatchTriggered(port->watch, port, data, false);
|
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
|
// Check if debugging is enabled for this CPU
|
||||||
if (!enabled)
|
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++;
|
instrCount++;
|
||||||
|
totalCycles += lastCycles;
|
||||||
pc = newPC;
|
pc = newPC;
|
||||||
opcode = newOpcode;
|
opcode = newOpcode;
|
||||||
return false;
|
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++;
|
instrCount++;
|
||||||
|
totalCycles += lastCycles;
|
||||||
pc = newPC;
|
pc = newPC;
|
||||||
opcode = newOpcode;
|
opcode = newOpcode;
|
||||||
|
|
||||||
|
@ -862,16 +911,12 @@ namespace Debugger
|
||||||
if (m_break || m_stateUpdated || stepBreak || countBreak || untilBreak)
|
if (m_break || m_stateUpdated || stepBreak || countBreak || untilBreak)
|
||||||
{
|
{
|
||||||
// See if execution halt was caused by user manually breaking execution in some manner
|
// 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);
|
||||||
EHaltReason reason = HaltNone;
|
if (m_breakUser) reason = (EHaltReason)(reason | HaltUser);
|
||||||
if (m_stateUpdated) reason = (EHaltReason)(reason | HaltState);
|
if (stepBreak) reason = (EHaltReason)(reason | HaltStep);
|
||||||
if (m_userBreak) reason = (EHaltReason)(reason | HaltUser);
|
if (countBreak) reason = (EHaltReason)(reason | HaltCount);
|
||||||
if (stepBreak) reason = (EHaltReason)(reason | HaltStep);
|
if (untilBreak) reason = (EHaltReason)(reason | HaltUntil);
|
||||||
if (countBreak) reason = (EHaltReason)(reason | HaltCount);
|
|
||||||
if (untilBreak) reason = (EHaltReason)(reason | HaltUntil);
|
|
||||||
debugger->ExecutionHalted(this, reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep hold of breakpoint, if any, and its address so that can reset it later
|
// Keep hold of breakpoint, if any, and its address so that can reset it later
|
||||||
UINT32 bpAddr = 0;
|
UINT32 bpAddr = 0;
|
||||||
|
@ -883,7 +928,6 @@ namespace Debugger
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset all control flags
|
// Reset all control flags
|
||||||
debugger->ClearBreak();
|
|
||||||
m_stateUpdated = false;
|
m_stateUpdated = false;
|
||||||
m_step = false;
|
m_step = false;
|
||||||
m_steppingOver = false;
|
m_steppingOver = false;
|
||||||
|
@ -900,7 +944,7 @@ namespace Debugger
|
||||||
m_regMonTriggered = NULL;
|
m_regMonTriggered = NULL;
|
||||||
|
|
||||||
// Wait for instruction from user
|
// Wait for instruction from user
|
||||||
debugger->WaitCommand(this);
|
WaitCommand(reason);
|
||||||
|
|
||||||
// Reset breakpoint, if any
|
// Reset breakpoint, if any
|
||||||
if (bpToReset != NULL && m_bpTable != NULL)
|
if (bpToReset != NULL && m_bpTable != NULL)
|
||||||
|
|
|
@ -461,7 +461,7 @@ namespace Debugger
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
for (vector<UINT32>::iterator it = m_customEntryAddrs.begin(); it != m_customEntryAddrs.end(); it++)
|
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);
|
AddEntryPoint(entryPoints, *it, LFEntryPoint, labelStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -652,6 +652,11 @@ namespace Debugger
|
||||||
m_abortAnalysis = true;
|
m_abortAnalysis = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CCodeAnalyser::ClearCustomEntryAddrs()
|
||||||
|
{
|
||||||
|
m_customEntryAddrs.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void CCodeAnalyser::AddCustomEntryAddr(UINT32 entryAddr)
|
void CCodeAnalyser::AddCustomEntryAddr(UINT32 entryAddr)
|
||||||
{
|
{
|
||||||
if (find(m_customEntryAddrs.begin(), m_customEntryAddrs.end(), entryAddr) == m_customEntryAddrs.end())
|
if (find(m_customEntryAddrs.begin(), m_customEntryAddrs.end(), entryAddr) == m_customEntryAddrs.end())
|
||||||
|
@ -666,6 +671,43 @@ namespace Debugger
|
||||||
m_customEntryAddrs.erase(it);
|
m_customEntryAddrs.erase(it);
|
||||||
return true;
|
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
|
#endif // SUPERMODEL_DEBUGGER
|
|
@ -11,8 +11,13 @@ using namespace std;
|
||||||
|
|
||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
|
|
||||||
|
#include "Debugger.h"
|
||||||
#include "AddressTable.h"
|
#include "AddressTable.h"
|
||||||
|
|
||||||
|
#ifdef DEBUGGER_HASBLOCKFILE
|
||||||
|
#include "BlockFile.h"
|
||||||
|
#endif // DEBUGGER_HASBLOCKFILE
|
||||||
|
|
||||||
namespace Debugger
|
namespace Debugger
|
||||||
{
|
{
|
||||||
class CCPUDebug;
|
class CCPUDebug;
|
||||||
|
@ -202,15 +207,31 @@ namespace Debugger
|
||||||
|
|
||||||
bool GetIndexOfAddr(UINT32 addr, unsigned &index);
|
bool GetIndexOfAddr(UINT32 addr, unsigned &index);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Methods to check, run or abort analysis
|
||||||
|
//
|
||||||
|
|
||||||
bool NeedsAnalysis();
|
bool NeedsAnalysis();
|
||||||
|
|
||||||
bool AnalyseCode();
|
bool AnalyseCode();
|
||||||
|
|
||||||
void AbortAnalysis();
|
void AbortAnalysis();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Methods to manipulate custom entry addresses
|
||||||
|
//
|
||||||
|
|
||||||
|
void ClearCustomEntryAddrs();
|
||||||
|
|
||||||
void AddCustomEntryAddr(UINT32 entryAddr);
|
void AddCustomEntryAddr(UINT32 entryAddr);
|
||||||
|
|
||||||
bool RemoveCustomEntryAddr(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';
|
modifier[modSize] = '\0';
|
||||||
|
|
||||||
char actual[255];
|
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);
|
strncpy(actual, token, actSize);
|
||||||
actual[actSize] = '\0';
|
actual[actSize] = '\0';
|
||||||
return CheckToken(actual, simple, full);
|
return CheckToken(actual, simple, full);
|
||||||
|
@ -1932,16 +1932,30 @@ namespace Debugger
|
||||||
return;
|
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;
|
unsigned num = 0;
|
||||||
|
double freq;
|
||||||
|
char onCPU;
|
||||||
|
const char *debugStr;
|
||||||
const char *stateStr;
|
const char *stateStr;
|
||||||
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
|
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)
|
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
|
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 ? '<' : '>');
|
dirChar = ((*it)->last == &(*it)->lastIn ? '<' : '>');
|
||||||
else
|
else
|
||||||
dirChar = ' ';
|
dirChar = ' ';
|
||||||
// Formatt last input
|
// Format last input
|
||||||
if ((*it)->inCount > 0)
|
if ((*it)->inCount > 0)
|
||||||
m_cpu->FormatData(inStr, (*it)->dataSize, (*it)->lastIn);
|
m_cpu->FormatData(inStr, (*it)->dataSize, (*it)->lastIn);
|
||||||
else
|
else
|
||||||
|
@ -2109,7 +2123,7 @@ namespace Debugger
|
||||||
int inLPad = 5 - (int)inLen / 2;
|
int inLPad = 5 - (int)inLen / 2;
|
||||||
int inRPad = 5 - (int)inLen + (int)inLen / 2;
|
int inRPad = 5 - (int)inLen + (int)inLen / 2;
|
||||||
// Format last output
|
// Format last output
|
||||||
if ((*it)->inCount > 0)
|
if ((*it)->outCount > 0)
|
||||||
m_cpu->FormatData(outStr, (*it)->dataSize, (*it)->lastOut);
|
m_cpu->FormatData(outStr, (*it)->dataSize, (*it)->lastOut);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2402,7 +2416,8 @@ namespace Debugger
|
||||||
// In the absence of code analyser, try to align code with current PC address
|
// In the absence of code analyser, try to align code with current PC address
|
||||||
if (m_cpu->instrCount > 0 && pc >= start && pc <= end)
|
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;
|
bool okay = false;
|
||||||
addr = start;
|
addr = start;
|
||||||
|
|
|
@ -101,21 +101,33 @@ namespace Debugger
|
||||||
return sscanf(str, "%d", val) == 1;
|
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()
|
CDebugger::~CDebugger()
|
||||||
|
{
|
||||||
|
DeleteCPUs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDebugger::DeleteCPUs()
|
||||||
{
|
{
|
||||||
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
|
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
|
||||||
delete *it;
|
delete *it;
|
||||||
|
cpus.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDebugger::AddCPU(CCPUDebug *cpu)
|
void CDebugger::AddCPU(CCPUDebug *cpu)
|
||||||
{
|
{
|
||||||
cpu->AttachToDebugger(this);
|
cpu->AttachToDebugger(this);
|
||||||
cpus.push_back(cpu);
|
cpus.push_back(cpu);
|
||||||
|
if (m_break)
|
||||||
|
cpu->ForceBreak(m_breakUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDebugger::RemoveCPU(CCPUDebug *cpu)
|
void CDebugger::RemoveCPU(CCPUDebug *cpu)
|
||||||
|
@ -158,24 +170,70 @@ namespace Debugger
|
||||||
|
|
||||||
void CDebugger::ForceBreak(bool user)
|
void CDebugger::ForceBreak(bool user)
|
||||||
{
|
{
|
||||||
|
m_break = true;
|
||||||
|
m_breakUser = user;
|
||||||
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
|
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
|
||||||
(*it)->ForceBreak(user);
|
(*it)->ForceBreak(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDebugger::ClearBreak()
|
void CDebugger::ClearBreak()
|
||||||
{
|
{
|
||||||
|
m_break = false;
|
||||||
|
m_breakUser = false;
|
||||||
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
|
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
|
||||||
(*it)->ClearBreak();
|
(*it)->ClearBreak();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDebugger::SetContinue()
|
#ifdef DEBUGGER_HASTHREAD
|
||||||
|
bool CDebugger::MakePrimary(CCPUDebug *cpu)
|
||||||
{
|
{
|
||||||
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
|
m_mutex->Lock();
|
||||||
(*it)->SetContinue();
|
|
||||||
|
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()
|
void CDebugger::Attach()
|
||||||
{
|
{
|
||||||
|
AddCPUs();
|
||||||
|
|
||||||
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
|
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
|
||||||
(*it)->AttachToCPU();
|
(*it)->AttachToCPU();
|
||||||
}
|
}
|
||||||
|
@ -184,6 +242,8 @@ namespace Debugger
|
||||||
{
|
{
|
||||||
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
|
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
|
||||||
(*it)->DetachFromCPU();
|
(*it)->DetachFromCPU();
|
||||||
|
|
||||||
|
DeleteCPUs();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDebugger::Reset()
|
void CDebugger::Reset()
|
||||||
|
@ -196,6 +256,8 @@ namespace Debugger
|
||||||
void CDebugger::Poll()
|
void CDebugger::Poll()
|
||||||
{
|
{
|
||||||
frameCount++;
|
frameCount++;
|
||||||
|
for (vector<CCPUDebug*>::iterator it = cpus.begin(); it != cpus.end(); it++)
|
||||||
|
(*it)->DebuggerPolled();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDebugger::PrintEvent(CCPUDebug *cpu, const char *fmt, ...)
|
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)
|
#if defined(SUPERMODEL_WIN32) || defined(SUPERMODEL_UNIX) || defined(SUPERMODEL_OSX)
|
||||||
#define DEBUGGER_HASBLOCKFILE
|
#define DEBUGGER_HASBLOCKFILE
|
||||||
#define DEBUGGER_HASLOGGER
|
#define DEBUGGER_HASLOGGER
|
||||||
|
#define DEBUGGER_HASTHREAD
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DEBUGGER_STATEFILE_VERSION 0
|
#define DEBUGGER_STATEFILE_VERSION 0
|
||||||
|
@ -22,9 +23,16 @@ using namespace std;
|
||||||
#endif // DEBUGGER_HASBLOCKFILE
|
#endif // DEBUGGER_HASBLOCKFILE
|
||||||
|
|
||||||
#ifdef DEBUGGER_HASLOGGER
|
#ifdef DEBUGGER_HASLOGGER
|
||||||
|
#ifndef SUPERMODEL_VERSION
|
||||||
|
#define SUPERMODEL_VERSION ""
|
||||||
|
#endif // SUPERMODEL_VERSEION
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#endif // DEBUGGER_HASLOGGER
|
#endif // DEBUGGER_HASLOGGER
|
||||||
|
|
||||||
|
#ifdef DEBUGGER_HASTHREAD
|
||||||
|
#include "Thread.h"
|
||||||
|
#endif // DEBUGGER_HASTHREAD
|
||||||
|
|
||||||
#ifndef stricmp
|
#ifndef stricmp
|
||||||
#ifdef _MSC_VER // MS VisualC++
|
#ifdef _MSC_VER // MS VisualC++
|
||||||
#define stricmp _stricmp
|
#define stricmp _stricmp
|
||||||
|
@ -83,8 +91,19 @@ namespace Debugger
|
||||||
private:
|
private:
|
||||||
bool m_exit;
|
bool m_exit;
|
||||||
bool m_pause;
|
bool m_pause;
|
||||||
|
bool m_break;
|
||||||
|
bool m_breakUser;
|
||||||
|
|
||||||
|
#ifdef DEBUGGER_HASTHREAD
|
||||||
|
CMutex *m_mutex;
|
||||||
|
CCPUDebug *m_primaryCPU;
|
||||||
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual void AddCPUs() = 0;
|
||||||
|
|
||||||
|
virtual void DeleteCPUs();
|
||||||
|
|
||||||
#ifdef DEBUGGER_HASBLOCKFILE
|
#ifdef DEBUGGER_HASBLOCKFILE
|
||||||
virtual bool LoadState(CBlockFile *state);
|
virtual bool LoadState(CBlockFile *state);
|
||||||
|
|
||||||
|
@ -154,12 +173,16 @@ namespace Debugger
|
||||||
|
|
||||||
void ClearBreak();
|
void ClearBreak();
|
||||||
|
|
||||||
void SetContinue();
|
|
||||||
|
|
||||||
bool CheckExit();
|
bool CheckExit();
|
||||||
|
|
||||||
bool CheckPause();
|
bool CheckPause();
|
||||||
|
|
||||||
|
#ifdef DEBUGGER_HASTHREAD
|
||||||
|
bool MakePrimary(CCPUDebug *cpu);
|
||||||
|
|
||||||
|
void ReleasePrimary();
|
||||||
|
#endif // DEBUGGER_HASTHREAD
|
||||||
|
|
||||||
//
|
//
|
||||||
// Printing/logging
|
// Printing/logging
|
||||||
//
|
//
|
||||||
|
|
|
@ -92,7 +92,7 @@ namespace Debugger
|
||||||
void CPortIO::GetLocation(char *str)
|
void CPortIO::GetLocation(char *str)
|
||||||
{
|
{
|
||||||
if (name != NULL)
|
if (name != NULL)
|
||||||
sprintf(str, "port %s", name);
|
strcpy(str, name);
|
||||||
else
|
else
|
||||||
sprintf(str, "port %u", portNum);
|
sprintf(str, "port %u", portNum);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,20 +11,291 @@
|
||||||
|
|
||||||
namespace Debugger
|
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) :
|
CSupermodelDebugger::CSupermodelDebugger(::CModel3 *model3, ::CInputs *inputs, ::CLogger *logger) :
|
||||||
CConsoleDebugger(), m_model3(model3), m_inputs(inputs), m_logger(logger),
|
CConsoleDebugger(), m_model3(model3), m_inputs(inputs), m_logger(logger),
|
||||||
m_loadEmuState(false), m_saveEmuState(false), m_resetEmu(false)
|
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)
|
void CSupermodelDebugger::WaitCommand(CCPUDebug *cpu)
|
||||||
{
|
{
|
||||||
|
// Ungrab mouse and disable audio
|
||||||
m_inputs->GetInputSystem()->UngrabMouse();
|
m_inputs->GetInputSystem()->UngrabMouse();
|
||||||
|
SetAudioEnabled(false);
|
||||||
|
|
||||||
CConsoleDebugger::WaitCommand(cpu);
|
CConsoleDebugger::WaitCommand(cpu);
|
||||||
|
|
||||||
m_inputs->GetInputSystem()->GrabMouse();
|
m_inputs->GetInputSystem()->GrabMouse();
|
||||||
|
SetAudioEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSupermodelDebugger::ProcessToken(const char *token, const char *cmd)
|
bool CSupermodelDebugger::ProcessToken(const char *token, const char *cmd)
|
||||||
|
|
|
@ -36,6 +36,8 @@ namespace Debugger
|
||||||
void ListInputs();
|
void ListInputs();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void AddCPUs();
|
||||||
|
|
||||||
void WaitCommand(CCPUDebug *cpu);
|
void WaitCommand(CCPUDebug *cpu);
|
||||||
|
|
||||||
bool ProcessToken(const char *token, const char *cmd);
|
bool ProcessToken(const char *token, const char *cmd);
|
||||||
|
@ -45,6 +47,14 @@ namespace Debugger
|
||||||
void Detaching();
|
void Detaching();
|
||||||
|
|
||||||
public:
|
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);
|
CSupermodelDebugger(::CModel3 *model3, ::CInputs *inputs, ::CLogger *logger);
|
||||||
|
|
||||||
void Poll();
|
void Poll();
|
||||||
|
|
Loading…
Reference in a new issue