mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
Revert 3ce242886b (Disabled force symbol loading) until solution is found
If this isn't caught when the game is loaded, the symbols will not be properly loaded while the game is running.
DisassemblyManager: Don't spin continuously if the guest CPU is dead
920 lines
16 KiB
C++
920 lines
16 KiB
C++
/* PCSX2 - PS2 Emulator for PCs
|
|
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
|
*
|
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
|
* ation, either version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "PrecompiledHeader.h"
|
|
|
|
#include "DebugInterface.h"
|
|
#include "Memory.h"
|
|
#include "R5900.h"
|
|
#include "Debug.h"
|
|
#include "VU.h"
|
|
#include "GS.h" // Required for gsNonMirroredRead()
|
|
#include "Counters.h"
|
|
|
|
#include "R3000A.h"
|
|
#include "IopMem.h"
|
|
#include "SymbolMap.h"
|
|
#include "VMManager.h"
|
|
|
|
#include "common/StringUtil.h"
|
|
|
|
#ifndef PCSX2_CORE
|
|
#include "gui/SysThreads.h"
|
|
#endif
|
|
|
|
R5900DebugInterface r5900Debug;
|
|
R3000DebugInterface r3000Debug;
|
|
|
|
#ifdef _WIN32
|
|
#define strcasecmp stricmp
|
|
#endif
|
|
|
|
enum ReferenceIndexType
|
|
{
|
|
REF_INDEX_PC = 32,
|
|
REF_INDEX_HI = 33,
|
|
REF_INDEX_LO = 34,
|
|
REF_INDEX_FPU = 0x1000,
|
|
REF_INDEX_FPU_INT = 0x2000,
|
|
REF_INDEX_VFPU = 0x4000,
|
|
REF_INDEX_VFPU_INT = 0x8000,
|
|
REF_INDEX_IS_FLOAT = REF_INDEX_FPU | REF_INDEX_VFPU,
|
|
};
|
|
|
|
|
|
class MipsExpressionFunctions : public IExpressionFunctions
|
|
{
|
|
public:
|
|
explicit MipsExpressionFunctions(DebugInterface* cpu)
|
|
: cpu(cpu){};
|
|
|
|
virtual bool parseReference(char* str, u64& referenceIndex)
|
|
{
|
|
for (int i = 0; i < 32; i++)
|
|
{
|
|
char reg[8];
|
|
sprintf(reg, "r%d", i);
|
|
|
|
if (strcasecmp(str, reg) == 0 || strcasecmp(str, cpu->getRegisterName(0, i)) == 0)
|
|
{
|
|
referenceIndex = i;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (strcasecmp(str, "pc") == 0)
|
|
{
|
|
referenceIndex = REF_INDEX_PC;
|
|
return true;
|
|
}
|
|
|
|
if (strcasecmp(str, "hi") == 0)
|
|
{
|
|
referenceIndex = REF_INDEX_HI;
|
|
return true;
|
|
}
|
|
|
|
if (strcasecmp(str, "lo") == 0)
|
|
{
|
|
referenceIndex = REF_INDEX_LO;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
virtual bool parseSymbol(char* str, u64& symbolValue)
|
|
{
|
|
u32 value;
|
|
bool result = cpu->GetSymbolMap().GetLabelValue(str, value);
|
|
symbolValue = value;
|
|
return result;
|
|
}
|
|
|
|
virtual u64 getReferenceValue(u64 referenceIndex)
|
|
{
|
|
if (referenceIndex < 32)
|
|
return cpu->getRegister(0, referenceIndex)._u64[0];
|
|
if (referenceIndex == REF_INDEX_PC)
|
|
return cpu->getPC();
|
|
if (referenceIndex == REF_INDEX_HI)
|
|
return cpu->getHI()._u64[0];
|
|
if (referenceIndex == REF_INDEX_LO)
|
|
return cpu->getLO()._u64[0];
|
|
return -1;
|
|
}
|
|
|
|
virtual ExpressionType getReferenceType(u64 referenceIndex)
|
|
{
|
|
if (referenceIndex & REF_INDEX_IS_FLOAT)
|
|
{
|
|
return EXPR_TYPE_FLOAT;
|
|
}
|
|
return EXPR_TYPE_UINT;
|
|
}
|
|
|
|
virtual bool getMemoryValue(u32 address, int size, u64& dest, char* error)
|
|
{
|
|
switch (size)
|
|
{
|
|
case 1:
|
|
case 2:
|
|
case 4:
|
|
case 8:
|
|
break;
|
|
default:
|
|
sprintf(error, "Invalid memory access size %d", size);
|
|
return false;
|
|
}
|
|
|
|
if (address % size)
|
|
{
|
|
sprintf(error, "Invalid memory access (unaligned)");
|
|
return false;
|
|
}
|
|
|
|
switch (size)
|
|
{
|
|
case 1:
|
|
dest = cpu->read8(address);
|
|
break;
|
|
case 2:
|
|
dest = cpu->read16(address);
|
|
break;
|
|
case 4:
|
|
dest = cpu->read32(address);
|
|
break;
|
|
case 8:
|
|
dest = cpu->read64(address);
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
DebugInterface* cpu;
|
|
};
|
|
|
|
//
|
|
// DebugInterface
|
|
//
|
|
|
|
bool DebugInterface::isAlive()
|
|
{
|
|
#ifndef PCSX2_CORE
|
|
return GetCoreThread().IsOpen() && g_FrameCount > 0;
|
|
#else
|
|
return VMManager::HasValidVM() && g_FrameCount > 0;
|
|
#endif
|
|
}
|
|
|
|
bool DebugInterface::isCpuPaused()
|
|
{
|
|
#ifndef PCSX2_CORE
|
|
return GetCoreThread().IsPaused();
|
|
#else
|
|
return VMManager::GetState() == VMState::Paused;
|
|
#endif
|
|
}
|
|
|
|
void DebugInterface::pauseCpu()
|
|
{
|
|
#ifndef PCSX2_CORE
|
|
SysCoreThread& core = GetCoreThread();
|
|
if (!core.IsPaused())
|
|
core.Pause({}, true);
|
|
#else
|
|
VMManager::SetPaused(true);
|
|
#endif
|
|
}
|
|
|
|
void DebugInterface::resumeCpu()
|
|
{
|
|
#ifndef PCSX2_CORE
|
|
SysCoreThread& core = GetCoreThread();
|
|
if (core.IsPaused())
|
|
core.Resume();
|
|
#else
|
|
VMManager::SetPaused(false);
|
|
#endif
|
|
}
|
|
|
|
|
|
char* DebugInterface::stringFromPointer(u32 p)
|
|
{
|
|
const int BUFFER_LEN = 25;
|
|
static char buf[BUFFER_LEN] = {0};
|
|
|
|
if (!isValidAddress(p))
|
|
return NULL;
|
|
|
|
try
|
|
{
|
|
for (u32 i = 0; i < BUFFER_LEN; i++)
|
|
{
|
|
char c = read8(p + i);
|
|
buf[i] = c;
|
|
|
|
if (c == 0)
|
|
{
|
|
return i > 0 ? buf : NULL;
|
|
}
|
|
else if (c < 0x20 || c >= 0x7f)
|
|
{
|
|
// non printable character
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception::Ps2Generic&)
|
|
{
|
|
return NULL;
|
|
}
|
|
buf[BUFFER_LEN - 1] = 0;
|
|
buf[BUFFER_LEN - 2] = '~';
|
|
return buf;
|
|
}
|
|
|
|
bool DebugInterface::initExpression(const char* exp, PostfixExpression& dest)
|
|
{
|
|
MipsExpressionFunctions funcs(this);
|
|
return initPostfixExpression(exp, &funcs, dest);
|
|
}
|
|
|
|
bool DebugInterface::parseExpression(PostfixExpression& exp, u64& dest)
|
|
{
|
|
MipsExpressionFunctions funcs(this);
|
|
return parsePostfixExpression(exp, &funcs, dest);
|
|
}
|
|
|
|
|
|
//
|
|
// R5900DebugInterface
|
|
//
|
|
|
|
BreakPointCpu R5900DebugInterface::getCpuType()
|
|
{
|
|
return BREAKPOINT_EE;
|
|
}
|
|
|
|
u32 R5900DebugInterface::read8(u32 address)
|
|
{
|
|
if (!isValidAddress(address))
|
|
return -1;
|
|
|
|
return memRead8(address);
|
|
}
|
|
|
|
u32 R5900DebugInterface::read16(u32 address)
|
|
{
|
|
if (!isValidAddress(address) || address % 2)
|
|
return -1;
|
|
|
|
return memRead16(address);
|
|
}
|
|
|
|
u32 R5900DebugInterface::read32(u32 address)
|
|
{
|
|
if (!isValidAddress(address) || address % 4)
|
|
return -1;
|
|
|
|
return memRead32(address);
|
|
}
|
|
|
|
u64 R5900DebugInterface::read64(u32 address)
|
|
{
|
|
if (!isValidAddress(address) || address % 8)
|
|
return -1;
|
|
|
|
return memRead64(address);
|
|
}
|
|
|
|
u128 R5900DebugInterface::read128(u32 address)
|
|
{
|
|
alignas(16) u128 result;
|
|
if (!isValidAddress(address) || address % 16)
|
|
{
|
|
result.hi = result.lo = -1;
|
|
return result;
|
|
}
|
|
|
|
memRead128(address, result);
|
|
return result;
|
|
}
|
|
|
|
void R5900DebugInterface::write8(u32 address, u8 value)
|
|
{
|
|
if (!isValidAddress(address))
|
|
return;
|
|
|
|
memWrite8(address, value);
|
|
}
|
|
|
|
void R5900DebugInterface::write32(u32 address, u32 value)
|
|
{
|
|
if (!isValidAddress(address))
|
|
return;
|
|
|
|
memWrite32(address, value);
|
|
}
|
|
|
|
|
|
int R5900DebugInterface::getRegisterCategoryCount()
|
|
{
|
|
return EECAT_COUNT;
|
|
}
|
|
|
|
const char* R5900DebugInterface::getRegisterCategoryName(int cat)
|
|
{
|
|
switch (cat)
|
|
{
|
|
case EECAT_GPR:
|
|
return "GPR";
|
|
case EECAT_CP0:
|
|
return "CP0";
|
|
case EECAT_FPR:
|
|
return "FPR";
|
|
case EECAT_FCR:
|
|
return "FCR";
|
|
case EECAT_VU0F:
|
|
return "VU0f";
|
|
case EECAT_VU0I:
|
|
return "VU0i";
|
|
case EECAT_GSPRIV:
|
|
return "GS";
|
|
default:
|
|
return "Invalid";
|
|
}
|
|
}
|
|
|
|
int R5900DebugInterface::getRegisterSize(int cat)
|
|
{
|
|
switch (cat)
|
|
{
|
|
case EECAT_GPR:
|
|
case EECAT_VU0F:
|
|
return 128;
|
|
case EECAT_CP0:
|
|
case EECAT_FPR:
|
|
case EECAT_FCR:
|
|
case EECAT_VU0I:
|
|
return 32;
|
|
case EECAT_GSPRIV:
|
|
return 64;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int R5900DebugInterface::getRegisterCount(int cat)
|
|
{
|
|
switch (cat)
|
|
{
|
|
case EECAT_GPR:
|
|
return 35; // 32 + pc + hi + lo
|
|
case EECAT_CP0:
|
|
case EECAT_FPR:
|
|
case EECAT_FCR:
|
|
case EECAT_VU0I:
|
|
return 32;
|
|
case EECAT_VU0F:
|
|
return 33; // 32 + ACC
|
|
case EECAT_GSPRIV:
|
|
return 19;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
DebugInterface::RegisterType R5900DebugInterface::getRegisterType(int cat)
|
|
{
|
|
switch (cat)
|
|
{
|
|
case EECAT_GPR:
|
|
case EECAT_CP0:
|
|
case EECAT_VU0I:
|
|
case EECAT_FCR:
|
|
case EECAT_GSPRIV:
|
|
default:
|
|
return NORMAL;
|
|
case EECAT_FPR:
|
|
case EECAT_VU0F:
|
|
return SPECIAL;
|
|
}
|
|
}
|
|
|
|
const char* R5900DebugInterface::getRegisterName(int cat, int num)
|
|
{
|
|
switch (cat)
|
|
{
|
|
case EECAT_GPR:
|
|
switch (num)
|
|
{
|
|
case 32: // pc
|
|
return "pc";
|
|
case 33: // hi
|
|
return "hi";
|
|
case 34: // lo
|
|
return "lo";
|
|
default:
|
|
return R5900::GPR_REG[num];
|
|
}
|
|
case EECAT_CP0:
|
|
return R5900::COP0_REG[num];
|
|
case EECAT_FPR:
|
|
return R5900::COP1_REG_FP[num];
|
|
case EECAT_FCR:
|
|
return R5900::COP1_REG_FCR[num];
|
|
case EECAT_VU0F:
|
|
switch (num)
|
|
{
|
|
case 32: // ACC
|
|
return "ACC";
|
|
default:
|
|
return R5900::COP2_REG_FP[num];
|
|
}
|
|
case EECAT_VU0I:
|
|
return R5900::COP2_REG_CTL[num];
|
|
case EECAT_GSPRIV:
|
|
return R5900::GS_REG_PRIV[num];
|
|
default:
|
|
return "Invalid";
|
|
}
|
|
}
|
|
|
|
u128 R5900DebugInterface::getRegister(int cat, int num)
|
|
{
|
|
u128 result;
|
|
switch (cat)
|
|
{
|
|
case EECAT_GPR:
|
|
switch (num)
|
|
{
|
|
case 32: // pc
|
|
result = u128::From32(cpuRegs.pc);
|
|
break;
|
|
case 33: // hi
|
|
result = cpuRegs.HI.UQ;
|
|
break;
|
|
case 34: // lo
|
|
result = cpuRegs.LO.UQ;
|
|
break;
|
|
default:
|
|
result = cpuRegs.GPR.r[num].UQ;
|
|
break;
|
|
}
|
|
break;
|
|
case EECAT_CP0:
|
|
result = u128::From32(cpuRegs.CP0.r[num]);
|
|
break;
|
|
case EECAT_FPR:
|
|
result = u128::From32(fpuRegs.fpr[num].UL);
|
|
break;
|
|
case EECAT_FCR:
|
|
result = u128::From32(fpuRegs.fprc[num]);
|
|
break;
|
|
case EECAT_VU0F:
|
|
switch (num)
|
|
{
|
|
case 32: // ACC
|
|
result = VU0.ACC.UQ;
|
|
break;
|
|
default:
|
|
result = VU0.VF[num].UQ;
|
|
break;
|
|
}
|
|
break;
|
|
case EECAT_VU0I:
|
|
result = u128::From32(VU0.VI[num].UL);
|
|
break;
|
|
case EECAT_GSPRIV:
|
|
result = gsNonMirroredRead(0x12000000 | R5900::GS_REG_PRIV_ADDR[num]);
|
|
break;
|
|
default:
|
|
result = u128::From32(0);
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
std::string R5900DebugInterface::getRegisterString(int cat, int num)
|
|
{
|
|
switch (cat)
|
|
{
|
|
case EECAT_GPR:
|
|
case EECAT_CP0:
|
|
case EECAT_FCR:
|
|
case EECAT_VU0F:
|
|
return StringUtil::U128ToString(getRegister(cat, num));
|
|
case EECAT_FPR:
|
|
return StringUtil::StdStringFromFormat("%f", fpuRegs.fpr[num].f);
|
|
default:
|
|
return {};
|
|
}
|
|
}
|
|
|
|
|
|
u128 R5900DebugInterface::getHI()
|
|
{
|
|
return cpuRegs.HI.UQ;
|
|
}
|
|
|
|
u128 R5900DebugInterface::getLO()
|
|
{
|
|
return cpuRegs.LO.UQ;
|
|
}
|
|
|
|
u32 R5900DebugInterface::getPC()
|
|
{
|
|
return cpuRegs.pc;
|
|
}
|
|
|
|
void R5900DebugInterface::setPc(u32 newPc)
|
|
{
|
|
cpuRegs.pc = newPc;
|
|
}
|
|
|
|
void R5900DebugInterface::setRegister(int cat, int num, u128 newValue)
|
|
{
|
|
switch (cat)
|
|
{
|
|
case EECAT_GPR:
|
|
switch (num)
|
|
{
|
|
case 32: // pc
|
|
cpuRegs.pc = newValue._u32[0];
|
|
break;
|
|
case 33: // hi
|
|
cpuRegs.HI.UQ = newValue;
|
|
break;
|
|
case 34: // lo
|
|
cpuRegs.LO.UQ = newValue;
|
|
break;
|
|
default:
|
|
cpuRegs.GPR.r[num].UQ = newValue;
|
|
break;
|
|
}
|
|
break;
|
|
case EECAT_CP0:
|
|
cpuRegs.CP0.r[num] = newValue._u32[0];
|
|
break;
|
|
case EECAT_FPR:
|
|
fpuRegs.fpr[num].UL = newValue._u32[0];
|
|
break;
|
|
case EECAT_FCR:
|
|
fpuRegs.fprc[num] = newValue._u32[0];
|
|
break;
|
|
case EECAT_VU0F:
|
|
switch (num)
|
|
{
|
|
case 32: // ACC
|
|
VU0.ACC.UQ = newValue;
|
|
break;
|
|
default:
|
|
VU0.VF[num].UQ = newValue;
|
|
break;
|
|
}
|
|
break;
|
|
case EECAT_VU0I:
|
|
VU0.VI[num].UL = newValue._u32[0];
|
|
break;
|
|
case EECAT_GSPRIV:
|
|
memWrite64(0x12000000 | R5900::GS_REG_PRIV_ADDR[num], newValue.lo);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
std::string R5900DebugInterface::disasm(u32 address, bool simplify)
|
|
{
|
|
std::string out;
|
|
|
|
u32 op = read32(address);
|
|
R5900::disR5900Fasm(out, op, address, simplify);
|
|
return out;
|
|
}
|
|
|
|
bool R5900DebugInterface::isValidAddress(u32 addr)
|
|
{
|
|
u32 lopart = addr & 0xfFFffFF;
|
|
|
|
// get rid of ee ram mirrors
|
|
switch (addr >> 28)
|
|
{
|
|
case 0:
|
|
case 2:
|
|
// case 3: throw exception (not mapped ?)
|
|
// [ 0000_8000 - 01FF_FFFF ] RAM
|
|
// [ 2000_8000 - 21FF_FFFF ] RAM MIRROR
|
|
// [ 3000_8000 - 31FF_FFFF ] RAM MIRROR
|
|
if (lopart >= 0x80000 && lopart <= 0x1ffFFff)
|
|
return !!vtlb_GetPhyPtr(lopart);
|
|
break;
|
|
case 1:
|
|
// [ 1000_0000 - 1000_CFFF ] EE register
|
|
if (lopart <= 0xcfff)
|
|
return true;
|
|
|
|
// [ 1100_0000 - 1100_FFFF ] VU mem
|
|
if (lopart >= 0x1000000 && lopart <= 0x100FFff)
|
|
return true;
|
|
|
|
// [ 1200_0000 - 1200_FFFF ] GS regs
|
|
if (lopart >= 0x2000000 && lopart <= 0x20010ff)
|
|
return true;
|
|
|
|
// [ 1E00_0000 - 1FFF_FFFF ] ROM
|
|
// if (lopart >= 0xe000000)
|
|
// return true; throw exception (not mapped ?)
|
|
break;
|
|
case 7:
|
|
// [ 7000_0000 - 7000_3FFF ] Scratchpad
|
|
if (lopart <= 0x3fff)
|
|
return true;
|
|
break;
|
|
case 8:
|
|
case 9:
|
|
case 0xA:
|
|
case 0xB:
|
|
// [ 8000_0000 - BFFF_FFFF ] kernel
|
|
return true;
|
|
case 0xF:
|
|
// [ 8000_0000 - BFFF_FFFF ] IOP or kernel stack
|
|
if (lopart >= 0xfff8000)
|
|
return true;
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
u32 R5900DebugInterface::getCycles()
|
|
{
|
|
return cpuRegs.cycle;
|
|
}
|
|
|
|
SymbolMap& R5900DebugInterface::GetSymbolMap() const
|
|
{
|
|
return R5900SymbolMap;
|
|
}
|
|
|
|
//
|
|
// R3000DebugInterface
|
|
//
|
|
|
|
|
|
BreakPointCpu R3000DebugInterface::getCpuType()
|
|
{
|
|
return BREAKPOINT_IOP;
|
|
}
|
|
|
|
u32 R3000DebugInterface::read8(u32 address)
|
|
{
|
|
if (!isValidAddress(address))
|
|
return -1;
|
|
return iopMemRead8(address);
|
|
}
|
|
|
|
u32 R3000DebugInterface::read16(u32 address)
|
|
{
|
|
if (!isValidAddress(address))
|
|
return -1;
|
|
return iopMemRead16(address);
|
|
}
|
|
|
|
u32 R3000DebugInterface::read32(u32 address)
|
|
{
|
|
if (!isValidAddress(address))
|
|
return -1;
|
|
return iopMemRead32(address);
|
|
}
|
|
|
|
u64 R3000DebugInterface::read64(u32 address)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
u128 R3000DebugInterface::read128(u32 address)
|
|
{
|
|
return u128::From32(0);
|
|
}
|
|
|
|
void R3000DebugInterface::write8(u32 address, u8 value)
|
|
{
|
|
if (!isValidAddress(address))
|
|
return;
|
|
|
|
iopMemWrite8(address, value);
|
|
}
|
|
|
|
void R3000DebugInterface::write32(u32 address, u32 value)
|
|
{
|
|
if (!isValidAddress(address))
|
|
return;
|
|
|
|
iopMemWrite32(address, value);
|
|
}
|
|
|
|
int R3000DebugInterface::getRegisterCategoryCount()
|
|
{
|
|
return IOPCAT_COUNT;
|
|
}
|
|
|
|
const char* R3000DebugInterface::getRegisterCategoryName(int cat)
|
|
{
|
|
switch (cat)
|
|
{
|
|
case IOPCAT_GPR:
|
|
return "GPR";
|
|
default:
|
|
return "Invalid";
|
|
}
|
|
}
|
|
|
|
int R3000DebugInterface::getRegisterSize(int cat)
|
|
{
|
|
switch (cat)
|
|
{
|
|
case IOPCAT_GPR:
|
|
return 32;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int R3000DebugInterface::getRegisterCount(int cat)
|
|
{
|
|
switch (cat)
|
|
{
|
|
case IOPCAT_GPR:
|
|
return 35; // 32 + pc + hi + lo
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
DebugInterface::RegisterType R3000DebugInterface::getRegisterType(int cat)
|
|
{
|
|
switch (cat)
|
|
{
|
|
case IOPCAT_GPR:
|
|
default:
|
|
return DebugInterface::NORMAL;
|
|
}
|
|
}
|
|
|
|
const char* R3000DebugInterface::getRegisterName(int cat, int num)
|
|
{
|
|
switch (cat)
|
|
{
|
|
case IOPCAT_GPR:
|
|
switch (num)
|
|
{
|
|
case 32: // pc
|
|
return "pc";
|
|
case 33: // hi
|
|
return "hi";
|
|
case 34: // lo
|
|
return "lo";
|
|
default:
|
|
return R5900::GPR_REG[num];
|
|
}
|
|
default:
|
|
return "Invalid";
|
|
}
|
|
}
|
|
|
|
u128 R3000DebugInterface::getRegister(int cat, int num)
|
|
{
|
|
u32 value;
|
|
|
|
switch (cat)
|
|
{
|
|
case IOPCAT_GPR:
|
|
switch (num)
|
|
{
|
|
case 32: // pc
|
|
value = psxRegs.pc;
|
|
break;
|
|
case 33: // hi
|
|
value = psxRegs.GPR.n.hi;
|
|
break;
|
|
case 34: // lo
|
|
value = psxRegs.GPR.n.lo;
|
|
break;
|
|
default:
|
|
value = psxRegs.GPR.r[num];
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
value = -1;
|
|
break;
|
|
}
|
|
|
|
return u128::From32(value);
|
|
}
|
|
|
|
std::string R3000DebugInterface::getRegisterString(int cat, int num)
|
|
{
|
|
switch (cat)
|
|
{
|
|
case IOPCAT_GPR:
|
|
return StringUtil::U128ToString(getRegister(cat, num));
|
|
default:
|
|
return "Invalid";
|
|
}
|
|
}
|
|
|
|
u128 R3000DebugInterface::getHI()
|
|
{
|
|
return u128::From32(psxRegs.GPR.n.hi);
|
|
}
|
|
|
|
u128 R3000DebugInterface::getLO()
|
|
{
|
|
return u128::From32(psxRegs.GPR.n.lo);
|
|
}
|
|
|
|
u32 R3000DebugInterface::getPC()
|
|
{
|
|
return psxRegs.pc;
|
|
}
|
|
|
|
void R3000DebugInterface::setPc(u32 newPc)
|
|
{
|
|
psxRegs.pc = newPc;
|
|
}
|
|
|
|
void R3000DebugInterface::setRegister(int cat, int num, u128 newValue)
|
|
{
|
|
switch (cat)
|
|
{
|
|
case IOPCAT_GPR:
|
|
switch (num)
|
|
{
|
|
case 32: // pc
|
|
psxRegs.pc = newValue._u32[0];
|
|
break;
|
|
case 33: // hi
|
|
psxRegs.GPR.n.hi = newValue._u32[0];
|
|
break;
|
|
case 34: // lo
|
|
psxRegs.GPR.n.lo = newValue._u32[0];
|
|
break;
|
|
default:
|
|
psxRegs.GPR.r[num] = newValue._u32[0];
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
std::string R3000DebugInterface::disasm(u32 address, bool simplify)
|
|
{
|
|
std::string out;
|
|
|
|
u32 op = read32(address);
|
|
R5900::disR5900Fasm(out, op, address, simplify);
|
|
return out;
|
|
}
|
|
|
|
bool R3000DebugInterface::isValidAddress(u32 addr)
|
|
{
|
|
if (addr >= 0x10000000 && addr < 0x10010000)
|
|
return true;
|
|
if (addr >= 0x12000000 && addr < 0x12001100)
|
|
return true;
|
|
if (addr >= 0x70000000 && addr < 0x70004000)
|
|
return true;
|
|
|
|
return !(addr & 0x40000000) && vtlb_GetPhyPtr(addr & 0x1FFFFFFF) != NULL;
|
|
}
|
|
|
|
u32 R3000DebugInterface::getCycles()
|
|
{
|
|
return psxRegs.cycle;
|
|
}
|
|
|
|
SymbolMap& R3000DebugInterface::GetSymbolMap() const
|
|
{
|
|
return R3000SymbolMap;
|
|
}
|