Debugger/Disasm: Name PPU Syscalls

This commit is contained in:
Eladash 2021-09-27 21:22:05 +03:00 committed by Ivan
parent 2821eb7397
commit 34c36c73ee
3 changed files with 150 additions and 1 deletions

View file

@ -1,11 +1,16 @@
#include "stdafx.h" #include "stdafx.h"
#include "PPUDisAsm.h" #include "PPUDisAsm.h"
#include "PPUFunction.h" #include "PPUFunction.h"
#include "PPUAnalyser.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
const ppu_decoder<PPUDisAsm> s_ppu_disasm; const ppu_decoder<PPUDisAsm> s_ppu_disasm;
const ppu_decoder<ppu_itype> s_ppu_itype;
extern const std::unordered_map<u32, std::string_view>& get_exported_function_names_as_addr_indexed_map(); extern const std::unordered_map<u32, std::string_view>& get_exported_function_names_as_addr_indexed_map();
enum class ppu_syscall_code : u64;
u32 PPUDisAsm::disasm(u32 pc) u32 PPUDisAsm::disasm(u32 pc)
{ {
dump_pc = pc; dump_pc = pc;
@ -14,6 +19,11 @@ u32 PPUDisAsm::disasm(u32 pc)
m_op = op; m_op = op;
(this->*(s_ppu_disasm.decode(m_op)))({ m_op }); (this->*(s_ppu_disasm.decode(m_op)))({ m_op });
if (m_mode != cpu_disasm_mode::interpreter && m_mode != cpu_disasm_mode::normal)
{
return 4;
}
const auto& map = get_exported_function_names_as_addr_indexed_map(); const auto& map = get_exported_function_names_as_addr_indexed_map();
if (auto it = map.find(pc); it != map.end()) if (auto it = map.find(pc); it != map.end())
@ -25,6 +35,137 @@ u32 PPUDisAsm::disasm(u32 pc)
return 4; return 4;
} }
std::pair<bool, u64> PPUDisAsm::try_get_const_gpr_value(u32 reg, u32 pc) const
{
if (m_mode != cpu_disasm_mode::interpreter && m_mode != cpu_disasm_mode::normal)
{
return {};
}
if (pc == umax)
{
pc = dump_pc;
}
if (!vm::check_addr(pc, vm::page_executable))
{
return {};
}
// Scan PPU executable memory backwards until unmapped or non-executable memory block is encountered
for (u32 i = pc - 4; vm::check_addr(i, vm::page_executable); i -= 4)
{
const u32 opcode = *reinterpret_cast<const be_t<u32>*>(m_offset + i);
const ppu_opcode_t op{ opcode };
const auto type = s_ppu_itype.decode(opcode);
auto is_branch = [](enum ppu_itype::type itype)
{
return itype == ppu_itype::BC || itype == ppu_itype::B || itype == ppu_itype::BCLR || itype == ppu_itype::BCCTR;
};
if (is_branch(type) || type == ppu_itype::UNK)
{
// TODO: Detect calls, ignore them if reg is a non-volatile register
return {};
}
// Get constant register value
#define GET_CONST_REG(var, reg) \
{\
/* Search for the constant value of the register*/\
const auto [is_const, value] = try_get_const_gpr_value(reg, i);\
\
if (!is_const)\
{\
/* Cannot compute constant value if register is not constant*/\
return {};\
}\
\
var = value;\
} void() /*<- Require a semicolon*/
switch (type)
{
case ppu_itype::ADDI:
{
if (op.rd != reg)
{
// Destination register is not relevant to us
break;
}
u64 reg_ra = 0;
if (op.ra)
{
GET_CONST_REG(reg_ra, op.ra);
}
return { true, reg_ra + op.simm16 };
}
case ppu_itype::ADDIS:
{
if (op.rd != reg)
{
break;
}
u64 reg_ra = 0;
if (op.ra)
{
GET_CONST_REG(reg_ra, op.ra);
}
return { true, reg_ra + op.simm16 * 65536 };
}
case ppu_itype::ORI:
{
if (op.ra != reg)
{
// Destination register is not relevant to us
break;
}
u64 reg_rs = 0;
GET_CONST_REG(reg_rs, op.rs);
return { true, reg_rs | op.uimm16 };
}
case ppu_itype::ORIS:
{
if (op.ra != reg)
{
break;
}
u64 reg_rs = 0;
GET_CONST_REG(reg_rs, op.rs);
return { true, reg_rs | (u64{op.uimm16} << 16)};
}
default:
{
// Ordinary test
// TODO: Proper detection of destination register(s) modification (if there are any)
if (op.ra == reg || op.rd == reg)
{
return {};
}
break;
}
}
}
return {};
}
constexpr std::pair<const char*, char> get_BC_info(u32 bo, u32 bi) constexpr std::pair<const char*, char> get_BC_info(u32 bo, u32 bi)
{ {
std::pair<const char*, char> info{}; std::pair<const char*, char> info{};
@ -999,6 +1140,13 @@ void PPUDisAsm::SC(ppu_opcode_t op)
return UNK(op); return UNK(op);
} }
// Try to get constant syscall index
if (auto [is_const, index] = try_get_const_gpr_value(11); is_const && index < 1024u)
{
Write(fmt::format("sc #%s", ppu_syscall_code{index}));
return;
}
Write("sc"); Write("sc");
} }

View file

@ -287,6 +287,7 @@ private:
public: public:
u32 disasm(u32 pc) override; u32 disasm(u32 pc) override;
std::pair<bool, u64> try_get_const_gpr_value(u32 reg, u32 pc = -1) const;
void MFVSCR(ppu_opcode_t op); void MFVSCR(ppu_opcode_t op);
void MTVSCR(ppu_opcode_t op); void MTVSCR(ppu_opcode_t op);

View file

@ -22,7 +22,7 @@ u32 SPUDisAsm::disasm(u32 pc)
std::pair<bool, v128> SPUDisAsm::try_get_const_value(u32 reg, u32 pc) const std::pair<bool, v128> SPUDisAsm::try_get_const_value(u32 reg, u32 pc) const
{ {
if (m_mode != cpu_disasm_mode::interpreter) if (m_mode != cpu_disasm_mode::interpreter && m_mode != cpu_disasm_mode::normal)
{ {
return {}; return {};
} }