pureikyubu/src/gekkodebug.cpp

973 lines
34 KiB
C++

// Processor debug commands.
#include "pch.h"
namespace Debug
{
// Run processor until break or stop
static Json::Value* CmdRun(std::vector<std::string>& args)
{
Core->Run();
return nullptr;
}
// Stop processor execution
static Json::Value* CmdStop(std::vector<std::string>& args)
{
if (Core->IsRunning())
{
Core->Suspend();
}
return nullptr;
}
// r
// Get pointer to Gekko register.
static uint32_t* getreg(const char* name)
{
if (!_stricmp(name, "r0")) return &Core->regs.gpr[0];
else if (!_stricmp(name, "r1")) return &Core->regs.gpr[1];
else if (!_stricmp(name, "r2")) return &Core->regs.gpr[2];
else if (!_stricmp(name, "r3")) return &Core->regs.gpr[3];
else if (!_stricmp(name, "r4")) return &Core->regs.gpr[4];
else if (!_stricmp(name, "r5")) return &Core->regs.gpr[5];
else if (!_stricmp(name, "r6")) return &Core->regs.gpr[6];
else if (!_stricmp(name, "r7")) return &Core->regs.gpr[7];
else if (!_stricmp(name, "r8")) return &Core->regs.gpr[8];
else if (!_stricmp(name, "r9")) return &Core->regs.gpr[9];
else if (!_stricmp(name, "r10")) return &Core->regs.gpr[10];
else if (!_stricmp(name, "r11")) return &Core->regs.gpr[11];
else if (!_stricmp(name, "r12")) return &Core->regs.gpr[12];
else if (!_stricmp(name, "r13")) return &Core->regs.gpr[13];
else if (!_stricmp(name, "r14")) return &Core->regs.gpr[14];
else if (!_stricmp(name, "r15")) return &Core->regs.gpr[15];
else if (!_stricmp(name, "r16")) return &Core->regs.gpr[16];
else if (!_stricmp(name, "r17")) return &Core->regs.gpr[17];
else if (!_stricmp(name, "r18")) return &Core->regs.gpr[18];
else if (!_stricmp(name, "r19")) return &Core->regs.gpr[19];
else if (!_stricmp(name, "r20")) return &Core->regs.gpr[20];
else if (!_stricmp(name, "r21")) return &Core->regs.gpr[21];
else if (!_stricmp(name, "r22")) return &Core->regs.gpr[22];
else if (!_stricmp(name, "r23")) return &Core->regs.gpr[23];
else if (!_stricmp(name, "r24")) return &Core->regs.gpr[24];
else if (!_stricmp(name, "r25")) return &Core->regs.gpr[25];
else if (!_stricmp(name, "r26")) return &Core->regs.gpr[26];
else if (!_stricmp(name, "r27")) return &Core->regs.gpr[27];
else if (!_stricmp(name, "r28")) return &Core->regs.gpr[28];
else if (!_stricmp(name, "r29")) return &Core->regs.gpr[29];
else if (!_stricmp(name, "r30")) return &Core->regs.gpr[30];
else if (!_stricmp(name, "r31")) return &Core->regs.gpr[31];
else if (!_stricmp(name, "sp")) return &Core->regs.gpr[1];
else if (!_stricmp(name, "sd1")) return &Core->regs.gpr[13];
else if (!_stricmp(name, "sd2")) return &Core->regs.gpr[2];
else if (!_stricmp(name, "cr")) return &Core->regs.cr;
else if (!_stricmp(name, "fpscr")) return &Core->regs.fpscr;
else if (!_stricmp(name, "xer")) return &Core->regs.spr[(int)Gekko::SPR::XER];
else if (!_stricmp(name, "lr")) return &Core->regs.spr[(int)Gekko::SPR::LR];
else if (!_stricmp(name, "ctr")) return &Core->regs.spr[(int)Gekko::SPR::CTR];
else if (!_stricmp(name, "msr")) return &Core->regs.msr;
else if (!_stricmp(name, "sr0")) return &Core->regs.sr[0];
else if (!_stricmp(name, "sr1")) return &Core->regs.sr[1];
else if (!_stricmp(name, "sr2")) return &Core->regs.sr[2];
else if (!_stricmp(name, "sr3")) return &Core->regs.sr[3];
else if (!_stricmp(name, "sr4")) return &Core->regs.sr[4];
else if (!_stricmp(name, "sr5")) return &Core->regs.sr[5];
else if (!_stricmp(name, "sr6")) return &Core->regs.sr[6];
else if (!_stricmp(name, "sr7")) return &Core->regs.sr[7];
else if (!_stricmp(name, "sr8")) return &Core->regs.sr[8];
else if (!_stricmp(name, "sr9")) return &Core->regs.sr[9];
else if (!_stricmp(name, "sr10")) return &Core->regs.sr[10];
else if (!_stricmp(name, "sr11")) return &Core->regs.sr[11];
else if (!_stricmp(name, "sr12")) return &Core->regs.sr[12];
else if (!_stricmp(name, "sr13")) return &Core->regs.sr[13];
else if (!_stricmp(name, "sr14")) return &Core->regs.sr[14];
else if (!_stricmp(name, "sr15")) return &Core->regs.sr[15];
else if (!_stricmp(name, "ibat0u")) return &Core->regs.spr[(int)Gekko::SPR::IBAT0U];
else if (!_stricmp(name, "ibat1u")) return &Core->regs.spr[(int)Gekko::SPR::IBAT1U];
else if (!_stricmp(name, "ibat2u")) return &Core->regs.spr[(int)Gekko::SPR::IBAT2U];
else if (!_stricmp(name, "ibat3u")) return &Core->regs.spr[(int)Gekko::SPR::IBAT3U];
else if (!_stricmp(name, "ibat0l")) return &Core->regs.spr[(int)Gekko::SPR::IBAT0L];
else if (!_stricmp(name, "ibat1l")) return &Core->regs.spr[(int)Gekko::SPR::IBAT1L];
else if (!_stricmp(name, "ibat2l")) return &Core->regs.spr[(int)Gekko::SPR::IBAT2L];
else if (!_stricmp(name, "ibat3l")) return &Core->regs.spr[(int)Gekko::SPR::IBAT3L];
else if (!_stricmp(name, "dbat0u")) return &Core->regs.spr[(int)Gekko::SPR::DBAT0U];
else if (!_stricmp(name, "dbat1u")) return &Core->regs.spr[(int)Gekko::SPR::DBAT1U];
else if (!_stricmp(name, "dbat2u")) return &Core->regs.spr[(int)Gekko::SPR::DBAT2U];
else if (!_stricmp(name, "dbat3u")) return &Core->regs.spr[(int)Gekko::SPR::DBAT3U];
else if (!_stricmp(name, "dbat0l")) return &Core->regs.spr[(int)Gekko::SPR::DBAT0L];
else if (!_stricmp(name, "dbat1l")) return &Core->regs.spr[(int)Gekko::SPR::DBAT1L];
else if (!_stricmp(name, "dbat2l")) return &Core->regs.spr[(int)Gekko::SPR::DBAT2L];
else if (!_stricmp(name, "dbat3l")) return &Core->regs.spr[(int)Gekko::SPR::DBAT3L];
else if (!_stricmp(name, "sdr1")) return &Core->regs.spr[(int)Gekko::SPR::SDR1];
else if (!_stricmp(name, "sprg0")) return &Core->regs.spr[(int)Gekko::SPR::SPRG0];
else if (!_stricmp(name, "sprg1")) return &Core->regs.spr[(int)Gekko::SPR::SPRG1];
else if (!_stricmp(name, "sprg2")) return &Core->regs.spr[(int)Gekko::SPR::SPRG2];
else if (!_stricmp(name, "sprg3")) return &Core->regs.spr[(int)Gekko::SPR::SPRG3];
else if (!_stricmp(name, "dar")) return &Core->regs.spr[(int)Gekko::SPR::DAR];
else if (!_stricmp(name, "dsisr")) return &Core->regs.spr[(int)Gekko::SPR::DSISR];
else if (!_stricmp(name, "srr0")) return &Core->regs.spr[(int)Gekko::SPR::SRR0];
else if (!_stricmp(name, "srr1")) return &Core->regs.spr[(int)Gekko::SPR::SRR1];
else if (!_stricmp(name, "pmc1")) return &Core->regs.spr[953];
else if (!_stricmp(name, "pmc2")) return &Core->regs.spr[954];
else if (!_stricmp(name, "pmc3")) return &Core->regs.spr[957];
else if (!_stricmp(name, "pmc4")) return &Core->regs.spr[958];
else if (!_stricmp(name, "mmcr0")) return &Core->regs.spr[952];
else if (!_stricmp(name, "mmcr1")) return &Core->regs.spr[956];
else if (!_stricmp(name, "sia")) return &Core->regs.spr[955];
else if (!_stricmp(name, "sda")) return &Core->regs.spr[959];
else if (!_stricmp(name, "gqr0")) return &Core->regs.spr[(int)Gekko::SPR::GQR0];
else if (!_stricmp(name, "gqr1")) return &Core->regs.spr[(int)Gekko::SPR::GQR1];
else if (!_stricmp(name, "gqr2")) return &Core->regs.spr[(int)Gekko::SPR::GQR2];
else if (!_stricmp(name, "gqr3")) return &Core->regs.spr[(int)Gekko::SPR::GQR3];
else if (!_stricmp(name, "gqr4")) return &Core->regs.spr[(int)Gekko::SPR::GQR4];
else if (!_stricmp(name, "gqr5")) return &Core->regs.spr[(int)Gekko::SPR::GQR5];
else if (!_stricmp(name, "gqr6")) return &Core->regs.spr[(int)Gekko::SPR::GQR6];
else if (!_stricmp(name, "gqr7")) return &Core->regs.spr[(int)Gekko::SPR::GQR7];
else if (!_stricmp(name, "hid0")) return &Core->regs.spr[(int)Gekko::SPR::HID0];
else if (!_stricmp(name, "hid1")) return &Core->regs.spr[(int)Gekko::SPR::HID1];
else if (!_stricmp(name, "hid2")) return &Core->regs.spr[(int)Gekko::SPR::HID2];
else if (!_stricmp(name, "dabr")) return &Core->regs.spr[(int)Gekko::SPR::DABR];
else if (!_stricmp(name, "iabr")) return &Core->regs.spr[(int)Gekko::SPR::IABR];
else if (!_stricmp(name, "wpar")) return &Core->regs.spr[(int)Gekko::SPR::WPAR];
else if (!_stricmp(name, "l2cr")) return &Core->regs.spr[1017];
else if (!_stricmp(name, "dmau")) return &Core->regs.spr[(int)Gekko::SPR::DMAU];
else if (!_stricmp(name, "dmal")) return &Core->regs.spr[(int)Gekko::SPR::DMAL];
else if (!_stricmp(name, "thrm1")) return &Core->regs.spr[1020];
else if (!_stricmp(name, "thrm2")) return &Core->regs.spr[1021];
else if (!_stricmp(name, "thrm3")) return &Core->regs.spr[1022];
else if (!_stricmp(name, "ictc")) return &Core->regs.spr[1019];
else if (!_stricmp(name, "pc")) return &Core->regs.pc; // Wow !
return NULL;
}
// Operations.
static uint32_t op_replace(uint32_t a, uint32_t b) { return b; }
static uint32_t op_add(uint32_t a, uint32_t b) { return a + b; }
static uint32_t op_sub(uint32_t a, uint32_t b) { return a - b; }
static uint32_t op_mul(uint32_t a, uint32_t b) { return a * b; }
static uint32_t op_div(uint32_t a, uint32_t b) { return b ? (a / b) : 0; }
static uint32_t op_or(uint32_t a, uint32_t b) { return a | b; }
static uint32_t op_and(uint32_t a, uint32_t b) { return a & b; }
static uint32_t op_xor(uint32_t a, uint32_t b) { return a ^ b; }
static uint32_t op_shl(uint32_t a, uint32_t b) { return a << b; }
static uint32_t op_shr(uint32_t a, uint32_t b) { return a >> b; }
// Special handling for MSR register.
static void describe_msr(uint32_t msr_val)
{
static const char* fpmod[4] =
{
"exceptions disabled",
"imprecise nonrecoverable",
"imprecise recoverable",
"precise mode",
};
int f, fe[2];
Report(Channel::Norm, "MSR: 0x%08X\n", msr_val);
if (msr_val & MSR_POW) Report(Channel::Norm, "MSR[POW]: 1, power management enabled\n");
else Report(Channel::Norm, "MSR[POW]: 0, power management disabled\n");
if (msr_val & MSR_ILE) Report(Channel::Norm, "MSR[ILE]: 1\n");
else Report(Channel::Norm, "MSR[ILE]: 0\n");
if (msr_val & MSR_EE) Report(Channel::Norm, "MSR[EE] : 1, external interrupts and decrementer exception are enabled\n");
else Report(Channel::Norm, "MSR[EE] : 0, external interrupts and decrementer exception are disabled\n");
if (msr_val & MSR_PR) Report(Channel::Norm, "MSR[PR] : 1, processor execute in user mode (UISA)\n");
else Report(Channel::Norm, "MSR[PR] : 0, processor execute in supervisor mode (OEA)\n");
if (msr_val & MSR_FP) Report(Channel::Norm, "MSR[FP] : 1, floating-point is available\n");
else Report(Channel::Norm, "MSR[FP] : 0, floating-point unavailable\n");
if (msr_val & MSR_ME) Report(Channel::Norm, "MSR[ME] : 1, machine check exceptions are enabled\n");
else Report(Channel::Norm, "MSR[ME] : 0, machine check exceptions are disabled\n");
fe[0] = msr_val & MSR_FE0 ? 1 : 0;
fe[1] = msr_val & MSR_FE1 ? 1 : 0;
f = (fe[0] << 1) | (fe[1]);
Report(Channel::Norm, "MSR[FE] : %i, floating-point %s\n", f, fpmod[f]);
if (msr_val & MSR_SE) Report(Channel::Norm, "MSR[SE] : 1, single-step tracing is enabled\n");
else Report(Channel::Norm, "MSR[SE] : 0, single-step tracing is disabled\n");
if (msr_val & MSR_BE) Report(Channel::Norm, "MSR[BE] : 1, branch tracing is enabled\n");
else Report(Channel::Norm, "MSR[BE] : 0, branch tracing is disabled\n");
if (msr_val & MSR_IP) Report(Channel::Norm, "MSR[IP] : 1, exception prefix to physical address is 0xFFFn_nnnn\n");
else Report(Channel::Norm, "MSR[IP] : 0, exception prefix to physical address is 0x000n_nnnn\n");
if (msr_val & MSR_IR) Report(Channel::Norm, "MSR[IR] : 1, instruction address translation is enabled\n");
else Report(Channel::Norm, "MSR[IR] : 0, instruction address translation is disabled\n");
if (msr_val & MSR_DR) Report(Channel::Norm, "MSR[DR] : 1, data address translation is enabled\n");
else Report(Channel::Norm, "MSR[DR] : 0, data address translation is disabled\n");
if (msr_val & MSR_PM) Report(Channel::Norm, "MSR[PM] : 1, performance monitoring is enabled for this thread\n");
else Report(Channel::Norm, "MSR[PM] : 0, performance monitoring is disabled for this thread\n");
if (msr_val & MSR_RI) Report(Channel::Norm, "MSR[RI] : 1\n");
else Report(Channel::Norm, "MSR[RI] : 0\n");
if (msr_val & MSR_LE) Report(Channel::Norm, "MSR[LE] : 1, processor runs in little-endian mode\n");
else Report(Channel::Norm, "MSR[LE] : 0, processor runs in big-endian mode\n");
}
// HID0 info
static void describe_hid0(uint32_t val)
{
Report(Channel::Norm, "HID0: 0x%08X\n", val);
if (val & HID0_EMCP) Report(Channel::Norm, "HID0[EMCP] : 1, Asserting MCP causes checkstop or a machine check\n");
else Report(Channel::Norm, "HID0[EMCP] : 0, Masks MCP. Asserting MCP does not generate a machine check exception or a checkstop\n");
if (val & HID0_DBP) Report(Channel::Norm, "HID0[DBP] : 1, Disable parity generation\n");
else Report(Channel::Norm, "HID0[DBP] : 0, Parity generation is enabled\n");
if (val & HID0_EBA) Report(Channel::Norm, "HID0[EBA] : 1, Allows a address parity error to cause a checkstop or a machine check\n");
else Report(Channel::Norm, "HID0[EBA] : 0, Prevents address parity checking\n");
if (val & HID0_EBD) Report(Channel::Norm, "HID0[EBD] : 1, Allows a data parity error to cause a checkstop or machine check\n");
else Report(Channel::Norm, "HID0[EBD] : 0, Parity checking is disabled\n");
if (val & HID0_PAR) Report(Channel::Norm, "HID0[PAR] : 1, Alters bus protocol slightly by preventing the processor from driving ARTRY to high\n");
else Report(Channel::Norm, "HID0[PAR] : 0, Precharge of ARTRY enabled\n");
if (val & HID0_DOZE) Report(Channel::Norm, "HID0[DOZE] : 1, Doze mode enabled\n");
else Report(Channel::Norm, "HID0[DOZE] : 0, Doze mode disabled\n");
if (val & HID0_NAP) Report(Channel::Norm, "HID0[NAP] : 1, Nap mode enabled\n");
else Report(Channel::Norm, "HID0[NAP] : 0, Nap mode disabled\n");
if (val & HID0_SLEEP) Report(Channel::Norm, "HID0[SLEEP]: 1, Sleep mode enabled\n");
else Report(Channel::Norm, "HID0[SLEEP]: 0, Sleep mode disabled\n");
if (val & HID0_DPM) Report(Channel::Norm, "HID0[DPM] : 1, Dynamic power management is enabled\n");
else Report(Channel::Norm, "HID0[DPM] : 0, Dynamic power management is disabled\n");
if (val & HID0_NHR) Report(Channel::Norm, "HID0[NHR] : 1, Hard reset has not occurred\n");
else Report(Channel::Norm, "HID0[NHR] : 0, Hard reset occurred\n");
if (val & HID0_ICE) Report(Channel::Norm, "HID0[ICE] : 1, Instruction cache is enabled\n");
else Report(Channel::Norm, "HID0[ICE] : 0, Instruction cache is disabled\n");
if (val & HID0_DCE) Report(Channel::Norm, "HID0[DCE] : 1, Data cache is enabled\n");
else Report(Channel::Norm, "HID0[DCE] : 0, Data cache is disabled\n");
if (val & HID0_ILOCK) Report(Channel::Norm, "HID0[ILOCK]: 1, Instruction cache locked (frozen)\n");
else Report(Channel::Norm, "HID0[ILOCK]: 0, Instruction cache not locked\n");
if (val & HID0_DLOCK) Report(Channel::Norm, "HID0[DLOCK]: 1, Data cache locked (frozen)\n");
else Report(Channel::Norm, "HID0[DLOCK]: 0, Data cache not locked\n");
if (val & HID0_ICFI) Report(Channel::Norm, "HID0[ICFI] : 1, Instruction cache invalidating\n");
else Report(Channel::Norm, "HID0[ICFI] : 0, Instruction cache is not invalidated\n");
if (val & HID0_DCFI) Report(Channel::Norm, "HID0[DCFI] : 1, Data cache invalidating\n");
else Report(Channel::Norm, "HID0[DCFI] : 0, Data cache is not invalidated\n");
if (val & HID0_SPD) Report(Channel::Norm, "HID0[SPD] : 1, Speculative bus accesses to nonguarded space disabled\n");
else Report(Channel::Norm, "HID0[SPD] : 0, Speculative bus accesses to nonguarded space enabled\n");
if (val & HID0_IFEM) Report(Channel::Norm, "HID0[IFEM] : 1, Instruction fetches reflect the M bit from the WIM settings\n");
else Report(Channel::Norm, "HID0[IFEM] : 0, Instruction fetches M bit disabled\n");
if (val & HID0_SGE) Report(Channel::Norm, "HID0[SGE] : 1, Store gathering is enabled\n");
else Report(Channel::Norm, "HID0[SGE] : 0, Store gathering is disabled \n");
if (val & HID0_DCFA) Report(Channel::Norm, "HID0[DCFA] : 1, Data cache flush assist facility is enabled\n");
else Report(Channel::Norm, "HID0[DCFA] : 0, Data cache flush assist facility is disabled\n");
if (val & HID0_BTIC) Report(Channel::Norm, "HID0[BTIC] : 1, BTIC is enabled\n");
else Report(Channel::Norm, "HID0[BTIC] : 0, BTIC is disabled\n");
if (val & HID0_ABE) Report(Channel::Norm, "HID0[ABE] : 1, Address-only operations are broadcast on the 60x bus\n");
else Report(Channel::Norm, "HID0[ABE] : 0, Address-only operations affect only local L1 and L2 caches and are not broadcast\n");
if (val & HID0_BHT) Report(Channel::Norm, "HID0[BHT] : 1, Branch history enabled\n");
else Report(Channel::Norm, "HID0[BHT] : 0, Branch history disabled\n");
if (val & HID0_NOOPTI) Report(Channel::Norm, "HID0[NOOPTI]: 1, The dcbt and dcbtst instructions are no-oped globally\n");
else Report(Channel::Norm, "HID0[NOOPTI]: 0, The dcbt and dcbtst instructions are enabled\n");
}
static Json::Value* CmdGetSetReg(std::vector<std::string>& args)
{
uint32_t(*op)(uint32_t a, uint32_t b) = NULL;
uint32_t* n = getreg(args[1].c_str());
if (n == NULL)
{
Report(Channel::Norm, "unknown register : %s\n", args[1].c_str());
return nullptr;
}
// show register
if (args.size() <= 3)
{
if (!_stricmp(args[1].c_str(), "msr")) describe_msr(*n);
else if (!_stricmp(args[1].c_str(), "hid0")) describe_hid0(*n);
else Report(Channel::Norm, "%s = %i (0x%X)\n", args[1].c_str(), *n, *n);
return nullptr;
}
// Get operation.
if (!strcmp(args[2].c_str(), "=")) op = op_replace;
else if (!strcmp(args[2].c_str(), "+")) op = op_add;
else if (!strcmp(args[2].c_str(), "-")) op = op_sub;
else if (!strcmp(args[2].c_str(), "*")) op = op_mul;
else if (!strcmp(args[2].c_str(), "/")) op = op_div;
else if (!strcmp(args[2].c_str(), "|")) op = op_or;
else if (!strcmp(args[2].c_str(), "&")) op = op_and;
else if (!strcmp(args[2].c_str(), "^")) op = op_xor;
else if (!strcmp(args[2].c_str(), "<<")) op = op_shl;
else if (!strcmp(args[2].c_str(), ">>")) op = op_shr;
if (op == NULL)
{
Report(Channel::Norm, "Unknown operation: %s\n", args[2].c_str());
return nullptr;
}
// New value
uint32_t* m = getreg(args[3].c_str());
if (m == NULL)
{
int i = strtoul(args[3].c_str(), NULL, 0);
Report(Channel::Norm, "%s %s %i (0x%X)\n", args[1].c_str(), args[2].c_str(), i, i);
*n = op(*n, i);
}
else
{
Report(Channel::Norm, "%s %s %s\n", args[1].c_str(), args[2].c_str(), args[3].c_str());
*n = op(*n, *m);
}
return nullptr;
}
static Json::Value* CmdBreakExec(std::vector<std::string>& args)
{
uint32_t addr = strtoul(args[1].c_str(), nullptr, 0);
Core->AddBreakpoint(addr);
return nullptr;
}
static Json::Value* CmdBreakRead(std::vector<std::string>& args)
{
uint32_t addr = strtoul(args[1].c_str(), nullptr, 0);
Core->AddReadBreak(addr);
return nullptr;
}
static Json::Value* CmdBreakWrite(std::vector<std::string>& args)
{
uint32_t addr = strtoul(args[1].c_str(), nullptr, 0);
Core->AddWriteBreak(addr);
return nullptr;
}
static Json::Value* CmdBreakClearAll(std::vector<std::string>& args)
{
Core->ClearBreakpoints();
return nullptr;
}
static Json::Value* CmdCacheLog(std::vector<std::string>& args)
{
Gekko::CacheLogLevel level = (Gekko::CacheLogLevel)atoi(args[1].c_str());
Core->cache->SetLogLevel(level);
return nullptr;
}
static Json::Value* CmdIsRunning(std::vector<std::string>& args)
{
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Bool;
output->value.AsBool = Core->IsRunning();
return output;
}
static Json::Value* CmdGekkoRun(std::vector<std::string>& args)
{
Core->Run();
return nullptr;
}
static Json::Value* CmdGekkoSuspend(std::vector<std::string>& args)
{
Core->Suspend();
return nullptr;
}
static Json::Value* CmdGekkoStep(std::vector<std::string>& args)
{
if (!Core->IsRunning())
{
Core->Step();
}
return nullptr;
}
static Json::Value* CmdGekkoSkipInstruction(std::vector<std::string>& args)
{
if (!Core->IsRunning())
{
Report(Channel::CPU, "Skipped instruction at: 0x%08X!\n", Core->regs.pc);
Core->regs.pc += 4;
}
return nullptr;
}
static Json::Value* CmdGetGpr(std::vector<std::string>& args)
{
int n = atoi(args[1].c_str());
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Int;
output->value.AsUint32 = Core->regs.gpr[n];
return output;
}
static Json::Value* CmdGetPs0(std::vector<std::string>& args)
{
int n = atoi(args[1].c_str());
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Int;
output->value.AsInt = Core->regs.fpr[n].uval;
return output;
}
static Json::Value* CmdGetPs1(std::vector<std::string>& args)
{
int n = atoi(args[1].c_str());
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Int;
output->value.AsInt = Core->regs.ps1[n].uval;
return output;
}
static Json::Value* CmdGetPc(std::vector<std::string>& args)
{
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Int;
output->value.AsInt = Core->regs.pc;
return output;
}
static Json::Value* CmdGetMsr(std::vector<std::string>& args)
{
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Int;
output->value.AsInt = Core->regs.msr;
return output;
}
static Json::Value* CmdGetCr(std::vector<std::string>& args)
{
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Int;
output->value.AsInt = Core->regs.cr;
return output;
}
static Json::Value* CmdGetFpscr(std::vector<std::string>& args)
{
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Int;
output->value.AsInt = Core->regs.fpscr;
return output;
}
static Json::Value* CmdGetSpr(std::vector<std::string>& args)
{
int n = atoi(args[1].c_str());
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Int;
output->value.AsUint32 = Core->regs.spr[n];
return output;
}
static Json::Value* CmdGetSr(std::vector<std::string>& args)
{
int n = atoi(args[1].c_str());
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Int;
output->value.AsUint32 = Core->regs.sr[n];
return output;
}
static Json::Value* CmdGetTbu(std::vector<std::string>& args)
{
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Int;
output->value.AsUint32 = Core->regs.tb.Part.u;
return output;
}
static Json::Value* CmdGetTbl(std::vector<std::string>& args)
{
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Int;
output->value.AsUint32 = Core->regs.tb.Part.l;
return output;
}
static Json::Value* CmdTranslateDMmu(std::vector<std::string>& args)
{
uint32_t addr = strtoul(args[1].c_str(), nullptr, 0);
uint32_t pa = Gekko::BadAddress;
if (JDI::Hub.ExecuteFastBool("IsLoaded"))
{
int WIMG;
pa = Core->EffectiveToPhysical(addr, Gekko::MmuAccess::Read, WIMG);
}
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Int;
output->value.AsInt = (uint64_t)MITranslatePhysicalAddress(pa, sizeof(uint32_t));
return output;
}
static Json::Value* CmdTranslateIMmu(std::vector<std::string>& args)
{
uint32_t addr = strtoul(args[1].c_str(), nullptr, 0);
uint32_t pa = Gekko::BadAddress;
if (JDI::Hub.ExecuteFastBool("IsLoaded"))
{
int WIMG;
pa = Core->EffectiveToPhysical(addr, Gekko::MmuAccess::Execute, WIMG);
}
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Int;
output->value.AsInt = (uint64_t)MITranslatePhysicalAddress(pa, sizeof(uint32_t));
return output;
}
static Json::Value* CmdVirtualToPhysicalDMmu(std::vector<std::string>& args)
{
uint32_t addr = strtoul(args[1].c_str(), nullptr, 0);
uint32_t pa = Gekko::BadAddress;
if (JDI::Hub.ExecuteFastBool("IsLoaded"))
{
int WIMG;
pa = Core->EffectiveToPhysical(addr, Gekko::MmuAccess::Read, WIMG);
}
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Int;
output->value.AsUint32 = pa;
return output;
}
static Json::Value* CmdVirtualToPhysicalIMmu(std::vector<std::string>& args)
{
uint32_t addr = strtoul(args[1].c_str(), nullptr, 0);
uint32_t pa = Gekko::BadAddress;
if (JDI::Hub.ExecuteFastBool("IsLoaded"))
{
int WIMG;
pa = Core->EffectiveToPhysical(addr, Gekko::MmuAccess::Execute, WIMG);
}
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Int;
output->value.AsUint32 = pa;
return output;
}
static Json::Value* CmdGekkoTestBreakpoint(std::vector<std::string>& args)
{
uint32_t addr = strtoul(args[1].c_str(), nullptr, 0);
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Bool;
output->value.AsBool = Core->IsBreakpoint(addr);
return output;
}
static Json::Value* CmdGekkoToggleBreakpoint(std::vector<std::string>& args)
{
uint32_t addr = strtoul(args[1].c_str(), nullptr, 0);
Core->ToggleBreakpoint(addr);
return nullptr;
}
static Json::Value* CmdGekkoAddOneShotBreakpoint(std::vector<std::string>& args)
{
uint32_t addr = strtoul(args[1].c_str(), nullptr, 0);
Core->AddOneShotBreakpoint(addr);
return nullptr;
}
// Disassemble instruction at Gekko virtual memory address
static Json::Value* CmdGekkoDisasm(std::vector<std::string>& args)
{
uint32_t addr = strtoul(args[1].c_str(), nullptr, 0);
uint32_t pa = Gekko::BadAddress;
if (JDI::Hub.ExecuteFastBool("IsLoaded"))
{
int WIMG;
pa = Core->EffectiveToPhysical(addr, Gekko::MmuAccess::Execute, WIMG);
}
std::string text = "";
uint8_t* ptr = MITranslatePhysicalAddress(pa, sizeof(uint32_t));
if (ptr != nullptr)
{
Gekko::DecoderInfo info = { 0 };
uint32_t instr = _BYTESWAP_UINT32(*(uint32_t*)ptr);
Gekko::Decoder::Decode(addr, instr, &info);
text = Gekko::GekkoDisasm::Disasm(addr, &info, false, false);
}
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Array;
output->AddAnsiString(nullptr, text.c_str());
return output;
}
// Disassemble the instruction without accessing memory (all necessary information is passed through parameters)
static Json::Value* CmdGekkoDisasmNoMemAccess(std::vector<std::string>& args)
{
uint32_t addr = strtoul(args[1].c_str(), nullptr, 0);
uint32_t instr = strtoul(args[2].c_str(), nullptr, 0);
bool showAddress = strtoul(args[3].c_str(), nullptr, 0) != 0;
bool showBytes = strtoul(args[4].c_str(), nullptr, 0) != 0;
Gekko::DecoderInfo info = { 0 };
Gekko::Decoder::Decode(addr, instr, &info);
std::string text = Gekko::GekkoDisasm::Disasm(addr, &info, showAddress, showBytes);
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Array;
output->AddAnsiString(nullptr, text.c_str());
return output;
}
static Json::Value* CmdGekkoIsBranch(std::vector<std::string>& args)
{
uint32_t addr = strtoul(args[1].c_str(), nullptr, 0);
uint32_t pa = Gekko::BadAddress;
if (JDI::Hub.ExecuteFastBool("IsLoaded"))
{
int WIMG;
pa = Core->EffectiveToPhysical(addr, Gekko::MmuAccess::Execute, WIMG);
}
bool flowControl = false;
uint32_t targetAddress = 0;
if (pa < RAMSIZE)
{
Gekko::DecoderInfo info = { 0 };
uint8_t* ptr = &mi.ram[pa];
uint32_t instr = _BYTESWAP_UINT32(*(uint32_t*)ptr);
Gekko::Decoder::Decode(addr, instr, &info);
flowControl = info.flow;
targetAddress = info.Imm.Address;
}
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Array;
output->AddBool(nullptr, flowControl);
output->AddUInt32(nullptr, targetAddress);
return output;
}
static Json::Value* CmdNop(std::vector<std::string>& args)
{
if (!JDI::Hub.ExecuteFastBool("IsLoaded"))
{
return nullptr;
}
uint32_t ea = strtoul(args[1].c_str(), nullptr, 0);
Core->WriteWord(ea, 0x6000'0000);
// Refresh physical memory (MEM) storage
int wimg;
uint32_t pa = Core->EffectiveToPhysical(ea, Gekko::MmuAccess::Read , wimg);
if (pa != Gekko::BadAddress) {
PIWriteWord(pa, 0x6000'0000);
}
// You also need to invalidate the Gekko instruction cache
Core->icache->Invalidate(pa);
// Refresh the debugger contents
if (debugger != nullptr) {
debugger->InvalidateAll();
}
return nullptr;
}
// Enables or disables the maintenance of opcode usage statistics
static Json::Value* CmdEnableOpcodeStats(std::vector<std::string>& args)
{
bool enable = strtoul(args[1].c_str(), nullptr, 0) != 0 ? true : false;
Core->EnableOpcodeStats(enable);
return nullptr;
}
// Displays the most commonly used Gekko opcodes
static Json::Value* CmdPrintOpcodeStats(std::vector<std::string>& args)
{
size_t maxCount = strtoul(args[1].c_str(), nullptr, 0);
Core->PrintOpcodeStats(maxCount);
return nullptr;
}
// Clears statistics of opcode usage
static Json::Value* CmdResetOpcodeStats(std::vector<std::string>& args)
{
Core->ResetOpcodeStats();
return nullptr;
}
// Runs a low priority thread that prints opcode statistics once a second
static Json::Value* CmdRunOpcodeStats(std::vector<std::string>& args)
{
Core->RunOpcodeStatsThread();
return nullptr;
}
// Stop the thread that outputs the opcode statistics
static Json::Value* CmdStopOpcodeStats(std::vector<std::string>& args)
{
Core->StopOpcodeStatsThread();
return nullptr;
}
// Parse Gekko instruction
static Json::Value* CmdGekkoAnalyze(std::vector<std::string>& args)
{
uint32_t pc = strtoul(args[1].c_str(), nullptr, 0);
uint32_t opcode = strtoul(args[2].c_str(), nullptr, 0);
Gekko::DecoderInfo info = { 0 };
Gekko::Decoder::Decode(pc, opcode, &info);
// Array: [Int instr, Int numParams, Int param0, Int paramBits0, Int param1, Int paramBits1, Int param2, Int paramBits2, Int param3, Int paramBits3, Int param4, Int paramBits4, UInt32 immedValue, UInt32 newPc, Bool flow]
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Array;
output->AddInt(nullptr, (int)info.instr);
output->AddInt(nullptr, (int)info.numParam);
uint32_t imm = 0;
for (int i = 0; i < 5; i++)
{
if (i >= info.numParam)
{
output->AddInt(nullptr, (int)Gekko::Param::Unknown);
output->AddInt(nullptr, 0);
continue;
}
// Immediate parameter values are stored in a separate field.
switch (info.param[i])
{
case Gekko::Param::Simm:
imm = (uint32_t)(int32_t)info.Imm.Signed;
break;
case Gekko::Param::Uimm:
imm = (uint32_t)info.Imm.Unsigned;
break;
case Gekko::Param::Address:
imm = info.Imm.Address;
break;
}
output->AddInt(nullptr, (int)info.param[i]);
output->AddInt(nullptr, (int)info.paramBits[i]); // Doesn't make sense for Immediate parameters, but remains for conformity.
}
output->AddUInt32(nullptr, imm); // If the Immediate parameter is missing, it is 0
output->AddUInt32(nullptr, info.pc);
output->AddBool(nullptr, info.flow);
return output;
}
// Return the name of the Gekko instruction (Gekko::Instruction)
static Json::Value* CmdGekkoInstrToString(std::vector<std::string>& args)
{
Gekko::DecoderInfo info = { 0 };
info.instr = (Gekko::Instruction)strtoul(args[1].c_str(), nullptr, 0);
std::string instrName = Gekko::GekkoDisasm::InstrToString(&info);
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Array;
output->AddAnsiString(nullptr, instrName.c_str());
return output;
}
// Return the parameter name of a Gekko instruction (Gekko::Param)
static Json::Value* CmdGekkoInstrParamToString(std::vector<std::string>& args)
{
Gekko::DecoderInfo info = { 0 };
info.param[0] = (Gekko::Param)strtoul(args[1].c_str(), nullptr, 0);
info.paramBits[0] = strtoul(args[2].c_str(), nullptr, 0);
uint32_t imm = strtoul(args[3].c_str(), nullptr, 0);
// Immediate parameter values are stored in a separate field.
switch (info.param[0])
{
case Gekko::Param::Simm:
info.Imm.Signed = imm;
break;
case Gekko::Param::Uimm:
info.Imm.Unsigned = imm;
break;
case Gekko::Param::Address:
info.Imm.Address = imm;
break;
}
std::string paramName = Gekko::GekkoDisasm::ParamName(info.param[0]);
std::string paramText = Gekko::GekkoDisasm::ParamToString(info.param[0], info.paramBits[0], &info);
Json::Value* output = new Json::Value();
output->type = Json::ValueType::Array;
output->AddAnsiString(nullptr, paramName.c_str());
output->AddAnsiString(nullptr, paramText.c_str());
return output;
}
static Json::Value* CmdDumpDTLB(std::vector<std::string>& args)
{
Core->DumpDTLB();
return nullptr;
}
static Json::Value* CmdDumpITLB(std::vector<std::string>& args)
{
Core->DumpITLB();
return nullptr;
}
static Json::Value* CmdInvalidateTLB(std::vector<std::string>& args)
{
Core->InvalidateTLBAll();
Report(Channel::CPU, "All TLB are invalidated\n");
return nullptr;
}
void gekko_init_handlers()
{
JDI::Hub.AddCmd("run", CmdRun);
JDI::Hub.AddCmd("stop", CmdStop);
JDI::Hub.AddCmd("r", CmdGetSetReg);
JDI::Hub.AddCmd("b", CmdBreakExec);
JDI::Hub.AddCmd("br", CmdBreakRead);
JDI::Hub.AddCmd("bw", CmdBreakWrite);
JDI::Hub.AddCmd("bc", CmdBreakClearAll);
JDI::Hub.AddCmd("CacheLog", CmdCacheLog);
JDI::Hub.AddCmd("IsRunning", CmdIsRunning);
JDI::Hub.AddCmd("GekkoRun", CmdGekkoRun);
JDI::Hub.AddCmd("GekkoSuspend", CmdGekkoSuspend);
JDI::Hub.AddCmd("GekkoStep", CmdGekkoStep);
JDI::Hub.AddCmd("GekkoSkipInstruction", CmdGekkoSkipInstruction);
JDI::Hub.AddCmd("GetGpr", CmdGetGpr);
JDI::Hub.AddCmd("GetPs0", CmdGetPs0);
JDI::Hub.AddCmd("GetPs1", CmdGetPs1);
JDI::Hub.AddCmd("GetPc", CmdGetPc);
JDI::Hub.AddCmd("GetMsr", CmdGetMsr);
JDI::Hub.AddCmd("GetCr", CmdGetCr);
JDI::Hub.AddCmd("GetFpscr", CmdGetFpscr);
JDI::Hub.AddCmd("GetSpr", CmdGetSpr);
JDI::Hub.AddCmd("GetSr", CmdGetSr);
JDI::Hub.AddCmd("GetTbu", CmdGetTbu);
JDI::Hub.AddCmd("GetTbl", CmdGetTbl);
JDI::Hub.AddCmd("TranslateDMmu", CmdTranslateDMmu);
JDI::Hub.AddCmd("TranslateIMmu", CmdTranslateIMmu);
JDI::Hub.AddCmd("VirtualToPhysicalDMmu", CmdVirtualToPhysicalDMmu);
JDI::Hub.AddCmd("VirtualToPhysicalIMmu", CmdVirtualToPhysicalIMmu);
JDI::Hub.AddCmd("GekkoTestBreakpoint", CmdGekkoTestBreakpoint);
JDI::Hub.AddCmd("GekkoToggleBreakpoint", CmdGekkoToggleBreakpoint);
JDI::Hub.AddCmd("GekkoAddOneShotBreakpoint", CmdGekkoAddOneShotBreakpoint);
JDI::Hub.AddCmd("GekkoDisasm", CmdGekkoDisasm);
JDI::Hub.AddCmd("GekkoDisasmNoMemAccess", CmdGekkoDisasmNoMemAccess);
JDI::Hub.AddCmd("GekkoIsBranch", CmdGekkoIsBranch);
JDI::Hub.AddCmd("nop", CmdNop);
JDI::Hub.AddCmd("EnableOpcodeStats", CmdEnableOpcodeStats);
JDI::Hub.AddCmd("PrintOpcodeStats", CmdPrintOpcodeStats);
JDI::Hub.AddCmd("ResetOpcodeStats", CmdResetOpcodeStats);
JDI::Hub.AddCmd("RunOpcodeStats", CmdRunOpcodeStats);
JDI::Hub.AddCmd("StopOpcodeStats", CmdStopOpcodeStats);
JDI::Hub.AddCmd("GekkoAnalyze", CmdGekkoAnalyze);
JDI::Hub.AddCmd("GekkoInstrToString", CmdGekkoInstrToString);
JDI::Hub.AddCmd("GekkoInstrParamToString", CmdGekkoInstrParamToString);
JDI::Hub.AddCmd("dtlb", CmdDumpDTLB);
JDI::Hub.AddCmd("itlb", CmdDumpITLB);
JDI::Hub.AddCmd("tlbinv", CmdInvalidateTLB);
}
}