diff --git a/external/imgui/CMakeLists.txt b/external/imgui/CMakeLists.txt index 258774d8..0851e218 100644 --- a/external/imgui/CMakeLists.txt +++ b/external/imgui/CMakeLists.txt @@ -1,8 +1,3 @@ -cmake_minimum_required(VERSION 3.20) -project(imgui) - -find_package(SDL2 CONFIG REQUIRED) - add_library(imgui imgui/imgui_demo.cpp imgui/imgui_draw.cpp @@ -23,5 +18,5 @@ if(WIN32) add_compile_options(/EHa) endif() -target_include_directories(imgui PUBLIC ${SDL2_INCLUDE_DIR} ../parallel-rdp/parallel-rdp-standalone/vulkan-headers/include imgui imgui/backends) -target_link_libraries(imgui PUBLIC SDL2::SDL2main SDL2::SDL2) \ No newline at end of file +target_include_directories(imgui PUBLIC ../parallel-rdp/parallel-rdp-standalone/volk + ../parallel-rdp/parallel-rdp-standalone/vulkan-headers/include) \ No newline at end of file diff --git a/external/parallel-rdp/CMakeLists.txt b/external/parallel-rdp/CMakeLists.txt index cae48e70..b1e9f342 100644 --- a/external/parallel-rdp/CMakeLists.txt +++ b/external/parallel-rdp/CMakeLists.txt @@ -1,10 +1,5 @@ -cmake_minimum_required(VERSION 3.20) -project(parallel-rdp) - file(GLOB_RECURSE parallel-rdp-cpp parallel-rdp-standalone/parallel-rdp/*.cpp) -find_package(SDL2 CONFIG REQUIRED) - add_library(parallel-rdp ${parallel-rdp-cpp} ParallelRDPWrapper.cpp @@ -52,32 +47,12 @@ add_library(parallel-rdp target_compile_definitions(parallel-rdp PUBLIC GRANITE_VULKAN_MT) target_include_directories(parallel-rdp PUBLIC - ${SDL2_INCLUDE_DIR} - ${Vulkan_INCLUDE_DIR} parallel-rdp-standalone/parallel-rdp parallel-rdp-standalone/volk parallel-rdp-standalone/spirv-cross parallel-rdp-standalone/vulkan parallel-rdp-standalone/vulkan-headers/include parallel-rdp-standalone/util - ../../src/backend - ../../src/utils - ../../src/backend/core/ - ../../src/backend/core/mmio - ../../src/backend/core/interpreter/ - ../../src/backend/core/registers - parallel-rdp-standalone - .. - ../../src/frontend - ../../src/frontend/imgui - ../../src/frontend/imgui/debugger - ../../src - ../imgui - ../imgui/imgui - ../imgui/imgui/backends - ../fmt/include - ../discord-rpc/include - . ) if(WIN32) @@ -85,10 +60,8 @@ if(WIN32) add_compile_options(/EHa) endif() -target_link_libraries(parallel-rdp SDL2::SDL2main SDL2::SDL2) - if(WIN32) target_compile_definitions(parallel-rdp PUBLIC VK_USE_PLATFORM_WIN32_KHR) else() - target_link_libraries(parallel-rdp dl) + target_link_libraries(parallel-rdp PUBLIC dl) endif() \ No newline at end of file diff --git a/external/parallel-rdp/ParallelRDPWrapper.cpp b/external/parallel-rdp/ParallelRDPWrapper.cpp index 3072685e..eb14ffdb 100644 --- a/external/parallel-rdp/ParallelRDPWrapper.cpp +++ b/external/parallel-rdp/ParallelRDPWrapper.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include using namespace Vulkan; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a9c99cbc..24ce44f0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,54 +4,56 @@ project(gadolinium) set(BUILD_SHARED_LIBS OFF) set(CMAKE_CXX_STANDARD 17) -file(GLOB_RECURSE CORE_SOURCES backend/*.cpp) -file(GLOB_RECURSE CORE_HEADERS backend/*.hpp) -file(GLOB_RECURSE FRONTEND_SOURCES frontend/*.cpp) -file(GLOB_RECURSE FRONTEND_HEADERS frontend/*.hpp) - -find_package(fmt REQUIRED) find_package(SDL2 REQUIRED) +find_package(fmt REQUIRED) find_package(nlohmann_json REQUIRED) option(RAPIDJSON_BUILD_DOC "Build rapidjson documentation." OFF) option(RAPIDJSON_BUILD_EXAMPLES "Build rapidjson examples." OFF) option(RAPIDJSON_BUILD_TESTS "Build rapidjson perftests and unittests." OFF) -add_subdirectory(../external/parallel-rdp prdp) -add_subdirectory(../external/imgui imgui) -add_subdirectory(../external/nativefiledialog-extended nfd) -add_subdirectory(../external/discord-rpc discord-rpc) - -add_executable(gadolinium - ${CORE_SOURCES} - ${CORE_HEADERS} - ${FRONTEND_SOURCES} - ${FRONTEND_HEADERS} - main.cpp - common.hpp - backend/Scheduler.cpp - backend/Scheduler.hpp) - -target_include_directories(gadolinium PRIVATE +include_directories( . - backend - backend/core - backend/core/interpreter/ - backend/core/registers - backend/core/mmio - backend/core/rsp + utils frontend frontend/imgui - utils + backend + backend/core + backend/core/mmio + backend/core/registers + backend/core/rsp ../external ../external/xbyak - ../external/imgui/imgui - ../external/parallel-rdp/ + ../external/parallel-rdp + ../external/parallel-rdp/parallel-rdp-standalone/parallel-rdp + ../external/parallel-rdp/parallel-rdp-standalone/volk + ../external/parallel-rdp/parallel-rdp-standalone/spirv-cross + ../external/parallel-rdp/parallel-rdp-standalone/vulkan + ../external/parallel-rdp/parallel-rdp-standalone/vulkan-headers/include + ../external/parallel-rdp/parallel-rdp-standalone/util ../external/nativefiledialog-extended/src/include + ../external/imgui/imgui + ../external/imgui/imgui/backends ../external/discord-rpc/include - ${SDL2_INCLUDE_DIR} + ${SDL2_INCLUDE_DIRS} ) +add_subdirectory(frontend) +add_subdirectory(frontend/imgui) +add_subdirectory(backend) +add_subdirectory(backend/core) +add_subdirectory(backend/core/dynarec) +add_subdirectory(backend/core/interpreter) +add_subdirectory(backend/core/mmio) +add_subdirectory(backend/core/registers) +add_subdirectory(backend/core/rsp) +add_subdirectory(../external/discord-rpc discord-rpc) +add_subdirectory(../external/imgui imgui) +add_subdirectory(../external/nativefiledialog-extended nfd) +add_subdirectory(../external/parallel-rdp parallel-rdp) + +add_executable(gadolinium main.cpp) + file(COPY ${PROJECT_SOURCE_DIR}/../resources/ DESTINATION ${PROJECT_BINARY_DIR}/resources/) file(REMOVE ${PROJECT_BINARY_DIR}/resources/mario.png @@ -80,4 +82,5 @@ else() endif() endif() -target_link_libraries(gadolinium PRIVATE discord-rpc SDL2::SDL2main SDL2::SDL2 nfd parallel-rdp fmt::fmt imgui nlohmann_json::nlohmann_json) \ No newline at end of file +target_link_libraries(gadolinium PUBLIC SDL2::SDL2main SDL2::SDL2 frontend frontend-imgui + discord-rpc imgui nfd parallel-rdp backend fmt::fmt nlohmann_json::nlohmann_json core dynarec registers interpreter mmio rsp) \ No newline at end of file diff --git a/src/backend/CMakeLists.txt b/src/backend/CMakeLists.txt new file mode 100644 index 00000000..5206b441 --- /dev/null +++ b/src/backend/CMakeLists.txt @@ -0,0 +1,4 @@ +file(GLOB SOURCES *.cpp) +file(GLOB HEADERS *.hpp) + +add_library(backend ${SOURCES} ${HEADERS}) \ No newline at end of file diff --git a/src/backend/Core.cpp b/src/backend/Core.cpp index ea40d5b4..9246627b 100644 --- a/src/backend/Core.cpp +++ b/src/backend/Core.cpp @@ -45,17 +45,19 @@ void Core::Run(Window& window, float volumeL, float volumeR) { } for(;cycles <= mmio.vi.cyclesPerHalfline; cycles++, frameCycles++) { - CpuStep(); - if(!mmio.rsp.spStatus.halt) { - regs.steps++; - if(regs.steps > 2) { - mmio.rsp.steps += 2; - regs.steps -= 3; - } + int cpuCount = CpuStep(); + while(cpuCount--) { + if (!mmio.rsp.spStatus.halt) { + regs.steps++; + if (regs.steps > 2) { + mmio.rsp.steps += 2; + regs.steps -= 3; + } - while(mmio.rsp.steps > 0) { - mmio.rsp.steps--; - mmio.rsp.Step(regs, mem); + while (mmio.rsp.steps > 0) { + mmio.rsp.steps--; + mmio.rsp.Step(regs, mem); + } } } diff --git a/src/backend/Core.hpp b/src/backend/Core.hpp index 51b8d900..44f1ecf1 100644 --- a/src/backend/Core.hpp +++ b/src/backend/Core.hpp @@ -1,9 +1,10 @@ #pragma once -#include -#include -#include +#include +#include +#include #include -#include +#include +#include struct Window; @@ -29,10 +30,10 @@ struct Core { } } - void CpuStep() { + int CpuStep() { switch(cpuType) { - case CpuType::Dynarec: cpuDynarec.Step(mem, regs); break; - case CpuType::Interpreter: cpuInterp.Step(mem, regs); break; + case CpuType::Dynarec: return cpuDynarec.Step(mem, regs); + case CpuType::Interpreter: cpuInterp.Step(mem, regs); return 1; } } @@ -48,7 +49,7 @@ struct Core { Mem mem; CpuType cpuType = CpuType::Dynarec; Interpreter cpuInterp; - Dynarec cpuDynarec; + JIT::Dynarec cpuDynarec; Registers regs; }; } diff --git a/src/backend/MupenMovie.hpp b/src/backend/MupenMovie.hpp index 62fa9b86..edac585b 100644 --- a/src/backend/MupenMovie.hpp +++ b/src/backend/MupenMovie.hpp @@ -1,5 +1,5 @@ #pragma once -#include +#include void LoadTAS(const char* filename); void UnloadTAS(); diff --git a/src/backend/core/CMakeLists.txt b/src/backend/core/CMakeLists.txt new file mode 100644 index 00000000..460cee9a --- /dev/null +++ b/src/backend/core/CMakeLists.txt @@ -0,0 +1,4 @@ +file(GLOB SOURCES *.cpp) +file(GLOB HEADERS *.hpp) + +add_library(core ${SOURCES} ${HEADERS}) \ No newline at end of file diff --git a/src/backend/core/Dynarec.cpp b/src/backend/core/Dynarec.cpp index 0d9bba57..22600512 100644 --- a/src/backend/core/Dynarec.cpp +++ b/src/backend/core/Dynarec.cpp @@ -1,11 +1,52 @@ #include +#include -namespace n64 { -void Dynarec::Reset() { +namespace n64::JIT { +Dynarec::Dynarec() : code(Xbyak::DEFAULT_MAX_CODE_SIZE, Xbyak::AutoGrow) {} +void Dynarec::Recompile(Registers& regs, Mem& mem) { + bool branch = false, prevBranch = false; + u16 start_addr = regs.pc; + Fn block = code.getCurr(); + + while(!prevBranch) { + instrInBlock++; + prevBranch = branch; + u32 instr = mem.Read32(regs, regs.pc, regs.pc); + + regs.oldPC = regs.pc; + regs.pc = regs.nextPC; + regs.nextPC += 4; + + branch = Exec(regs, mem, instr); + } + + code.ret(); + codeCache[start_addr >> 12][start_addr & 15] = block; + block(); } -void Dynarec::Step(Mem &mem, Registers& regs) { +void Dynarec::AllocateOuter(Registers& regs) { + codeCache[regs.pc >> 20] = (Fn*)calloc(0xFFF, sizeof(Fn)); +} +int Dynarec::Step(Mem &mem, Registers& regs) { + instrInBlock = 0; + regs.gpr[0] = 0; + regs.prevDelaySlot = regs.delaySlot; + regs.delaySlot = false; + + if(codeCache[regs.pc >> 20]) { + if(codeCache[regs.pc >> 20][regs.pc & 0xfff]) { + codeCache[regs.pc >> 20][regs.pc & 0xfff](); + } else { + Recompile(regs, mem); + } + } else { + AllocateOuter(regs); + Recompile(regs, mem); + } + + return instrInBlock; } } \ No newline at end of file diff --git a/src/backend/core/Dynarec.hpp b/src/backend/core/Dynarec.hpp index c15014b5..57ce1392 100644 --- a/src/backend/core/Dynarec.hpp +++ b/src/backend/core/Dynarec.hpp @@ -1,114 +1,28 @@ #pragma once #include -#include -#include +#include -namespace n64 { -using Block = void (*)(Mem&, Registers&); +namespace n64::JIT { +using Fn = void (*)(); struct Dynarec { - void Step(Mem&, Registers&); - void Reset(); -private: + Dynarec(); + int Step(Mem&, n64::Registers&); + void Reset() { + code.reset(); + } u64 cop2Latch{}; - friend struct Cop1; - - void cop2Decode(Registers&, u32); - void special(Registers&, Mem&, u32); - void regimm(Registers&, u32); - void Exec(Registers&, Mem&, u32); - void add(Registers&, u32); - void addu(Registers&, u32); - void addi(Registers&, u32); - void addiu(Registers&, u32); - void andi(Registers&, u32); - void and_(Registers&, u32); - void branch(Registers&, bool, s64); - void branch_likely(Registers&, bool, s64); - void b(Registers&, u32, bool); - void blink(Registers&, u32, bool); - void bl(Registers&, u32, bool); - void bllink(Registers&, u32, bool); - void dadd(Registers&, u32); - void daddu(Registers&, u32); - void daddi(Registers&, u32); - void daddiu(Registers&, u32); - void ddiv(Registers&, u32); - void ddivu(Registers&, u32); - void div(Registers&, u32); - void divu(Registers&, u32); - void dmult(Registers&, u32); - void dmultu(Registers&, u32); - void dsll(Registers&, u32); - void dsllv(Registers&, u32); - void dsll32(Registers&, u32); - void dsra(Registers&, u32); - void dsrav(Registers&, u32); - void dsra32(Registers&, u32); - void dsrl(Registers&, u32); - void dsrlv(Registers&, u32); - void dsrl32(Registers&, u32); - void dsub(Registers&, u32); - void dsubu(Registers&, u32); - void j(Registers&, u32); - void jr(Registers&, u32); - void jal(Registers&, u32); - void jalr(Registers&, u32); - void lui(Registers&, u32); - void lbu(Registers&, Mem&, u32); - void lb(Registers&, Mem&, u32); - void ld(Registers&, Mem&, u32); - void ldl(Registers&, Mem&, u32); - void ldr(Registers&, Mem&, u32); - void lh(Registers&, Mem&, u32); - void lhu(Registers&, Mem&, u32); - void ll(Registers&, Mem&, u32); - void lld(Registers&, Mem&, u32); - void lw(Registers&, Mem&, u32); - void lwl(Registers&, Mem&, u32); - void lwu(Registers&, Mem&, u32); - void lwr(Registers&, Mem&, u32); - void mfhi(Registers&, u32); - void mflo(Registers&, u32); - void mult(Registers&, u32); - void multu(Registers&, u32); - void mthi(Registers&, u32); - void mtlo(Registers&, u32); - void nor(Registers&, u32); - void sb(Registers&, Mem&, u32); - void sc(Registers&, Mem&, u32); - void scd(Registers&, Mem&, u32); - void sd(Registers&, Mem&, u32); - void sdl(Registers&, Mem&, u32); - void sdr(Registers&, Mem&, u32); - void sh(Registers&, Mem&, u32); - void sw(Registers&, Mem&, u32); - void swl(Registers&, Mem&, u32); - void swr(Registers&, Mem&, u32); - void slti(Registers&, u32); - void sltiu(Registers&, u32); - void slt(Registers&, u32); - void sltu(Registers&, u32); - void sll(Registers&, u32); - void sllv(Registers&, u32); - void sub(Registers&, u32); - void subu(Registers&, u32); - void sra(Registers&, u32); - void srav(Registers&, u32); - void srl(Registers&, u32); - void srlv(Registers&, u32); - void trap(Registers&, bool); - void or_(Registers&, u32); - void ori(Registers&, u32); - void xor_(Registers&, u32); - void xori(Registers&, u32); - - void mtc2(Registers&, u32); - void mfc2(Registers&, u32); - void dmtc2(Registers&, u32); - void dmfc2(Registers&, u32); - void ctc2(Registers&, u32); - void cfc2(Registers&, u32); Xbyak::CodeGenerator code; +private: + friend struct Cop1; + Fn* codeCache[0x80000]{}; + int instrInBlock = 0; + + void Recompile(n64::Registers&, Mem&); + void AllocateOuter(n64::Registers&); + void cop2Decode(n64::Registers&, u32); + bool special(n64::Registers&, u32); + bool regimm(n64::Registers&, u32); + bool Exec(n64::Registers&, Mem&, u32); }; } diff --git a/src/backend/core/Interpreter.cpp b/src/backend/core/Interpreter.cpp index aebef8c2..968a8fd3 100644 --- a/src/backend/core/Interpreter.cpp +++ b/src/backend/core/Interpreter.cpp @@ -30,7 +30,7 @@ void Interpreter::Step(Mem& mem, Registers& regs) { regs.delaySlot = false; if(ShouldServiceInterrupt(regs)) { - FireException(regs, ExceptionCode::Interrupt, 0, regs.pc); + FireException(regs, ExceptionCode::Interrupt, 0, false); return; } diff --git a/src/backend/core/Interpreter.hpp b/src/backend/core/Interpreter.hpp index 7ce6c3a2..6dcd2de5 100644 --- a/src/backend/core/Interpreter.hpp +++ b/src/backend/core/Interpreter.hpp @@ -13,7 +13,7 @@ private: friend struct Cop1; void cop2Decode(Registers&, u32); - void special(Registers&, Mem&, u32); + void special(Registers&, u32); void regimm(Registers&, u32); void Exec(Registers&, Mem&, u32); void add(Registers&, u32); diff --git a/src/backend/core/Mem.cpp b/src/backend/core/Mem.cpp index aa1341a6..643bebc0 100644 --- a/src/backend/core/Mem.cpp +++ b/src/backend/core/Mem.cpp @@ -93,7 +93,7 @@ u8 Mem::Read8(n64::Registers ®s, u64 vaddr, s64 pc) { u32 paddr = vaddr; if (!MapVAddr(regs, LOAD, vaddr, paddr)) { HandleTLBException(regs, vaddr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, pc); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false); } const auto page = paddr >> 12; @@ -144,7 +144,7 @@ u16 Mem::Read16(n64::Registers ®s, u64 vaddr, s64 pc) { u32 paddr = vaddr; if (!MapVAddr(regs, LOAD, vaddr, paddr)) { HandleTLBException(regs, vaddr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, pc); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false); } const auto page = paddr >> 12; @@ -190,7 +190,7 @@ u32 Mem::Read32(n64::Registers ®s, u64 vaddr, s64 pc) { u32 paddr = vaddr; if (!MapVAddr(regs, LOAD, vaddr, paddr)) { HandleTLBException(regs, vaddr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, pc); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false); } const auto page = paddr >> 12; @@ -230,7 +230,7 @@ u64 Mem::Read64(n64::Registers ®s, u64 vaddr, s64 pc) { u32 paddr = vaddr; if (!MapVAddr(regs, LOAD, vaddr, paddr)) { HandleTLBException(regs, vaddr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, pc); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false); } const auto page = paddr >> 12; @@ -284,7 +284,7 @@ void Mem::Write8(Registers& regs, u64 vaddr, u32 val, s64 pc) { u32 paddr = vaddr; if (!MapVAddr(regs, LOAD, vaddr, paddr)) { HandleTLBException(regs, vaddr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, pc); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false); } const auto page = paddr >> 12; @@ -343,7 +343,7 @@ void Mem::Write16(Registers& regs, u64 vaddr, u32 val, s64 pc) { u32 paddr = vaddr; if (!MapVAddr(regs, STORE, vaddr, paddr)) { HandleTLBException(regs, vaddr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, pc); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, false); } const auto page = paddr >> 12; @@ -402,7 +402,7 @@ void Mem::Write32(Registers& regs, u64 vaddr, u32 val, s64 pc) { u32 paddr = vaddr; if(!MapVAddr(regs, STORE, vaddr, paddr)) { HandleTLBException(regs, vaddr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, pc); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, false); } const auto page = paddr >> 12; @@ -453,7 +453,7 @@ void Mem::Write64(Registers& regs, u64 vaddr, u64 val, s64 pc) { u32 paddr = vaddr; if(!MapVAddr(regs, STORE, vaddr, paddr)) { HandleTLBException(regs, vaddr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, pc); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, false); } const auto page = paddr >> 12; diff --git a/src/backend/core/Mem.hpp b/src/backend/core/Mem.hpp index 9975b7de..008c3de9 100644 --- a/src/backend/core/Mem.hpp +++ b/src/backend/core/Mem.hpp @@ -1,9 +1,9 @@ #pragma once #include -#include -#include +#include +#include #include -#include +#include #include namespace n64 { diff --git a/src/backend/core/dynarec/CMakeLists.txt b/src/backend/core/dynarec/CMakeLists.txt new file mode 100644 index 00000000..045cbd92 --- /dev/null +++ b/src/backend/core/dynarec/CMakeLists.txt @@ -0,0 +1,4 @@ +file(GLOB_RECURSE SOURCES *.cpp) +file(GLOB_RECURSE HEADERS *.hpp) + +add_library(dynarec ${SOURCES} ${HEADERS}) \ No newline at end of file diff --git a/src/backend/core/dynarec/cop/cop0decode.cpp b/src/backend/core/dynarec/cop/cop0decode.cpp new file mode 100644 index 00000000..4f6304bc --- /dev/null +++ b/src/backend/core/dynarec/cop/cop0decode.cpp @@ -0,0 +1,27 @@ +#include +#include +#include + +namespace n64::JIT { +void cop0Decode(n64::Registers& regs, u32 instr) { + u8 mask_cop = (instr >> 21) & 0x1F; + u8 mask_cop2 = instr & 0x3F; + switch(mask_cop) { + case 0x00: mfc0(regs, instr); break; + case 0x01: dmfc0(regs, instr); break; + case 0x04: mtc0(regs, instr); break; + case 0x05: dmtc0(regs, instr); break; + case 0x10 ... 0x1F: + switch(mask_cop2) { + case 0x01: tlbr(regs); break; + case 0x02: tlbw(regs.cop0.index & 0x3F, regs); break; + case 0x06: tlbw(regs.cop0.GetRandom(), regs); break; + case 0x08: tlbp(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; + default: util::panic("Unimplemented COP0 instruction {} {}", mask_cop >> 4, mask_cop & 7); + } +} +} \ No newline at end of file diff --git a/src/backend/core/dynarec/cop/cop0decode.hpp b/src/backend/core/dynarec/cop/cop0decode.hpp new file mode 100644 index 00000000..6b46e3a0 --- /dev/null +++ b/src/backend/core/dynarec/cop/cop0decode.hpp @@ -0,0 +1,10 @@ +#pragma once +#include + +namespace n64 { +struct Registers; +} + +namespace n64::JIT { +void cop0Decode(n64::Registers& regs, u32 instr); +} \ No newline at end of file diff --git a/src/backend/core/dynarec/cop/cop0instructions.cpp b/src/backend/core/dynarec/cop/cop0instructions.cpp new file mode 100644 index 00000000..fc0fec3c --- /dev/null +++ b/src/backend/core/dynarec/cop/cop0instructions.cpp @@ -0,0 +1,81 @@ +#include +#include +#include + +namespace n64::JIT { +void mtc0(n64::Registers& regs, u32 instr) { + regs.cop0.SetReg32(RD(instr), regs.gpr[RT(instr)]); +} + +void dmtc0(n64::Registers& regs, u32 instr) { + regs.cop0.SetReg64(RD(instr), regs.gpr[RT(instr)]); +} + +void mfc0(n64::Registers& regs, u32 instr) { + regs.gpr[RT(instr)] = s32(regs.cop0.GetReg32(RD(instr))); +} + +void dmfc0(n64::Registers& regs, u32 instr) { + regs.gpr[RT(instr)] = s64(regs.cop0.GetReg64(RD(instr))); +} + +void eret(n64::Registers& regs) { + if(regs.cop0.status.erl) { + regs.SetPC(regs.cop0.ErrorEPC); + regs.cop0.status.erl = false; + } else { + regs.SetPC(regs.cop0.EPC); + regs.cop0.status.exl = false; + } + regs.cop0.llbit = false; +} + + +void tlbr(n64::Registers& regs) { + u8 Index = regs.cop0.index & 0b111111; + if (Index >= 32) { + util::panic("TLBR with TLB index {}", Index); + } + + TLBEntry entry = regs.cop0.tlb[Index]; + + regs.cop0.entryHi.raw = entry.entryHi.raw; + regs.cop0.entryLo0.raw = entry.entryLo0.raw & 0x3FFFFFFF; + regs.cop0.entryLo1.raw = entry.entryLo1.raw & 0x3FFFFFFF; + + regs.cop0.entryLo0.g = entry.global; + regs.cop0.entryLo1.g = entry.global; + regs.cop0.pageMask.raw = entry.pageMask.raw; +} + +void tlbw(int index_, n64::Registers& regs) { + PageMask page_mask = regs.cop0.pageMask; + u32 top = page_mask.mask & 0xAAA; + page_mask.mask = top | (top >> 1); + + if(index_ >= 32) { + util::panic("TLBWI with TLB index {}", index_); + } + + regs.cop0.tlb[index_].entryHi.raw = regs.cop0.entryHi.raw; + regs.cop0.tlb[index_].entryHi.vpn2 &= ~page_mask.mask; + + regs.cop0.tlb[index_].entryLo0.raw = regs.cop0.entryLo0.raw & 0x03FFFFFE; + regs.cop0.tlb[index_].entryLo1.raw = regs.cop0.entryLo1.raw & 0x03FFFFFE; + regs.cop0.tlb[index_].pageMask.raw = page_mask.raw; + + regs.cop0.tlb[index_].global = regs.cop0.entryLo0.g && regs.cop0.entryLo1.g; + regs.cop0.tlb[index_].initialized = true; +} + +void tlbp(n64::Registers& regs) { + int match = -1; + TLBEntry* entry = TLBTryMatch(regs, regs.cop0.entryHi.raw, &match); + if(entry && match >= 0) { + regs.cop0.index = match; + } else { + regs.cop0.index = 0x80000000; + } +} + +} \ No newline at end of file diff --git a/src/backend/core/dynarec/cop/cop0instructions.hpp b/src/backend/core/dynarec/cop/cop0instructions.hpp new file mode 100644 index 00000000..72049a7d --- /dev/null +++ b/src/backend/core/dynarec/cop/cop0instructions.hpp @@ -0,0 +1,13 @@ +#pragma once +#include + +namespace n64::JIT { +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 tlbr(n64::Registers&); +void tlbw(int, n64::Registers&); +void tlbp(n64::Registers&); +} \ No newline at end of file diff --git a/src/backend/core/dynarec/cop/cop1decode.cpp b/src/backend/core/dynarec/cop/cop1decode.cpp new file mode 100644 index 00000000..9ae4f728 --- /dev/null +++ b/src/backend/core/dynarec/cop/cop1decode.cpp @@ -0,0 +1,484 @@ +#include +#include +#include + +namespace n64::JIT { +bool cop1Decode(n64::Registers& regs, Dynarec& cpu, u32 instr) { + Xbyak::CodeGenerator& code = cpu.code; + code.push(code.rbp); + code.mov(code.rbp, (u64)®s.cop0.status.raw); + code.mov(code.eax, code.dword[code.rbp]); + code.pop(code.rbp); + code.and_(code.eax, 0x20000000); + code.cmp(code.eax, 1); + code.je("NoException1"); + + code.mov(code.rdi, (u64)®s); + code.mov(code.rsi, (u64)ExceptionCode::CoprocessorUnusable); + code.mov(code.rdx, 1); + code.mov(code.rcx, 1); + code.mov(code.rax, (u64) FireException); + code.call(code.rax); + code.xor_(code.rax, code.rax); + code.ret(); + + code.L("NoException1"); + + u8 mask_sub = (instr >> 21) & 0x1F; + u8 mask_fun = instr & 0x3F; + u8 mask_branch = (instr >> 16) & 0x1F; + + code.mov(code.rdi, (u64)®s); + code.mov(code.esi, instr); + + switch(mask_sub) { + // 000r_rccc + case 0x00: + code.mov(code.rax, (u64)mfc1); + code.call(code.rax); + break; + case 0x01: + code.mov(code.rax, (u64)dmfc1); + code.call(code.rax); + break; + case 0x02: + code.mov(code.rax, (u64)cfc1); + code.call(code.rax); + break; + case 0x03: + util::panic("[RECOMPILER] FPU Reserved instruction exception!\n"); + case 0x04: + code.mov(code.rax, (u64)mtc1); + code.call(code.rax); + break; + case 0x05: + code.mov(code.rax, (u64)dmtc1); + code.call(code.rax); + break; + case 0x06: + code.mov(code.rax, (u64)ctc1); + code.call(code.rax); + break; + case 0x07: + util::panic("[RECOMPILER] FPU Reserved instruction exception!\n"); + case 0x08: + switch(mask_branch) { + case 0: + code.mov(code.rdi, !regs.cop1.fcr31.compare); + code.mov(code.rax, (u64)b); + code.call(code.rax); + return true; + case 1: + code.mov(code.rdi, regs.cop1.fcr31.compare); + code.mov(code.rax, (u64)b); + code.call(code.rax); + return true; + case 2: + code.mov(code.rdi, !regs.cop1.fcr31.compare); + code.mov(code.rax, (u64)bl); + code.call(code.rax); + return true; + case 3: + code.mov(code.rdi, regs.cop1.fcr31.compare); + code.mov(code.rax, (u64)bl); + code.call(code.rax); + return true; + default: util::panic("Undefined BC COP1 {:02X}\n", mask_branch); + } + break; + case 0x10: // s + switch(mask_fun) { + case 0x00: + code.mov(code.rax, (u64)adds); + code.call(code.rax); + break; + case 0x01: + code.mov(code.rax, (u64)subs); + code.call(code.rax); + break; + case 0x02: + code.mov(code.rax, (u64)muls); + code.call(code.rax); + break; + case 0x03: + code.mov(code.rax, (u64)divs); + code.call(code.rax); + break; + case 0x04: + code.mov(code.rax, (u64)sqrts); + code.call(code.rax); + break; + case 0x05: + code.mov(code.rax, (u64)abss); + code.call(code.rax); + break; + case 0x06: + code.mov(code.rax, (u64)movs); + code.call(code.rax); + break; + case 0x07: + code.mov(code.rax, (u64)negs); + code.call(code.rax); + break; + case 0x08: + code.mov(code.rax, (u64)roundls); + code.call(code.rax); + break; + case 0x09: + code.mov(code.rax, (u64)truncls); + code.call(code.rax); + break; + case 0x0A: + code.mov(code.rax, (u64)ceills); + code.call(code.rax); + break; + case 0x0B: + code.mov(code.rax, (u64)floorls); + code.call(code.rax); + break; + case 0x0C: + code.mov(code.rax, (u64)roundws); + code.call(code.rax); + break; + case 0x0D: + code.mov(code.rax, (u64)truncws); + code.call(code.rax); + break; + case 0x0E: + code.mov(code.rax, (u64)ceilws); + code.call(code.rax); + break; + case 0x0F: + code.mov(code.rax, (u64)floorws); + code.call(code.rax); + break; + case 0x20: + util::panic("[RECOMPILER] FPU Reserved instruction exception!\n"); + case 0x21: + code.mov(code.rax, (u64)cvtds); + code.call(code.rax); + break; + case 0x24: + code.mov(code.rax, (u64)cvtws); + code.call(code.rax); + break; + case 0x25: + code.mov(code.rax, (u64)cvtls); + code.call(code.rax); + break; + case 0x30: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, F); + code.call(code.rax); + break; + case 0x31: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, UN); + code.call(code.rax); + break; + case 0x32: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, EQ); + code.call(code.rax); + break; + case 0x33: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, UEQ); + code.call(code.rax); + break; + case 0x34: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, OLT); + code.call(code.rax); + break; + case 0x35: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, ULT); + code.call(code.rax); + break; + case 0x36: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, OLE); + code.call(code.rax); + break; + case 0x37: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, ULE); + code.call(code.rax); + break; + case 0x38: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, SF); + code.call(code.rax); + break; + case 0x39: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, NGLE); + code.call(code.rax); + break; + case 0x3A: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, SEQ); + code.call(code.rax); + break; + case 0x3B: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, NGL); + code.call(code.rax); + break; + case 0x3C: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, LT); + code.call(code.rax); + break; + case 0x3D: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, NGE); + code.call(code.rax); + break; + case 0x3E: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, LE); + code.call(code.rax); + break; + case 0x3F: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, NGT); + code.call(code.rax); + 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: + code.mov(code.rax, (u64)addd); + code.call(code.rax); + break; + case 0x01: + code.mov(code.rax, (u64)subd); + code.call(code.rax); + break; + case 0x02: + code.mov(code.rax, (u64)muld); + code.call(code.rax); + break; + case 0x03: + code.mov(code.rax, (u64)divd); + code.call(code.rax); + break; + case 0x04: + code.mov(code.rax, (u64)sqrtd); + code.call(code.rax); + break; + case 0x05: + code.mov(code.rax, (u64)absd); + code.call(code.rax); + break; + case 0x06: + code.mov(code.rax, (u64)movd); + code.call(code.rax); + break; + case 0x07: + code.mov(code.rax, (u64)negd); + code.call(code.rax); + break; + case 0x08: + code.mov(code.rax, (u64)roundld); + code.call(code.rax); + break; + case 0x09: + code.mov(code.rax, (u64)truncld); + code.call(code.rax); + break; + case 0x0A: + code.mov(code.rax, (u64)ceilld); + code.call(code.rax); + break; + case 0x0B: + code.mov(code.rax, (u64)floorld); + code.call(code.rax); + break; + case 0x0C: + code.mov(code.rax, (u64)roundwd); + code.call(code.rax); + break; + case 0x0D: + code.mov(code.rax, (u64)truncwd); + code.call(code.rax); + break; + case 0x0E: + code.mov(code.rax, (u64)ceilwd); + code.call(code.rax); + break; + case 0x0F: + code.mov(code.rax, (u64)floorwd); + code.call(code.rax); + break; + case 0x20: + code.mov(code.rax, (u64)cvtsd); + code.call(code.rax); + break; + case 0x21: + util::panic("[RECOMPILER] FPU Reserved instruction exception!\n"); + case 0x24: + code.mov(code.rax, (u64)cvtwd); + code.call(code.rax); + break; + case 0x25: + code.mov(code.rax, (u64)cvtld); + code.call(code.rax); + break; + case 0x30: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, F); + code.call(code.rax); + break; + case 0x31: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, UN); + code.call(code.rax); + break; + case 0x32: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, EQ); + code.call(code.rax); + break; + case 0x33: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, UEQ); + code.call(code.rax); + break; + case 0x34: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, OLT); + code.call(code.rax); + break; + case 0x35: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, ULT); + code.call(code.rax); + break; + case 0x36: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, OLE); + code.call(code.rax); + break; + case 0x37: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, ULE); + code.call(code.rax); + break; + case 0x38: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, SF); + code.call(code.rax); + break; + case 0x39: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, NGLE); + code.call(code.rax); + break; + case 0x3A: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, SEQ); + code.call(code.rax); + break; + case 0x3B: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, NGL); + code.call(code.rax); + break; + case 0x3C: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, LT); + code.call(code.rax); + break; + case 0x3D: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, NGE); + code.call(code.rax); + break; + case 0x3E: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, LE); + code.call(code.rax); + break; + case 0x3F: + code.mov(code.rax, (u64)ccond); + code.mov(code.rdx, NGT); + code.call(code.rax); + 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: + code.mov(code.rax, (u64)subw); + code.call(code.rax); + break; + case 0x05: + code.mov(code.rax, (u64)absw); + code.call(code.rax); + break; + case 0x02: + code.mov(code.rax, (u64)mulw); + code.call(code.rax); + break; + case 0x06: + code.mov(code.rax, (u64)movw); + code.call(code.rax); + break; + case 0x20: + code.mov(code.rax, (u64)cvtsw); + code.call(code.rax); + break; + case 0x21: + code.mov(code.rax, (u64)cvtdw); + code.call(code.rax); + break; + case 0x24: + util::panic("[RECOMPILER] FPU reserved instruction exception!\n"); + 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: + code.mov(code.rax, (u64)subl); + code.call(code.rax); + break; + case 0x05: + code.mov(code.rax, (u64)absl); + code.call(code.rax); + break; + case 0x02: + code.mov(code.rax, (u64)mull); + code.call(code.rax); + break; + case 0x06: + code.mov(code.rax, (u64)movl); + code.call(code.rax); + break; + case 0x20: + code.mov(code.rax, (u64)cvtsl); + code.call(code.rax); + break; + case 0x21: + code.mov(code.rax, (u64)cvtdl); + code.call(code.rax); + break; + case 0x24: + util::panic("[RECOMPILER] FPU reserved instruction exception!\n"); + case 0x25: + util::panic("[RECOMPILER] FPU reserved instruction exception!\n"); + 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); + } + + return false; +} +} \ No newline at end of file diff --git a/src/backend/core/dynarec/cop/cop1decode.hpp b/src/backend/core/dynarec/cop/cop1decode.hpp new file mode 100644 index 00000000..af3590e4 --- /dev/null +++ b/src/backend/core/dynarec/cop/cop1decode.hpp @@ -0,0 +1,6 @@ +#pragma once +#include + +namespace n64::JIT { +bool cop1Decode(n64::Registers& regs, Dynarec& cpu, u32 instr); +} \ No newline at end of file diff --git a/src/backend/core/dynarec/cop/cop1instructions.cpp b/src/backend/core/dynarec/cop/cop1instructions.cpp new file mode 100644 index 00000000..fe6d4caa --- /dev/null +++ b/src/backend/core/dynarec/cop/cop1instructions.cpp @@ -0,0 +1,590 @@ +#include +#include +#include +#include + +namespace n64::JIT { +inline int PushRoundingMode(const FCR31& fcr31) { + int og = fegetround(); + switch(fcr31.rounding_mode) { + case 0: fesetround(FE_TONEAREST); break; + case 1: fesetround(FE_TOWARDZERO); break; + case 2: fesetround(FE_UPWARD); break; + case 3: fesetround(FE_DOWNWARD); break; + } + + return og; +} + +#define PUSHROUNDINGMODE int og = PushRoundingMode(regs.cop1.fcr31) +#define POPROUNDINGMODE fesetround(og) + +#ifdef _WIN32 +#define isnanf isnan +#define checknanregsf(fs, ft) \ + if(isnanf(fs) || isnanf(ft)) { \ + regs.cop1.fcr31.flag_invalid_operation = true; \ + regs.cop1.fcr31.cause_invalid_operation = true; \ + FireException(regs, ExceptionCode::FloatingPointError, 1, true); \ + return; \ + } + +#define checknanregsd(fs, ft) \ + if(isnan(fs) || isnan(ft)) { \ + regs.cop1.fcr31.flag_invalid_operation = true; \ + regs.cop1.fcr31.cause_invalid_operation = true; \ + FireException(regs, ExceptionCode::FloatingPointError, 1, true); \ + return; \ + } +#else +#define checknanregsf(fs, ft) \ + if(isnanf(fs) || isnanf(ft)) { \ + regs.cop1.fcr31.flag_invalid_operation = true; \ + regs.cop1.fcr31.cause_invalid_operation = true; \ + FireException(regs, ExceptionCode::FloatingPointError, 1, true); \ + return; \ + } + +#define checknanregsd(fs, ft) \ + if(isnan(fs) || isnan(ft)) { \ + regs.cop1.fcr31.flag_invalid_operation = true; \ + regs.cop1.fcr31.cause_invalid_operation = true; \ + FireException(regs, ExceptionCode::FloatingPointError, 1, true); \ + return; \ + } +#endif + +void absd(n64::Registers& regs, u32 instr) { + double fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + regs.cop1.SetCop1Reg(regs.cop0, FD(instr), fabs(fs)); +} + +void abss(n64::Registers& regs, u32 instr) { + float fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + regs.cop1.SetCop1Reg(regs.cop0, FD(instr), fabsf(fs)); +} + +void absw(n64::Registers& regs, u32 instr) { + s32 fs = regs.cop1.GetReg(regs.cop0, FS(instr)); + regs.cop1.SetReg(regs.cop0, FD(instr), abs(fs)); +} + +void absl(n64::Registers& regs, u32 instr) { + s64 fs = regs.cop1.GetReg(regs.cop0, FS(instr)); + regs.cop1.SetReg(regs.cop0, FD(instr), labs(fs)); +} + +void adds(n64::Registers& regs, u32 instr) { + float fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + float ft = regs.cop1.GetCop1Reg(regs.cop0, FT(instr)); + checknanregsf(fs, ft) + float result = fs + ft; + regs.cop1.SetCop1Reg(regs.cop0, FD(instr), result); +} + +void addd(n64::Registers& regs, u32 instr) { + double fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + double ft = regs.cop1.GetCop1Reg(regs.cop0, FT(instr)); + checknanregsf(fs, ft) + double result = fs + ft; + regs.cop1.SetCop1Reg(regs.cop0, FD(instr), result); +} + +void ceills(n64::Registers& regs, u32 instr) { + float fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + s64 result = ceilf(fs); + regs.cop1.SetReg(regs.cop0, FD(instr), result); +} + +void ceilws(n64::Registers& regs, u32 instr) { + float fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + s32 result = ceilf(fs); + regs.cop1.SetReg(regs.cop0, FD(instr), result); +} + +void ceilld(n64::Registers& regs, u32 instr) { + double fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + s64 result = ceil(fs); + regs.cop1.SetReg(regs.cop0, FD(instr), result); +} + +void ceilwd(n64::Registers& regs, u32 instr) { + double fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + s32 result = ceil(fs); + regs.cop1.SetReg(regs.cop0, FD(instr), result); +} + +void cfc1(n64::Registers& regs, u32 instr) { + u8 fd = FD(instr); + s32 val = 0; + switch(fd) { + case 0: val = regs.cop1.fcr0; break; + case 31: val = regs.cop1.fcr31.raw; break; + default: util::panic("Undefined CFC1 with rd != 0 or 31\n"); + } + regs.gpr[RT(instr)] = val; +} + +void ctc1(n64::Registers& regs, u32 instr) { + u8 fs = FS(instr); + u32 val = regs.gpr[RT(instr)]; + switch(fs) { + case 0: break; + case 31: { + val &= 0x183ffff; + regs.cop1.fcr31.raw = val; + } break; + default: util::panic("Undefined CTC1 with rd != 0 or 31\n"); + } +} + +void cvtds(n64::Registers& regs, u32 instr) { + regs.cop1.SetCop1Reg( + regs.cop0, + FD(instr), + regs.cop1.GetCop1Reg( + regs.cop0, + FS(instr) + ) + ); +} + +void cvtsd(n64::Registers& regs, u32 instr) { + regs.cop1.SetCop1Reg( + regs.cop0, + FD(instr), + regs.cop1.GetCop1Reg( + regs.cop0, + FS(instr) + ) + ); +} + +void cvtwd(n64::Registers& regs, u32 instr) { + regs.cop1.SetReg( + regs.cop0, + FD(instr), + regs.cop1.GetCop1Reg( + regs.cop0, + FS(instr) + ) + ); +} + +void cvtws(n64::Registers& regs, u32 instr) { + regs.cop1.SetReg( + regs.cop0, + FD(instr), + regs.cop1.GetCop1Reg( + regs.cop0, + FS(instr) + ) + ); +} + +void cvtls(n64::Registers& regs, u32 instr) { + regs.cop1.SetReg( + regs.cop0, + FD(instr), + regs.cop1.GetCop1Reg( + regs.cop0, + FS(instr) + ) + ); +} + +void cvtsl(n64::Registers& regs, u32 instr) { + regs.cop1.SetCop1Reg( + regs.cop0, + FD(instr), + (s64)regs.cop1.GetReg( + regs.cop0, + FS(instr) + ) + ); +} + +void cvtdw(n64::Registers& regs, u32 instr) { + regs.cop1.SetCop1Reg( + regs.cop0, + FD(instr), + (s32)regs.cop1.GetReg( + regs.cop0, + FS(instr) + ) + ); +} + +void cvtsw(n64::Registers& regs, u32 instr) { + regs.cop1.SetCop1Reg( + regs.cop0, + FD(instr), + (s32)regs.cop1.GetReg( + regs.cop0, + FS(instr) + ) + ); +} + +void cvtdl(n64::Registers& regs, u32 instr) { + regs.cop1.SetCop1Reg( + regs.cop0, + FD(instr), + (s64)regs.cop1.GetReg( + regs.cop0, + FS(instr) + ) + ); +} + +void cvtld(n64::Registers& regs, u32 instr) { + regs.cop1.SetReg( + regs.cop0, + FD(instr), + regs.cop1.GetCop1Reg( + regs.cop0, + FS(instr) + ) + ); +} + +template +inline bool CalculateCondition(n64::Registers& regs, T fs, T ft, CompConds cond) { + switch(cond) { + case F: return false; + case UN: return std::isnan(fs) || std::isnan(ft); + case EQ: return fs == ft; + case UEQ: return (std::isnan(fs) || std::isnan(ft)) || (fs == ft); + case OLT: return (!std::isnan(fs) && !std::isnan(ft)) && (fs < ft); + case ULT: return (std::isnan(fs) || std::isnan(ft)) || (fs < ft); + case OLE: return (!std::isnan(fs) && !std::isnan(ft)) && (fs <= ft); + case ULE: return (std::isnan(fs) || std::isnan(ft)) || (fs <= ft); + default: + if(std::isnan(fs) || std::isnan(ft)) { + regs.cop1.fcr31.flag_invalid_operation = true; + regs.cop1.fcr31.cause_invalid_operation = true; + FireException(regs, ExceptionCode::FloatingPointError, 1, true); + return false; + } + + return CalculateCondition(regs, fs, ft, static_cast(cond - 8)); + } +} + +template +void ccond(n64::Registers& regs, u32 instr, CompConds cond) { + T fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + T ft = regs.cop1.GetCop1Reg(regs.cop0, FT(instr)); + + regs.cop1.fcr31.compare = CalculateCondition(regs, fs, ft, cond); +} + +template void ccond(n64::Registers& regs, u32 instr, CompConds cond); +template void ccond(n64::Registers& regs, u32 instr, CompConds cond); + +void divs(Registers ®s, u32 instr) { + float fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + float ft = regs.cop1.GetCop1Reg(regs.cop0, FT(instr)); + regs.cop1.SetCop1Reg(regs.cop0, FD(instr), fs / ft); +} + +void divd(Registers ®s, u32 instr) { + double fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + double ft = regs.cop1.GetCop1Reg(regs.cop0, FT(instr)); + regs.cop1.SetCop1Reg(regs.cop0, FD(instr), fs / ft); +} + +void muls(Registers ®s, u32 instr) { + float fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + float ft = regs.cop1.GetCop1Reg(regs.cop0, FT(instr)); + regs.cop1.SetCop1Reg(regs.cop0, FD(instr), fs * ft); +} + +void muld(n64::Registers& regs, u32 instr) { + double fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + double ft = regs.cop1.GetCop1Reg(regs.cop0, FT(instr)); + regs.cop1.SetCop1Reg(regs.cop0, FD(instr), fs * ft); +} + +void mulw(Registers ®s, u32 instr) { + u32 fs = regs.cop1.GetReg(regs.cop0, FS(instr)); + u32 ft = regs.cop1.GetReg(regs.cop0, FT(instr)); + regs.cop1.SetReg(regs.cop0, FD(instr), fs * ft); +} + +void mull(Registers ®s, u32 instr) { + u64 fs = regs.cop1.GetReg(regs.cop0, FS(instr)); + u64 ft = regs.cop1.GetReg(regs.cop0, FT(instr)); + regs.cop1.SetReg(regs.cop0, FD(instr), fs * ft); +} + +void subs(Registers ®s, u32 instr) { + float fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + float ft = regs.cop1.GetCop1Reg(regs.cop0, FT(instr)); + regs.cop1.SetCop1Reg(regs.cop0, FD(instr), fs - ft); +} + +void subd(Registers ®s, u32 instr) { + double fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + double ft = regs.cop1.GetCop1Reg(regs.cop0, FT(instr)); + regs.cop1.SetCop1Reg(regs.cop0, FD(instr), fs - ft); +} + +void subw(Registers ®s, u32 instr) { + u32 fs = regs.cop1.GetReg(regs.cop0, FS(instr)); + u32 ft = regs.cop1.GetReg(regs.cop0, FT(instr)); + regs.cop1.SetReg(regs.cop0, FD(instr), fs - ft); +} + +void subl(Registers ®s, u32 instr) { + u64 fs = regs.cop1.GetReg(regs.cop0, FS(instr)); + u64 ft = regs.cop1.GetReg(regs.cop0, FT(instr)); + regs.cop1.SetReg(regs.cop0, FD(instr), fs - ft); +} + +void movs(n64::Registers& regs, u32 instr) { + regs.cop1.SetCop1Reg( + regs.cop0, + FD(instr), + regs.cop1.GetCop1Reg( + regs.cop0, + FS(instr) + ) + ); +} + +void movd(n64::Registers& regs, u32 instr) { + regs.cop1.SetCop1Reg( + regs.cop0, + FD(instr), + regs.cop1.GetCop1Reg( + regs.cop0, + FS(instr) + ) + ); +} + +void movw(n64::Registers& regs, u32 instr) { + regs.cop1.SetReg( + regs.cop0, + FD(instr), + regs.cop1.GetReg( + regs.cop0, + FS(instr) + ) + ); +} + +void movl(n64::Registers& regs, u32 instr) { + regs.cop1.SetReg( + regs.cop0, + FD(instr), + regs.cop1.GetReg( + regs.cop0, + FS(instr) + ) + ); +} + +void negs(Registers ®s, u32 instr) { + regs.cop1.SetCop1Reg( + regs.cop0, + FD(instr), + -regs.cop1.GetCop1Reg( + regs.cop0, + FS(instr) + ) + ); +} + +void negd(Registers ®s, u32 instr) { + regs.cop1.SetCop1Reg( + regs.cop0, + FD(instr), + -regs.cop1.GetCop1Reg( + regs.cop0, + FS(instr) + ) + ); +} + +void sqrts(Registers ®s, u32 instr) { + float fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + regs.cop1.SetCop1Reg(regs.cop0, FD(instr), sqrtf(fs)); +} + +void sqrtd(Registers ®s, u32 instr) { + double fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + regs.cop1.SetCop1Reg(regs.cop0, FD(instr), sqrt(fs)); +} + +void roundls(n64::Registers& regs, u32 instr) { + float fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + PUSHROUNDINGMODE; + regs.cop1.SetReg(regs.cop0, FD(instr), (s32)nearbyintf(fs)); + POPROUNDINGMODE; +} + +void roundld(n64::Registers& regs, u32 instr) { + double fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + PUSHROUNDINGMODE; + regs.cop1.SetReg(regs.cop0, FD(instr), (s64)nearbyint(fs)); + POPROUNDINGMODE; +} + +void roundws(n64::Registers& regs, u32 instr) { + float fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + PUSHROUNDINGMODE; + regs.cop1.SetReg(regs.cop0, FD(instr), (s32)nearbyintf(fs)); + POPROUNDINGMODE; +} + +void roundwd(n64::Registers& regs, u32 instr) { + double fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + PUSHROUNDINGMODE; + regs.cop1.SetReg(regs.cop0, FD(instr), (s32)nearbyint(fs)); + POPROUNDINGMODE; +} + +void floorls(n64::Registers& regs, u32 instr) { + float fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + regs.cop1.SetReg(regs.cop0, FD(instr), (s64)floorf(fs)); +} + +void floorld(n64::Registers& regs, u32 instr) { + double fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + regs.cop1.SetReg(regs.cop0, FD(instr), (s64)floor(fs)); +} + +void floorws(n64::Registers& regs, u32 instr) { + float fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + regs.cop1.SetReg(regs.cop0, FD(instr), (s64)floorf(fs)); +} + +void floorwd(n64::Registers& regs, u32 instr) { + double fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + regs.cop1.SetReg(regs.cop0, FD(instr), (s64)floor(fs)); +} + +void lwc1(n64::Registers& regs, Mem& mem, u32 instr) { + if(!regs.cop0.status.cu1) { + FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true); + return; + } + + u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; + if(addr & 3) { + FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); + } + + u32 physical; + if(!MapVAddr(regs, LOAD, addr, physical)) { + HandleTLBException(regs, addr); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); + } else { + u32 data = mem.Read32(regs, physical, regs.oldPC); + regs.cop1.SetReg(regs.cop0, FT(instr), data); + } +} + +void swc1(n64::Registers& regs, Mem& mem, u32 instr) { + if(!regs.cop0.status.cu1) { + FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true); + return; + } + + u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; + if(addr & 3) { + FireException(regs, ExceptionCode::AddressErrorStore, 0, true); + } + + u32 physical; + if(!MapVAddr(regs, STORE, addr, physical)) { + HandleTLBException(regs, addr); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + } else { + mem.Write32(regs, physical, regs.cop1.GetReg(regs.cop0, FT(instr)), regs.oldPC); + } +} + +void ldc1(n64::Registers& regs, Mem& mem, u32 instr) { + if(!regs.cop0.status.cu1) { + FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC); + return; + } + + u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; + if(addr & 7) { + FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + } + + u32 physical; + if(!MapVAddr(regs, LOAD, addr, physical)) { + HandleTLBException(regs, addr); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); + } else { + u64 data = mem.Read64(regs, physical, regs.oldPC); + regs.cop1.SetReg(regs.cop0, FT(instr), data); + } +} + +void sdc1(n64::Registers& regs, Mem& mem, u32 instr) { + if(!regs.cop0.status.cu1) { + FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC); + return; + } + + u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; + if(addr & 7) { + FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); + } + + u32 physical; + if(!MapVAddr(regs, STORE, addr, physical)) { + HandleTLBException(regs, addr); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + } else { + mem.Write64(regs, physical, regs.cop1.GetReg(regs.cop0, FT(instr)), regs.oldPC); + } +} + +void truncws(n64::Registers& regs, u32 instr) { + float fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + s32 result = (s32)truncf(fs); + regs.cop1.SetReg(regs.cop0, FD(instr), result); +} + +void truncwd(n64::Registers& regs, u32 instr) { + double fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + s32 result = (s32)trunc(fs); + regs.cop1.SetReg(regs.cop0, FD(instr), result); +} + +void truncls(n64::Registers& regs, u32 instr) { + float fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + s64 result = (s64)truncf(fs); + regs.cop1.SetReg(regs.cop0, FD(instr), result); +} + +void truncld(n64::Registers& regs, u32 instr) { + double fs = regs.cop1.GetCop1Reg(regs.cop0, FS(instr)); + s64 result = (s64)trunc(fs); + regs.cop1.SetReg(regs.cop0, FD(instr), result); +} + +void mfc1(n64::Registers& regs, u32 instr) { + regs.gpr[RT(instr)] = (s32)regs.cop1.GetReg(regs.cop0, FS(instr)); +} + +void dmfc1(n64::Registers& regs, u32 instr) { + regs.gpr[RT(instr)] = (s64)regs.cop1.GetReg(regs.cop0, FS(instr)); +} + +void mtc1(n64::Registers& regs, u32 instr) { + regs.cop1.SetReg(regs.cop0, FS(instr), regs.gpr[RT(instr)]); +} + +void dmtc1(n64::Registers& regs, u32 instr) { + regs.cop1.SetReg(regs.cop0, FS(instr), regs.gpr[RT(instr)]); +} +} \ No newline at end of file diff --git a/src/backend/core/dynarec/cop/cop1instructions.hpp b/src/backend/core/dynarec/cop/cop1instructions.hpp new file mode 100644 index 00000000..40d2c95f --- /dev/null +++ b/src/backend/core/dynarec/cop/cop1instructions.hpp @@ -0,0 +1,68 @@ +#pragma once +#include +#include + +namespace n64::JIT { +void absd(n64::Registers&, u32 instr); +void abss(n64::Registers&, u32 instr); +void absw(n64::Registers&, u32 instr); +void absl(n64::Registers&, u32 instr); +void adds(n64::Registers&, u32 instr); +void addd(n64::Registers&, u32 instr); +void subs(n64::Registers&, u32 instr); +void subd(n64::Registers&, u32 instr); +void subw(n64::Registers&, u32 instr); +void subl(n64::Registers&, u32 instr); +void ceills(n64::Registers&, u32 instr); +void ceilws(n64::Registers&, u32 instr); +void ceilld(n64::Registers&, u32 instr); +void ceilwd(n64::Registers&, u32 instr); +void cfc1(n64::Registers&, u32 instr); +void ctc1(n64::Registers&, u32 instr); +void roundls(n64::Registers&, u32 instr); +void roundld(n64::Registers&, u32 instr); +void roundws(n64::Registers&, u32 instr); +void roundwd(n64::Registers&, u32 instr); +void floorls(n64::Registers&, u32 instr); +void floorld(n64::Registers&, u32 instr); +void floorws(n64::Registers&, u32 instr); +void floorwd(n64::Registers&, u32 instr); +void cvtls(n64::Registers&, u32 instr); +void cvtws(n64::Registers&, u32 instr); +void cvtds(n64::Registers&, u32 instr); +void cvtsw(n64::Registers&, u32 instr); +void cvtdw(n64::Registers&, u32 instr); +void cvtsd(n64::Registers&, u32 instr); +void cvtwd(n64::Registers&, u32 instr); +void cvtld(n64::Registers&, u32 instr); +void cvtdl(n64::Registers&, u32 instr); +void cvtsl(n64::Registers&, u32 instr); +template +void ccond(n64::Registers&, u32 instr, CompConds); +void divs(n64::Registers&, u32 instr); +void divd(n64::Registers&, u32 instr); +void muls(n64::Registers&, u32 instr); +void muld(n64::Registers&, u32 instr); +void mulw(n64::Registers&, u32 instr); +void mull(n64::Registers&, u32 instr); +void movs(n64::Registers&, u32 instr); +void movd(n64::Registers&, u32 instr); +void movw(n64::Registers&, u32 instr); +void movl(n64::Registers&, u32 instr); +void negs(n64::Registers&, u32 instr); +void negd(n64::Registers&, u32 instr); +void sqrts(n64::Registers&, u32 instr); +void sqrtd(n64::Registers&, u32 instr); +void lwc1(n64::Registers&, Mem&, u32 instr); +void swc1(n64::Registers&, Mem&, u32 instr); +void ldc1(n64::Registers&, Mem&, u32 instr); +void mfc1(n64::Registers&, u32 instr); +void dmfc1(n64::Registers&, u32 instr); +void mtc1(n64::Registers&, u32 instr); +void dmtc1(n64::Registers&, u32 instr); +void sdc1(n64::Registers&, Mem&, u32 instr); +void truncws(n64::Registers&, u32 instr); +void truncwd(n64::Registers&, u32 instr); +void truncls(n64::Registers&, u32 instr); +void truncld(n64::Registers&, u32 instr); +} \ No newline at end of file diff --git a/src/backend/core/dynarec/decode.cpp b/src/backend/core/dynarec/decode.cpp new file mode 100644 index 00000000..b8838b94 --- /dev/null +++ b/src/backend/core/dynarec/decode.cpp @@ -0,0 +1,254 @@ +#include +#include +#include +#include + +namespace n64::JIT { +void Dynarec::cop2Decode(n64::Registers& regs, u32 instr) { + code.push(code.rbp); + code.mov(code.rbp, (u64)®s.cop0.status.raw); + code.mov(code.eax, code.dword[code.rbp]); + code.pop(code.rbp); + code.and_(code.eax, 0x40000000); + code.cmp(code.eax, 1); + code.je("NoException2"); + + code.mov(code.rdi, (u64)®s); + code.mov(code.rsi, (u64)ExceptionCode::CoprocessorUnusable); + code.mov(code.rdx, 2); + code.mov(code.rcx, 1); + code.mov(code.rax, (u64) FireException); + code.call(code.rax); + code.xor_(code.eax, code.eax); + code.ret(); + + code.L("NoException2"); + + code.mov(code.rdi, (u64)this); + code.mov(code.rsi, (u64)®s); + code.mov(code.rdx, (u64)instr); + + switch(RS(instr)) { + case 0x00: + code.mov(code.rax, (u64)mfc2); + code.call(code.rax); + break; + case 0x01: + code.mov(code.rax, (u64)dmfc2); + code.call(code.rax); + break; + case 0x02: case 0x06: code.nop(); break; + case 0x04: + code.mov(code.rax, (u64)mtc2); + code.call(code.rax); + break; + case 0x05: + code.mov(code.rax, (u64)dmtc2); + code.call(code.rax); + break; + default: + util::panic("[RECOMPILER] Unhandled reserved instruction exception {:016X}\n", (u64)regs.pc); + } +} + +bool Dynarec::special(n64::Registers& regs, u32 instr) { + u8 mask = (instr & 0x3F); + bool res = false; + // 00rr_rccc + switch (mask) { // TODO: named constants for clearer code + case 0: + if (instr != 0) { + sll(regs, instr); + } + break; + case 0x02: srl(regs, instr); break; + case 0x03: sra(regs, instr); break; + case 0x04: sllv(regs, instr); break; + case 0x06: srlv(regs, instr); break; + case 0x07: srav(regs, instr); break; + case 0x08: + jr(regs, instr); + res = true; + break; + case 0x09: + jalr(regs, instr); + res = true; + break; + case 0x0C: util::panic("[RECOMPILER] Unhandled syscall instruction {:016X}\n", (u64)regs.pc); + case 0x0D: util::panic("[RECOMPILER] Unhandled break instruction {:016X}\n", (u64)regs.pc); + case 0x0F: code.nop(); break; // SYNC + case 0x10: mfhi(regs, instr); break; + case 0x11: mthi(regs, instr); break; + case 0x12: mflo(regs, instr); break; + case 0x13: mtlo(regs, instr); break; + case 0x14: dsllv(regs, instr); break; + case 0x16: dsrlv(regs, instr); break; + case 0x17: dsrav(regs, instr); break; + case 0x18: mult(regs, instr); break; + case 0x19: multu(regs, instr); break; + case 0x1A: div(regs, instr); break; + case 0x1B: divu(regs, instr); break; + case 0x1C: dmult(regs, instr); break; + case 0x1D: dmultu(regs, instr); break; + case 0x1E: ddiv(regs, instr); break; + case 0x1F: ddivu(regs, instr); break; + case 0x20: add(regs, instr); break; + case 0x21: addu(regs, instr); break; + case 0x22: sub(regs, instr); break; + case 0x23: subu(regs, instr); break; + case 0x24: and_(regs, instr); break; + case 0x25: or_(regs, instr); break; + case 0x26: xor_(regs, instr); break; + case 0x27: nor(regs, instr); break; + case 0x2A: slt(regs, instr); break; + case 0x2B: sltu(regs, instr); break; + case 0x2C: dadd(regs, instr); break; + case 0x2D: daddu(regs, instr); break; + case 0x2E: dsub(regs, instr); break; + case 0x2F: dsubu(regs, instr); break; + case 0x30: + trap(regs, regs.gpr[RS(instr)] >= regs.gpr[RT(instr)]); + res = true; + break; + case 0x31: + trap(regs, (u64)regs.gpr[RS(instr)] >= (u64)regs.gpr[RT(instr)]); + res = true; + break; + case 0x32: + trap(regs, regs.gpr[RS(instr)] < regs.gpr[RT(instr)]); + res = true; + break; + case 0x33: + trap(regs, (u64)regs.gpr[RS(instr)] < (u64)regs.gpr[RT(instr)]); + res = true; + break; + case 0x34: + trap(regs, regs.gpr[RS(instr)] == regs.gpr[RT(instr)]); + res = true; + break; + case 0x36: + trap(regs, regs.gpr[RS(instr)] != regs.gpr[RT(instr)]); + res = true; + break; + case 0x38: dsll(regs, instr); break; + case 0x3A: dsrl(regs, instr); break; + case 0x3B: dsra(regs, instr); break; + case 0x3C: dsll32(regs, instr); break; + case 0x3E: dsrl32(regs, instr); break; + case 0x3F: dsra32(regs, instr); break; + default: + util::panic("Unimplemented special {} {} ({:08X}) (pc: {:016X})\n", (mask >> 3) & 7, mask & 7, instr, (u64)regs.oldPC); + } + + return res; +} + +bool Dynarec::regimm(n64::Registers& regs, u32 instr) { + u8 mask = ((instr >> 16) & 0x1F); + // 000r_rccc + switch (mask) { // TODO: named constants for clearer code + case 0x00: b(regs, instr, regs.gpr[RS(instr)] < 0); break; + case 0x01: b(regs, instr, regs.gpr[RS(instr)] >= 0); break; + case 0x02: bl(regs, instr, regs.gpr[RS(instr)] < 0); break; + case 0x03: bl(regs, instr, regs.gpr[RS(instr)] >= 0); break; + case 0x08: trap(regs, regs.gpr[RS(instr)] >= s64(s16(instr))); break; + case 0x09: trap(regs, u64(regs.gpr[RS(instr)]) >= u64(s64(s16(instr)))); break; + case 0x0A: trap(regs, regs.gpr[RS(instr)] < s64(s16(instr))); break; + case 0x0B: trap(regs, u64(regs.gpr[RS(instr)]) < u64(s64(s16(instr)))); break; + case 0x0C: trap(regs, regs.gpr[RS(instr)] == s64(s16(instr))); break; + case 0x0E: trap(regs, regs.gpr[RS(instr)] != s64(s16(instr))); break; + case 0x10: blink(regs, instr, regs.gpr[RS(instr)] < 0); break; + case 0x11: blink(regs, instr, regs.gpr[RS(instr)] >= 0); break; + case 0x12: bllink(regs, instr, regs.gpr[RS(instr)] < 0); break; + case 0x13: bllink(regs, instr, regs.gpr[RS(instr)] >= 0); break; + default: + util::panic("Unimplemented regimm {} {} ({:08X}) (pc: {:016X})\n", (mask >> 3) & 3, mask & 7, instr, (u64)regs.oldPC); + } + + return true; +} + +bool Dynarec::Exec(n64::Registers& regs, Mem& mem, u32 instr) { + u8 mask = (instr >> 26) & 0x3f; + bool res = false; + // 00rr_rccc + switch(mask) { // TODO: named constants for clearer code + case 0x00: res = special(regs, instr); break; + case 0x01: res = regimm(regs, instr); break; + case 0x02: + j(regs, instr); + res = true; + break; + case 0x03: + jal(regs, instr); + res = true; + break; + case 0x04: + b(regs, instr, regs.gpr[RS(instr)] == regs.gpr[RT(instr)]); + res = true; + break; + case 0x05: + b(regs, instr, regs.gpr[RS(instr)] != regs.gpr[RT(instr)]); + res = true; + break; + case 0x06: + b(regs, instr, regs.gpr[RS(instr)] <= 0); + res = true; + break; + case 0x07: + b(regs, instr, regs.gpr[RS(instr)] > 0); + res = true; + break; + case 0x08: addi(regs, instr); break; + case 0x09: addiu(regs, instr); break; + case 0x0A: slti(regs, instr); break; + case 0x0B: sltiu(regs, instr); break; + case 0x0C: andi(regs, instr); break; + case 0x0D: ori(regs, instr); break; + case 0x0E: xori(regs, instr); break; + case 0x0F: lui(regs, instr); break; + case 0x10: cop0Decode(regs, instr); break; + case 0x11: res = cop1Decode(regs, *this, instr); break; + case 0x12: cop2Decode(regs, instr); break; + case 0x14: bl(regs, instr, regs.gpr[RS(instr)] == regs.gpr[RT(instr)]); break; + case 0x15: bl(regs, instr, regs.gpr[RS(instr)] != regs.gpr[RT(instr)]); break; + case 0x16: bl(regs, instr, regs.gpr[RS(instr)] <= 0); break; + case 0x17: bl(regs, instr, regs.gpr[RS(instr)] > 0); break; + case 0x18: daddi(regs, instr); break; + case 0x19: daddiu(regs, instr); break; + case 0x1A: ldl(regs, mem, instr); break; + case 0x1B: ldr(regs, mem, instr); break; + case 0x1F: FireException(regs, ExceptionCode::ReservedInstruction, 0, true); break; + case 0x20: lb(regs, mem, instr); break; + case 0x21: lh(regs, mem, instr); break; + case 0x22: lwl(regs, mem, instr); break; + case 0x23: lw(regs, mem, instr); break; + case 0x24: lbu(regs, mem, instr); break; + case 0x25: lhu(regs, mem, instr); break; + case 0x26: lwr(regs, mem, instr); break; + case 0x27: lwu(regs, mem, instr); break; + case 0x28: sb(regs, mem, instr); break; + case 0x29: sh(regs, mem, instr); break; + case 0x2A: swl(regs, mem, instr); break; + case 0x2B: sw(regs, mem, instr); break; + case 0x2C: sdl(regs, mem, instr); break; + case 0x2D: sdr(regs, mem, instr); break; + case 0x2E: swr(regs, mem, instr); break; + case 0x2F: break; // CACHE + case 0x30: ll(regs, mem, instr); break; + case 0x31: lwc1(regs, mem, instr); break; + case 0x34: lld(regs, mem, instr); break; + case 0x35: ldc1(regs, mem, instr); break; + case 0x37: ld(regs, mem, instr); break; + case 0x38: sc(regs, mem, instr); break; + case 0x39: swc1(regs, mem, instr); break; + case 0x3C: scd(regs, mem, instr); break; + case 0x3D: sdc1(regs, mem, instr); break; + case 0x3F: sd(regs, mem, instr); break; + default: + util::panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})\n", mask, instr, (u64)regs.oldPC); + } + + return res; +} +} diff --git a/src/backend/core/dynarec/instructions.cpp b/src/backend/core/dynarec/instructions.cpp index 54d3889a..87481d18 100644 --- a/src/backend/core/dynarec/instructions.cpp +++ b/src/backend/core/dynarec/instructions.cpp @@ -1,82 +1,83 @@ -#include +#include +#include #define se_imm(x) ((s16)((x) & 0xFFFF)) #define check_address_error(mask, addr) (((!regs.cop0.is_64bit_addressing) && (s32)(addr) != (addr)) || (((addr) & (mask)) != 0)) #define check_signed_overflow(op1, op2, res) (((~((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1) #define check_signed_underflow(op1, op2, res) (((((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1) -namespace n64 { -void Dynarec::add(Registers& regs, u32 instr) { +namespace n64::JIT { +void add(Registers& regs, u32 instr) { u32 rs = (s32)regs.gpr[RS(instr)]; u32 rt = (s32)regs.gpr[RT(instr)]; u32 result = rs + rt; if(check_signed_overflow(rs, rt, result)) { - FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); + FireException(regs, ExceptionCode::Overflow, 0, true); } else { regs.gpr[RD(instr)] = s32(result); } } -void Dynarec::addu(Registers& regs, u32 instr) { +void addu(Registers& regs, u32 instr) { s32 rs = (s32)regs.gpr[RS(instr)]; s32 rt = (s32)regs.gpr[RT(instr)]; s32 result = rs + rt; regs.gpr[RD(instr)] = result; } -void Dynarec::addi(Registers& regs, u32 instr) { +void addi(Registers& regs, u32 instr) { u32 rs = regs.gpr[RS(instr)]; u32 imm = s32(s16(instr)); u32 result = rs + imm; if(check_signed_overflow(rs, imm, result)) { - FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); + FireException(regs, ExceptionCode::Overflow, 0, true); } else { regs.gpr[RT(instr)] = s32(result); } } -void Dynarec::addiu(Registers& regs, u32 instr) { +void addiu(Registers& regs, u32 instr) { s32 rs = (s32)regs.gpr[RS(instr)]; s16 imm = (s16)(instr); s32 result = rs + imm; regs.gpr[RT(instr)] = result; } -void Dynarec::dadd(Registers& regs, u32 instr) { +void dadd(Registers& regs, u32 instr) { u64 rs = regs.gpr[RS(instr)]; u64 rt = regs.gpr[RT(instr)]; u64 result = rt + rs; if(check_signed_overflow(rs, rt, result)) { - FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); + FireException(regs, ExceptionCode::Overflow, 0, true); } else { regs.gpr[RD(instr)] = result; } } -void Dynarec::daddu(Registers& regs, u32 instr) { +void daddu(Registers& regs, u32 instr) { s64 rs = regs.gpr[RS(instr)]; s64 rt = regs.gpr[RT(instr)]; regs.gpr[RD(instr)] = rs + rt; } -void Dynarec::daddi(Registers& regs, u32 instr) { +void daddi(Registers& regs, u32 instr) { u64 imm = s64(s16(instr)); u64 rs = regs.gpr[RS(instr)]; u64 result = imm + rs; if(check_signed_overflow(rs, imm, result)) { - FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); + FireException(regs, ExceptionCode::Overflow, 0, true); } else { regs.gpr[RT(instr)] = result; } } -void Dynarec::daddiu(Registers& regs, u32 instr) { +void daddiu(Registers& regs, u32 instr) { s16 imm = (s16)(instr); s64 rs = regs.gpr[RS(instr)]; regs.gpr[RT(instr)] = rs + imm; } -void Dynarec::div(Registers& regs, u32 instr) { +void div(Registers& regs, u32 instr) { s64 dividend = (s32)regs.gpr[RS(instr)]; s64 divisor = (s32)regs.gpr[RT(instr)]; @@ -95,7 +96,7 @@ void Dynarec::div(Registers& regs, u32 instr) { } } -void Dynarec::divu(Registers& regs, u32 instr) { +void divu(Registers& regs, u32 instr) { u32 dividend = regs.gpr[RS(instr)]; u32 divisor = regs.gpr[RT(instr)]; if(divisor == 0) { @@ -109,7 +110,7 @@ void Dynarec::divu(Registers& regs, u32 instr) { } } -void Dynarec::ddiv(Registers& regs, u32 instr) { +void ddiv(Registers& regs, u32 instr) { s64 dividend = regs.gpr[RS(instr)]; s64 divisor = regs.gpr[RT(instr)]; if (dividend == 0x8000000000000000 && divisor == 0xFFFFFFFFFFFFFFFF) { @@ -130,7 +131,7 @@ void Dynarec::ddiv(Registers& regs, u32 instr) { } } -void Dynarec::ddivu(Registers& regs, u32 instr) { +void ddivu(Registers& regs, u32 instr) { u64 dividend = regs.gpr[RS(instr)]; u64 divisor = regs.gpr[RT(instr)]; if(divisor == 0) { @@ -144,14 +145,14 @@ void Dynarec::ddivu(Registers& regs, u32 instr) { } } -void Dynarec::branch(Registers& regs, bool cond, s64 address) { +void branch(Registers& regs, bool cond, s64 address) { regs.delaySlot = true; if (cond) { regs.nextPC = address; } } -void Dynarec::branch_likely(Registers& regs, bool cond, s64 address) { +void branch_likely(Registers& regs, bool cond, s64 address) { regs.delaySlot = true; if (cond) { regs.nextPC = address; @@ -160,78 +161,78 @@ void Dynarec::branch_likely(Registers& regs, bool cond, s64 address) { } } -void Dynarec::b(Registers& regs, u32 instr, bool cond) { +void b(Registers& regs, u32 instr, bool cond) { s64 offset = (s64)se_imm(instr) << 2; s64 address = regs.pc + offset; branch(regs, cond, address); } -void Dynarec::blink(Registers& regs, u32 instr, bool cond) { +void blink(Registers& regs, u32 instr, bool cond) { regs.gpr[31] = regs.nextPC; s64 offset = (s64)se_imm(instr) << 2; s64 address = regs.pc + offset; branch(regs, cond, address); } -void Dynarec::bl(Registers& regs, u32 instr, bool cond) { +void bl(Registers& regs, u32 instr, bool cond) { s64 offset = (s64)se_imm(instr) << 2; s64 address = regs.pc + offset; branch_likely(regs, cond, address); } -void Dynarec::bllink(Registers& regs, u32 instr, bool cond) { +void bllink(Registers& regs, u32 instr, bool cond) { regs.gpr[31] = regs.nextPC; s64 offset = (s64)se_imm(instr) << 2; s64 address = regs.pc + offset; branch_likely(regs, cond, address); } -void Dynarec::lui(Registers& regs, u32 instr) { +void lui(Registers& regs, u32 instr) { s64 val = (s16)instr; val <<= 16; regs.gpr[RT(instr)] = val; } -void Dynarec::lb(Registers& regs, Mem& mem, u32 instr) { +void lb(Registers& regs, Mem& mem, u32 instr) { u64 address = regs.gpr[RS(instr)] + (s16)instr; regs.gpr[RT(instr)] = (s8)mem.Read8(regs, address, regs.oldPC); } -void Dynarec::lh(Registers& regs, Mem& mem, u32 instr) { +void lh(Registers& regs, Mem& mem, u32 instr) { u64 address = regs.gpr[RS(instr)] + (s16)instr; if (check_address_error(address, 0b1)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); return; } regs.gpr[RT(instr)] = (s16)mem.Read16(regs, address, regs.oldPC); } -void Dynarec::lw(Registers& regs, Mem& mem, u32 instr) { +void lw(Registers& regs, Mem& mem, u32 instr) { s16 offset = instr; u64 address = regs.gpr[RS(instr)] + offset; if (check_address_error(address, 0b11)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); return; } u32 physical; if (!MapVAddr(regs, LOAD, address, physical)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { regs.gpr[RT(instr)] = (s32)mem.Read32(regs, physical, regs.oldPC); } } -void Dynarec::ll(Registers& regs, Mem& mem, u32 instr) { +void ll(Registers& regs, Mem& mem, u32 instr) { s64 address = regs.gpr[RS(instr)] + (s16)instr; u32 physical; if (!MapVAddr(regs, LOAD, address, physical)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { regs.gpr[RT(instr)] = (s32)mem.Read32(regs, physical, regs.oldPC); } @@ -240,12 +241,12 @@ void Dynarec::ll(Registers& regs, Mem& mem, u32 instr) { regs.cop0.LLAddr = physical >> 4; } -void Dynarec::lwl(Registers& regs, Mem& mem, u32 instr) { +void lwl(Registers& regs, Mem& mem, u32 instr) { u64 address = regs.gpr[RS(instr)] + (s16)instr; u32 paddr = 0; if(!MapVAddr(regs, LOAD, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { u32 shift = 8 * ((address ^ 0) & 3); u32 mask = 0xFFFFFFFF << shift; @@ -255,12 +256,12 @@ void Dynarec::lwl(Registers& regs, Mem& mem, u32 instr) { } } -void Dynarec::lwr(Registers& regs, Mem& mem, u32 instr) { +void lwr(Registers& regs, Mem& mem, u32 instr) { u64 address = regs.gpr[RS(instr)] + (s16)instr; u32 paddr = 0; if(!MapVAddr(regs, LOAD, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { u32 shift = 8 * ((address ^ 3) & 3); u32 mask = 0xFFFFFFFF >> shift; @@ -270,11 +271,11 @@ void Dynarec::lwr(Registers& regs, Mem& mem, u32 instr) { } } -void Dynarec::ld(Registers& regs, Mem& mem, u32 instr) { +void ld(Registers& regs, Mem& mem, u32 instr) { s64 address = regs.gpr[RS(instr)] + (s16)instr; if (check_address_error(address, 0b111)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); return; } @@ -282,12 +283,12 @@ void Dynarec::ld(Registers& regs, Mem& mem, u32 instr) { regs.gpr[RT(instr)] = value; } -void Dynarec::lld(Registers& regs, Mem& mem, u32 instr) { +void lld(Registers& regs, Mem& mem, u32 instr) { s64 address = regs.gpr[RS(instr)] + (s16)instr; u32 paddr; if (!MapVAddr(regs, LOAD, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { regs.gpr[RT(instr)] = mem.Read64(regs, paddr, regs.oldPC); } @@ -296,12 +297,12 @@ void Dynarec::lld(Registers& regs, Mem& mem, u32 instr) { regs.cop0.LLAddr = paddr >> 4; } -void Dynarec::ldl(Registers& regs, Mem& mem, u32 instr) { +void ldl(Registers& regs, Mem& mem, u32 instr) { u64 address = regs.gpr[RS(instr)] + (s16)instr; u32 paddr = 0; if (!MapVAddr(regs, LOAD, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { s32 shift = 8 * ((address ^ 0) & 7); u64 mask = 0xFFFFFFFFFFFFFFFF << shift; @@ -311,12 +312,12 @@ void Dynarec::ldl(Registers& regs, Mem& mem, u32 instr) { } } -void Dynarec::ldr(Registers& regs, Mem& mem, u32 instr) { +void ldr(Registers& regs, Mem& mem, u32 instr) { u64 address = regs.gpr[RS(instr)] + (s16)instr; u32 paddr; if (!MapVAddr(regs, LOAD, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { s32 shift = 8 * ((address ^ 7) & 7); u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; @@ -326,17 +327,17 @@ void Dynarec::ldr(Registers& regs, Mem& mem, u32 instr) { } } -void Dynarec::lbu(Registers& regs, Mem& mem, u32 instr) { +void lbu(Registers& regs, Mem& mem, u32 instr) { u64 address = regs.gpr[RS(instr)] + (s16)instr; u8 value = mem.Read8(regs, address, regs.oldPC); regs.gpr[RT(instr)] = value; } -void Dynarec::lhu(Registers& regs, Mem& mem, u32 instr) { +void lhu(Registers& regs, Mem& mem, u32 instr) { s64 address = regs.gpr[RS(instr)] + (s16)instr; if (check_address_error(address, 0b1)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); return; } @@ -344,11 +345,11 @@ void Dynarec::lhu(Registers& regs, Mem& mem, u32 instr) { regs.gpr[RT(instr)] = value; } -void Dynarec::lwu(Registers& regs, Mem& mem, u32 instr) { +void lwu(Registers& regs, Mem& mem, u32 instr) { s64 address = regs.gpr[RS(instr)] + (s16)instr; if (check_address_error(address, 0b11)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); return; } @@ -356,16 +357,16 @@ void Dynarec::lwu(Registers& regs, Mem& mem, u32 instr) { regs.gpr[RT(instr)] = value; } -void Dynarec::sb(Registers& regs, Mem& mem, u32 instr) { +void sb(Registers& regs, Mem& mem, u32 instr) { u32 address = regs.gpr[RS(instr)] + (s16)instr; mem.Write8(regs, address, regs.gpr[RT(instr)], regs.oldPC); } -void Dynarec::sc(Registers& regs, Mem& mem, u32 instr) { +void sc(Registers& regs, Mem& mem, u32 instr) { s64 address = regs.gpr[RS(instr)] + (s16)instr; if (check_address_error(address, 0b11)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorStore, 0, true); } if(regs.cop0.llbit) { @@ -376,11 +377,11 @@ void Dynarec::sc(Registers& regs, Mem& mem, u32 instr) { regs.cop0.llbit = false; } -void Dynarec::scd(Registers& regs, Mem& mem, u32 instr) { +void scd(Registers& regs, Mem& mem, u32 instr) { s64 address = regs.gpr[RS(instr)] + (s16)instr; if (check_address_error(address, 0b111)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorStore, 0, true); return; } @@ -392,65 +393,65 @@ void Dynarec::scd(Registers& regs, Mem& mem, u32 instr) { regs.cop0.llbit = false; } -void Dynarec::sh(Registers& regs, Mem& mem, u32 instr) { +void sh(Registers& regs, Mem& mem, u32 instr) { s64 address = regs.gpr[RS(instr)] + (s16)instr; if (check_address_error(address, 0b1)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorStore, 0, true); return; } u32 physical; if(!MapVAddr(regs, STORE, address, physical)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { mem.Write16(regs, physical, regs.gpr[RT(instr)], regs.oldPC); } } -void Dynarec::sw(Registers& regs, Mem& mem, u32 instr) { +void sw(Registers& regs, Mem& mem, u32 instr) { s16 offset = instr; u64 address = regs.gpr[RS(instr)] + offset; if (check_address_error(address, 0b11)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorStore, 0, true); return; } u32 physical; if(!MapVAddr(regs, STORE, address, physical)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { mem.Write32(regs, physical, regs.gpr[RT(instr)], regs.oldPC); } } -void Dynarec::sd(Registers& regs, Mem& mem, u32 instr) { +void sd(Registers& regs, Mem& mem, u32 instr) { s64 address = regs.gpr[RS(instr)] + (s16)instr; if (check_address_error(address, 0b11)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorStore, 0, true); return; } u32 physical; if(!MapVAddr(regs, STORE, address, physical)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { mem.Write64(regs, physical, regs.gpr[RT(instr)], regs.oldPC); } } -void Dynarec::sdl(Registers& regs, Mem& mem, u32 instr) { +void sdl(Registers& regs, Mem& mem, u32 instr) { u64 address = regs.gpr[RS(instr)] + (s16)instr; u32 paddr; if (!MapVAddr(regs, STORE, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { s32 shift = 8 * ((address ^ 0) & 7); u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; @@ -460,12 +461,12 @@ void Dynarec::sdl(Registers& regs, Mem& mem, u32 instr) { } } -void Dynarec::sdr(Registers& regs, Mem& mem, u32 instr) { +void sdr(Registers& regs, Mem& mem, u32 instr) { u64 address = regs.gpr[RS(instr)] + (s16)instr; u32 paddr; if (!MapVAddr(regs, STORE, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { s32 shift = 8 * ((address ^ 7) & 7); u64 mask = 0xFFFFFFFFFFFFFFFF << shift; @@ -475,12 +476,12 @@ void Dynarec::sdr(Registers& regs, Mem& mem, u32 instr) { } } -void Dynarec::swl(Registers& regs, Mem& mem, u32 instr) { +void swl(Registers& regs, Mem& mem, u32 instr) { u64 address = regs.gpr[RS(instr)] + (s16)instr; u32 paddr; if (!MapVAddr(regs, STORE, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { u32 shift = 8 * ((address ^ 0) & 3); u32 mask = 0xFFFFFFFF >> shift; @@ -490,12 +491,12 @@ void Dynarec::swl(Registers& regs, Mem& mem, u32 instr) { } } -void Dynarec::swr(Registers& regs, Mem& mem, u32 instr) { +void swr(Registers& regs, Mem& mem, u32 instr) { u64 address = regs.gpr[RS(instr)] + (s16)instr; u32 paddr; if (!MapVAddr(regs, STORE, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { u32 shift = 8 * ((address ^ 3) & 3); u32 mask = 0xFFFFFFFF << shift; @@ -505,149 +506,149 @@ void Dynarec::swr(Registers& regs, Mem& mem, u32 instr) { } } -void Dynarec::ori(Registers& regs, u32 instr) { +void ori(Registers& regs, u32 instr) { s64 imm = (u16)instr; s64 result = imm | regs.gpr[RS(instr)]; regs.gpr[RT(instr)] = result; } -void Dynarec::or_(Registers& regs, u32 instr) { +void or_(Registers& regs, u32 instr) { regs.gpr[RD(instr)] = regs.gpr[RS(instr)] | regs.gpr[RT(instr)]; } -void Dynarec::nor(Registers& regs, u32 instr) { +void nor(Registers& regs, u32 instr) { regs.gpr[RD(instr)] = ~(regs.gpr[RS(instr)] | regs.gpr[RT(instr)]); } -void Dynarec::j(Registers& regs, u32 instr) { +void j(Registers& regs, u32 instr) { s32 target = (instr & 0x3ffffff) << 2; s64 address = (regs.oldPC & ~0xfffffff) | target; if (check_address_error(address, 0b11)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::DataBusError, 0, regs.oldPC); + FireException(regs, ExceptionCode::DataBusError, 0, true); } branch(regs, true, address); } -void Dynarec::jal(Registers& regs, u32 instr) { +void jal(Registers& regs, u32 instr) { regs.gpr[31] = regs.nextPC; j(regs, instr); } -void Dynarec::jalr(Registers& regs, u32 instr) { +void jalr(Registers& regs, u32 instr) { branch(regs, true, regs.gpr[RS(instr)]); regs.gpr[RD(instr)] = regs.pc + 4; } -void Dynarec::slti(Registers& regs, u32 instr) { +void slti(Registers& regs, u32 instr) { regs.gpr[RT(instr)] = regs.gpr[RS(instr)] < se_imm(instr); } -void Dynarec::sltiu(Registers& regs, u32 instr) { +void sltiu(Registers& regs, u32 instr) { regs.gpr[RT(instr)] = (u64)regs.gpr[RS(instr)] < se_imm(instr); } -void Dynarec::slt(Registers& regs, u32 instr) { +void slt(Registers& regs, u32 instr) { regs.gpr[RD(instr)] = regs.gpr[RS(instr)] < regs.gpr[RT(instr)]; } -void Dynarec::sltu(Registers& regs, u32 instr) { +void sltu(Registers& regs, u32 instr) { regs.gpr[RD(instr)] = (u64)regs.gpr[RS(instr)] < (u64)regs.gpr[RT(instr)]; } -void Dynarec::xori(Registers& regs, u32 instr) { +void xori(Registers& regs, u32 instr) { s64 imm = (u16)instr; regs.gpr[RT(instr)] = regs.gpr[RS(instr)] ^ imm; } -void Dynarec::xor_(Registers& regs, u32 instr) { +void xor_(Registers& regs, u32 instr) { regs.gpr[RD(instr)] = regs.gpr[RT(instr)] ^ regs.gpr[RS(instr)]; } -void Dynarec::andi(Registers& regs, u32 instr) { +void andi(Registers& regs, u32 instr) { s64 imm = (u16)instr; regs.gpr[RT(instr)] = regs.gpr[RS(instr)] & imm; } -void Dynarec::and_(Registers& regs, u32 instr) { +void and_(Registers& regs, u32 instr) { regs.gpr[RD(instr)] = regs.gpr[RS(instr)] & regs.gpr[RT(instr)]; } -void Dynarec::sll(Registers& regs, u32 instr) { +void sll(Registers& regs, u32 instr) { u8 sa = ((instr >> 6) & 0x1f); s32 result = regs.gpr[RT(instr)] << sa; regs.gpr[RD(instr)] = (s64)result; } -void Dynarec::sllv(Registers& regs, u32 instr) { +void sllv(Registers& regs, u32 instr) { u8 sa = (regs.gpr[RS(instr)]) & 0x1F; u32 rt = regs.gpr[RT(instr)]; s32 result = rt << sa; regs.gpr[RD(instr)] = (s64)result; } -void Dynarec::dsll32(Registers& regs, u32 instr) { +void dsll32(Registers& regs, u32 instr) { u8 sa = ((instr >> 6) & 0x1f); s64 result = regs.gpr[RT(instr)] << (sa + 32); regs.gpr[RD(instr)] = result; } -void Dynarec::dsll(Registers& regs, u32 instr) { +void dsll(Registers& regs, u32 instr) { u8 sa = ((instr >> 6) & 0x1f); s64 result = regs.gpr[RT(instr)] << sa; regs.gpr[RD(instr)] = result; } -void Dynarec::dsllv(Registers& regs, u32 instr) { +void dsllv(Registers& regs, u32 instr) { s64 sa = regs.gpr[RS(instr)] & 63; s64 result = regs.gpr[RT(instr)] << sa; regs.gpr[RD(instr)] = result; } -void Dynarec::srl(Registers& regs, u32 instr) { +void srl(Registers& regs, u32 instr) { u32 rt = regs.gpr[RT(instr)]; u8 sa = ((instr >> 6) & 0x1f); u32 result = rt >> sa; regs.gpr[RD(instr)] = (s32)result; } -void Dynarec::srlv(Registers& regs, u32 instr) { +void srlv(Registers& regs, u32 instr) { u8 sa = (regs.gpr[RS(instr)] & 0x1F); u32 rt = regs.gpr[RT(instr)]; s32 result = rt >> sa; regs.gpr[RD(instr)] = (s64)result; } -void Dynarec::dsrl(Registers& regs, u32 instr) { +void dsrl(Registers& regs, u32 instr) { u64 rt = regs.gpr[RT(instr)]; u8 sa = ((instr >> 6) & 0x1f); u64 result = rt >> sa; regs.gpr[RD(instr)] = s64(result); } -void Dynarec::dsrlv(Registers& regs, u32 instr) { +void dsrlv(Registers& regs, u32 instr) { u8 amount = (regs.gpr[RS(instr)] & 63); u64 rt = regs.gpr[RT(instr)]; u64 result = rt >> amount; regs.gpr[RD(instr)] = s64(result); } -void Dynarec::dsrl32(Registers& regs, u32 instr) { +void dsrl32(Registers& regs, u32 instr) { u64 rt = regs.gpr[RT(instr)]; u8 sa = ((instr >> 6) & 0x1f); u64 result = rt >> (sa + 32); regs.gpr[RD(instr)] = s64(result); } -void Dynarec::sra(Registers& regs, u32 instr) { +void sra(Registers& regs, u32 instr) { s64 rt = regs.gpr[RT(instr)]; u8 sa = ((instr >> 6) & 0x1f); s32 result = rt >> sa; regs.gpr[RD(instr)] = result; } -void Dynarec::srav(Registers& regs, u32 instr) { +void srav(Registers& regs, u32 instr) { s64 rt = regs.gpr[RT(instr)]; s64 rs = regs.gpr[RS(instr)]; u8 sa = rs & 0x1f; @@ -655,14 +656,14 @@ void Dynarec::srav(Registers& regs, u32 instr) { regs.gpr[RD(instr)] = result; } -void Dynarec::dsra(Registers& regs, u32 instr) { +void dsra(Registers& regs, u32 instr) { s64 rt = regs.gpr[RT(instr)]; u8 sa = ((instr >> 6) & 0x1f); s64 result = rt >> sa; regs.gpr[RD(instr)] = result; } -void Dynarec::dsrav(Registers& regs, u32 instr) { +void dsrav(Registers& regs, u32 instr) { s64 rt = regs.gpr[RT(instr)]; s64 rs = regs.gpr[RS(instr)]; s64 sa = rs & 63; @@ -670,14 +671,14 @@ void Dynarec::dsrav(Registers& regs, u32 instr) { regs.gpr[RD(instr)] = result; } -void Dynarec::dsra32(Registers& regs, u32 instr) { +void dsra32(Registers& regs, u32 instr) { s64 rt = regs.gpr[RT(instr)]; u8 sa = ((instr >> 6) & 0x1f); s64 result = rt >> (sa + 32); regs.gpr[RD(instr)] = result; } -void Dynarec::jr(Registers& regs, u32 instr) { +void jr(Registers& regs, u32 instr) { s64 address = regs.gpr[RS(instr)]; if (check_address_error(address, 0b11)) { HandleTLBException(regs, address); @@ -687,7 +688,7 @@ void Dynarec::jr(Registers& regs, u32 instr) { branch(regs, true, address); } -void Dynarec::dsub(Registers& regs, u32 instr) { +void dsub(Registers& regs, u32 instr) { s64 rt = regs.gpr[RT(instr)]; s64 rs = regs.gpr[RS(instr)]; s64 result = rs - rt; @@ -698,14 +699,14 @@ void Dynarec::dsub(Registers& regs, u32 instr) { } } -void Dynarec::dsubu(Registers& regs, u32 instr) { +void dsubu(Registers& regs, u32 instr) { u64 rt = regs.gpr[RT(instr)]; u64 rs = regs.gpr[RS(instr)]; u64 result = rs - rt; regs.gpr[RD(instr)] = s64(result); } -void Dynarec::sub(Registers& regs, u32 instr) { +void sub(Registers& regs, u32 instr) { s32 rt = regs.gpr[RT(instr)]; s32 rs = regs.gpr[RS(instr)]; s32 result = rs - rt; @@ -716,14 +717,14 @@ void Dynarec::sub(Registers& regs, u32 instr) { } } -void Dynarec::subu(Registers& regs, u32 instr) { +void subu(Registers& regs, u32 instr) { u32 rt = regs.gpr[RT(instr)]; u32 rs = regs.gpr[RS(instr)]; u32 result = rs - rt; regs.gpr[RD(instr)] = (s64)((s32)result); } -void Dynarec::dmultu(Registers& regs, u32 instr) { +void dmultu(Registers& regs, u32 instr) { u64 rt = regs.gpr[RT(instr)]; u64 rs = regs.gpr[RS(instr)]; u128 result = (u128)rt * (u128)rs; @@ -731,7 +732,7 @@ void Dynarec::dmultu(Registers& regs, u32 instr) { regs.hi = (s64)(result >> 64); } -void Dynarec::dmult(Registers& regs, u32 instr) { +void dmult(Registers& regs, u32 instr) { s64 rt = regs.gpr[RT(instr)]; s64 rs = regs.gpr[RS(instr)]; s128 result = (s128)rt * (s128)rs; @@ -739,7 +740,7 @@ void Dynarec::dmult(Registers& regs, u32 instr) { regs.hi = result >> 64; } -void Dynarec::multu(Registers& regs, u32 instr) { +void multu(Registers& regs, u32 instr) { u32 rt = regs.gpr[RT(instr)]; u32 rs = regs.gpr[RS(instr)]; u64 result = (u64)rt * (u64)rs; @@ -747,7 +748,7 @@ void Dynarec::multu(Registers& regs, u32 instr) { regs.hi = (s64)((s32)(result >> 32)); } -void Dynarec::mult(Registers& regs, u32 instr) { +void mult(Registers& regs, u32 instr) { s32 rt = regs.gpr[RT(instr)]; s32 rs = regs.gpr[RS(instr)]; s64 result = (s64)rt * (s64)rs; @@ -755,51 +756,42 @@ void Dynarec::mult(Registers& regs, u32 instr) { regs.hi = (s64)((s32)(result >> 32)); } -void Dynarec::mflo(Registers& regs, u32 instr) { +void mflo(Registers& regs, u32 instr) { regs.gpr[RD(instr)] = regs.lo; } -void Dynarec::mfhi(Registers& regs, u32 instr) { +void mfhi(Registers& regs, u32 instr) { regs.gpr[RD(instr)] = regs.hi; } -void Dynarec::mtlo(Registers& regs, u32 instr) { +void mtlo(Registers& regs, u32 instr) { regs.lo = regs.gpr[RS(instr)]; } -void Dynarec::mthi(Registers& regs, u32 instr) { +void mthi(Registers& regs, u32 instr) { regs.hi = regs.gpr[RS(instr)]; } -void Dynarec::trap(Registers& regs, bool cond) { +void trap(Registers& regs, bool cond) { if(cond) { FireException(regs, ExceptionCode::Trap, 0, regs.oldPC); } } -void Dynarec::mtc2(Registers& regs, u32 instr) { - cop2Latch = regs.gpr[RT(instr)]; +void mtc2(Dynarec& dyn, Registers& regs, u32 instr) { + dyn.cop2Latch = regs.gpr[RT(instr)]; } -void Dynarec::mfc2(Registers& regs, u32 instr) { - s32 value = cop2Latch; +void mfc2(Dynarec& dyn, Registers& regs, u32 instr) { + s32 value = dyn.cop2Latch; regs.gpr[RT(instr)] = value; } -void Dynarec::dmtc2(Registers& regs, u32 instr) { - cop2Latch = regs.gpr[RT(instr)]; +void dmtc2(Dynarec& dyn, Registers& regs, u32 instr) { + dyn.cop2Latch = regs.gpr[RT(instr)]; } -void Dynarec::dmfc2(Registers& regs, u32 instr) { - regs.gpr[RT(instr)] = cop2Latch; +void dmfc2(Dynarec& dyn, Registers& regs, u32 instr) { + regs.gpr[RT(instr)] = dyn.cop2Latch; } - -void Dynarec::ctc2(Registers& regs, u32) { - -} - -void Dynarec::cfc2(Registers& regs, u32) { - -} - } \ No newline at end of file diff --git a/src/backend/core/dynarec/instructions.hpp b/src/backend/core/dynarec/instructions.hpp new file mode 100644 index 00000000..246a00f5 --- /dev/null +++ b/src/backend/core/dynarec/instructions.hpp @@ -0,0 +1,94 @@ +#pragma once +#include + +namespace n64::JIT { +void add(Registers&, u32); +void addu(Registers&, u32); +void addi(Registers&, u32); +void addiu(Registers&, u32); +void andi(Registers&, u32); +void and_(Registers&, u32); +void branch(Registers&, bool, s64); +void branch_likely(Registers&, bool, s64); +void b(Registers&, u32, bool); +void blink(Registers&, u32, bool); +void bl(Registers&, u32, bool); +void bllink(Registers&, u32, bool); +void dadd(Registers&, u32); +void daddu(Registers&, u32); +void daddi(Registers&, u32); +void daddiu(Registers&, u32); +void ddiv(Registers&, u32); +void ddivu(Registers&, u32); +void div(Registers&, u32); +void divu(Registers&, u32); +void dmult(Registers&, u32); +void dmultu(Registers&, u32); +void dsll(Registers&, u32); +void dsllv(Registers&, u32); +void dsll32(Registers&, u32); +void dsra(Registers&, u32); +void dsrav(Registers&, u32); +void dsra32(Registers&, u32); +void dsrl(Registers&, u32); +void dsrlv(Registers&, u32); +void dsrl32(Registers&, u32); +void dsub(Registers&, u32); +void dsubu(Registers&, u32); +void j(Registers&, u32); +void jr(Registers&, u32); +void jal(Registers&, u32); +void jalr(Registers&, u32); +void lui(Registers&, u32); +void lbu(Registers&, Mem&, u32); +void lb(Registers&, Mem&, u32); +void ld(Registers&, Mem&, u32); +void ldl(Registers&, Mem&, u32); +void ldr(Registers&, Mem&, u32); +void lh(Registers&, Mem&, u32); +void lhu(Registers&, Mem&, u32); +void ll(Registers&, Mem&, u32); +void lld(Registers&, Mem&, u32); +void lw(Registers&, Mem&, u32); +void lwl(Registers&, Mem&, u32); +void lwu(Registers&, Mem&, u32); +void lwr(Registers&, Mem&, u32); +void mfhi(Registers&, u32); +void mflo(Registers&, u32); +void mult(Registers&, u32); +void multu(Registers&, u32); +void mthi(Registers&, u32); +void mtlo(Registers&, u32); +void nor(Registers&, u32); +void sb(Registers&, Mem&, u32); +void sc(Registers&, Mem&, u32); +void scd(Registers&, Mem&, u32); +void sd(Registers&, Mem&, u32); +void sdl(Registers&, Mem&, u32); +void sdr(Registers&, Mem&, u32); +void sh(Registers&, Mem&, u32); +void sw(Registers&, Mem&, u32); +void swl(Registers&, Mem&, u32); +void swr(Registers&, Mem&, u32); +void slti(Registers&, u32); +void sltiu(Registers&, u32); +void slt(Registers&, u32); +void sltu(Registers&, u32); +void sll(Registers&, u32); +void sllv(Registers&, u32); +void sub(Registers&, u32); +void subu(Registers&, u32); +void sra(Registers&, u32); +void srav(Registers&, u32); +void srl(Registers&, u32); +void srlv(Registers&, u32); +void trap(Registers&, bool); +void or_(Registers&, u32); +void ori(Registers&, u32); +void xor_(Registers&, u32); +void xori(Registers&, u32); +void mtc2(Dynarec& dyn, Registers&, u32); +void mfc2(Dynarec& dyn, Registers&, u32); +void dmtc2(Dynarec& dyn, Registers&, u32); +void dmfc2(Dynarec& dyn, Registers&, u32); +} \ No newline at end of file diff --git a/src/backend/core/interpreter/CMakeLists.txt b/src/backend/core/interpreter/CMakeLists.txt new file mode 100644 index 00000000..7ebdaa03 --- /dev/null +++ b/src/backend/core/interpreter/CMakeLists.txt @@ -0,0 +1,4 @@ +file(GLOB_RECURSE SOURCES *.cpp) +file(GLOB_RECURSE HEADERS *.hpp) + +add_library(interpreter ${SOURCES} ${HEADERS}) \ No newline at end of file diff --git a/src/backend/core/interpreter/cop/cop1instructions.cpp b/src/backend/core/interpreter/cop/cop1instructions.cpp index 99298a6f..d9e34384 100644 --- a/src/backend/core/interpreter/cop/cop1instructions.cpp +++ b/src/backend/core/interpreter/cop/cop1instructions.cpp @@ -26,7 +26,7 @@ inline int PushRoundingMode(const FCR31& fcr31) { if(isnanf(fs) || isnanf(ft)) { \ regs.cop1.fcr31.flag_invalid_operation = true; \ regs.cop1.fcr31.cause_invalid_operation = true; \ - FireException(regs, ExceptionCode::FloatingPointError, 1, regs.oldPC); \ + FireException(regs, ExceptionCode::FloatingPointError, 1, true); \ return; \ } @@ -34,7 +34,7 @@ inline int PushRoundingMode(const FCR31& fcr31) { if(isnan(fs) || isnan(ft)) { \ regs.cop1.fcr31.flag_invalid_operation = true; \ regs.cop1.fcr31.cause_invalid_operation = true; \ - FireException(regs, ExceptionCode::FloatingPointError, 1, regs.oldPC); \ + FireException(regs, ExceptionCode::FloatingPointError, 1, true); \ return; \ } #else @@ -42,7 +42,7 @@ inline int PushRoundingMode(const FCR31& fcr31) { if(isnanf(fs) || isnanf(ft)) { \ regs.cop1.fcr31.flag_invalid_operation = true; \ regs.cop1.fcr31.cause_invalid_operation = true; \ - FireException(regs, ExceptionCode::FloatingPointError, 1, regs.oldPC); \ + FireException(regs, ExceptionCode::FloatingPointError, 1, true); \ return; \ } @@ -50,7 +50,7 @@ inline int PushRoundingMode(const FCR31& fcr31) { if(isnan(fs) || isnan(ft)) { \ regs.cop1.fcr31.flag_invalid_operation = true; \ regs.cop1.fcr31.cause_invalid_operation = true; \ - FireException(regs, ExceptionCode::FloatingPointError, 1, regs.oldPC); \ + FireException(regs, ExceptionCode::FloatingPointError, 1, true); \ return; \ } #endif @@ -264,7 +264,7 @@ inline bool CalculateCondition(Registers& regs, T fs, T ft, CompConds cond) { if(std::isnan(fs) || std::isnan(ft)) { regs.cop1.fcr31.flag_invalid_operation = true; regs.cop1.fcr31.cause_invalid_operation = true; - FireException(regs, ExceptionCode::FloatingPointError, 1, regs.oldPC); + FireException(regs, ExceptionCode::FloatingPointError, 1, true); return false; } @@ -469,19 +469,19 @@ void Cop1::floorwd(Registers& regs, u32 instr) { void Cop1::lwc1(Registers& regs, Mem& mem, u32 instr) { if(!regs.cop0.status.cu1) { - FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC); + FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true); return; } u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; if(addr & 3) { - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); } u32 physical; if(!MapVAddr(regs, LOAD, addr, physical)) { HandleTLBException(regs, addr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { u32 data = mem.Read32(regs, physical, regs.oldPC); SetReg(regs.cop0, FT(instr), data); @@ -490,19 +490,19 @@ void Cop1::lwc1(Registers& regs, Mem& mem, u32 instr) { void Cop1::swc1(Registers& regs, Mem& mem, u32 instr) { if(!regs.cop0.status.cu1) { - FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC); + FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true); return; } u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; if(addr & 3) { - FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorStore, 0, true); } u32 physical; if(!MapVAddr(regs, STORE, addr, physical)) { HandleTLBException(regs, addr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { mem.Write32(regs, physical, GetReg(regs.cop0, FT(instr)), regs.oldPC); } @@ -510,13 +510,13 @@ void Cop1::swc1(Registers& regs, Mem& mem, u32 instr) { void Cop1::ldc1(Registers& regs, Mem& mem, u32 instr) { if(!regs.cop0.status.cu1) { - FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC); + FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true); return; } u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; if(addr & 7) { - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); } u32 physical; diff --git a/src/backend/core/interpreter/decode.cpp b/src/backend/core/interpreter/decode.cpp index f1f68b3a..eb088b00 100644 --- a/src/backend/core/interpreter/decode.cpp +++ b/src/backend/core/interpreter/decode.cpp @@ -2,7 +2,7 @@ #include namespace n64 { -void Interpreter::special(Registers& regs, Mem& mem, u32 instr) { +void Interpreter::special(Registers& regs, u32 instr) { u8 mask = (instr & 0x3F); // 00rr_rccc switch (mask) { // TODO: named constants for clearer code @@ -18,8 +18,8 @@ void Interpreter::special(Registers& regs, Mem& mem, u32 instr) { case 0x07: srav(regs, instr); break; case 0x08: jr(regs, instr); break; case 0x09: jalr(regs, instr); break; - case 0x0C: FireException(regs, ExceptionCode::Syscall, 0, regs.oldPC); break; - case 0x0D: FireException(regs, ExceptionCode::Breakpoint, 0, regs.oldPC); break; + case 0x0C: FireException(regs, ExceptionCode::Syscall, 0, true); break; + case 0x0D: FireException(regs, ExceptionCode::Breakpoint, 0, true); break; case 0x0F: break; // SYNC case 0x10: mfhi(regs, instr); break; case 0x11: mthi(regs, instr); break; @@ -92,7 +92,7 @@ void Interpreter::regimm(Registers& regs, u32 instr) { void Interpreter::cop2Decode(Registers& regs, u32 instr) { if(!regs.cop0.status.cu2) { - FireException(regs, ExceptionCode::CoprocessorUnusable, 2, regs.oldPC); + FireException(regs, ExceptionCode::CoprocessorUnusable, 2, true); return; } switch(RS(instr)) { @@ -103,7 +103,7 @@ void Interpreter::cop2Decode(Registers& regs, u32 instr) { case 0x05: dmtc2(regs, instr); break; case 0x06: ctc2(regs, instr); break; default: - FireException(regs, ExceptionCode::ReservedInstruction, 2, regs.oldPC); + FireException(regs, ExceptionCode::ReservedInstruction, 2, true); } } @@ -111,7 +111,7 @@ void Interpreter::Exec(Registers& regs, Mem& mem, u32 instr) { u8 mask = (instr >> 26) & 0x3f; // 00rr_rccc switch(mask) { // TODO: named constants for clearer code - case 0x00: special(regs, mem, instr); break; + case 0x00: special(regs, instr); break; case 0x01: regimm(regs, instr); break; case 0x02: j(regs, instr); break; case 0x03: jal(regs, instr); break; @@ -141,7 +141,7 @@ void Interpreter::Exec(Registers& regs, Mem& mem, u32 instr) { case 0x19: daddiu(regs, instr); break; case 0x1A: ldl(regs, mem, instr); break; case 0x1B: ldr(regs, mem, instr); break; - case 0x1F: FireException(regs, ExceptionCode::ReservedInstruction, 0, regs.oldPC); break; + case 0x1F: FireException(regs, ExceptionCode::ReservedInstruction, 0, true); break; case 0x20: lb(regs, mem, instr); break; case 0x21: lh(regs, mem, instr); break; case 0x22: lwl(regs, mem, instr); break; diff --git a/src/backend/core/interpreter/instructions.cpp b/src/backend/core/interpreter/instructions.cpp index 5ee3a00e..877b6553 100644 --- a/src/backend/core/interpreter/instructions.cpp +++ b/src/backend/core/interpreter/instructions.cpp @@ -11,7 +11,7 @@ void Interpreter::add(Registers& regs, u32 instr) { u32 rt = (s32)regs.gpr[RT(instr)]; u32 result = rs + rt; if(check_signed_overflow(rs, rt, result)) { - FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); + FireException(regs, ExceptionCode::Overflow, 0, true); } else { regs.gpr[RD(instr)] = s32(result); } @@ -29,7 +29,7 @@ void Interpreter::addi(Registers& regs, u32 instr) { u32 imm = s32(s16(instr)); u32 result = rs + imm; if(check_signed_overflow(rs, imm, result)) { - FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); + FireException(regs, ExceptionCode::Overflow, 0, true); } else { regs.gpr[RT(instr)] = s32(result); } @@ -47,7 +47,7 @@ void Interpreter::dadd(Registers& regs, u32 instr) { u64 rt = regs.gpr[RT(instr)]; u64 result = rt + rs; if(check_signed_overflow(rs, rt, result)) { - FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); + FireException(regs, ExceptionCode::Overflow, 0, true); } else { regs.gpr[RD(instr)] = result; } @@ -64,7 +64,7 @@ void Interpreter::daddi(Registers& regs, u32 instr) { u64 rs = regs.gpr[RS(instr)]; u64 result = imm + rs; if(check_signed_overflow(rs, imm, result)) { - FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); + FireException(regs, ExceptionCode::Overflow, 0, true); } else { regs.gpr[RT(instr)] = result; } @@ -201,7 +201,7 @@ void Interpreter::lh(Registers& regs, Mem& mem, u32 instr) { u64 address = regs.gpr[RS(instr)] + (s16)instr; if (check_address_error(address, 0b1)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); return; } @@ -213,14 +213,14 @@ void Interpreter::lw(Registers& regs, Mem& mem, u32 instr) { u64 address = regs.gpr[RS(instr)] + offset; if (check_address_error(address, 0b11)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); return; } u32 physical; if (!MapVAddr(regs, LOAD, address, physical)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { regs.gpr[RT(instr)] = (s32)mem.Read32(regs, physical, regs.oldPC); } @@ -231,7 +231,7 @@ void Interpreter::ll(Registers& regs, Mem& mem, u32 instr) { u32 physical; if (!MapVAddr(regs, LOAD, address, physical)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { regs.gpr[RT(instr)] = (s32)mem.Read32(regs, physical, regs.oldPC); } @@ -245,7 +245,7 @@ void Interpreter::lwl(Registers& regs, Mem& mem, u32 instr) { u32 paddr = 0; if(!MapVAddr(regs, LOAD, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { u32 shift = 8 * ((address ^ 0) & 3); u32 mask = 0xFFFFFFFF << shift; @@ -260,7 +260,7 @@ void Interpreter::lwr(Registers& regs, Mem& mem, u32 instr) { u32 paddr = 0; if(!MapVAddr(regs, LOAD, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { u32 shift = 8 * ((address ^ 3) & 3); u32 mask = 0xFFFFFFFF >> shift; @@ -274,7 +274,7 @@ void Interpreter::ld(Registers& regs, Mem& mem, u32 instr) { s64 address = regs.gpr[RS(instr)] + (s16)instr; if (check_address_error(address, 0b111)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); return; } @@ -287,7 +287,7 @@ void Interpreter::lld(Registers& regs, Mem& mem, u32 instr) { u32 paddr; if (!MapVAddr(regs, LOAD, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { regs.gpr[RT(instr)] = mem.Read64(regs, paddr, regs.oldPC); } @@ -301,7 +301,7 @@ void Interpreter::ldl(Registers& regs, Mem& mem, u32 instr) { u32 paddr = 0; if (!MapVAddr(regs, LOAD, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { s32 shift = 8 * ((address ^ 0) & 7); u64 mask = 0xFFFFFFFFFFFFFFFF << shift; @@ -316,7 +316,7 @@ void Interpreter::ldr(Registers& regs, Mem& mem, u32 instr) { u32 paddr; if (!MapVAddr(regs, LOAD, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { s32 shift = 8 * ((address ^ 7) & 7); u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; @@ -336,7 +336,7 @@ void Interpreter::lhu(Registers& regs, Mem& mem, u32 instr) { s64 address = regs.gpr[RS(instr)] + (s16)instr; if (check_address_error(address, 0b1)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); return; } @@ -348,7 +348,7 @@ void Interpreter::lwu(Registers& regs, Mem& mem, u32 instr) { s64 address = regs.gpr[RS(instr)] + (s16)instr; if (check_address_error(address, 0b11)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); return; } @@ -365,7 +365,7 @@ void Interpreter::sc(Registers& regs, Mem& mem, u32 instr) { s64 address = regs.gpr[RS(instr)] + (s16)instr; if (check_address_error(address, 0b11)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorStore, 0, true); } if(regs.cop0.llbit) { @@ -380,7 +380,7 @@ void Interpreter::scd(Registers& regs, Mem& mem, u32 instr) { s64 address = regs.gpr[RS(instr)] + (s16)instr; if (check_address_error(address, 0b111)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorStore, 0, true); return; } @@ -396,14 +396,14 @@ void Interpreter::sh(Registers& regs, Mem& mem, u32 instr) { s64 address = regs.gpr[RS(instr)] + (s16)instr; if (check_address_error(address, 0b1)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorStore, 0, true); return; } u32 physical; if(!MapVAddr(regs, STORE, address, physical)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { mem.Write16(regs, physical, regs.gpr[RT(instr)], regs.oldPC); } @@ -414,14 +414,14 @@ void Interpreter::sw(Registers& regs, Mem& mem, u32 instr) { u64 address = regs.gpr[RS(instr)] + offset; if (check_address_error(address, 0b11)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorStore, 0, true); return; } u32 physical; if(!MapVAddr(regs, STORE, address, physical)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { mem.Write32(regs, physical, regs.gpr[RT(instr)], regs.oldPC); } @@ -431,14 +431,14 @@ void Interpreter::sd(Registers& regs, Mem& mem, u32 instr) { s64 address = regs.gpr[RS(instr)] + (s16)instr; if (check_address_error(address, 0b11)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorStore, 0, true); return; } u32 physical; if(!MapVAddr(regs, STORE, address, physical)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { mem.Write64(regs, physical, regs.gpr[RT(instr)], regs.oldPC); } @@ -450,7 +450,7 @@ void Interpreter::sdl(Registers& regs, Mem& mem, u32 instr) { u32 paddr; if (!MapVAddr(regs, STORE, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { s32 shift = 8 * ((address ^ 0) & 7); u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; @@ -465,7 +465,7 @@ void Interpreter::sdr(Registers& regs, Mem& mem, u32 instr) { u32 paddr; if (!MapVAddr(regs, STORE, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { s32 shift = 8 * ((address ^ 7) & 7); u64 mask = 0xFFFFFFFFFFFFFFFF << shift; @@ -480,7 +480,7 @@ void Interpreter::swl(Registers& regs, Mem& mem, u32 instr) { u32 paddr; if (!MapVAddr(regs, STORE, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { u32 shift = 8 * ((address ^ 0) & 3); u32 mask = 0xFFFFFFFF >> shift; @@ -495,7 +495,7 @@ void Interpreter::swr(Registers& regs, Mem& mem, u32 instr) { u32 paddr; if (!MapVAddr(regs, STORE, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { u32 shift = 8 * ((address ^ 3) & 3); u32 mask = 0xFFFFFFFF << shift; @@ -524,7 +524,7 @@ void Interpreter::j(Registers& regs, u32 instr) { s64 address = (regs.oldPC & ~0xfffffff) | target; if (check_address_error(address, 0b11)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::DataBusError, 0, regs.oldPC); + FireException(regs, ExceptionCode::DataBusError, 0, true); } branch(regs, true, address); diff --git a/src/backend/core/mmio/CMakeLists.txt b/src/backend/core/mmio/CMakeLists.txt new file mode 100644 index 00000000..6551e557 --- /dev/null +++ b/src/backend/core/mmio/CMakeLists.txt @@ -0,0 +1,4 @@ +file(GLOB SOURCES *.cpp) +file(GLOB HEADERS *.hpp) + +add_library(mmio ${SOURCES} ${HEADERS}) \ No newline at end of file diff --git a/src/backend/core/registers/CMakeLists.txt b/src/backend/core/registers/CMakeLists.txt new file mode 100644 index 00000000..f2a7ac0a --- /dev/null +++ b/src/backend/core/registers/CMakeLists.txt @@ -0,0 +1,4 @@ +file(GLOB SOURCES *.cpp) +file(GLOB HEADERS *.cpp) + +add_library(registers ${SOURCES} ${HEADERS}) \ No newline at end of file diff --git a/src/backend/core/registers/Cop0.cpp b/src/backend/core/registers/Cop0.cpp index ea14b3f7..9e828c63 100644 --- a/src/backend/core/registers/Cop0.cpp +++ b/src/backend/core/registers/Cop0.cpp @@ -244,8 +244,9 @@ inline bool Is64BitAddressing(Cop0& cp0, u64 addr) { } } -void FireException(Registers& regs, ExceptionCode code, int cop, s64 pc) { +void FireException(Registers& regs, ExceptionCode code, int cop, bool useOldPC) { bool old_exl = regs.cop0.status.exl; + s64 pc = useOldPC ? regs.oldPC : regs.pc; if(!regs.cop0.status.exl) { if(regs.prevDelaySlot) { diff --git a/src/backend/core/registers/Cop0.hpp b/src/backend/core/registers/Cop0.hpp index 210492b8..5f737ca4 100644 --- a/src/backend/core/registers/Cop0.hpp +++ b/src/backend/core/registers/Cop0.hpp @@ -177,7 +177,7 @@ enum class ExceptionCode : u8 { Watch = 23 }; -void FireException(Registers& regs, ExceptionCode code, int cop, s64 pc); +void FireException(Registers& regs, ExceptionCode code, int cop, bool useOldPC); union Cop0Context { u64 raw; @@ -235,9 +235,6 @@ struct Cop0 { TLBError tlbError = NONE; s64 openbus{}; void decode(Registers&, Mem&, u32); -private: - inline u32 GetWired() { return wired & 0x3F; } - inline u32 GetCount() { return u32(u64(count >> 1)); } inline u32 GetRandom() { int val = rand(); int wired = GetWired(); @@ -253,16 +250,19 @@ private: val = (val % upper) + lower; return val; } +private: + inline u32 GetWired() { return wired & 0x3F; } + inline u32 GetCount() { return u32(u64(count >> 1)); } - void mtc0(Registers&, u32); - void dmtc0(Registers&, u32); - void mfc0(Registers&, u32); - void dmfc0(Registers&, u32); - void eret(Registers&); + 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 tlbr(Registers&); - void tlbw(int, Registers&); - void tlbp(Registers&); + void tlbr(n64::Registers&); + void tlbw(int, n64::Registers&); + void tlbp(n64::Registers&); }; struct Registers; diff --git a/src/backend/core/registers/Cop1.cpp b/src/backend/core/registers/Cop1.cpp index f8af3dc6..2df1c63f 100644 --- a/src/backend/core/registers/Cop1.cpp +++ b/src/backend/core/registers/Cop1.cpp @@ -16,7 +16,7 @@ void Cop1::Reset() { void Cop1::decode(Registers& regs, Interpreter& cpu, u32 instr) { if(!regs.cop0.status.cu1) { - FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC); + FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true); return; } @@ -28,11 +28,11 @@ void Cop1::decode(Registers& regs, Interpreter& cpu, u32 instr) { 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, regs.oldPC); 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, regs.oldPC); break; + case 0x07: FireException(regs, ExceptionCode::ReservedInstruction, 1, true); break; case 0x08: switch(mask_branch) { case 0: cpu.b(regs, instr, !regs.cop1.fcr31.compare); break; @@ -61,7 +61,7 @@ void Cop1::decode(Registers& regs, Interpreter& cpu, u32 instr) { case 0x0E: ceilws(regs, instr); break; case 0x0F: floorws(regs, instr); break; case 0x20: - FireException(regs, ExceptionCode::ReservedInstruction, 1, regs.oldPC); + FireException(regs, ExceptionCode::ReservedInstruction, 1, true); break; case 0x21: cvtds(regs, instr); break; case 0x24: cvtws(regs, instr); break; @@ -105,7 +105,7 @@ void Cop1::decode(Registers& regs, Interpreter& cpu, u32 instr) { case 0x0F: floorwd(regs, instr); break; case 0x20: cvtsd(regs, instr); break; case 0x21: - FireException(regs, ExceptionCode::ReservedInstruction, 1, regs.oldPC); + FireException(regs, ExceptionCode::ReservedInstruction, 1, true); break; case 0x24: cvtwd(regs, instr); break; case 0x25: cvtld(regs, instr); break; @@ -137,7 +137,7 @@ void Cop1::decode(Registers& regs, Interpreter& cpu, u32 instr) { case 0x20: cvtsw(regs, instr); break; case 0x21: cvtdw(regs, instr); break; case 0x24: - FireException(regs, ExceptionCode::ReservedInstruction, 1, regs.oldPC); + 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); } @@ -151,10 +151,10 @@ void Cop1::decode(Registers& regs, Interpreter& cpu, u32 instr) { case 0x20: cvtsl(regs, instr); break; case 0x21: cvtdl(regs, instr); break; case 0x24: - FireException(regs, ExceptionCode::ReservedInstruction, 1, regs.oldPC); + FireException(regs, ExceptionCode::ReservedInstruction, 1, true); break; case 0x25: - FireException(regs, ExceptionCode::ReservedInstruction, 1, regs.oldPC); + 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); } diff --git a/src/backend/core/registers/Cop1.hpp b/src/backend/core/registers/Cop1.hpp index 4ef1f4ac..1b1fb3a1 100644 --- a/src/backend/core/registers/Cop1.hpp +++ b/src/backend/core/registers/Cop1.hpp @@ -66,7 +66,7 @@ struct Cop1 { void Reset(); void decode(Registers&, Interpreter&, u32); friend struct Interpreter; -private: + template inline void SetReg(Cop0& cop0, u8 index, T value) { if constexpr(sizeof(T) == 4) { @@ -134,7 +134,7 @@ private: } return value; } - +private: void absd(Registers&, u32 instr); void abss(Registers&, u32 instr); void absw(Registers&, u32 instr); diff --git a/src/backend/core/registers/Registers.hpp b/src/backend/core/registers/Registers.hpp index 3566a1a8..08c1f741 100644 --- a/src/backend/core/registers/Registers.hpp +++ b/src/backend/core/registers/Registers.hpp @@ -1,6 +1,6 @@ #pragma once -#include -#include +#include +#include namespace n64 { struct Registers { diff --git a/src/backend/core/rsp/CMakeLists.txt b/src/backend/core/rsp/CMakeLists.txt new file mode 100644 index 00000000..537335f2 --- /dev/null +++ b/src/backend/core/rsp/CMakeLists.txt @@ -0,0 +1 @@ +add_library(rsp decode.cpp instructions.cpp) \ No newline at end of file diff --git a/src/frontend/CMakeLists.txt b/src/frontend/CMakeLists.txt new file mode 100644 index 00000000..f51c9e15 --- /dev/null +++ b/src/frontend/CMakeLists.txt @@ -0,0 +1,4 @@ +file(GLOB SOURCES *.cpp) +file(GLOB HEADERS *.hpp) + +add_library(frontend ${SOURCES} ${HEADERS}) \ No newline at end of file diff --git a/src/frontend/imgui/CMakeLists.txt b/src/frontend/imgui/CMakeLists.txt new file mode 100644 index 00000000..8f114168 --- /dev/null +++ b/src/frontend/imgui/CMakeLists.txt @@ -0,0 +1,4 @@ +file(GLOB SOURCES *.cpp) +file(GLOB HEADERS *.hpp) + +add_library(frontend-imgui ${SOURCES} ${HEADERS}) \ No newline at end of file diff --git a/src/frontend/imgui/Window.hpp b/src/frontend/imgui/Window.hpp index a98c1186..9d4903da 100644 --- a/src/frontend/imgui/Window.hpp +++ b/src/frontend/imgui/Window.hpp @@ -1,13 +1,13 @@ #pragma once -#include +#include #include #include #include -#include -#include +#include +#include #include -#include -#include +#include +#include struct DrawData { ImDrawData* first; diff --git a/src/main.cpp b/src/main.cpp index 81b9df18..8d8d4050 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,5 @@ #include -#include +#include #ifdef _WIN32 #define main SDL_main