2013-11-03 20:23:16 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
2018-09-26 00:14:10 +02:00
|
|
|
#include <string>
|
|
|
|
|
#include "Utilities/StrFmt.h"
|
|
|
|
|
|
2021-01-22 09:11:54 +01:00
|
|
|
enum class cpu_disasm_mode
|
2013-11-03 20:23:16 +01:00
|
|
|
{
|
2021-01-22 09:11:54 +01:00
|
|
|
dump,
|
|
|
|
|
interpreter,
|
|
|
|
|
normal,
|
|
|
|
|
compiler_elf,
|
|
|
|
|
list, // RSX exclusive
|
2022-03-25 16:17:25 +01:00
|
|
|
survey_cmd_size, // RSX exclusive
|
2013-11-03 20:23:16 +01:00
|
|
|
};
|
|
|
|
|
|
2021-01-22 09:11:54 +01:00
|
|
|
class cpu_thread;
|
|
|
|
|
|
2013-11-03 20:23:16 +01:00
|
|
|
class CPUDisAsm
|
|
|
|
|
{
|
|
|
|
|
protected:
|
2021-10-12 22:12:30 +02:00
|
|
|
cpu_disasm_mode m_mode{};
|
2021-10-30 16:37:53 +02:00
|
|
|
const u8* m_offset{};
|
2021-10-12 22:12:30 +02:00
|
|
|
const u32 m_start_pc;
|
2021-03-30 17:31:46 +02:00
|
|
|
const std::add_pointer_t<const cpu_thread> m_cpu{};
|
2020-12-16 17:50:21 +01:00
|
|
|
u32 m_op = 0;
|
2013-11-03 20:23:16 +01:00
|
|
|
|
2021-10-12 22:12:30 +02:00
|
|
|
void format_by_mode()
|
2013-11-03 20:23:16 +01:00
|
|
|
{
|
2020-12-10 11:37:26 +01:00
|
|
|
switch (m_mode)
|
2013-11-03 20:23:16 +01:00
|
|
|
{
|
2021-01-22 09:11:54 +01:00
|
|
|
case cpu_disasm_mode::dump:
|
2020-11-10 15:57:06 +01:00
|
|
|
{
|
2015-01-18 23:54:56 +01:00
|
|
|
last_opcode = fmt::format("\t%08x:\t%02x %02x %02x %02x\t%s\n", dump_pc,
|
2020-12-16 17:50:21 +01:00
|
|
|
static_cast<u8>(m_op >> 24),
|
|
|
|
|
static_cast<u8>(m_op >> 16),
|
|
|
|
|
static_cast<u8>(m_op >> 8),
|
2021-10-12 22:12:30 +02:00
|
|
|
static_cast<u8>(m_op >> 0), last_opcode);
|
2020-11-10 15:57:06 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2013-11-03 20:23:16 +01:00
|
|
|
|
2021-01-22 09:11:54 +01:00
|
|
|
case cpu_disasm_mode::interpreter:
|
2020-11-10 15:57:06 +01:00
|
|
|
{
|
2021-10-12 22:12:30 +02:00
|
|
|
last_opcode.insert(0, fmt::format("[%08x] %02x %02x %02x %02x: ", dump_pc,
|
2020-12-16 17:50:21 +01:00
|
|
|
static_cast<u8>(m_op >> 24),
|
|
|
|
|
static_cast<u8>(m_op >> 16),
|
|
|
|
|
static_cast<u8>(m_op >> 8),
|
2021-10-12 22:12:30 +02:00
|
|
|
static_cast<u8>(m_op >> 0)));
|
2020-11-10 15:57:06 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2013-11-03 20:23:16 +01:00
|
|
|
|
2021-01-22 09:11:54 +01:00
|
|
|
case cpu_disasm_mode::compiler_elf:
|
2020-11-10 15:57:06 +01:00
|
|
|
{
|
2021-10-12 22:12:30 +02:00
|
|
|
last_opcode += '\n';
|
2020-11-10 15:57:06 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2021-01-22 09:11:54 +01:00
|
|
|
case cpu_disasm_mode::normal:
|
2020-11-10 15:57:06 +01:00
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-12-10 11:37:26 +01:00
|
|
|
default: fmt::throw_exception("Unreachable");
|
2013-11-03 20:23:16 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
2021-03-30 17:31:46 +02:00
|
|
|
std::string last_opcode{};
|
|
|
|
|
u32 dump_pc{};
|
2013-11-03 20:23:16 +01:00
|
|
|
|
2021-10-30 16:37:53 +02:00
|
|
|
cpu_disasm_mode change_mode(cpu_disasm_mode mode)
|
2021-01-22 09:11:54 +01:00
|
|
|
{
|
2021-10-30 16:37:53 +02:00
|
|
|
return std::exchange(m_mode, mode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const u8* change_ptr(const u8* ptr)
|
|
|
|
|
{
|
|
|
|
|
return std::exchange(m_offset, ptr);
|
2021-01-22 09:11:54 +01:00
|
|
|
}
|
|
|
|
|
|
2013-11-03 20:23:16 +01:00
|
|
|
protected:
|
2021-10-12 22:12:30 +02:00
|
|
|
CPUDisAsm(cpu_disasm_mode mode, const u8* offset, u32 start_pc = 0, const cpu_thread* cpu = nullptr)
|
2013-11-03 20:23:16 +01:00
|
|
|
: m_mode(mode)
|
2021-10-12 22:12:30 +02:00
|
|
|
, m_offset(offset - start_pc)
|
|
|
|
|
, m_start_pc(start_pc)
|
2021-01-22 09:11:54 +01:00
|
|
|
, m_cpu(cpu)
|
2013-11-03 20:23:16 +01:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-30 17:31:46 +02:00
|
|
|
CPUDisAsm& operator=(const CPUDisAsm&) = delete;
|
|
|
|
|
|
|
|
|
|
virtual u32 DisAsmBranchTarget(s32 /*imm*/);
|
2013-11-03 20:23:16 +01:00
|
|
|
|
2020-08-20 23:07:31 +02:00
|
|
|
// TODO: Add builtin fmt helpper for best performance
|
|
|
|
|
template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
|
|
|
|
|
static std::string SignedHex(T value)
|
|
|
|
|
{
|
|
|
|
|
const auto v = static_cast<std::make_signed_t<T>>(value);
|
2020-10-22 23:09:00 +02:00
|
|
|
|
2021-05-22 20:46:10 +02:00
|
|
|
if (v == smin)
|
2020-10-22 23:09:00 +02:00
|
|
|
{
|
|
|
|
|
// for INTx_MIN
|
|
|
|
|
return fmt::format("-0x%x", v);
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-20 23:07:31 +02:00
|
|
|
const auto av = std::abs(v);
|
|
|
|
|
|
|
|
|
|
if (av < 10)
|
|
|
|
|
{
|
|
|
|
|
// Does not need hex
|
|
|
|
|
return fmt::format("%d", v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fmt::format("%s%s", v < 0 ? "-" : "", av);
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-12 22:12:30 +02:00
|
|
|
// Signify the formatting function the minimum required amount of characters to print for an instruction
|
|
|
|
|
// Padding with spaces
|
|
|
|
|
int PadOp(std::string_view op = {}, int min_spaces = 0) const
|
2013-11-03 20:23:16 +01:00
|
|
|
{
|
2021-10-12 22:12:30 +02:00
|
|
|
return m_mode == cpu_disasm_mode::normal ? (static_cast<int>(op.size()) + min_spaces) : 10;
|
2013-11-03 20:23:16 +01:00
|
|
|
}
|
2016-04-14 00:59:00 +02:00
|
|
|
|
|
|
|
|
public:
|
2021-10-12 22:12:30 +02:00
|
|
|
virtual ~CPUDisAsm() = default;
|
|
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
virtual u32 disasm(u32 pc) = 0;
|
2021-10-12 22:12:30 +02:00
|
|
|
virtual std::pair<const void*, usz> get_memory_span() const = 0;
|
|
|
|
|
virtual std::unique_ptr<CPUDisAsm> copy_type_erased() const = 0;
|
2013-11-19 11:30:58 +01:00
|
|
|
};
|