From 4a7997b91e35715adce2059bb12c8d04a3bf3e35 Mon Sep 17 00:00:00 2001 From: SimoneN64 Date: Fri, 11 Aug 2023 15:39:43 +0200 Subject: [PATCH] structure jit --- CMakeLists.txt | 3 +- src/backend/core/JIT.hpp | 2 + src/backend/core/JIT/CMakeLists.txt | 4 + src/backend/core/JIT/decode.cpp | 4 +- src/backend/core/registers/Cop0.cpp | 17 +- src/backend/core/registers/Cop0.hpp | 18 +- src/backend/core/registers/Cop1.cpp | 162 +++++++++++++++++- src/backend/core/registers/Cop1.hpp | 29 +++- .../core/registers/cop/cop1instructions.cpp | 52 +++++- 9 files changed, 268 insertions(+), 23 deletions(-) create mode 100644 src/backend/core/JIT/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 3108455f..835f891e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,7 @@ add_subdirectory(src/backend) add_subdirectory(src/backend/netplay) add_subdirectory(src/backend/core) add_subdirectory(src/backend/core/interpreter) +add_subdirectory(src/backend/core/JIT) add_subdirectory(src/backend/core/mem) add_subdirectory(src/backend/core/mmio) add_subdirectory(src/backend/core/registers) @@ -80,4 +81,4 @@ file(REMOVE ${PROJECT_BINARY_DIR}/resources/shader.vert) target_link_libraries(kaizen PUBLIC frontend frontend-imgui - discord-rpc imgui nfd parallel-rdp backend fmt::fmt mio::mio nlohmann_json::nlohmann_json core registers interpreter mem unarr mmio rsp SDL2::SDL2main SDL2::SDL2) + discord-rpc imgui nfd parallel-rdp backend fmt::fmt mio::mio nlohmann_json::nlohmann_json core registers jit interpreter mem unarr mmio rsp SDL2::SDL2main SDL2::SDL2) diff --git a/src/backend/core/JIT.hpp b/src/backend/core/JIT.hpp index 8a4a289d..904ac7ea 100644 --- a/src/backend/core/JIT.hpp +++ b/src/backend/core/JIT.hpp @@ -12,6 +12,8 @@ struct JIT : BaseCPU, Xbyak::CodeGenerator { ~JIT() override = default; int Step() override; void Reset() override; + friend struct Cop1; + friend struct Cop0; private: bool ShouldServiceInterrupt() override; void CheckCompareInterrupt() override; diff --git a/src/backend/core/JIT/CMakeLists.txt b/src/backend/core/JIT/CMakeLists.txt new file mode 100644 index 00000000..9042a394 --- /dev/null +++ b/src/backend/core/JIT/CMakeLists.txt @@ -0,0 +1,4 @@ +file(GLOB_RECURSE SOURCES *.cpp) +file(GLOB_RECURSE HEADERS *.hpp) + +add_library(jit ${SOURCES} ${HEADERS}) \ No newline at end of file diff --git a/src/backend/core/JIT/decode.cpp b/src/backend/core/JIT/decode.cpp index c6a67ee3..749f8805 100644 --- a/src/backend/core/JIT/decode.cpp +++ b/src/backend/core/JIT/decode.cpp @@ -130,8 +130,8 @@ void JIT::Emit(u32 instr) { case 0x0D: ori(instr); break; case 0x0E: xori(instr); break; case 0x0F: lui(instr); break; - case 0x10: regs.cop0.decode(regs, instr); break; - case 0x11: regs.cop1.decode(regs, *this, instr); break; + case 0x10: regs.cop0.decode(*this, instr); break; + case 0x11: regs.cop1.decode(*this, instr); break; case 0x12: cop2Decode(instr); break; case 0x14: bl(instr, regs.gpr[RS(instr)] == regs.gpr[RT(instr)]); break; case 0x15: bl(instr, regs.gpr[RS(instr)] != regs.gpr[RT(instr)]); break; diff --git a/src/backend/core/registers/Cop0.cpp b/src/backend/core/registers/Cop0.cpp index 4bbbfc3a..575f7d21 100644 --- a/src/backend/core/registers/Cop0.cpp +++ b/src/backend/core/registers/Cop0.cpp @@ -323,7 +323,22 @@ ExceptionCode GetTLBExceptionCode(TLBError error, TLBAccessType accessType) { } } -void Cop0::decode(Registers& regs, u32 instr) { +template +void Cop0::decode(T& cpu, u32 instr) { + if constexpr (std::is_same_v()) { + decodeInterpreter(cpu.regs, instr); + } else if constexpr (std::is_same_v()) { + decodeJIT(cpu, instr); + } else { + Util::panic("What the fuck did you just give me?!!"); + } +} + +void Cop0::decodeJIT(JIT& cpu, u32 instr) { + +} + +void Cop0::decodeInterp(Registers& regs, u32 instr) { u8 mask_cop = (instr >> 21) & 0x1F; u8 mask_cop2 = instr & 0x3F; switch(mask_cop) { diff --git a/src/backend/core/registers/Cop0.hpp b/src/backend/core/registers/Cop0.hpp index b96072c0..4b190e9c 100644 --- a/src/backend/core/registers/Cop0.hpp +++ b/src/backend/core/registers/Cop0.hpp @@ -35,7 +35,8 @@ namespace n64 { #define ENTRY_HI_MASK 0xC00000FFFFFFE0FF #define PAGEMASK_MASK 0x1FFE000 -struct Cpu; +struct JIT; +struct Interpreter; struct Registers; struct Mem; @@ -235,7 +236,8 @@ struct Cop0 { TLBEntry tlb[32]{}; TLBError tlbError = NONE; s64 openbus{}; - void decode(Registers&, u32); + template + void decode(T&, u32); FORCE_INLINE u32 GetRandom() { int val = rand(); int wired = GetWired(); @@ -255,11 +257,13 @@ private: FORCE_INLINE u32 GetWired() { return wired & 0x3F; } FORCE_INLINE u32 GetCount() { return u32(u64(count >> 1)); } - void mtc0(n64::Registers&, u32); - void dmtc0(n64::Registers&, u32); - void mfc0(n64::Registers&, u32); - void dmfc0(n64::Registers&, u32); - void eret(n64::Registers&); + void decodeInterp(Registers&, u32); + void decodeJIT(JIT&, u32); + void mtc0(Registers&, u32); + void dmtc0(Registers&, u32); + void mfc0(Registers&, u32); + void dmfc0(Registers&, u32); + void eret(Registers&); void tlbr(); void tlbw(int); diff --git a/src/backend/core/registers/Cop1.cpp b/src/backend/core/registers/Cop1.cpp index 2849d32c..bdac2fe1 100644 --- a/src/backend/core/registers/Cop1.cpp +++ b/src/backend/core/registers/Cop1.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include namespace n64 { @@ -14,7 +15,166 @@ void Cop1::Reset() { memset(fgr, 0, 32 * sizeof(FGR)); } -void Cop1::decode(Registers& regs, Interpreter& cpu, u32 instr) { +template +void Cop1::decode(T& cpu, u32 instr) { + if constexpr (std::is_same_v()) { + decodeInterp(cpu, instr); + } else if constexpr (std::is_same_v()) { + decodeJIT(cpu, instr); + } else { + Util::panic("What the fuck did you just give me?!"); + } +} + +void Cop1::decodeInterp(Interpreter &cpu, u32 instr) { + Registers ®s = cpu.regs; + if(!regs.cop0.status.cu1) { + FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true); + return; + } + + u8 mask_sub = (instr >> 21) & 0x1F; + u8 mask_fun = instr & 0x3F; + u8 mask_branch = (instr >> 16) & 0x1F; + switch(mask_sub) { + // 000r_rccc + case 0x00: mfc1(regs, instr); break; + case 0x01: dmfc1(regs, instr); break; + case 0x02: cfc1(regs, instr); break; + case 0x03: FireException(regs, ExceptionCode::ReservedInstruction, 1, true); break; + case 0x04: mtc1(regs, instr); break; + case 0x05: dmtc1(regs, instr); break; + case 0x06: ctc1(regs, instr); break; + case 0x07: FireException(regs, ExceptionCode::ReservedInstruction, 1, true); break; + case 0x08: + switch(mask_branch) { + case 0: cpu.b(instr, !regs.cop1.fcr31.compare); break; + case 1: cpu.b(instr, regs.cop1.fcr31.compare); break; + case 2: cpu.bl(instr, !regs.cop1.fcr31.compare); break; + case 3: cpu.bl(instr, regs.cop1.fcr31.compare); break; + default: Util::panic("Undefined BC COP1 {:02X}", mask_branch); + } + break; + case 0x10: // s + switch(mask_fun) { + case 0x00: adds(regs, instr); break; + case 0x01: subs(regs, instr); break; + case 0x02: muls(regs, instr); break; + case 0x03: divs(regs, instr); break; + case 0x04: sqrts(regs, instr); break; + case 0x05: abss(regs, instr); break; + case 0x06: movs(regs, instr); break; + case 0x07: negs(regs, instr); break; + case 0x08: roundls(regs, instr); break; + case 0x09: truncls(regs, instr); break; + case 0x0A: ceills(regs, instr); break; + case 0x0B: floorls(regs, instr); break; + case 0x0C: roundws(regs, instr); break; + case 0x0D: truncws(regs, instr); break; + case 0x0E: ceilws(regs, instr); break; + case 0x0F: floorws(regs, instr); break; + case 0x20: + FireException(regs, ExceptionCode::ReservedInstruction, 1, true); + break; + case 0x21: cvtds(regs, instr); break; + case 0x24: cvtws(regs, instr); break; + case 0x25: cvtls(regs, instr); break; + case 0x30: ccond(regs, instr, F); break; + case 0x31: ccond(regs, instr, UN); break; + case 0x32: ccond(regs, instr, EQ); break; + case 0x33: ccond(regs, instr, UEQ); break; + case 0x34: ccond(regs, instr, OLT); break; + case 0x35: ccond(regs, instr, ULT); break; + case 0x36: ccond(regs, instr, OLE); break; + case 0x37: ccond(regs, instr, ULE); break; + case 0x38: ccond(regs, instr, SF); break; + case 0x39: ccond(regs, instr, NGLE); break; + case 0x3A: ccond(regs, instr, SEQ); break; + case 0x3B: ccond(regs, instr, NGL); break; + case 0x3C: ccond(regs, instr, LT); break; + case 0x3D: ccond(regs, instr, NGE); break; + case 0x3E: ccond(regs, instr, LE); break; + case 0x3F: ccond(regs, instr, NGT); break; + default: Util::panic("Unimplemented COP1 function S[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC); + } + break; + case 0x11: // d + switch(mask_fun) { + case 0x00: addd(regs, instr); break; + case 0x01: subd(regs, instr); break; + case 0x02: muld(regs, instr); break; + case 0x03: divd(regs, instr); break; + case 0x04: sqrtd(regs, instr); break; + case 0x05: absd(regs, instr); break; + case 0x06: movd(regs, instr); break; + case 0x07: negd(regs, instr); break; + case 0x08: roundld(regs, instr); break; + case 0x09: truncld(regs, instr); break; + case 0x0A: ceilld(regs, instr); break; + case 0x0B: floorld(regs, instr); break; + case 0x0C: roundwd(regs, instr); break; + case 0x0D: truncwd(regs, instr); break; + case 0x0E: ceilwd(regs, instr); break; + case 0x0F: floorwd(regs, instr); break; + case 0x20: cvtsd(regs, instr); break; + case 0x21: + FireException(regs, ExceptionCode::ReservedInstruction, 1, true); + break; + case 0x24: cvtwd(regs, instr); break; + case 0x25: cvtld(regs, instr); break; + case 0x30: ccond(regs, instr, F); break; + case 0x31: ccond(regs, instr, UN); break; + case 0x32: ccond(regs, instr, EQ); break; + case 0x33: ccond(regs, instr, UEQ); break; + case 0x34: ccond(regs, instr, OLT); break; + case 0x35: ccond(regs, instr, ULT); break; + case 0x36: ccond(regs, instr, OLE); break; + case 0x37: ccond(regs, instr, ULE); break; + case 0x38: ccond(regs, instr, SF); break; + case 0x39: ccond(regs, instr, NGLE); break; + case 0x3A: ccond(regs, instr, SEQ); break; + case 0x3B: ccond(regs, instr, NGL); break; + case 0x3C: ccond(regs, instr, LT); break; + case 0x3D: ccond(regs, instr, NGE); break; + case 0x3E: ccond(regs, instr, LE); break; + case 0x3F: ccond(regs, instr, NGT); break; + default: Util::panic("Unimplemented COP1 function D[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC); + } + break; + case 0x14: // w + switch(mask_fun) { + case 0x01: subw(regs, instr); break; + case 0x05: absw(regs, instr); break; + case 0x02: mulw(regs, instr); break; + case 0x06: movw(regs, instr); break; + case 0x20: cvtsw(regs, instr); break; + case 0x21: cvtdw(regs, instr); break; + case 0x24: + FireException(regs, ExceptionCode::ReservedInstruction, 1, true); + break; + default: Util::panic("Unimplemented COP1 function W[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC); + } + break; + case 0x15: // l + switch(mask_fun) { + case 0x01: subl(regs, instr); break; + case 0x05: absl(regs, instr); break; + case 0x02: mull(regs, instr); break; + case 0x06: movl(regs, instr); break; + case 0x20: cvtsl(regs, instr); break; + case 0x21: cvtdl(regs, instr); break; + case 0x24: case 0x25: + FireException(regs, ExceptionCode::ReservedInstruction, 1, true); + break; + default: Util::panic("Unimplemented COP1 function L[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC); + } + break; + default: Util::panic("Unimplemented COP1 instruction {} {}", mask_sub >> 3, mask_sub & 7); + } +} + +void Cop1::decodeJIT(JIT &cpu, u32 instr) { + Registers ®s = cpu.regs; if(!regs.cop0.status.cu1) { FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true); return; diff --git a/src/backend/core/registers/Cop1.hpp b/src/backend/core/registers/Cop1.hpp index b3143cda..d5544c0a 100644 --- a/src/backend/core/registers/Cop1.hpp +++ b/src/backend/core/registers/Cop1.hpp @@ -56,6 +56,7 @@ union FGR { }; struct Interpreter; +struct JIT; struct Registers; struct Cop1 { @@ -65,8 +66,9 @@ struct Cop1 { FGR fgr[32]{}; void Reset(); template // either JIT or Interpreter - void decode(Registers&, T&, u32); + void decode(T&, u32); friend struct Interpreter; + friend struct JIT; template FORCE_INLINE void SetReg(Cop0& cop0, u8 index, T value) { @@ -136,8 +138,8 @@ struct Cop1 { return value; } private: - void decodeInterp(Registers&, Interpreter&, u32); - void decodeJIT(Registers&, JIT&, u32); + void decodeInterp(Interpreter&, u32); + void decodeJIT(JIT&, u32); void absd(Registers&, u32 instr); void abss(Registers&, u32 instr); void absw(Registers&, u32 instr); @@ -188,14 +190,27 @@ private: void negd(Registers&, u32 instr); void sqrts(Registers&, u32 instr); void sqrtd(Registers&, u32 instr); - void lwc1(Registers&, Mem&, u32 instr); - void swc1(Registers&, Mem&, u32 instr); - void ldc1(Registers&, Mem&, u32 instr); + template + void lwc1(T&, Mem&, u32); + template + void swc1(T&, Mem&, u32); + template + void ldc1(T&, Mem&, u32); + template + void sdc1(T&, Mem&, u32); + + void lwc1Interp(Registers&, Mem&, u32); + void swc1Interp(Registers&, Mem&, u32); + void ldc1Interp(Registers&, Mem&, u32); + void sdc1Interp(Registers&, Mem&, u32); + void lwc1JIT(JIT&, Mem&, u32); + void swc1JIT(JIT&, Mem&, u32); + void ldc1JIT(JIT&, Mem&, u32); + void sdc1JIT(JIT&, Mem&, u32); void mfc1(Registers&, u32 instr); void dmfc1(Registers&, u32 instr); void mtc1(Registers&, u32 instr); void dmtc1(Registers&, u32 instr); - void sdc1(Registers&, Mem&, u32 instr); void truncws(Registers&, u32 instr); void truncwd(Registers&, u32 instr); void truncls(Registers&, u32 instr); diff --git a/src/backend/core/registers/cop/cop1instructions.cpp b/src/backend/core/registers/cop/cop1instructions.cpp index beed7cc3..1f182cd9 100644 --- a/src/backend/core/registers/cop/cop1instructions.cpp +++ b/src/backend/core/registers/cop/cop1instructions.cpp @@ -443,7 +443,51 @@ void Cop1::floorwd(Registers& regs, u32 instr) { SetReg(regs.cop0, FD(instr), (s64)std::floor(fs)); } -void Cop1::lwc1(Registers& regs, Mem& mem, u32 instr) { +template +void Cop1::lwc1(T &cpu, Mem &mem, u32 instr) { + if constexpr(std::is_same_v()) { + lwc1Interp(cpu.regs, mem, instr); + } else if(std::is_same_v()) { + lwc1JIT(cpu, mem, instr); + } else { + Util::panic("What the fuck did you just give me?!!"); + } +} + +template +void Cop1::swc1(T &cpu, Mem &mem, u32 instr) { + if constexpr(std::is_same_v()) { + swc1Interp(cpu.regs, mem, instr); + } else if(std::is_same_v()) { + swc1JIT(cpu, mem, instr); + } else { + Util::panic("What the fuck did you just give me?!!"); + } +} + +template +void Cop1::ldc1(T &cpu, Mem &mem, u32 instr) { + if constexpr(std::is_same_v()) { + ldc1Interp(cpu.regs, mem, instr); + } else if(std::is_same_v()) { + ldc1JIT(cpu, mem, instr); + } else { + Util::panic("What the fuck did you just give me?!!"); + } +} + +template +void Cop1::sdc1(T &cpu, Mem &mem, u32 instr) { + if constexpr(std::is_same_v()) { + sdc1Interp(cpu.regs, mem, instr); + } else if(std::is_same_v()) { + sdc1JIT(cpu, mem, instr); + } else { + Util::panic("What the fuck did you just give me?!!"); + } +} + +void Cop1::lwc1Interp(Registers& regs, Mem& mem, u32 instr) { if(!regs.cop0.status.cu1) { FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true); return; @@ -461,7 +505,7 @@ void Cop1::lwc1(Registers& regs, Mem& mem, u32 instr) { } } -void Cop1::swc1(Registers& regs, Mem& mem, u32 instr) { +void Cop1::swc1Interp(Registers& regs, Mem& mem, u32 instr) { if(!regs.cop0.status.cu1) { FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true); return; @@ -478,7 +522,7 @@ void Cop1::swc1(Registers& regs, Mem& mem, u32 instr) { } } -void Cop1::ldc1(Registers& regs, Mem& mem, u32 instr) { +void Cop1::ldc1Interp(Registers& regs, Mem& mem, u32 instr) { if(!regs.cop0.status.cu1) { FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true); return; @@ -496,7 +540,7 @@ void Cop1::ldc1(Registers& regs, Mem& mem, u32 instr) { } } -void Cop1::sdc1(Registers& regs, Mem& mem, u32 instr) { +void Cop1::sdc1Interp(Registers& regs, Mem& mem, u32 instr) { if(!regs.cop0.status.cu1) { FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true); return;