mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2025-03-06 14:27:44 +00:00
New debugger classes - implementations for ppc and Turbo68K CPU cores
This commit is contained in:
parent
7ea5d31b6c
commit
9416f9c521
2471
Src/Debugger/CPU/68KDebug.cpp
Normal file
2471
Src/Debugger/CPU/68KDebug.cpp
Normal file
File diff suppressed because it is too large
Load diff
335
Src/Debugger/CPU/68KDebug.h
Normal file
335
Src/Debugger/CPU/68KDebug.h
Normal file
|
@ -0,0 +1,335 @@
|
|||
#ifdef SUPERMODEL_DEBUGGER
|
||||
#ifdef SUPERMODEL_SOUND
|
||||
#ifndef INCLUDED_68KDEBUG_H
|
||||
#define INCLUDED_68KDEBUG_H
|
||||
|
||||
#include "Debugger/CPUDebug.h"
|
||||
#include "Types.h"
|
||||
|
||||
#include "CPU/68K/Turbo68K.h"
|
||||
|
||||
#define M68KSPECIAL_SP 0
|
||||
#define M68KSPECIAL_SR 1
|
||||
|
||||
#define USE_NATIVE_READ 0
|
||||
#define USE_NATIVE_WRITE 0
|
||||
|
||||
namespace Debugger
|
||||
{
|
||||
class C68KDebug;
|
||||
|
||||
static C68KDebug *debug = NULL;
|
||||
|
||||
typedef bool (*DebugPtr)(TURBO68K_INT32 pc, TURBO68K_INT32 opcode);
|
||||
typedef void (*IntAckPtr)(TURBO68K_UINT32 intVec);
|
||||
|
||||
static DebugPtr origDebugPtr = NULL;
|
||||
static IntAckPtr origIntAckPtr = NULL;
|
||||
|
||||
static TURBO68K_DATAREGION *origRead8Regions;
|
||||
static TURBO68K_DATAREGION *origRead16Regions;
|
||||
static TURBO68K_DATAREGION *origRead32Regions;
|
||||
static TURBO68K_DATAREGION *origWrite8Regions;
|
||||
static TURBO68K_DATAREGION *origWrite16Regions;
|
||||
static TURBO68K_DATAREGION *origWrite32Regions;
|
||||
|
||||
static TURBO68K_DATAREGION debugRead8Regions[] =
|
||||
{
|
||||
{ 0x000000, 0xFFFFFF, TURBO68K_NULL, TURBO68K_NULL },
|
||||
{ -1, -1, TURBO68K_NULL, TURBO68K_NULL }
|
||||
};
|
||||
static TURBO68K_DATAREGION debugRead16Regions[] =
|
||||
{
|
||||
{ 0x000000, 0xFFFFFF, TURBO68K_NULL, TURBO68K_NULL },
|
||||
{ -1, -1, TURBO68K_NULL, TURBO68K_NULL }
|
||||
};
|
||||
static TURBO68K_DATAREGION debugRead32Regions[] =
|
||||
{
|
||||
{ 0x000000, 0xFFFFFF, TURBO68K_NULL, TURBO68K_NULL },
|
||||
{ -1, -1, TURBO68K_NULL, TURBO68K_NULL }
|
||||
};
|
||||
static TURBO68K_DATAREGION debugWrite8Regions[] =
|
||||
{
|
||||
{ 0x000000, 0xFFFFFF, TURBO68K_NULL, TURBO68K_NULL },
|
||||
{ -1, -1, TURBO68K_NULL, TURBO68K_NULL }
|
||||
};
|
||||
static TURBO68K_DATAREGION debugWrite16Regions[] =
|
||||
{
|
||||
{ 0x000000, 0xFFFFFF, TURBO68K_NULL, TURBO68K_NULL },
|
||||
{ -1, -1, TURBO68K_NULL, TURBO68K_NULL }
|
||||
};
|
||||
static TURBO68K_DATAREGION debugWrite32Regions[] =
|
||||
{
|
||||
{ 0x000000, 0xFFFFFF, TURBO68K_NULL, TURBO68K_NULL },
|
||||
{ -1, -1, TURBO68K_NULL, TURBO68K_NULL }
|
||||
};
|
||||
|
||||
static UINT32 GetSpecialReg(CCPUDebug *cpu, unsigned id);
|
||||
static bool SetSpecialReg(CCPUDebug *cpu, unsigned id, UINT32 data);
|
||||
static UINT32 GetDataReg(CCPUDebug *cpu, unsigned id);
|
||||
static bool SetDataReg(CCPUDebug *cpu, unsigned id, UINT32 data) ;
|
||||
static UINT32 GetAddressReg(CCPUDebug *cpu, unsigned id);
|
||||
static bool SetAddressReg(CCPUDebug *cpu, unsigned id, UINT32 data);
|
||||
|
||||
static TURBO68K_UINT8 ReadByteDebug(TURBO68K_UINT32 addr);
|
||||
static TURBO68K_UINT16 ReadWordDebug(TURBO68K_UINT32 addr);
|
||||
static TURBO68K_UINT32 ReadLongDebug(TURBO68K_UINT32 addr);
|
||||
static void WriteByteDebug(TURBO68K_UINT32 addr, TURBO68K_UINT8 data);
|
||||
static void WriteWordDebug(TURBO68K_UINT32 addr, TURBO68K_UINT16 data);
|
||||
static void WriteLongDebug(TURBO68K_UINT32 addr, TURBO68K_UINT32 data);
|
||||
|
||||
static TURBO68K_UINT8 ReadByteDirect(TURBO68K_UINT32 addr);
|
||||
static TURBO68K_UINT16 ReadWordDirect(TURBO68K_UINT32 addr);
|
||||
static TURBO68K_UINT32 ReadLongDirect(TURBO68K_UINT32 addr);
|
||||
static void WriteByteDirect(TURBO68K_UINT32 addr, TURBO68K_UINT8 data);
|
||||
static void WriteWordDirect(TURBO68K_UINT32 addr, TURBO68K_UINT16 data);
|
||||
static void WriteLongDirect(TURBO68K_UINT32 addr, TURBO68K_UINT32 data);
|
||||
|
||||
/*
|
||||
* CCPUDebug implementation for the Turbo68K Motorola 68000 emulator.
|
||||
*/
|
||||
class C68KDebug : public CCPUDebug
|
||||
{
|
||||
private:
|
||||
char m_drNames[8][3];
|
||||
char m_arNames[8][3];
|
||||
|
||||
char m_mSlotStr[32][20];
|
||||
char m_sSlotStr[32][20];
|
||||
char m_regStr[16][12];
|
||||
|
||||
UINT32 m_resetAddr;
|
||||
|
||||
bool FormatAddrMode(UINT32 addr, UINT32 opcode, int &offset, UINT8 addrMode, char sizeC, char *dest);
|
||||
|
||||
public:
|
||||
C68KDebug();
|
||||
|
||||
virtual ~C68KDebug();
|
||||
|
||||
// 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);
|
||||
|
||||
int Disassemble(UINT32 addr, char *mnemonic, char *operands);
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
//
|
||||
// Inlined functions
|
||||
//
|
||||
|
||||
typedef TURBO68K_UINT8 (*ReadByteFPtr)(TURBO68K_UINT32);
|
||||
typedef TURBO68K_UINT16 (*ReadWordFPtr)(TURBO68K_UINT32);
|
||||
typedef TURBO68K_UINT32 (*ReadLongFPtr)(TURBO68K_UINT32);
|
||||
typedef void (*WriteByteFPtr)(TURBO68K_UINT32, TURBO68K_UINT8);
|
||||
typedef void (*WriteWordFPtr)(TURBO68K_UINT32, TURBO68K_UINT16);
|
||||
typedef void (*WriteLongFPtr)(TURBO68K_UINT32, TURBO68K_UINT32);
|
||||
|
||||
inline TURBO68K_UINT8 ReadByteDirect(TURBO68K_UINT32 addr)
|
||||
{
|
||||
#if USE_NATIVE_READ
|
||||
Turbo68KSetReadByte(origRead8Regions, TURBO68K_NULL);
|
||||
TURBO68K_UINT8 data = Turbo68KReadByte(addr);
|
||||
Turbo68KSetReadByte(debugRead8Regions, TURBO68K_NULL);
|
||||
return data;
|
||||
#else
|
||||
for (TURBO68K_DATAREGION *region = origRead8Regions; region->ptr != TURBO68K_NULL || region->handler != TURBO68K_NULL; region++)
|
||||
{
|
||||
if (region->base <= addr && addr <= region->limit)
|
||||
{
|
||||
if (region->ptr != TURBO68K_NULL)
|
||||
{
|
||||
// Turbo68K requires native memory to be byte swapped, so must reverse this when reading bytes
|
||||
TURBO68K_UINT8 *dataP = (TURBO68K_UINT8*)(region->ptr + (addr^1));
|
||||
return *dataP;
|
||||
}
|
||||
else
|
||||
{
|
||||
ReadByteFPtr fPtr = (ReadByteFPtr)region->handler;
|
||||
return fPtr(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline TURBO68K_UINT16 ReadWordDirect(TURBO68K_UINT32 addr)
|
||||
{
|
||||
#if USE_NATIVE_READ
|
||||
Turbo68KSetReadWord(origRead16Regions, TURBO68K_NULL);
|
||||
TURBO68K_UINT16 data = Turbo68KReadWord(addr);
|
||||
Turbo68KSetReadWord(debugRead16Regions, TURBO68K_NULL);
|
||||
return data;
|
||||
#else
|
||||
for (TURBO68K_DATAREGION *region = origRead16Regions; region->ptr != TURBO68K_NULL || region->handler != TURBO68K_NULL; region++)
|
||||
{
|
||||
if (region->base <= addr && addr <= region->limit)
|
||||
{
|
||||
if (region->ptr != TURBO68K_NULL)
|
||||
{
|
||||
// Turbo68K requires native memory to be byte swapped, so must reverse this when reading bytes
|
||||
TURBO68K_UINT16 *dataP = (TURBO68K_UINT16*)(region->ptr + addr);
|
||||
return *dataP;
|
||||
}
|
||||
else
|
||||
{
|
||||
ReadWordFPtr fPtr = (ReadWordFPtr)region->handler;
|
||||
return fPtr(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline TURBO68K_UINT32 ReadLongDirect(TURBO68K_UINT32 addr)
|
||||
{
|
||||
#if USE_NATIVE_READ
|
||||
Turbo68KSetReadLong(origRead32Regions, TURBO68K_NULL);
|
||||
TURBO68K_UINT32 data = Turbo68KReadLong(addr);
|
||||
Turbo68KSetReadLong(debugRead32Regions, TURBO68K_NULL);
|
||||
return data;
|
||||
#else
|
||||
for (TURBO68K_DATAREGION *region = origRead32Regions; region->ptr != TURBO68K_NULL || region->handler != TURBO68K_NULL; region++)
|
||||
{
|
||||
if (region->base <= addr && addr <= region->limit)
|
||||
{
|
||||
if (region->ptr != TURBO68K_NULL)
|
||||
{
|
||||
// Turbo68K requires native memory to be byte swapped, so must reverse this when reading bytes
|
||||
TURBO68K_UINT16 *dataP = (TURBO68K_UINT16*)(region->ptr + addr);
|
||||
return (TURBO68K_UINT32)dataP[1] | ((TURBO68K_UINT32)dataP[0])<<16;
|
||||
}
|
||||
else
|
||||
{
|
||||
ReadLongFPtr fPtr = (ReadLongFPtr)region->handler;
|
||||
return fPtr(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void WriteByteDirect(TURBO68K_UINT32 addr, TURBO68K_UINT8 data)
|
||||
{
|
||||
#if USE_NATIVE_WRITE
|
||||
Turbo68KSetWriteByte(origWrite8Regions, TURBO68K_NULL);
|
||||
Turbo68KWriteByte(addr, data);
|
||||
Turbo68KSetWriteByte(debugWrite8Regions, TURBO68K_NULL);
|
||||
#else
|
||||
for (TURBO68K_DATAREGION *region = origWrite8Regions; region->ptr != TURBO68K_NULL || region->handler != TURBO68K_NULL; region++)
|
||||
{
|
||||
if (region->base <= addr && addr <= region->limit)
|
||||
{
|
||||
if (region->ptr != TURBO68K_NULL)
|
||||
{
|
||||
// Turbo68K requires native memory to be byte swapped, so must reverse this when writing bytes
|
||||
TURBO68K_UINT8 *dataP = (TURBO68K_UINT8*)(region->ptr + (addr^1));
|
||||
*dataP = data;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteByteFPtr fPtr = (WriteByteFPtr)region->handler;
|
||||
fPtr(addr, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void WriteWordDirect(TURBO68K_UINT32 addr, TURBO68K_UINT16 data)
|
||||
{
|
||||
#if USE_NATIVE_WRITE
|
||||
Turbo68KSetWriteWord(origWrite16Regions, TURBO68K_NULL);
|
||||
Turbo68KWriteWord(addr, data);
|
||||
Turbo68KSetWriteWord(debugWrite16Regions, TURBO68K_NULL);
|
||||
#else
|
||||
for (TURBO68K_DATAREGION *region = origWrite16Regions; region->ptr != TURBO68K_NULL || region->handler != TURBO68K_NULL; region++)
|
||||
{
|
||||
if (region->base <= addr && addr <= region->limit)
|
||||
{
|
||||
if (region->ptr != TURBO68K_NULL)
|
||||
{
|
||||
// Turbo68K requires native memory to be byte swapped, so must reverse this when writing bytes
|
||||
TURBO68K_UINT16 *dataP = (TURBO68K_UINT16*)(region->ptr + addr);
|
||||
*dataP = data;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteWordFPtr fPtr = (WriteWordFPtr)region->handler;
|
||||
fPtr(addr, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void WriteLongDirect(TURBO68K_UINT32 addr, TURBO68K_UINT32 data)
|
||||
{
|
||||
#if USE_NATIVE_WRITE
|
||||
Turbo68KSetWriteLong(origWrite32Regions, TURBO68K_NULL);
|
||||
Turbo68KWriteLong(addr, data);
|
||||
Turbo68KSetWriteLong(debugWrite32Regions, TURBO68K_NULL);
|
||||
#else
|
||||
for (TURBO68K_DATAREGION *region = origWrite32Regions; region->ptr != TURBO68K_NULL || region->handler != TURBO68K_NULL; region++)
|
||||
{
|
||||
if (region->base <= addr && addr <= region->limit)
|
||||
{
|
||||
if (region->ptr != TURBO68K_NULL)
|
||||
{
|
||||
// Turbo68K requires native memory to be byte swapped, so must reverse this when writing bytes
|
||||
TURBO68K_UINT16 *dataP = (TURBO68K_UINT16*)(region->ptr + addr);
|
||||
dataP[0] = data>>16;
|
||||
dataP[1] = data&0xFFFF;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLongFPtr fPtr = (WriteLongFPtr)region->handler;
|
||||
fPtr(addr, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif // INCLUDED_68KDEBUG_H
|
||||
#endif // SUPERMODEL_SOUND
|
||||
#endif // SUPERMODEL_DEBUGGER
|
586
Src/Debugger/CPU/PPCDebug.cpp
Normal file
586
Src/Debugger/CPU/PPCDebug.cpp
Normal file
|
@ -0,0 +1,586 @@
|
|||
#ifdef SUPERMODEL_DEBUGGER
|
||||
|
||||
#include "PPCDebug.h"
|
||||
#include "CPU/PowerPC/ppc.h"
|
||||
#include "CPU/PowerPC/PPCDisasm.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#define M_AA 0x00000002
|
||||
#define M_LK 0x00000001
|
||||
#define M_BO 0x03E00000
|
||||
#define M_BD 0x0000FFFC
|
||||
#define M_LI 0x03FFFFFC
|
||||
|
||||
#define MSR_IP 0x00000040
|
||||
|
||||
namespace Debugger
|
||||
{
|
||||
UINT32 GetSpecialReg(CCPUDebug *cpu, unsigned id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case PPCSPECIAL_LR: return ::ppc_get_lr();
|
||||
case PPCSPECIAL_FPSCR: return 0; // TODO
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool SetSpecialReg(CCPUDebug *cpu, unsigned id, UINT32 data)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case PPCSPECIAL_LR: /* TODO */ return false;
|
||||
case PPCSPECIAL_FPSCR: /* TODO */ return false;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
UINT8 GetCR(CCPUDebug *cpu, unsigned id)
|
||||
{
|
||||
return ::ppc_get_cr(id);
|
||||
}
|
||||
|
||||
bool SetCR(CCPUDebug *cpu, unsigned id, UINT8 data)
|
||||
{
|
||||
::ppc_set_cr(id, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
UINT32 GetSPR(CCPUDebug *cpu, unsigned id)
|
||||
{
|
||||
return ::ppc_read_spr(id);
|
||||
}
|
||||
|
||||
bool SetSPR(CCPUDebug *cpu, unsigned id, UINT32 data)
|
||||
{
|
||||
::ppc_write_spr(id, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
UINT32 GetGPR(CCPUDebug *cpu, unsigned id)
|
||||
{
|
||||
return ::ppc_get_gpr(id);
|
||||
}
|
||||
|
||||
bool SetGPR(CCPUDebug *cpu, unsigned id, UINT32 data)
|
||||
{
|
||||
::ppc_set_gpr(id, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
double GetFPR(CCPUDebug *cpu, unsigned id)
|
||||
{
|
||||
return ::ppc_get_fpr(id);
|
||||
}
|
||||
|
||||
bool SetFPR(CCPUDebug *cpu, unsigned id, double data)
|
||||
{
|
||||
::ppc_set_fpr(id, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char *srGroup = "Special Registers";
|
||||
static const char *crGroup = "Condition Registers";
|
||||
static const char *grGroup = "GPR Registers";
|
||||
static const char *frGroup = "FPR Registers";
|
||||
static const char *giGroup = "Game Inputs";
|
||||
static const char *sbGroup = "Sound Board";
|
||||
|
||||
CPPCDebug::CPPCDebug() : CCPUDebug("PPC", 4, 4, true, 32, 7), m_irqState(0)
|
||||
{
|
||||
// PC & Link registers
|
||||
AddPCRegister ("pc", srGroup);
|
||||
AddAddrRegister("lr", srGroup, PPCSPECIAL_LR, GetSpecialReg, SetSpecialReg);
|
||||
|
||||
// SPR registers
|
||||
AddInt32Register ("ctr", srGroup, SPR_LR, GetSPR, SetSPR);
|
||||
AddStatus32Register("xer", srGroup, SPR_XER, "SOC", GetSPR, SetSPR);
|
||||
AddInt32Register ("srr0", srGroup, SPR_SRR0, GetSPR, SetSPR);
|
||||
AddInt32Register ("srr1", srGroup, SPR_SRR1, GetSPR, SetSPR);
|
||||
// etc...
|
||||
|
||||
// Condition registers
|
||||
for (unsigned id = 0; id < 8; id++)
|
||||
{
|
||||
sprintf(m_crNames[id], "cr%u", id);
|
||||
AddStatus8Register(m_crNames[id], crGroup, id, "O=><", GetCR, SetCR);
|
||||
}
|
||||
//AddStatus16Register("fpscr", "Condition Registers", PPCSPECIAL_FPSCR, "FEVOUZX789ABCRI 0123", GetSpecial, SetSpecial);
|
||||
|
||||
// GPR registers
|
||||
for (unsigned id = 0; id < 32; id++)
|
||||
{
|
||||
sprintf(m_gprNames[id], "r%u", id);
|
||||
AddInt32Register(m_gprNames[id], grGroup, id, GetGPR, SetGPR);
|
||||
}
|
||||
|
||||
// FPR registers
|
||||
for (unsigned id = 0; id < 32; id++)
|
||||
{
|
||||
sprintf(m_fprNames[id], "f%u", id);
|
||||
AddFPointRegister(m_fprNames[id], frGroup, id, GetFPR, SetFPR);
|
||||
}
|
||||
|
||||
// Exceptions
|
||||
AddException("IRQ", EXCEPTION_IRQ, "External Interrupt");
|
||||
AddException("DEC", EXCEPTION_DECREMENTER, "Decrement Overflow");
|
||||
AddException("TRAP", EXCEPTION_TRAP, "Program Exception/Trap");
|
||||
AddException("SYSCALL", EXCEPTION_SYSTEM_CALL, "System Call");
|
||||
AddException("SMI", EXCEPTION_SMI, "SMI");
|
||||
AddException("DSI", EXCEPTION_DSI, "DSI");
|
||||
AddException("ISI", EXCEPTION_ISI, "ISI");
|
||||
|
||||
// TODO - following Model3-specific stuff should be moved to SupermodelDebugger
|
||||
|
||||
// Interrupts
|
||||
AddInterrupt("VD0", 0, "Unknown video-related");
|
||||
AddInterrupt("VBL", 1, "VBlank start");
|
||||
AddInterrupt("VD2", 2, "Unknown video-related");
|
||||
AddInterrupt("VD3", 3, "Unknown video-related");
|
||||
AddInterrupt("NET", 4, "Network");
|
||||
AddInterrupt("UN5", 5, "Unknown");
|
||||
AddInterrupt("SND", 6, "SCSP (sound)");
|
||||
AddInterrupt("UN7", 7, "Unknown");
|
||||
|
||||
// Memory regions
|
||||
AddRegion(0x00000000, 0x007FFFFF, true, false, "RAM");
|
||||
AddRegion(0x84000000, 0x8400003F, false, false, "Real3D Status Registers");
|
||||
AddRegion(0x88000000, 0x88000007, false, false, "Real3D Command Port");
|
||||
AddRegion(0x8C000000, 0x8C3FFFFF, false, false, "Real3D Culling RAM (Low)");
|
||||
AddRegion(0x8E000000, 0x8E0FFFFF, false, false, "Real3D Culling RAM (High)");
|
||||
AddRegion(0x90000000, 0x9000000B, false, false, "Real3D VROM Texture Port");
|
||||
AddRegion(0x94000000, 0x940FFFFF, false, false, "Real3D Texture FIFO");
|
||||
AddRegion(0x98000000, 0x980FFFFF, false, false, "Real3D Polygon RAM");
|
||||
AddRegion(0xC0000000, 0xC00000FF, false, false, "SCSI (Step 1.x)");
|
||||
AddRegion(0xC1000000, 0xC10000FF, false, false, "SCSI (Step 1.x) (Lost World expects it here)");
|
||||
AddRegion(0xC2000000, 0xC20000FF, false, false, "Real3D DMA (Step 2.x)");
|
||||
AddRegion(0xF0040000, 0xF004003F, false, false, "Input (Controls) Registers");
|
||||
AddRegion(0xF0080000, 0xF0080007, false, false, "Sound Board Registers");
|
||||
AddRegion(0xF00C0000, 0xF00DFFFF, false, false, "Backup RAM");
|
||||
AddRegion(0xF0100000, 0xF010003F, false, false, "System Registers");
|
||||
AddRegion(0xF0140000, 0xF014003F, false, false, "Real, 0xTime Clock");
|
||||
AddRegion(0xF0180000, 0xF019FFFF, false, false, "Security Board RAM");
|
||||
AddRegion(0xF01A0000, 0xF01A003F, false, false, "Security Board Registers");
|
||||
AddRegion(0xF0800CF8, 0xF0800CFF, false, false, "MPC105 CONFIG_ADDR (Step 1.x)");
|
||||
AddRegion(0xF0C00CF8, 0xF0C00CFF, false, false, "MPC105 CONFIG_DATA (Step 1.x)");
|
||||
AddRegion(0xF1000000, 0xF10F7FFF, false, false, "Tile Generator Pattern Table");
|
||||
AddRegion(0xF10F8000, 0xF10FFFFF, false, false, "Tile Generator Name Table");
|
||||
AddRegion(0xF1100000, 0xF111FFFF, false, false, "Tile Generator Palette");
|
||||
AddRegion(0xF1180000, 0xF11800FF, false, false, "Tile Generator Registers");
|
||||
AddRegion(0xF8FFF000, 0xF8FFF0FF, false, false, "MPC105 (Step 1.x) or MPC106 (Step 2.x) Registers");
|
||||
AddRegion(0xF9000000, 0xF90000FF, false, false, "NCR 53C810 Registers (Step 1.x?)");
|
||||
AddRegion(0xFE040000, 0xFE04003F, false, false, "Mirrored Input Registers");
|
||||
AddRegion(0xFEC00000, 0xFEDFFFFF, false, false, "MPC106 CONFIG_ADDR (Step 2.x)");
|
||||
AddRegion(0xFEE00000, 0xFEFFFFFF, false, false, "MPC106 CONFIG_DATA (Step 2.x)");
|
||||
AddRegion(0xFF000000, 0xFF7FFFFF, true, true, "Banked CROM (CROMxx)");
|
||||
AddRegion(0xFF800000, 0xFFFFFFFF, true, true, "Fixed CROM");
|
||||
|
||||
// Memory-mapped IO
|
||||
AddMappedIO(0xF0040000, 1, "Input Bank Select", giGroup);
|
||||
AddMappedIO(0xF0040004, 1, "Current Input Bank", giGroup);
|
||||
AddMappedIO(0xF0040008, 1, "Game Specific Inputs 1", giGroup);
|
||||
AddMappedIO(0xF004000C, 1, "Game Specific Inputs 2", giGroup);
|
||||
AddMappedIO(0xF0040010, 1, "Drive Board", giGroup);
|
||||
AddMappedIO(0xF0040014, 1, "LED Outputs?", giGroup);
|
||||
AddMappedIO(0xF0040018, 1, "Unknown?", giGroup);
|
||||
AddMappedIO(0xF0040024, 1, "Serial FIFO 1 Control", giGroup);
|
||||
AddMappedIO(0xF0040028, 1, "Serial FIFO 2 Control", giGroup);
|
||||
AddMappedIO(0xF004002C, 1, "Serial FIFO 1", giGroup);
|
||||
AddMappedIO(0xF0040030, 1, "Serial FIFO 2", giGroup);
|
||||
AddMappedIO(0xF0040034, 1, "Serial FIFO Flags", giGroup);
|
||||
AddMappedIO(0xF004003C, 1, "ADC", giGroup);
|
||||
|
||||
AddMappedIO(0xF0080000, 1, "MIDI", sbGroup);
|
||||
AddMappedIO(0xF0080004, 1, "Control", sbGroup);
|
||||
}
|
||||
|
||||
CPPCDebug::~CPPCDebug()
|
||||
{
|
||||
DetachFromCPU();
|
||||
}
|
||||
|
||||
void CPPCDebug::AttachToCPU()
|
||||
{
|
||||
::ppc_attach_debugger(this);
|
||||
}
|
||||
|
||||
::CBus *CPPCDebug::AttachBus(::CBus *bus)
|
||||
{
|
||||
m_bus = bus;
|
||||
return this;
|
||||
}
|
||||
|
||||
void CPPCDebug::DetachFromCPU()
|
||||
{
|
||||
::ppc_detach_debugger();
|
||||
}
|
||||
|
||||
::CBus *CPPCDebug::DetachBus()
|
||||
{
|
||||
::CBus *bus = m_bus;
|
||||
m_bus = NULL;
|
||||
return bus;
|
||||
}
|
||||
|
||||
UINT32 CPPCDebug::GetResetAddr()
|
||||
{
|
||||
// Reset address appears to be hardcoded to 0xFFF00100
|
||||
return 0xFFF00100;
|
||||
}
|
||||
|
||||
bool CPPCDebug::UpdatePC(UINT32 pc)
|
||||
{
|
||||
::ppc_set_pc(pc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPPCDebug::ForceException(CException *ex)
|
||||
{
|
||||
// TODO - no way to force exceptions
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CPPCDebug::ForceInterrupt(CInterrupt *in)
|
||||
{
|
||||
if (in->code > 7)
|
||||
return false;
|
||||
UINT8 irqState = m_bus->Read8(0xF0100018) | 1<<in->code;
|
||||
m_bus->Write8(0xF0100018, irqState);
|
||||
::ppc_set_irq_line(1); // TODO - what is irqline arg for? not actually used?
|
||||
return true;
|
||||
}
|
||||
|
||||
UINT64 CPPCDebug::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);
|
||||
case 8: return m_bus->Read64(addr);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool CPPCDebug::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: m_bus->Write64(addr, data); return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CPPCDebug::CheckException(UINT16 exCode)
|
||||
{
|
||||
CCPUDebug::CheckException(exCode);
|
||||
|
||||
if (exCode == EXCEPTION_IRQ)
|
||||
{
|
||||
UINT8 irqState = m_bus->Read8(0xF0100018); // TODO - replace this with function pointer
|
||||
|
||||
UINT8 newIRQs = (irqState^m_irqState)&irqState;
|
||||
for (int intCode = 0; newIRQs && intCode < 8; intCode++)
|
||||
{
|
||||
if (newIRQs&0x01)
|
||||
CheckInterrupt(intCode);
|
||||
newIRQs >>= 1;
|
||||
}
|
||||
m_irqState = irqState;
|
||||
}
|
||||
}
|
||||
|
||||
int CPPCDebug::Disassemble(UINT32 addr, char *mnemonic, char *operands)
|
||||
{
|
||||
char opStr[255];
|
||||
char valStr[40];
|
||||
UINT32 opcode = m_bus->Read32(addr);
|
||||
operands[0] = '\0';
|
||||
if (!::DisassemblePowerPC(opcode, addr, mnemonic, opStr, TRUE))
|
||||
{
|
||||
char *o = opStr;
|
||||
char *s = strstr(o, "0x");
|
||||
while (s)
|
||||
{
|
||||
strncpy(operands, o, s - o);
|
||||
operands[s - o] = '\0';
|
||||
s += 2;
|
||||
|
||||
char *p = s;
|
||||
unsigned len = 0;
|
||||
UINT64 data = 0;
|
||||
while (p)
|
||||
{
|
||||
char c = toupper(*(p++));
|
||||
if (c >= '0' && c <= '9')
|
||||
{
|
||||
data <<= 4;
|
||||
data += (UINT64)(c - '0');
|
||||
}
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
{
|
||||
data <<= 4;
|
||||
data += (UINT64)(10 + c - 'A');
|
||||
}
|
||||
else
|
||||
break;
|
||||
len++;
|
||||
}
|
||||
|
||||
unsigned dataSize = (p - s) / 2;
|
||||
if (dataSize == (unsigned)(memBusWidth / 8))
|
||||
{
|
||||
EOpFlags opFlags = GetOpFlags(addr, opcode);
|
||||
FormatJumpAddress(valStr, (UINT32)data, opFlags);
|
||||
}
|
||||
else
|
||||
FormatData(valStr, dataSize, data);
|
||||
|
||||
strcat(operands, valStr);
|
||||
operands += strlen(operands);
|
||||
o = p - 1;
|
||||
s = strstr(o, "0x");
|
||||
}
|
||||
strcat(operands, o);
|
||||
return 4;
|
||||
}
|
||||
else
|
||||
|
||||
return -4;
|
||||
}
|
||||
|
||||
EOpFlags CPPCDebug::GetOpFlags(UINT32 addr, UINT32 opcode)
|
||||
{
|
||||
EOpFlags opFlags;
|
||||
|
||||
UINT32 op = opcode>>26;
|
||||
if (op == 0x10)
|
||||
{
|
||||
// Instruction is branch conditional: bc, bca, bcl or bcla
|
||||
UINT32 bo = (opcode&M_BO)>>21;
|
||||
if (opcode&M_LK)
|
||||
{
|
||||
if (opcode&M_AA)
|
||||
opFlags = JumpSub; // bcla
|
||||
else if (bo&0x04)
|
||||
opFlags = (EOpFlags)(JumpSub | Relative); // bcl without counter
|
||||
else
|
||||
opFlags = (EOpFlags)(JumpSub | Relative); // bcl with counter
|
||||
}
|
||||
else
|
||||
{
|
||||
if (opcode&M_AA)
|
||||
opFlags = JumpSimple; // bca
|
||||
else if (bo&0x04)
|
||||
opFlags = (EOpFlags)(JumpSimple | Relative); // bc without counter
|
||||
else
|
||||
opFlags = (EOpFlags)(JumpLoop | Relative); // bc with counter
|
||||
}
|
||||
// Check BO is not just branch always
|
||||
return ((bo&0x14) == 0x14 ? opFlags : (EOpFlags)(opFlags | Conditional));
|
||||
}
|
||||
else if (op == 0x12)
|
||||
{
|
||||
// Instruction is branch: b, ba, bl or bla
|
||||
if (opcode&M_LK)
|
||||
{
|
||||
if (opcode&M_AA)
|
||||
return JumpSub; // bla
|
||||
else
|
||||
return (EOpFlags)(JumpSub | Relative); // bl
|
||||
}
|
||||
else
|
||||
{
|
||||
if (opcode&M_AA)
|
||||
return JumpSimple; // ba
|
||||
else
|
||||
return (EOpFlags)(JumpSimple | Relative); // b
|
||||
}
|
||||
}
|
||||
else if (op == 0x13)
|
||||
{
|
||||
UINT32 exOp = (opcode>>1)&0x3ff;
|
||||
UINT32 bo = (opcode&M_BO)>>21;
|
||||
if (exOp == 0x0210)
|
||||
{
|
||||
// Instruction is branch conditional to count register: bcctr or bcctrl
|
||||
if (opcode&M_LK)
|
||||
opFlags = (EOpFlags)(JumpSub | Relative); // bcctrl
|
||||
else if (bo&0x04)
|
||||
opFlags = (EOpFlags)(JumpSimple | Relative); // bcctr without counter
|
||||
else
|
||||
opFlags = (EOpFlags)(JumpLoop | Relative); // bcctr with counter
|
||||
// Check BO is not just branch always
|
||||
return ((bo&0x14) == 0x14 ? opFlags : (EOpFlags)(opFlags | Conditional));
|
||||
}
|
||||
else if (exOp == 0x0010)
|
||||
{
|
||||
// Instruction is branch conditional to link register: bclr or bclrl
|
||||
if (opcode&M_LK)
|
||||
opFlags = (EOpFlags)(JumpSub | ReturnSub); // bclrl
|
||||
else
|
||||
opFlags = ReturnSub; // bclr
|
||||
// Check BO is not just branch always
|
||||
return ((bo&0x14) == 0x14 ? opFlags : (EOpFlags)(opFlags | Conditional));
|
||||
}
|
||||
else if (exOp == 0x0032)
|
||||
{
|
||||
// Instruction is return from interrupt: rfi
|
||||
return ReturnEx;
|
||||
}
|
||||
// TODO - traps etc
|
||||
}
|
||||
return NormalOp;
|
||||
}
|
||||
|
||||
bool CPPCDebug::GetJumpAddr(UINT32 addr, UINT32 opcode, UINT32 &jumpAddr)
|
||||
{
|
||||
// Check instruction is one of following branches: b, ba, bl, bla, bc, bca, bcl or bcla
|
||||
UINT32 disp;
|
||||
UINT32 op = opcode>>26;
|
||||
if (op == 0x10)
|
||||
{
|
||||
// Instruction is b, ba, bl or bla, so calculate branch displacement
|
||||
disp = ((opcode&M_BD)>>2) * 4;
|
||||
if (disp & 0x00008000)
|
||||
disp |= 0xFFFF0000; // Sign extended
|
||||
if (opcode&M_AA)
|
||||
jumpAddr = disp; // ba or bla
|
||||
else
|
||||
jumpAddr = addr + disp; // b or bl
|
||||
return true;
|
||||
}
|
||||
else if (op == 0x12)
|
||||
{
|
||||
// Instruction is bc, bca, bcl or bcla, so calculate branch displacement
|
||||
disp = ((opcode&M_LI) >> 2) * 4;
|
||||
if (disp & 0x02000000)
|
||||
disp |= 0xFC000000; // Sign extended
|
||||
if (opcode&M_AA)
|
||||
jumpAddr = disp; // bca or bcla
|
||||
else
|
||||
jumpAddr = addr + disp; // bc or bcl
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CPPCDebug::GetJumpRetAddr(UINT32 addr, UINT32 opcode, UINT32 &retAddr)
|
||||
{
|
||||
UINT32 op = opcode>>26;
|
||||
if ((op == 0x10 || op == 0x12) && (opcode&M_LK))
|
||||
{
|
||||
// Instruction is bl, bla, bcl or bcla (TODO - add bclrl?)
|
||||
retAddr = addr + 4;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CPPCDebug::GetReturnAddr(UINT32 addr, UINT32 opcode, UINT32 &retAddr)
|
||||
{
|
||||
// Check instruction is one of following: bclr, bclrl or rfi
|
||||
if ((opcode>>26) != 0x13)
|
||||
return false;
|
||||
|
||||
UINT32 exOp = (opcode>>1)&0x3ff;
|
||||
if (exOp == 0x0010)
|
||||
{
|
||||
// For bclr and blclr, return address is in link register
|
||||
retAddr = ::ppc_get_lr();
|
||||
return true;
|
||||
}
|
||||
else if (exOp == 0x0032)
|
||||
{
|
||||
// For rfi, return address is in SRR0
|
||||
retAddr = ::ppc_read_spr(SPR_SRR0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CPPCDebug::GetHandlerAddr(CException *ex, UINT32 &handlerAddr)
|
||||
{
|
||||
UINT32 msr = ::ppc_read_msr();
|
||||
UINT32 base = (msr&MSR_IP ? 0xFFF00000 : 0x00000000);
|
||||
switch (ex->code)
|
||||
{
|
||||
case EXCEPTION_DSI: handlerAddr = base + 0x0300; return true;
|
||||
case EXCEPTION_ISI: handlerAddr = base + 0x0400; return true;
|
||||
case EXCEPTION_IRQ: handlerAddr = base + 0x0500; return true;
|
||||
case EXCEPTION_TRAP: handlerAddr = base + 0x0700; return true;
|
||||
case EXCEPTION_DECREMENTER: handlerAddr = base + 0x0900; return true;
|
||||
case EXCEPTION_SYSTEM_CALL: handlerAddr = base + 0x0C00; return true;
|
||||
case EXCEPTION_SMI: handlerAddr = base + 0x1400; return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CPPCDebug::GetHandlerAddr(CInterrupt *in, UINT32 &handlerAddr)
|
||||
{
|
||||
UINT32 msr = ::ppc_read_msr();
|
||||
handlerAddr = (msr&MSR_IP ? 0xFFF00500 : 0x00000500);
|
||||
return true;
|
||||
}
|
||||
|
||||
// CBus methods
|
||||
|
||||
UINT8 CPPCDebug::Read8(UINT32 addr)
|
||||
{
|
||||
UINT8 data = m_bus->Read8(addr);
|
||||
CheckRead8(addr, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
UINT16 CPPCDebug::Read16(UINT32 addr)
|
||||
{
|
||||
UINT16 data = m_bus->Read16(addr);
|
||||
CheckRead16(addr, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
UINT32 CPPCDebug::Read32(UINT32 addr)
|
||||
{
|
||||
UINT32 data = m_bus->Read32(addr);
|
||||
CheckRead32(addr, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
UINT64 CPPCDebug::Read64(UINT32 addr)
|
||||
{
|
||||
UINT64 data = m_bus->Read64(addr);
|
||||
CheckRead64(addr, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void CPPCDebug::Write8(UINT32 addr, UINT8 data)
|
||||
{
|
||||
m_bus->Write8(addr, data);
|
||||
CheckWrite8(addr, data);
|
||||
}
|
||||
|
||||
void CPPCDebug::Write16(UINT32 addr, UINT16 data)
|
||||
{
|
||||
m_bus->Write16(addr, data);
|
||||
CheckWrite16(addr, data);
|
||||
}
|
||||
|
||||
void CPPCDebug::Write32(UINT32 addr, UINT32 data)
|
||||
{
|
||||
m_bus->Write32(addr, data);
|
||||
CheckWrite32(addr, data);
|
||||
}
|
||||
|
||||
void CPPCDebug::Write64(UINT32 addr, UINT64 data)
|
||||
{
|
||||
m_bus->Write64(addr, data);
|
||||
CheckWrite64(addr, data);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SUPERMODEL_DEBUGGER
|
101
Src/Debugger/CPU/PPCDebug.h
Normal file
101
Src/Debugger/CPU/PPCDebug.h
Normal file
|
@ -0,0 +1,101 @@
|
|||
#ifdef SUPERMODEL_DEBUGGER
|
||||
#ifndef INCLUDED_PPCDEBUG_H
|
||||
#define INCLUDED_PPCDEBUG_H
|
||||
|
||||
#include "Debugger/CPUDebug.h"
|
||||
#include "Model3/Bus.h"
|
||||
#include "Types.h"
|
||||
|
||||
#define PPCSPECIAL_LR 0
|
||||
#define PPCSPECIAL_FPSCR 1
|
||||
|
||||
namespace Debugger
|
||||
{
|
||||
static UINT32 GetSpecialReg(CCPUDebug *cpu, unsigned id);
|
||||
static bool SetSpecialReg(CCPUDebug *cpu, unsigned id, UINT32 data);
|
||||
static UINT32 GetSPR(CCPUDebug *cpu, unsigned id);
|
||||
static bool SetSPR(CCPUDebug *cpu, unsigned id, UINT32 data);
|
||||
static UINT32 GetGPR(CCPUDebug *cpu, unsigned id);
|
||||
static bool SetGPR(CCPUDebug *cpu, unsigned id, UINT32 data);
|
||||
static double GetFPR(CCPUDebug *cpu, unsigned id);
|
||||
static bool SetFRP(CCPUDebug *cpu, unsigned id, double data);
|
||||
|
||||
/*
|
||||
* CCPUDebug implementation for the PowerPC PPC603 emulator.
|
||||
*/
|
||||
class CPPCDebug : public CCPUDebug, public ::CBus
|
||||
{
|
||||
private:
|
||||
char m_crNames[32][5];
|
||||
char m_gprNames[32][4];
|
||||
char m_fprNames[32][4];
|
||||
|
||||
::CBus *m_bus;
|
||||
|
||||
UINT8 m_irqState;
|
||||
|
||||
public:
|
||||
CPPCDebug();
|
||||
|
||||
virtual ~CPPCDebug();
|
||||
|
||||
// CCPUDebug methods
|
||||
|
||||
void AttachToCPU();
|
||||
|
||||
::CBus *AttachBus(::CBus *bus);
|
||||
|
||||
void DetachFromCPU();
|
||||
|
||||
::CBus *DetachBus();
|
||||
|
||||
void CheckException(UINT16 exCode);
|
||||
|
||||
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);
|
||||
|
||||
int Disassemble(UINT32 addr, char *mnemonic, char *operands);
|
||||
|
||||
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);
|
||||
|
||||
UINT16 Read16(UINT32 addr);
|
||||
|
||||
UINT32 Read32(UINT32 addr);
|
||||
|
||||
UINT64 Read64(UINT32 addr);
|
||||
|
||||
void Write8(UINT32 addr, UINT8 data);
|
||||
|
||||
void Write16(UINT32 addr, UINT16 data);
|
||||
|
||||
void Write32(UINT32 addr, UINT32 data);
|
||||
|
||||
void Write64(UINT32 addr, UINT64 data);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // INCLUDED_PPCDEBUG_H
|
||||
#endif // SUPERMODEL_DEBUGGER
|
Loading…
Reference in a new issue