debugger work
This commit is contained in:
@@ -29,3 +29,11 @@ using m128 = __m128i;
|
|||||||
#define HALF_ADDRESS(addr) ((addr) ^ 2)
|
#define HALF_ADDRESS(addr) ((addr) ^ 2)
|
||||||
#define BYTE_ADDRESS(addr) ((addr) ^ 3)
|
#define BYTE_ADDRESS(addr) ((addr) ^ 3)
|
||||||
#define ASPECT_RATIO ((float)4/3)
|
#define ASPECT_RATIO ((float)4/3)
|
||||||
|
|
||||||
|
#define RD(x) (((x) >> 11) & 0x1F)
|
||||||
|
#define RT(x) (((x) >> 16) & 0x1F)
|
||||||
|
#define RS(x) (((x) >> 21) & 0x1F)
|
||||||
|
#define FD(x) (((x) >> 6) & 0x1F)
|
||||||
|
#define FT(x) RT(x)
|
||||||
|
#define FS(x) RD(x)
|
||||||
|
#define BASE(x) RS(x)
|
||||||
@@ -11,10 +11,17 @@ add_library(frontend-imgui STATIC
|
|||||||
Window.cpp
|
Window.cpp
|
||||||
Window.hpp
|
Window.hpp
|
||||||
widgets.cpp
|
widgets.cpp
|
||||||
debugger.hpp debugger.cpp)
|
debugger.hpp
|
||||||
|
debugger.cpp
|
||||||
|
debugger/cpu/decode.hpp
|
||||||
|
debugger/cop0/decode.hpp
|
||||||
|
debugger/fpu/decode.hpp
|
||||||
|
debugger/rsp/decode.hpp
|
||||||
|
debugger/debugger_common.hpp)
|
||||||
|
|
||||||
target_include_directories(frontend-imgui PUBLIC
|
target_include_directories(frontend-imgui PUBLIC
|
||||||
.
|
.
|
||||||
|
debugger
|
||||||
../..
|
../..
|
||||||
../../n64
|
../../n64
|
||||||
../../n64/core
|
../../n64/core
|
||||||
|
|||||||
@@ -1,115 +1,2 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
#include <debugger.hpp>
|
#include <debugger.hpp>
|
||||||
|
|
||||||
void DebugStart(void* user_data) {
|
|
||||||
auto* core = (n64::Core*)user_data;
|
|
||||||
core->debuggerState.broken = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebugStop(void* user_data) {
|
|
||||||
auto* core = (n64::Core*)user_data;
|
|
||||||
core->debuggerState.broken = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebugStep(void* user_data) {
|
|
||||||
auto* core = (n64::Core*)user_data;
|
|
||||||
bool old_broken = core->debuggerState.broken;
|
|
||||||
core->debuggerState.broken = false;
|
|
||||||
core->Step();
|
|
||||||
core->debuggerState.broken = old_broken;
|
|
||||||
core->debuggerState.steps += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebugSetBreakpoint(void* user_data, u32 address) {
|
|
||||||
auto* core = (n64::Core*)user_data;
|
|
||||||
auto* breakpoint = (Breakpoint*)malloc(sizeof(Breakpoint));
|
|
||||||
breakpoint->addr = address;
|
|
||||||
breakpoint->next = NULL;
|
|
||||||
|
|
||||||
// Special case for this being the first breakpoint
|
|
||||||
if (core->debuggerState.breakpoints == NULL) {
|
|
||||||
core->debuggerState.breakpoints = breakpoint;
|
|
||||||
} else {
|
|
||||||
// Find end of the list
|
|
||||||
Breakpoint* tail = core->debuggerState.breakpoints;
|
|
||||||
while (tail->next != NULL) {
|
|
||||||
tail = tail->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
tail->next = breakpoint;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebugClearBreakpoint(void* user_data, u32 address) {
|
|
||||||
auto* core = (n64::Core*)user_data;
|
|
||||||
if (core->debuggerState.breakpoints == NULL) {
|
|
||||||
return; // No breakpoints set at all
|
|
||||||
} else if (core->debuggerState.breakpoints->addr == address) {
|
|
||||||
// Special case for the first breakpoint being the one we want to clear
|
|
||||||
Breakpoint* next = core->debuggerState.breakpoints->next;
|
|
||||||
free(core->debuggerState.breakpoints);
|
|
||||||
core->debuggerState.breakpoints = next;
|
|
||||||
} else {
|
|
||||||
// Find the breakpoint somewhere in the list and free it
|
|
||||||
Breakpoint* iter = core->debuggerState.breakpoints;
|
|
||||||
while (iter->next != NULL) {
|
|
||||||
if (iter->next->addr == address) {
|
|
||||||
Breakpoint* next = iter->next->next;
|
|
||||||
free(iter->next);
|
|
||||||
iter->next = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t DebugGetMemory(void* user_data, char* buffer, size_t length, u32 address, size_t bytes) {
|
|
||||||
auto* core = (n64::Core*)user_data;
|
|
||||||
printf("Checking memory at address 0x%08X\n", address);
|
|
||||||
int printed = 0;
|
|
||||||
for (int i = 0; i < bytes; i++) {
|
|
||||||
u8 value = core->mem.Read<u8>(core->cpu.regs, address + i, core->cpu.regs.pc);
|
|
||||||
printed += snprintf(buffer + (i*2), length, "%02X", value);
|
|
||||||
}
|
|
||||||
printf("Get memory: %ld bytes from 0x%08X: %d\n", bytes, address, printed);
|
|
||||||
return printed + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t DebugGetRegisterValue(void* user_data, char * buffer, size_t buffer_length, int reg) {
|
|
||||||
auto* core = (n64::Core*)user_data;
|
|
||||||
switch (reg) {
|
|
||||||
case 0 ... 31:
|
|
||||||
return snprintf(buffer, buffer_length, "%016llx", core->cpu.regs.gpr[reg]);
|
|
||||||
case 32:
|
|
||||||
return snprintf(buffer, buffer_length, "%08x", core->cpu.regs.cop0.status.raw);
|
|
||||||
case 33:
|
|
||||||
return snprintf(buffer, buffer_length, "%016llx", core->cpu.regs.lo);
|
|
||||||
case 34:
|
|
||||||
return snprintf(buffer, buffer_length, "%016llx", core->cpu.regs.hi);
|
|
||||||
case 35:
|
|
||||||
return snprintf(buffer, buffer_length, "%016llx", core->cpu.regs.cop0.badVaddr);
|
|
||||||
case 36:
|
|
||||||
return snprintf(buffer, buffer_length, "%08x", core->cpu.regs.cop0.cause.raw);
|
|
||||||
case 37:
|
|
||||||
printf("Sending PC: 0x%016llX\n", core->cpu.regs.pc);
|
|
||||||
return snprintf(buffer, buffer_length, "%016llx", core->cpu.regs.pc);
|
|
||||||
case 38 ... 71: // TODO FPU stuff
|
|
||||||
return snprintf(buffer, buffer_length, "%08x", 0);
|
|
||||||
default:
|
|
||||||
util::panic("debug get register {} value", reg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t DebugGetGeneralRegisters(void* user_data, char * buffer, size_t buffer_length) {
|
|
||||||
auto* core = (n64::Core*)user_data;
|
|
||||||
printf("The buffer length is %zu!\n", buffer_length);
|
|
||||||
ssize_t printed = 0;
|
|
||||||
for (int i = 0; i < 32; i++) {
|
|
||||||
int ofs = i * 16; // 64 bit regs take up 16 ascii chars to print in hex
|
|
||||||
if (ofs + 16 > buffer_length) {
|
|
||||||
util::panic("Too big!");
|
|
||||||
}
|
|
||||||
u64 reg = core->cpu.regs.gpr[i];
|
|
||||||
printed += snprintf(buffer + ofs, buffer_length - ofs, "%016llx", reg);
|
|
||||||
}
|
|
||||||
return printed;
|
|
||||||
}
|
|
||||||
@@ -2,96 +2,13 @@
|
|||||||
#include <util.hpp>
|
#include <util.hpp>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <cpu/decode.hpp>
|
||||||
|
#include <fpu/decode.hpp>
|
||||||
|
#include <rsp/decode.hpp>
|
||||||
|
#include <cop0/decode.hpp>
|
||||||
|
|
||||||
struct Core;
|
struct Core;
|
||||||
|
|
||||||
const std::string gprStr[32] = {
|
|
||||||
"zero", "at", "v0", "v1",
|
|
||||||
"a0", "a1", "a2", "a3",
|
|
||||||
"t0", "t1", "t2", "t3",
|
|
||||||
"t4", "t5", "t6", "t7",
|
|
||||||
"s0", "s1", "s2", "s3",
|
|
||||||
"s4", "s5", "s6", "s7",
|
|
||||||
"t8", "t9", "k0", "k1",
|
|
||||||
"gp", "sp", "s8", "ra"
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string special(u32 instr) {
|
|
||||||
u8 mask = (instr & 0x3F);
|
|
||||||
u8 sa = (instr >> 6) & 0x1f;
|
|
||||||
switch (mask) { // TODO: named constants for clearer code
|
|
||||||
case 0:
|
|
||||||
if (mask != 0) {
|
|
||||||
return fmt::format("sll {}, {}, {:02X}", gprStr[RD(instr)], gprStr[RT(instr)], sa);
|
|
||||||
}
|
|
||||||
return "nop";
|
|
||||||
case 0x02: return fmt::format("srl {}, {}, {:02X}", gprStr[RD(instr)], gprStr[RT(instr)], sa);
|
|
||||||
case 0x03: return fmt::format("sra {}, {}, {:02X}", gprStr[RD(instr)], gprStr[RT(instr)], sa);
|
|
||||||
case 0x04: return fmt::format("sllv {}, {}, {}", gprStr[RD(instr)], gprStr[RT(instr)], gprStr[RS(instr)]);
|
|
||||||
case 0x06: return fmt::format("srlv {}, {}, {}", gprStr[RD(instr)], gprStr[RT(instr)], gprStr[RS(instr)]);
|
|
||||||
case 0x07: return fmt::format("srav {}, {}, {}", gprStr[RD(instr)], gprStr[RT(instr)], gprStr[RS(instr)]);
|
|
||||||
case 0x08: return fmt::format("jr {}", gprStr[RS(instr)]);
|
|
||||||
case 0x09: return fmt::format("jalr {}, {}", gprStr[RD(instr)], gprStr[RS(instr)]);
|
|
||||||
case 0x0C: return fmt::format("syscall");
|
|
||||||
case 0x0D: return fmt::format("break");
|
|
||||||
case 0x0F: return fmt::format("sync");
|
|
||||||
case 0x10: return fmt::format("mfhi {}", gprStr[RD(instr)]);
|
|
||||||
case 0x11: return fmt::format("mthi {}", gprStr[RS(instr)]);
|
|
||||||
case 0x12: return fmt::format("mflo {}", gprStr[RD(instr)]);
|
|
||||||
case 0x13: return fmt::format("mtlo {}", gprStr[RS(instr)]);
|
|
||||||
case 0x14: return fmt::format("dsllv {}, {}, {}", gprStr[RD(instr)], gprStr[RT(instr)], gprStr[RS(instr)]);
|
|
||||||
case 0x16: return fmt::format("dsrlv {}, {}, {}", gprStr[RD(instr)], gprStr[RT(instr)], gprStr[RS(instr)]);
|
|
||||||
case 0x17: return fmt::format("dsrav {}, {}, {}", gprStr[RD(instr)], gprStr[RT(instr)], gprStr[RS(instr)]);
|
|
||||||
case 0x18: return fmt::format("mult {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x19: return fmt::format("multu {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x1A: return fmt::format("div {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x1B: return fmt::format("divu {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x1C: return fmt::format("dmult {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x1D: return fmt::format("dmultu {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x1E: return fmt::format("ddiv {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x1F: return fmt::format("ddivu {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x20: return fmt::format("add {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x21: return fmt::format("addu {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x22: return fmt::format("sub {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x23: return fmt::format("subu {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x24: return fmt::format("and {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x25: return fmt::format("or {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x26: return fmt::format("xor {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x27: return fmt::format("nor {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x2A: return fmt::format("slt {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x2B: return fmt::format("sltu {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x2C: return fmt::format("dadd {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x2D: return fmt::format("daddu {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x2E: return fmt::format("dsub {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x2F: return fmt::format("dsubu {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x34: return fmt::format("teq {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]);
|
|
||||||
case 0x38: return fmt::format("dsll {}, {}, {:02X}", gprStr[RD(instr)], gprStr[RS(instr)], sa);
|
|
||||||
case 0x3A: return fmt::format("dsrl {}, {}, {:02X}", gprStr[RD(instr)], gprStr[RS(instr)], sa);
|
|
||||||
case 0x3B: return fmt::format("dsra {}, {}, {:02X}", gprStr[RD(instr)], gprStr[RS(instr)], sa);
|
|
||||||
case 0x3C: return fmt::format("dsll32 {}, {}, {:02X}", gprStr[RD(instr)], gprStr[RS(instr)], sa);
|
|
||||||
case 0x3E: return fmt::format("dsrl32 {}, {}, {:02X}", gprStr[RD(instr)], gprStr[RS(instr)], sa);
|
|
||||||
case 0x3F: return fmt::format("dsra32 {}, {}, {:02X}", gprStr[RD(instr)], gprStr[RS(instr)], sa);
|
|
||||||
default:
|
|
||||||
return fmt::format("INVALID ({:08X})\n", instr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string regimm(u32 instr) {
|
|
||||||
u8 mask = ((instr >> 16) & 0x1F);
|
|
||||||
// 000r_rccc
|
|
||||||
switch (mask) { // TODO: named constants for clearer code
|
|
||||||
case 0x00: return fmt::format("bltz {}", gprStr[RS(instr)]);
|
|
||||||
case 0x01: return fmt::format("bgez {}", gprStr[RS(instr)]);
|
|
||||||
case 0x02: return fmt::format("bltzl {}", gprStr[RS(instr)]);
|
|
||||||
case 0x03: return fmt::format("bgezl {}", gprStr[RS(instr)]);
|
|
||||||
case 0x10: return fmt::format("bltzal {}", gprStr[RS(instr)]);
|
|
||||||
case 0x11: return fmt::format("bgezal {}", gprStr[RS(instr)]);
|
|
||||||
case 0x12: return fmt::format("bltzall {}", gprStr[RS(instr)]);
|
|
||||||
case 0x13: return fmt::format("bgezall {}", gprStr[RS(instr)]);
|
|
||||||
default: return fmt::format("INVALID {:08X}", instr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::map<u8, std::function<std::string(u32)>> cpuInstr = {
|
const std::map<u8, std::function<std::string(u32)>> cpuInstr = {
|
||||||
{0b000000, special},
|
{0b000000, special},
|
||||||
{0b000001, regimm},
|
{0b000001, regimm},
|
||||||
@@ -123,10 +40,9 @@ const std::map<u8, std::function<std::string(u32)>> cpuInstr = {
|
|||||||
return fmt::format("xori {}", gprStr[RS(instr)]);
|
return fmt::format("xori {}", gprStr[RS(instr)]);
|
||||||
}}, {0b001111, [](u32 instr) {
|
}}, {0b001111, [](u32 instr) {
|
||||||
return fmt::format("lui {}", gprStr[RS(instr)]);
|
return fmt::format("lui {}", gprStr[RS(instr)]);
|
||||||
}}, {0b010000, /*cop0decode*/ },
|
}}, {0b010000, cop0decode
|
||||||
{0b010001, [](u32 instr) {
|
}, {0b010001, cop1decode
|
||||||
return fmt::format("j {:08X}", instr & 0x3FFFFFF);
|
}, {0b010010, [](u32 instr) {
|
||||||
}}, {0b010010, [](u32 instr) {
|
|
||||||
return fmt::format("j {:08X}", instr & 0x3FFFFFF);
|
return fmt::format("j {:08X}", instr & 0x3FFFFFF);
|
||||||
}}, {0b010011, [](u32 instr) {
|
}}, {0b010011, [](u32 instr) {
|
||||||
return fmt::format("jal {:08X}", instr & 0x3FFFFFF);
|
return fmt::format("jal {:08X}", instr & 0x3FFFFFF);
|
||||||
|
|||||||
22
src/frontend/imgui/debugger/cop0/decode.hpp
Normal file
22
src/frontend/imgui/debugger/cop0/decode.hpp
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <debugger_common.hpp>
|
||||||
|
|
||||||
|
inline std::string cop0decode(u32 instr) {
|
||||||
|
u8 mask_cop = (instr >> 21) & 0x1F;
|
||||||
|
u8 mask_cop2 = instr & 0x3F;
|
||||||
|
switch(mask_cop) {
|
||||||
|
case 0x00: return fmt::format("mfc0 {}, {}", gprStr[RT(instr)], cop0Str[RD(instr)]);
|
||||||
|
case 0x01: return fmt::format("dmfc0 {}, {}", gprStr[RT(instr)], cop0Str[RD(instr)]);
|
||||||
|
case 0x04: return fmt::format("mtc0 {}, {}", gprStr[RT(instr)], cop0Str[RD(instr)]);
|
||||||
|
case 0x05: return fmt::format("dmtc0 {}, {}", gprStr[RT(instr)], cop0Str[RD(instr)]);
|
||||||
|
case 0x10 ... 0x1F:
|
||||||
|
switch(mask_cop2) {
|
||||||
|
case 0x01: return fmt::format("tlbr");
|
||||||
|
case 0x02: return fmt::format("tlbwi");
|
||||||
|
case 0x08: return fmt::format("tlbp");
|
||||||
|
case 0x18: return fmt::format("eret");
|
||||||
|
default: return fmt::format("INVALID ({:08X})", instr);
|
||||||
|
}
|
||||||
|
default: return fmt::format("INVALID ({:08X})", instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
78
src/frontend/imgui/debugger/cpu/decode.hpp
Normal file
78
src/frontend/imgui/debugger/cpu/decode.hpp
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <debugger_common.hpp>
|
||||||
|
|
||||||
|
inline std::string special(u32 instr) {
|
||||||
|
u8 mask = (instr & 0x3F);
|
||||||
|
u8 sa = (instr >> 6) & 0x1f;
|
||||||
|
switch (mask) {
|
||||||
|
case 0:
|
||||||
|
if (mask != 0) {
|
||||||
|
return fmt::format("sll {}, {}, {:02X}", gprStr[RD(instr)], gprStr[RT(instr)], sa);
|
||||||
|
}
|
||||||
|
return "nop";
|
||||||
|
case 0x02: return fmt::format("srl {}, {}, {:02X}", gprStr[RD(instr)], gprStr[RT(instr)], sa);
|
||||||
|
case 0x03: return fmt::format("sra {}, {}, {:02X}", gprStr[RD(instr)], gprStr[RT(instr)], sa);
|
||||||
|
case 0x04: return fmt::format("sllv {}, {}, {}", gprStr[RD(instr)], gprStr[RT(instr)], gprStr[RS(instr)]);
|
||||||
|
case 0x06: return fmt::format("srlv {}, {}, {}", gprStr[RD(instr)], gprStr[RT(instr)], gprStr[RS(instr)]);
|
||||||
|
case 0x07: return fmt::format("srav {}, {}, {}", gprStr[RD(instr)], gprStr[RT(instr)], gprStr[RS(instr)]);
|
||||||
|
case 0x08: return fmt::format("jr {}", gprStr[RS(instr)]);
|
||||||
|
case 0x09: return fmt::format("jalr {}, {}", gprStr[RD(instr)], gprStr[RS(instr)]);
|
||||||
|
case 0x0C: return fmt::format("syscall");
|
||||||
|
case 0x0D: return fmt::format("break");
|
||||||
|
case 0x0F: return fmt::format("sync");
|
||||||
|
case 0x10: return fmt::format("mfhi {}", gprStr[RD(instr)]);
|
||||||
|
case 0x11: return fmt::format("mthi {}", gprStr[RS(instr)]);
|
||||||
|
case 0x12: return fmt::format("mflo {}", gprStr[RD(instr)]);
|
||||||
|
case 0x13: return fmt::format("mtlo {}", gprStr[RS(instr)]);
|
||||||
|
case 0x14: return fmt::format("dsllv {}, {}, {}", gprStr[RD(instr)], gprStr[RT(instr)], gprStr[RS(instr)]);
|
||||||
|
case 0x16: return fmt::format("dsrlv {}, {}, {}", gprStr[RD(instr)], gprStr[RT(instr)], gprStr[RS(instr)]);
|
||||||
|
case 0x17: return fmt::format("dsrav {}, {}, {}", gprStr[RD(instr)], gprStr[RT(instr)], gprStr[RS(instr)]);
|
||||||
|
case 0x18: return fmt::format("mult {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x19: return fmt::format("multu {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x1A: return fmt::format("div {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x1B: return fmt::format("divu {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x1C: return fmt::format("dmult {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x1D: return fmt::format("dmultu {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x1E: return fmt::format("ddiv {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x1F: return fmt::format("ddivu {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x20: return fmt::format("add {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x21: return fmt::format("addu {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x22: return fmt::format("sub {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x23: return fmt::format("subu {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x24: return fmt::format("and {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x25: return fmt::format("or {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x26: return fmt::format("xor {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x27: return fmt::format("nor {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x2A: return fmt::format("slt {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x2B: return fmt::format("sltu {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x2C: return fmt::format("dadd {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x2D: return fmt::format("daddu {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x2E: return fmt::format("dsub {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x2F: return fmt::format("dsubu {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x34: return fmt::format("teq {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x38: return fmt::format("dsll {}, {}, {:02X}", gprStr[RD(instr)], gprStr[RS(instr)], sa);
|
||||||
|
case 0x3A: return fmt::format("dsrl {}, {}, {:02X}", gprStr[RD(instr)], gprStr[RS(instr)], sa);
|
||||||
|
case 0x3B: return fmt::format("dsra {}, {}, {:02X}", gprStr[RD(instr)], gprStr[RS(instr)], sa);
|
||||||
|
case 0x3C: return fmt::format("dsll32 {}, {}, {:02X}", gprStr[RD(instr)], gprStr[RS(instr)], sa);
|
||||||
|
case 0x3E: return fmt::format("dsrl32 {}, {}, {:02X}", gprStr[RD(instr)], gprStr[RS(instr)], sa);
|
||||||
|
case 0x3F: return fmt::format("dsra32 {}, {}, {:02X}", gprStr[RD(instr)], gprStr[RS(instr)], sa);
|
||||||
|
default:
|
||||||
|
return fmt::format("INVALID ({:08X})", instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string regimm(u32 instr) {
|
||||||
|
u8 mask = ((instr >> 16) & 0x1F);
|
||||||
|
// 000r_rccc
|
||||||
|
switch (mask) { // TODO: named constants for clearer code
|
||||||
|
case 0x00: return fmt::format("bltz {}", gprStr[RS(instr)]);
|
||||||
|
case 0x01: return fmt::format("bgez {}", gprStr[RS(instr)]);
|
||||||
|
case 0x02: return fmt::format("bltzl {}", gprStr[RS(instr)]);
|
||||||
|
case 0x03: return fmt::format("bgezl {}", gprStr[RS(instr)]);
|
||||||
|
case 0x10: return fmt::format("bltzal {}", gprStr[RS(instr)]);
|
||||||
|
case 0x11: return fmt::format("bgezal {}", gprStr[RS(instr)]);
|
||||||
|
case 0x12: return fmt::format("bltzall {}", gprStr[RS(instr)]);
|
||||||
|
case 0x13: return fmt::format("bgezall {}", gprStr[RS(instr)]);
|
||||||
|
default: return fmt::format("INVALID ({:08X})", instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
39
src/frontend/imgui/debugger/debugger_common.hpp
Normal file
39
src/frontend/imgui/debugger/debugger_common.hpp
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <common.hpp>
|
||||||
|
|
||||||
|
const std::string gprStr[32] = {
|
||||||
|
"zero", "at", "v0", "v1",
|
||||||
|
"a0", "a1", "a2", "a3",
|
||||||
|
"t0", "t1", "t2", "t3",
|
||||||
|
"t4", "t5", "t6", "t7",
|
||||||
|
"s0", "s1", "s2", "s3",
|
||||||
|
"s4", "s5", "s6", "s7",
|
||||||
|
"t8", "t9", "k0", "k1",
|
||||||
|
"gp", "sp", "s8", "ra"
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::string cop0Str[32] = {
|
||||||
|
"Index", "Random", "EntryLo0", "EntryLo1",
|
||||||
|
"Context", "PageMask", "Wired", "r7",
|
||||||
|
"BadVAddr", "Count", "EntryHi", "Compare",
|
||||||
|
"Status", "Cause", "EPC", "PRId",
|
||||||
|
"Config", "LLAddr", "WatchLo", "WatchHi",
|
||||||
|
"XContext", "r21", "r22", "r23",
|
||||||
|
"r24", "r25", "Parity Error", "Cache Error",
|
||||||
|
"TagLo", "TagHi", "ErrorEPC", "r31"
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::string fgrStr[32] = {
|
||||||
|
"fgr0", "fgr1", "fgr2", "fgr3",
|
||||||
|
"fgr4", "fgr5", "fgr6", "fgr7",
|
||||||
|
"fgr8", "fgr9", "fgr10", "fgr11",
|
||||||
|
"fgr12", "fgr13", "fgr14", "fgr15",
|
||||||
|
"fgr16", "fgr17", "fgr18", "fgr19",
|
||||||
|
"fgr20", "fgr21", "fgr22", "fgr23",
|
||||||
|
"fgr24", "fgr25", "fgr26", "fgr27",
|
||||||
|
"fgr28", "fgr29", "fgr30", "fgr31"
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::string rspStr[] = {
|
||||||
|
|
||||||
|
};
|
||||||
124
src/frontend/imgui/debugger/fpu/decode.hpp
Normal file
124
src/frontend/imgui/debugger/fpu/decode.hpp
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <debugger_common.hpp>
|
||||||
|
|
||||||
|
inline std::string cop1decode(u32 instr) {
|
||||||
|
u8 mask_sub = (instr >> 21) & 0x1F;
|
||||||
|
u8 mask_fun = instr & 0x3F;
|
||||||
|
u8 mask_branch = (instr >> 16) & 0x1F;
|
||||||
|
switch(mask_sub) {
|
||||||
|
// 000r_rccc
|
||||||
|
case 0x00: return fmt::format("mfc1 {}, {}", gprStr[RT(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x01: return fmt::format("dmfc1 {}, {}", gprStr[RT(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x02: return fmt::format("cfc1 {}, {}", gprStr[RT(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x04: return fmt::format("mtc1 {}, {}", gprStr[RT(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x05: return fmt::format("dmtc1 {}, {}", gprStr[RT(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x06: return fmt::format("ctc1 {}, {}", gprStr[RT(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x08:
|
||||||
|
switch(mask_branch) {
|
||||||
|
case 0: return fmt::format("bcf {:04X}", instr & 0xffff);
|
||||||
|
case 1: return fmt::format("bct {:04X}", instr & 0xffff);
|
||||||
|
case 2: return fmt::format("bcfl {:04X}", instr & 0xffff);
|
||||||
|
case 3: return fmt::format("bctl {:04X}", instr & 0xffff);
|
||||||
|
default: return fmt::format("INVALID ({:08X})", instr);
|
||||||
|
} break;
|
||||||
|
case 0x10: // s
|
||||||
|
switch(mask_fun) {
|
||||||
|
case 0x00: return fmt::format("add.s {}, {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x01: return fmt::format("sub.s {}, {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x02: return fmt::format("mul.s {}, {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x03: return fmt::format("div.s {}, {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x04: return fmt::format("sqrt.s {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x05: return fmt::format("abs.s {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x06: return fmt::format("mov.s {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x07: return fmt::format("neg.s {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x08: return fmt::format("round.l.s {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x09: return fmt::format("trunc.l.s {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x0A: return fmt::format("ceil.l.s {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x0B: return fmt::format("floor.l.s {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x0C: return fmt::format("round.w.s {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x0D: return fmt::format("trunc.w.s {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x0E: return fmt::format("ceil.w.s {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x0F: return fmt::format("floor.w.s {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x21: return fmt::format("cvt.d.s {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x24: return fmt::format("cvt.w.s {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x25: return fmt::format("cvt.l.s {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x30: return fmt::format("c.f.s {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x31: return fmt::format("c.un.s {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x32: return fmt::format("c.eq.s {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x33: return fmt::format("c.ueq.s {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x34: return fmt::format("c.olt.s {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x35: return fmt::format("c.ult.s {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x36: return fmt::format("c.ole.s {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x37: return fmt::format("c.ule.s {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x38: return fmt::format("c.sf.s {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x39: return fmt::format("c.ngle.s {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x3A: return fmt::format("c.seq.s {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x3B: return fmt::format("c.ngl.s {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x3C: return fmt::format("c.lt.s {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x3D: return fmt::format("c.nge.s {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x3E: return fmt::format("c.le.s {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x3F: return fmt::format("c.ngt.s {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
default: return fmt::format("INVALID ({:08X})", instr);
|
||||||
|
} break;
|
||||||
|
case 0x11: // d
|
||||||
|
switch(mask_fun) {
|
||||||
|
case 0x00: return fmt::format("add.d {}, {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x01: return fmt::format("sub.d {}, {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x02: return fmt::format("mul.d {}, {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x03: return fmt::format("div.d {}, {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x04: return fmt::format("sqrt.d {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x05: return fmt::format("abs.d {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x06: return fmt::format("mov.d {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x07: return fmt::format("neg.d {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x08: return fmt::format("round.l.d {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x09: return fmt::format("trunc.l.d {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x0A: return fmt::format("ceil.l.d {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x0B: return fmt::format("floor.l.d {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x0C: return fmt::format("round.w.d {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x0D: return fmt::format("trunc.w.d {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x0E: return fmt::format("ceil.w.d {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x0F: return fmt::format("floor.w.d {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x20: return fmt::format("cvt.s.d {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x24: return fmt::format("cvt.w.d {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x25: return fmt::format("cvt.l.d {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x30: return fmt::format("c.f.d {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x31: return fmt::format("c.un.d {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x32: return fmt::format("c.eq.d {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x33: return fmt::format("c.ueq.d {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x34: return fmt::format("c.olt.d {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x35: return fmt::format("c.ult.d {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x36: return fmt::format("c.ole.d {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x37: return fmt::format("c.ule.d {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x38: return fmt::format("c.sf.d {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x39: return fmt::format("c.ngle.d {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x3A: return fmt::format("c.seq.d {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x3B: return fmt::format("c.ngl.d {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x3C: return fmt::format("c.lt.d {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x3D: return fmt::format("c.nge.d {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x3E: return fmt::format("c.le.d {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x3F: return fmt::format("c.ngt.d {}, {}", fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
default: return fmt::format("INVALID ({:08X})", instr);
|
||||||
|
} break;
|
||||||
|
case 0x14: // w
|
||||||
|
switch(mask_fun) {
|
||||||
|
case 0x01: return fmt::format("sub.w {}, {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x02: return fmt::format("mul.w {}, {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x05: return fmt::format("abs.w {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x06: return fmt::format("mov.w {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x20: return fmt::format("cvt.s.w {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x21: return fmt::format("cvt.d.w {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
default: return fmt::format("INVALID ({:08X})", instr);
|
||||||
|
} break;
|
||||||
|
case 0x15: // l
|
||||||
|
switch(mask_fun) {
|
||||||
|
case 0x01: return fmt::format("sub.l {}, {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x02: return fmt::format("mul.l {}, {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)], fgrStr[FT(instr)]);
|
||||||
|
case 0x05: return fmt::format("abs.l {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x06: return fmt::format("mov.l {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x20: return fmt::format("cvt.s.l {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
case 0x21: return fmt::format("cvt.d.l {}, {}", fgrStr[FD(instr)], fgrStr[FS(instr)]);
|
||||||
|
default: return fmt::format("INVALID ({:08X})", instr);
|
||||||
|
} break;
|
||||||
|
default: return fmt::format("INVALID ({:08X})", instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
101
src/frontend/imgui/debugger/rsp/decode.hpp
Normal file
101
src/frontend/imgui/debugger/rsp/decode.hpp
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <debugger_common.hpp>
|
||||||
|
|
||||||
|
inline std::string rspSpecial(u32 instr) {
|
||||||
|
u8 mask = instr & 0x3f;
|
||||||
|
u8 sa = (instr >> 6) & 0x1f;
|
||||||
|
switch(mask) {
|
||||||
|
case 0x00: return fmt::format("[rsp]: sll {}, {}, {:02X}", gprStr[RD(instr)], gprStr[RT(instr)], sa);
|
||||||
|
case 0x04: return fmt::format("[rsp]: sllv {}, {}, {}", gprStr[RD(instr)], gprStr[RT(instr)], gprStr[RS(instr)]);
|
||||||
|
case 0x08: return fmt::format("[rsp]: jr {}", gprStr[RS(instr)]);
|
||||||
|
case 0x0C: case 0x0D:
|
||||||
|
return fmt::format("[rsp]: break");
|
||||||
|
case 0x20: case 0x21:
|
||||||
|
return fmt::format("[rsp]: add {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x24: return fmt::format("[rsp]: and {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x25: return fmt::format("[rsp]: or {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
case 0x27: return fmt::format("[rsp]: nor {}, {}, {}", gprStr[RD(instr)], gprStr[RS(instr)], gprStr[RT(instr)]);
|
||||||
|
default: return fmt::format("INVALID ({:08X})", instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string rspRegimm(u32 instr) {
|
||||||
|
u8 mask = ((instr >> 16) & 0x1F);
|
||||||
|
switch(mask) {
|
||||||
|
case 0x00: return fmt::format("[rsp]: bltz {}", gprStr[RS(instr)]);
|
||||||
|
case 0x01: return fmt::format("[rsp]: bgez {}", gprStr[RS(instr)]);
|
||||||
|
default: return fmt::format("INVALID ({:08X})", instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string lwc2(u32 instr) {
|
||||||
|
u8 mask = (instr >> 11) & 0x1F;
|
||||||
|
switch(mask) {
|
||||||
|
case 0x04: return fmt::format("lqv", instr);
|
||||||
|
default: return fmt::format("INVALID ({:08X})", instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string swc2(u32 instr) {
|
||||||
|
u8 mask = (instr >> 11) & 0x1F;
|
||||||
|
switch(mask) {
|
||||||
|
//case 0x04: rsp.sqv(instr); break;
|
||||||
|
default: return fmt::format("INVALID ({:08X})", instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string cop2decode(u32 instr) {
|
||||||
|
u8 mask = instr & 0x3F;
|
||||||
|
u8 mask_sub = (instr >> 21) & 0x1F;
|
||||||
|
switch(mask) {
|
||||||
|
case 0x00:
|
||||||
|
switch(mask_sub) {
|
||||||
|
//case 0x02: rsp.cfc2(instr); break;
|
||||||
|
default: return fmt::format("INVALID ({:08X})", instr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
//case 0x13: rsp.vabs(instr); break;
|
||||||
|
//case 0x1D: rsp.vsar(instr); break;
|
||||||
|
//case 0x21: rsp.veq(instr); break;
|
||||||
|
//case 0x22: rsp.vne(instr); break;
|
||||||
|
//case 0x33: rsp.vmov(instr); break;
|
||||||
|
default: return fmt::format("INVALID ({:08X})", instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string rspCop0Decode(u32 instr) {
|
||||||
|
u8 mask = (instr >> 21) & 0x1F;
|
||||||
|
switch(mask) {
|
||||||
|
//case 0x00: rsp.mfc0(rdp, instr); break;
|
||||||
|
//case 0x04: rsp.mtc0(mi, regs, rdp, instr); break;
|
||||||
|
default: return fmt::format("INVALID ({:08X})", instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string rspDecode(u32 instr) {
|
||||||
|
u8 mask = (instr >> 26) & 0x3F;
|
||||||
|
switch(mask) {
|
||||||
|
case 0x00: return special(instr);
|
||||||
|
case 0x01: return regimm(instr);
|
||||||
|
case 0x02: return fmt::format("[rsp]: j {:04X}", instr & 0xffff);
|
||||||
|
case 0x03: return fmt::format("[rsp]: jal {:04X}", instr & 0xffff);
|
||||||
|
case 0x04: return fmt::format("[rsp]: beq {}, {}", gprStr[RT(instr)], gprStr[RS(instr)]);
|
||||||
|
case 0x05: return fmt::format("[rsp]: bne {}, {}", gprStr[RT(instr)], gprStr[RS(instr)]);
|
||||||
|
case 0x07: return fmt::format("[rsp]: bgtz {}", gprStr[RS(instr)]);
|
||||||
|
case 0x08: case 0x09:
|
||||||
|
return fmt::format("[rsp]: addi {}, {}, {:04X}", gprStr[RT(instr)], gprStr[RS(instr)], instr & 0xffff);
|
||||||
|
case 0x0C: return fmt::format("[rsp]: andi {}, {}, {:04X}", instr);
|
||||||
|
case 0x0D: return fmt::format("[rsp]: ori {}, {}, {:04X}", instr);
|
||||||
|
case 0x0F: return fmt::format("[rsp]: lui {}, {:04X}", gprStr[RT(instr)], instr & 0xffff);
|
||||||
|
case 0x10: return rspCop0Decode(instr);
|
||||||
|
case 0x12: return cop2decode(instr);
|
||||||
|
case 0x21: return fmt::format("[rsp]: lh {}, {:04X}({})", gprStr[RT(instr)], instr & 0xffff, gprStr[BASE(instr)]);
|
||||||
|
case 0x23: return fmt::format("[rsp]: lw {}, {:04X}({})", gprStr[RT(instr)], instr & 0xffff, gprStr[BASE(instr)]);
|
||||||
|
case 0x28: return fmt::format("[rsp]: sb {}, {:04X}({})", gprStr[RT(instr)], instr & 0xffff, gprStr[BASE(instr)]);
|
||||||
|
case 0x29: return fmt::format("[rsp]: sh {}, {:04X}({})", gprStr[RT(instr)], instr & 0xffff, gprStr[BASE(instr)]);
|
||||||
|
case 0x2B: return fmt::format("[rsp]: sw {}, {:04X}({})", gprStr[RT(instr)], instr & 0xffff, gprStr[BASE(instr)]);
|
||||||
|
case 0x32: return lwc2(instr);
|
||||||
|
case 0x3A: return swc2(instr);
|
||||||
|
default: return fmt::format("INVALID ({:08X})", instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,6 @@
|
|||||||
namespace n64 {
|
namespace n64 {
|
||||||
Core::Core() {
|
Core::Core() {
|
||||||
Stop();
|
Stop();
|
||||||
DebuggerInit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Stop() {
|
void Core::Stop() {
|
||||||
@@ -17,7 +16,6 @@ void Core::Stop() {
|
|||||||
pause = true;
|
pause = true;
|
||||||
romLoaded = false;
|
romLoaded = false;
|
||||||
rom.clear();
|
rom.clear();
|
||||||
DebuggerCleanup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Reset() {
|
void Core::Reset() {
|
||||||
@@ -25,8 +23,6 @@ void Core::Reset() {
|
|||||||
mem.Reset();
|
mem.Reset();
|
||||||
pause = true;
|
pause = true;
|
||||||
romLoaded = false;
|
romLoaded = false;
|
||||||
DebuggerCleanup();
|
|
||||||
DebuggerInit();
|
|
||||||
if(!rom.empty()) {
|
if(!rom.empty()) {
|
||||||
LoadROM(rom);
|
LoadROM(rom);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,12 +15,4 @@ struct Registers {
|
|||||||
bool LLBit;
|
bool LLBit;
|
||||||
bool prevDelaySlot, delaySlot;
|
bool prevDelaySlot, delaySlot;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define RD(x) (((x) >> 11) & 0x1F)
|
|
||||||
#define RT(x) (((x) >> 16) & 0x1F)
|
|
||||||
#define RS(x) (((x) >> 21) & 0x1F)
|
|
||||||
#define FD(x) (((x) >> 6) & 0x1F)
|
|
||||||
#define FT(x) RT(x)
|
|
||||||
#define FS(x) RD(x)
|
|
||||||
#define BASE(x) RS(x)
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user