trying to fix weird derailing

This commit is contained in:
CocoSimone
2022-08-28 23:48:08 +02:00
parent b4812cd442
commit 87ad20b519
29 changed files with 86 additions and 621 deletions

4
.gitmodules vendored
View File

@@ -4,7 +4,3 @@
[submodule "external/nativefiledialog-extended"]
path = external/nativefiledialog-extended
url = https://github.com/btzy/nativefiledialog-extended
[submodule "external/capstone"]
path = external/capstone
url = https://github.com/capstone-engine/capstone
branch = next

1
external/capstone vendored

Submodule external/capstone deleted from 0d0e684358

View File

@@ -70,7 +70,6 @@ target_include_directories(parallel-rdp PUBLIC
../imgui
../imgui/imgui
../imgui/imgui/backends
../capstone/include
.
)

View File

@@ -11,7 +11,6 @@ target_include_directories(frontend PUBLIC
.
..
../../external
../../external/capstone/include
../../external/parallel-rdp
../../external/parallel-rdp/parallel-rdp-standalone/vulkan
../../external/parallel-rdp/parallel-rdp-standalone/util

View File

@@ -9,15 +9,7 @@ find_package(fmt REQUIRED)
add_library(frontend-imgui STATIC
Window.cpp
Window.hpp
widgets.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)
Window.hpp)
target_include_directories(frontend-imgui PUBLIC
.
@@ -28,7 +20,6 @@ target_include_directories(frontend-imgui PUBLIC
../../n64/core/cpu
../../n64/core/cpu/registers
../../../external
../../../external/capstone/include
../../../external/parallel-rdp/parallel-rdp-standalone
../../../external/parallel-rdp/parallel-rdp-standalone/vulkan
../../../external/parallel-rdp/parallel-rdp-standalone/util

View File

@@ -140,6 +140,37 @@ ImDrawData* Window::Present(n64::Core& core) {
}
void Window::Render(n64::Core& core) {
MainMenuBar(core);
DebuggerWindow(core);
ImGui::PushFont(uiFont);
if(windowID == SDL_GetWindowID(SDL_GetMouseFocus())) {
ImGui::BeginMainMenuBar();
if (ImGui::BeginMenu("File")) {
if (ImGui::MenuItem("Open", "O")) {
nfdchar_t *outpath;
const nfdu8filteritem_t filter{"Nintendo 64 roms", "n64,z64,v64,N64,Z64,V64"};
nfdresult_t result = NFD_OpenDialog(&outpath, &filter, 1, nullptr);
if (result == NFD_OKAY) {
core.LoadROM(outpath);
NFD_FreePath(outpath);
}
}
if (ImGui::MenuItem("Exit")) {
core.done = true;
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Emulation")) {
if (ImGui::MenuItem("Reset")) {
core.Reset();
}
if (ImGui::MenuItem("Stop")) {
core.Stop();
}
if (ImGui::MenuItem(core.pause ? "Resume" : "Pause", nullptr, false, core.romLoaded)) {
core.TogglePause();
}
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
}
ImGui::PopFont();
}

View File

@@ -20,8 +20,6 @@ private:
void InitSDL();
void InitImgui();
void Render(n64::Core& core);
void MainMenuBar(n64::Core& core);
void DebuggerWindow(n64::Core& core) const;
VkPhysicalDevice physicalDevice{};
VkDevice device{};

View File

@@ -1,2 +0,0 @@
#include <Core.hpp>
#include <debugger.hpp>

View File

@@ -1,86 +0,0 @@
#pragma once
#include <util.hpp>
#include <map>
#include <functional>
#include <cpu/decode.hpp>
#include <fpu/decode.hpp>
#include <rsp/decode.hpp>
#include <cop0/decode.hpp>
struct Core;
// TODO: Fix syntax
static std::map<u8, std::function<std::string(u32)>> cpuInstr = {
{0b000000, special},
{0b000001, regimm},
{0b000010, [](u32 instr) { return fmt::format("j {:08X}", instr & 0x3FFFFFF); }},
{0b000011, [](u32 instr) { return fmt::format("jal {:08X}", instr & 0x3FFFFFF); }},
{0b000100, [](u32 instr) { return fmt::format("beq {}, {}, {:04X}", gprStr[RS(instr)], gprStr[RT(instr)], instr & 0xffff); }},
{0b000101, [](u32 instr) { return fmt::format("bne {}, {}, {:04X}", gprStr[RS(instr)], gprStr[RT(instr)], instr & 0xffff); }},
{0b000110, [](u32 instr) { return fmt::format("blez {}, {:04X}", gprStr[RS(instr)], instr & 0xffff); }},
{0b000111, [](u32 instr) { return fmt::format("bgtz {}, {:04X}", gprStr[RS(instr)], instr & 0xffff); }},
{0b001000, [](u32 instr) { return fmt::format("addi {}, {:04X}", gprStr[RS(instr)], instr & 0xFFFF); }},
{0b001001, [](u32 instr) { return fmt::format("addiu {}, {:04X}", gprStr[RS(instr)], instr & 0x3FFFFFF); }},
{0b001010, [](u32 instr) { return fmt::format("slti {}, {}, {:04X}", gprStr[RT(instr)], gprStr[RS(instr)], instr & 0xFFFF); }},
{0b001011, [](u32 instr) { return fmt::format("sltiu {}, {}, {:04X}", gprStr[RT(instr)], gprStr[RS(instr)], instr & 0xFFFF); }},
{0b001100, [](u32 instr) { return fmt::format("andi {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]); }},
{0b001101, [](u32 instr) { return fmt::format("ori {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]); }},
{0b001110, [](u32 instr) { return fmt::format("xori {}", gprStr[RS(instr)]); }},
{0b001111, [](u32 instr) { return fmt::format("lui {}", gprStr[RS(instr)]); }},
{0b010000, cop0decode},
{0b010001, cop1decode},
{0b010010, rspDecode},
{0b010011, [](u32 instr) { return fmt::format("RESERVED"); }},
{0b010100, [](u32 instr) { return fmt::format("beql {}, {}, {:04X}", gprStr[RS(instr)], gprStr[RT(instr)], instr & 0xffff); }},
{0b010101, [](u32 instr) { return fmt::format("bnel {}, {}, {:04X}", gprStr[RS(instr)], gprStr[RT(instr)], instr & 0xffff); }},
{0b010110, [](u32 instr) { return fmt::format("blezl {}, {:04X}", gprStr[RS(instr)], instr & 0xffff); }},
{0b010111, [](u32 instr) { return fmt::format("bgtzl {}, {:04X}", gprStr[RS(instr)], instr & 0xffff); }},
{0b011000, [](u32 instr) { return fmt::format("daddi {}, {}, {}", gprStr[RT(instr)], gprStr[RS(instr)], instr & 0xFFFF);}},
{0b011001, [](u32 instr) { return fmt::format("daddiu {}, {}, {}", gprStr[RT(instr)], gprStr[RS(instr)], instr & 0xFFFF); }},
{0b011010, [](u32 instr) { return fmt::format("ldl {:08X}", instr & 0x3FFFFFF); }},
{0b011011, [](u32 instr) { return fmt::format("ldr {:08X}", instr & 0x3FFFFFF); }},
{0b011100, [](u32 instr) { return fmt::format("RESERVED"); }},
{0b011101, [](u32 instr) { return fmt::format("RESERVED"); }},
{0b011110, [](u32 instr) { return fmt::format("RESERVED"); }},
{0b011111, [](u32 instr) { return fmt::format("RESERVED"); }},
{0b100000, [](u32 instr) { return fmt::format("lb {:08X}", instr & 0x3FFFFFF); }},
{0b100001, [](u32 instr) { return fmt::format("lh {:08X}", instr & 0x3FFFFFF); }},
{0b100010, [](u32 instr) { return fmt::format("lwl {:08X}", instr & 0x3FFFFFF); }},
{0b100011, [](u32 instr) { return fmt::format("lw {:08X}", instr & 0x3FFFFFF); }},
{0b100100, [](u32 instr) { return fmt::format("lbu {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]); }},
{0b100101, [](u32 instr) { return fmt::format("lhu {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]); }},
{0b100110, [](u32 instr) { return fmt::format("lwr {}", gprStr[RS(instr)]); }},
{0b100111, [](u32 instr) { return fmt::format("lwu {}", gprStr[RS(instr)]); }},
{0b101000, [](u32 instr) { return fmt::format("sb {:08X}", instr & 0x3FFFFFF); }},
{0b101001, [](u32 instr) { return fmt::format("sh {:08X}", instr & 0x3FFFFFF); }},
{0b101010, [](u32 instr) { return fmt::format("swl {:08X}", instr & 0x3FFFFFF); }},
{0b101011, [](u32 instr) { return fmt::format("sw {:08X}", instr & 0x3FFFFFF); }},
{0b101100, [](u32 instr) { return fmt::format("sdl {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]); }},
{0b101101, [](u32 instr) { return fmt::format("sdr {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]); }},
{0b101110, [](u32 instr) { return fmt::format("swr {}", gprStr[RS(instr)]); }},
{0b101111, [](u32 instr) { return fmt::format("cache", gprStr[RS(instr)]); }},
{0b110000, [](u32 instr) { return fmt::format("ll {:08X}", instr & 0x3FFFFFF); }},
{0b110001, [](u32 instr) { return fmt::format("lwc1 {:08X}", instr & 0x3FFFFFF); }},
{0b110010, [](u32 instr) { return fmt::format("lwc2 {:08X}", instr & 0x3FFFFFF); }},
{0b110011, [](u32 instr) { return fmt::format("RESERVED"); }},
{0b110100, [](u32 instr) { return fmt::format("lld {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]); }},
{0b110101, [](u32 instr) { return fmt::format("ldc1 {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]); }},
{0b110110, [](u32 instr) { return fmt::format("ldc2 {}", gprStr[RS(instr)]); }},
{0b110111, [](u32 instr) { return fmt::format("ld {}", gprStr[RS(instr)]); }},
{0b111000, [](u32 instr) { return fmt::format("sc {:08X}", instr & 0x3FFFFFF); }},
{0b111001, [](u32 instr) { return fmt::format("swc1 {:08X}", instr & 0x3FFFFFF); }},
{0b111010, [](u32 instr) { return fmt::format("swc2 {:08X}", instr & 0x3FFFFFF); }},
{0b111011, [](u32 instr) { return fmt::format("RESERVED"); }},
{0b111100, [](u32 instr) { return fmt::format("scd {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]); }},
{0b111101, [](u32 instr) { return fmt::format("sdc1 {}, {}", gprStr[RS(instr)], gprStr[RT(instr)]); }},
{0b111110, [](u32 instr) { return fmt::format("sdc2 {}", gprStr[RS(instr)]); }},
{0b111111, [](u32 instr) { return fmt::format("sd {}", gprStr[RS(instr)]); }}
};
struct Debugger {
util::CircularBuffer<20, std::string> disassembled;
inline void Decode(u32 instr) {
const u8 mask = (instr >> 26) & 0x3f;
disassembled.PushValue(cpuInstr[mask](instr));
}
};

View File

@@ -1,22 +0,0 @@
#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);
}
}

View File

@@ -1,78 +0,0 @@
#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 {}, {:04X}", gprStr[RS(instr)], instr & 0xffff);
case 0x01: return fmt::format("bgez {}, {:04X}", gprStr[RS(instr)], instr & 0xffff);
case 0x02: return fmt::format("bltzl {}, {:04X}", gprStr[RS(instr)], instr & 0xffff);
case 0x03: return fmt::format("bgezl {}, {:04X}", gprStr[RS(instr)], instr & 0xffff);
case 0x10: return fmt::format("bltzal {}, {:04X}", gprStr[RS(instr)], instr & 0xffff);
case 0x11: return fmt::format("bgezal {}, {:04X}", gprStr[RS(instr)], instr & 0xffff);
case 0x12: return fmt::format("bltzall {}, {:04X}", gprStr[RS(instr)], instr & 0xffff);
case 0x13: return fmt::format("bgezall {}, {:04X}", gprStr[RS(instr)], instr & 0xffff);
default: return fmt::format("INVALID ({:08X})", instr);
}
}

View File

@@ -1,66 +0,0 @@
#pragma once
#include <common.hpp>
static 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"
};
static 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"
};
static 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"
};
static const std::string vprStr[32] = {
"vpr0", "vpr1", "vpr2", "vpr3",
"vpr4", "vpr5", "vpr6", "vpr7",
"vpr8", "vpr9", "vpr10", "vpr11",
"vpr12", "vpr13", "vpr14", "vpr15",
"vpr16", "vpr17", "vpr18", "vpr19",
"vpr20", "vpr21", "vpr22", "vpr23",
"vpr24", "vpr25", "vpr26", "vpr27",
"vpr28", "vpr29", "vpr30", "vpr31"
};
static const std::string vprByteStr[16] = {
"e0_8", "e1_8", "e2_8", "e3_8",
"e4_8", "e5_8", "e6_8", "e7_8",
"e8_8", "e9_8", "e10_8", "e11_8",
"e12_8", "e13_8", "e14_8", "e15_8"
};
static const std::string vprElementStr[8] = {
"e0_16", "e2_16", "e4_16", "e6_16",
"e8_16", "e10_16", "e12_16", "e14_16"
};
static const std::string vprWordStr[4] = {
"e0_32", "e4_32", "e8_32", "e12_32"
};
static const std::string rspControlStr[4] = {
"vco", "vcc", "vce", "vce"
};

View File

@@ -1,124 +0,0 @@
#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);
}
}

View File

@@ -1,101 +0,0 @@
#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 {}, {:04X}", gprStr[RS(instr)], instr & 0xffff);
case 0x01: return fmt::format("[rsp]: bgez {}, {:04X}", gprStr[RS(instr)], instr & 0xffff);
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("[rsp]: lqv {}[{}], {:02X}({})", vprStr[VT(instr)], vprByteStr[BYTE_INDEX(E(instr))], instr & 0x7F, gprStr[BASE(instr)]);
default: return fmt::format("INVALID ({:08X})", instr);
}
}
inline std::string swc2(u32 instr) {
u8 mask = (instr >> 11) & 0x1F;
switch(mask) {
case 0x04: return fmt::format("[rsp]: sqv {}[{}], {:02X}({})", vprStr[VT(instr)], vprByteStr[BYTE_INDEX(E(instr))], instr & 0x7F, gprStr[BASE(instr)]);
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: return fmt::format("[rsp]: cfc2 {}, {}", gprStr[RT(instr)], rspControlStr[RD(instr) & 3]);
default: return fmt::format("INVALID ({:08X})", instr);
}
break;
case 0x13: return fmt::format("[rsp]: vabs {}, {}, {}", vprStr[VD(instr)], vprStr[VS(instr)], vprStr[VT(instr)]);
case 0x1D: return fmt::format("[rsp]: vsar {}, {}, {}", vprStr[VD(instr)], vprStr[VS(instr)], vprStr[VT(instr)]);
case 0x21: return fmt::format("[rsp]: veq {}, {}, {}", vprStr[VD(instr)], vprStr[VS(instr)], vprStr[VT(instr)]);
case 0x22: return fmt::format("[rsp]: vne {}, {}, {}", vprStr[VD(instr)], vprStr[VS(instr)], vprStr[VT(instr)]);
case 0x33: return fmt::format("[rsp]: vmov {}[{}], {}[{}]", vprStr[VD(instr)], vprElementStr[DE(instr)], vprStr[VT(instr)], vprElementStr[E(instr)]);
default: return fmt::format("INVALID ({:08X})", instr);
}
}
inline std::string rspCop0Decode(u32 instr) {
u8 mask = (instr >> 21) & 0x1F;
switch(mask) {
case 0x00: return fmt::format("[rsp]: mfc0 {}, {}", gprStr[RT(instr)], cop0Str[RD(instr)]);
case 0x04: return fmt::format("[rsp]: mtc0 {}, {}", gprStr[RT(instr)], cop0Str[RD(instr)]);
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 {}, {}, {:04X}", gprStr[RT(instr)], gprStr[RS(instr)], instr & 0xffff);
case 0x05: return fmt::format("[rsp]: bne {}, {}, {:04X}", gprStr[RT(instr)], gprStr[RS(instr)], instr & 0xffff);
case 0x07: return fmt::format("[rsp]: bgtz {}, {:04X}", gprStr[RS(instr)], instr & 0xffff);
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);
}
}

View File

@@ -1,49 +0,0 @@
#include <Window.hpp>
#include <nfd.h>
#include <debugger.hpp>
void Window::MainMenuBar(n64::Core& core) {
ImGui::PushFont(uiFont);
if(windowID == SDL_GetWindowID(SDL_GetMouseFocus())) {
ImGui::BeginMainMenuBar();
if (ImGui::BeginMenu("File")) {
if (ImGui::MenuItem("Open", "O")) {
nfdchar_t *outpath;
const nfdu8filteritem_t filter{"Nintendo 64 roms", "n64,z64,v64,N64,Z64,V64"};
nfdresult_t result = NFD_OpenDialog(&outpath, &filter, 1, nullptr);
if (result == NFD_OKAY) {
core.LoadROM(outpath);
NFD_FreePath(outpath);
}
}
if (ImGui::MenuItem("Exit")) {
core.done = true;
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Emulation")) {
if (ImGui::MenuItem("Reset")) {
core.Reset();
}
if (ImGui::MenuItem("Stop")) {
core.Stop();
}
if (ImGui::MenuItem(core.pause ? "Resume" : "Pause", nullptr, false, core.romLoaded)) {
core.TogglePause();
}
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
}
ImGui::PopFont();
}
void Window::DebuggerWindow(n64::Core& core) const {
ImGui::PushFont(uiFont);
ImGui::Begin("Debugger");
ImGui::PushFont(codeFont);
ImGui::Text("%s", core.Decode(core.mem.Read<u32>(core.cpu.regs, core.cpu.regs.pc, core.cpu.regs.pc)).c_str());
ImGui::PopFont();
ImGui::End();
ImGui::PopFont();
}

View File

@@ -15,5 +15,4 @@ target_include_directories(n64 PUBLIC
../frontend/imgui/debugger
../../external
../../external/imgui/imgui
../../external/imgui/imgui/backends
../../external/capstone/include)
../../external/imgui/imgui/backends)

View File

@@ -3,7 +3,6 @@
#include <Window.hpp>
#include <algorithm>
#include <util.hpp>
#include <debugger.hpp>
namespace n64 {
Core::Core() {
@@ -31,32 +30,29 @@ void Core::Reset() {
void Core::LoadROM(const std::string& rom_) {
rom = rom_;
mem.LoadROM(rom);
pause = false;
pause = true;
romLoaded = true;
}
void Core::Step() {
MMIO& mmio = mem.mmio;
cpu.Step(mem);
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
}
void Core::Run(Window& window) {
MMIO& mmio = mem.mmio;
int cycles = 0;
for(int field = 0; field < mmio.vi.numFields; field++) {
int frameCycles = 0;
if(!pause && romLoaded) {
for (int i = 0; i < mmio.vi.numHalflines; i++) {
if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) {
InterruptRaise(mmio.mi, cpu.regs, Interrupt::VI);
}
for(;cycles <= mmio.vi.cyclesPerHalfline; cycles++) {
for(;cycles <= mmio.vi.cyclesPerHalfline; cycles++, frameCycles++) {
cpu.Step(mem);
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
mmio.ai.Step(mem, cpu.regs, 1);
}
cycles -= mmio.vi.cyclesPerHalfline;
@@ -67,6 +63,9 @@ void Core::Run(Window& window) {
}
UpdateScreenParallelRdp(*this, window, GetVI());
int missedCycles = N64_CYCLES_PER_FRAME - frameCycles;
mmio.ai.Step(mem, cpu.regs, missedCycles);
} else if(pause && romLoaded) {
UpdateScreenParallelRdp(*this, window, GetVI());
} else if(pause && !romLoaded) {

View File

@@ -3,7 +3,6 @@
#include <Cpu.hpp>
#include <Mem.hpp>
#include <string>
#include <debugger.hpp>
struct Window;
namespace n64 {
@@ -12,13 +11,14 @@ struct Core {
Core();
void Stop();
void Reset();
void Step();
void LoadROM(const std::string&);
void Run(Window&);
void UpdateController(const u8*);
void TogglePause() { pause = !pause; }
VI& GetVI() { return mem.mmio.vi; }
u32 breakpoint = 0;
bool pause = true;
bool romLoaded = false;
SDL_GameController* gamepad;

View File

@@ -4,7 +4,6 @@ project(core)
add_subdirectory(cpu)
add_subdirectory(../../../external/parallel-rdp temp)
add_subdirectory(../../../external/capstone temp1)
find_package(fmt REQUIRED)
find_package(SDL2 REQUIRED)
@@ -50,7 +49,6 @@ target_include_directories(core PUBLIC
../../../external/imgui/imgui
../../../external/imgui/imgui/debugger
../../../external/imgui/imgui/backends
../../../external/capstone/include
mmio)
target_link_libraries(core PUBLIC SDL2main SDL2 fmt cpu parallel-rdp capstone)
target_link_libraries(core PUBLIC SDL2main SDL2 fmt cpu parallel-rdp)

View File

@@ -8,20 +8,6 @@ void Cpu::Reset() {
regs.Reset();
}
Cpu::Cpu() {
if (cs_open(CS_ARCH_MIPS, CS_MODE_MIPS64, &handle)) {
util::panic("Could not initialize capstone!\n");
}
if (cs_option(handle, CS_OPT_UNSIGNED, CS_OPT_ON)) {
util::panic("Could not initialize capstone!\n");
}
}
Cpu::~Cpu() {
cs_close(&handle);
}
inline bool ShouldServiceInterrupt(Registers& regs) {
bool interrupts_pending = (regs.cop0.status.im & regs.cop0.cause.interruptPending) != 0;
bool interrupts_enabled = regs.cop0.status.ie == 1;
@@ -37,7 +23,7 @@ inline void CheckCompareInterrupt(MI& mi, Registers& regs) {
regs.cop0.count &= 0x1FFFFFFFF;
if(regs.cop0.count == (u64)regs.cop0.compare << 1) {
regs.cop0.cause.ip7 = 1;
UpdateInterrupt(mi, regs);
//UpdateInterrupt(mi, regs);
}
}
@@ -55,7 +41,7 @@ void FireException(Registers& regs, ExceptionCode code, int cop, s64 pc) {
bool old_exl = regs.cop0.status.exl;
if(!regs.cop0.status.exl) {
if(regs.prevDelaySlot) { // TODO: cached value of delay_slot should be used, but Namco Museum breaks!
if(regs.delaySlot) { // TODO: cached value of delay_slot should be used, but Namco Museum breaks!
regs.cop0.cause.branchDelay = true;
pc -= 4;
} else {
@@ -102,31 +88,15 @@ inline void HandleInterrupt(Registers& regs) {
}
}
void Cpu::LogInstruction(u32 instruction) {
#ifndef NDEBUG
count = cs_disasm(handle, reinterpret_cast<u8*>(&instruction), 4, regs.pc, 0, &insn);
#endif
if (count > 0) {
for(auto j = 0; j < count; j++) {
util::logdebug("0x{:016X}:\t{}\t\t{}\n", insn[j].address, insn[j].mnemonic, insn[j].op_str);
}
cs_free(insn, count);
} else {
util::logdebug("Failed to disassemble 0x{:08X}!", instruction);
}
}
void Cpu::Step(Mem& mem) {
regs.gpr[0] = 0;
CheckCompareInterrupt(mem.mmio.mi, regs);
regs.prevDelaySlot = regs.delaySlot;
regs.delaySlot = false;
CheckCompareInterrupt(mem.mmio.mi, regs);
u32 instruction = mem.Read<u32>(regs, regs.pc, regs.pc);
//LogInstruction(instruction);
HandleInterrupt(regs);

View File

@@ -1,22 +1,17 @@
#pragma once
#include <Registers.hpp>
#include <Mem.hpp>
#include <capstone/capstone.h>
namespace n64 {
struct Cpu {
Cpu();
~Cpu();
Cpu() = default;
~Cpu() = default;
void Reset();
void Step(Mem&);
Registers regs;
private:
csh handle{};
cs_insn *insn = nullptr;
size_t count{};
friend struct Cop1;
void LogInstruction(u32);
void special(Mem&, u32);
void regimm(u32);
void Exec(Mem&, u32);

View File

@@ -16,7 +16,6 @@ add_library(cpu
target_include_directories(cpu PUBLIC registers
. ..
../../../../external
../../../../external/capstone/include
../../../../src
../../
)

View File

@@ -12,7 +12,6 @@ struct Registers {
Cop1 cop1;
s64 oldPC, pc, nextPC;
s64 hi, lo;
bool LLBit;
bool prevDelaySlot, delaySlot;
};
}

View File

@@ -20,7 +20,7 @@ void Cpu::special(Mem& mem, u32 instr) {
case 0x09: jalr(instr); break;
case 0x0C: FireException(regs, ExceptionCode::Syscall, 0, regs.oldPC); break;
case 0x0D: FireException(regs, ExceptionCode::Breakpoint, 0, regs.oldPC); break;
case 0x0F: break;
case 0x0F: break; // SYNC
case 0x10: mfhi(instr); break;
case 0x11: mthi(instr); break;
case 0x12: mflo(instr); break;
@@ -58,7 +58,7 @@ void Cpu::special(Mem& mem, u32 instr) {
case 0x3E: dsrl32(instr); break;
case 0x3F: dsra32(instr); break;
default:
util::panic("Unimplemented special {} {}", (mask >> 3) & 7, mask & 7);
util::panic("Unimplemented special {} {} (pc: {:+016X})", (mask >> 3) & 7, mask & 7, regs.oldPC);
}
}

View File

@@ -205,7 +205,7 @@ void Cpu::ll(Mem& mem, u32 instr) {
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
}
regs.LLBit = true;
regs.cop0.llbit = true;
regs.cop0.LLAddr = address;
regs.gpr[RT(instr)] = mem.Read<s32>(regs, address, regs.oldPC);
@@ -249,7 +249,7 @@ void Cpu::lld(Mem& mem, u32 instr) {
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
}
regs.LLBit = true;
regs.cop0.llbit = true;
regs.cop0.LLAddr = address;
s64 value = mem.Read<s64>(regs, address, regs.oldPC);
@@ -316,12 +316,12 @@ void Cpu::sc(Mem& mem, u32 instr) {
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
}
if(regs.LLBit) {
if(regs.cop0.llbit) {
mem.Write<u32>(regs, address, regs.gpr[RT(instr)], regs.oldPC);
}
regs.gpr[RT(instr)] = (s64)((u64)regs.LLBit);
regs.LLBit = false;
regs.gpr[RT(instr)] = (s64)((u64)regs.cop0.llbit);
regs.cop0.llbit = false;
}
void Cpu::scd(Mem& mem, u32 instr) {
@@ -331,12 +331,12 @@ void Cpu::scd(Mem& mem, u32 instr) {
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
}
if(regs.LLBit) {
if(regs.cop0.llbit) {
mem.Write<u64>(regs, address, regs.gpr[RT(instr)], regs.oldPC);
}
regs.gpr[RT(instr)] = (s64)((u64)regs.LLBit);
regs.LLBit = false;
regs.gpr[RT(instr)] = (s64)((u64)regs.cop0.llbit);
regs.cop0.llbit = false;
}
void Cpu::sh(Mem& mem, u32 instr) {

View File

@@ -82,7 +82,10 @@ void Cop0::SetReg(u8 addr, T value) {
cause.ip7 = 0;
compare = value;
} break;
case 12: status.raw = value & STATUS_MASK; break;
case 12:
status.raw &= ~STATUS_MASK;
status.raw |= value & STATUS_MASK;
break;
case 13: {
Cop0Cause tmp{};
tmp.raw = value;
@@ -220,7 +223,9 @@ void Cop0::decode(Registers& regs, Mem& mem, u32 instr) {
case 0x01: tlbr(regs); break;
case 0x02: tlbwi(regs); break;
case 0x08: tlbp(regs); break;
case 0x18: eret(regs); break;
case 0x18:
eret(regs);
break;
default: util::panic("Unimplemented COP0 function {} {} ({:08X}) ({:016lX})", mask_cop2 >> 3, mask_cop2 & 7, instr, regs.oldPC);
}
break;

View File

@@ -2,7 +2,7 @@
#include <common.hpp>
namespace n64 {
#define STATUS_MASK 0xFF77FFFF
#define STATUS_MASK 0xFF57FFFF
struct Cpu;
struct Registers;
@@ -161,6 +161,12 @@ struct Cop0 {
void Reset();
bool kernel_mode;
bool supervisor_mode;
bool user_mode;
bool is_64bit_addressing;
bool llbit;
PageMask pageMask{};
EntryHi entryHi{};
EntryLo entryLo0{}, entryLo1{};

View File

@@ -27,6 +27,7 @@ void Cop0::eret(Registers& regs) {
regs.SetPC((s64)EPC);
status.exl = false;
}
llbit = false;
}

View File

@@ -19,6 +19,7 @@ enum MessageType : u8 {
template <MessageType messageType = Info, typename ...Args>
constexpr void print(const std::string& fmt, Args... args) {
#ifndef __WIN32
if constexpr(messageType == Error) {
fmt::print(fmt::emphasis::bold | fg(fmt::color::red), fmt, args...);
exit(-1);
@@ -27,6 +28,14 @@ constexpr void print(const std::string& fmt, Args... args) {
} else if constexpr(messageType == Info) {
fmt::print(fmt, args...);
}
#else
if constexpr(messageType == Error) {
fmt::print(fmt, args...);
exit(-1);
} else {
fmt::print(fmt, args...);
}
#endif
}
template <typename ...Args>