From f67f968f91ad6b9ccad90305ff17b84a1f25b158 Mon Sep 17 00:00:00 2001 From: SimoneN64 Date: Mon, 20 Jan 2025 22:27:18 +0100 Subject: [PATCH] [JIT]: First compiled block! Figure out why scheduling an event from the emitted code makes the underlying queue point to 0x0... --- src/backend/core/JIT.cpp | 94 ++++- src/backend/core/JIT.hpp | 78 ++-- src/backend/core/Mem.cpp | 44 +-- src/backend/core/Mem.hpp | 1 + src/backend/core/interpreter/instructions.cpp | 6 +- src/backend/core/jit/helpers.hpp | 46 ++- src/backend/core/jit/instructions.cpp | 371 +++++++++++------- src/backend/core/registers/Registers.cpp | 94 +++-- src/backend/core/registers/Registers.hpp | 2 +- src/utils/File.hpp | 6 + 10 files changed, 452 insertions(+), 290 deletions(-) diff --git a/src/backend/core/JIT.cpp b/src/backend/core/JIT.cpp index f07325dd..7d6ca2d7 100644 --- a/src/backend/core/JIT.cpp +++ b/src/backend/core/JIT.cpp @@ -22,22 +22,52 @@ void JIT::CheckCompareInterrupt() { } } +void JIT::InvalidateBlock(const u32 paddr) { + if (const u32 index = paddr >> kUpperShift; !blockCache[index].empty()) + blockCache[index].erase(blockCache[index].begin(), blockCache[index].end()); +} + int JIT::Step() { blockPC = regs.pc; + u32 paddr = 0; - if (!blockCache[blockPC >> 8].empty()) { - if (blockCache[blockPC >> 8][blockPC >> 20]) { - return blockCache[blockPC >> 8][blockPC >> 20](); - } - } else { - blockCache[blockPC >> 8].resize(kLowerSize); + if (!regs.cop0.MapVAddr(Cop0::LOAD, blockPC, paddr)) { + /*regs.cop0.HandleTLBException(blockPC); + regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, blockPC); + return 1;*/ + Util::panic( + "[JIT]: Unhandled exception TLB exception {} when retrieving PC physical address! (virtual: 0x{:016lX})", + static_cast(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD)), static_cast(blockPC)); } - regs.block_delaySlot = false; + u32 upperIndex = paddr >> kUpperShift; + u32 lowerIndex = paddr & 0xff; - u32 instruction; + if (!blockCache[upperIndex].empty()) { + if (blockCache[upperIndex][lowerIndex]) { + return blockCache[upperIndex][lowerIndex](); + } + } else { + blockCache[upperIndex].resize(kLowerSize); + } - do { + const auto block = code.getCurr(); + blockCache[upperIndex][lowerIndex] = block; + + code.setProtectModeRW(); + + u32 instructionsInBlock = 0; + + bool instrEndsBlock = false; + bool instrInDelaySlot = false; + bool branchWasLikely = false; + bool blockEndsOnBranch = false; + + code.sub(code.rsp, 56); + code.push(code.rbp); + code.mov(code.rbp, reinterpret_cast(this)); // Load context pointer + + while (!instrInDelaySlot) { // CheckCompareInterrupt(); if (check_address_error(0b11, u64(blockPC))) [[unlikely]] { @@ -45,37 +75,61 @@ int JIT::Step() { regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, blockPC); return 1;*/ - Util::panic("[JIT]: Unhandled exception ADL due to unaligned PC virtual value! (0x{:016lX})", - static_cast(regs.pc)); + Util::panic("[JIT]: Unhandled exception ADL due to unaligned PC virtual value! (0x{:016lX})", blockPC); } - u32 paddr = 0; - if (!regs.cop0.MapVAddr(Cop0::LOAD, blockPC, paddr)) { /*regs.cop0.HandleTLBException(blockPC); regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, blockPC); return 1;*/ Util::panic( "[JIT]: Unhandled exception TLB exception {} when retrieving PC physical address! (virtual: 0x{:016lX})", - static_cast(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD)), static_cast(regs.pc)); + static_cast(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD)), static_cast(blockPC)); } - instruction = mem.Read(regs, paddr); + const u32 instruction = mem.Read(regs, paddr); /*if(ShouldServiceInterrupt()) { - regs.cop0.FireException(ExceptionCode::Interrupt, 0, regs.pc); + regs.cop0.FireException(ExceptionCode::Interrupt, 0, blockPC); return 1; }*/ blockPC += 4; - + instructionsInBlock++; Emit(instruction); + + instrInDelaySlot = instrEndsBlock; + instrEndsBlock = InstrEndsBlock(instruction); + if (instrEndsBlock) { + branchWasLikely = IsBranchLikely(instruction); + } + + if (instrInDelaySlot) { + blockEndsOnBranch = true; + } + + if (instrInDelaySlot && branchWasLikely) { + branchWasLikely = false; + code.L("not_taken"); + code.mov(code.rax, blockPC); + code.mov(REG(qword, pc), code.rax); + } } - while (!InstrEndsBlock(instruction)); // emit code to store the value of pc - blockCache[regs.pc >> 8][regs.pc >> 20] = code.getCurr(); - return blockCache[regs.pc >> 8][regs.pc >> 20](); + if (!blockEndsOnBranch) { + code.mov(code.rax, blockPC); + code.mov(REG(qword, pc), code.rax); + } + code.mov(code.rax, instructionsInBlock); + code.pop(code.rbp); + code.add(code.rsp, 56); + code.ret(); + code.setProtectModeRE(); + // const auto dump = code.getCode(); + // Util::WriteFileBinary(dump, code.getSize(), "jit.dump"); + // Util::panic(""); + return block(); } std::vector JIT::Serialize() { diff --git a/src/backend/core/JIT.hpp b/src/backend/core/JIT.hpp index 632d770b..d3395229 100644 --- a/src/backend/core/JIT.hpp +++ b/src/backend/core/JIT.hpp @@ -7,12 +7,14 @@ namespace n64 { struct Core; -static constexpr u32 kAddressSpaceSize = 0x8000'0000; // >> 20 = 0x800 -static constexpr u32 kLowerSize = kAddressSpaceSize >> 20; // 0x800 -static constexpr u32 kUpperSize = kAddressSpaceSize >> 8; // 0x100000 +static constexpr u64 kAddressSpaceSize = 0x8000'0000; +static constexpr u8 kUpperShift = 8; +static constexpr u8 kLowerMask = 0xff; +static constexpr u32 kUpperSize = kAddressSpaceSize >> kUpperShift; // 0x800000 +static constexpr u32 kLowerSize = 0x100; // 0x80 static constexpr u32 kCodeCacheSize = 32_mb; -static constexpr u32 kCodeCacheAllocSize = kCodeCacheSize + 4096; -#define REG(acc, x) code.acc[reinterpret_cast(®s.x)] +static constexpr u32 kCodeCacheAllocSize = kCodeCacheSize + 4_kb; +#define REG(acc, x) code.acc[code.rbp + (reinterpret_cast(®s.x) - (uintptr_t)this)] struct JIT : BaseCPU { explicit JIT(ParallelRDP &); @@ -46,13 +48,13 @@ private: template Xbyak::Address GPR(const size_t index) const { if constexpr (sizeof(T) == 1) { - return code.byte[reinterpret_cast(®s.gpr[index])]; + return code.byte[code.rbp + (reinterpret_cast(®s.gpr[index]) - reinterpret_cast(this))]; } else if constexpr (sizeof(T) == 2) { - return code.word[reinterpret_cast(®s.gpr[index])]; + return code.word[code.rbp + (reinterpret_cast(®s.gpr[index]) - reinterpret_cast(this))]; } else if constexpr (sizeof(T) == 4) { - return code.dword[reinterpret_cast(®s.gpr[index])]; + return code.dword[code.rbp + (reinterpret_cast(®s.gpr[index]) - reinterpret_cast(this))]; } else if constexpr (sizeof(T) == 8) { - return code.qword[reinterpret_cast(®s.gpr[index])]; + return code.qword[code.rbp + (reinterpret_cast(®s.gpr[index]) - reinterpret_cast(this))]; } Util::panic("[JIT]: Invalid register addressing"); @@ -60,18 +62,11 @@ private: return Xbyak::Address{0}; } - // Credits to PCSX-Redux: https://github.com/grumpycoders/pcsx-redux - // Sets dest to "pointer" - void loadAddress(const Xbyak::Reg64 dest, void *pointer) { code.mov(dest, reinterpret_cast(pointer)); } - + // Thanks to https://github.com/grumpycoders/pcsx-redux // Load a pointer to the JIT object in "reg" - void loadThisPointer(const Xbyak::Reg64 reg) { code.mov(reg, code.rbp); } - // Emit a call to a class member function, passing "thisObject" (+ an adjustment if necessary) - // As the function's "this" pointer. Only works with classes with single, non-virtual inheritance - // Hence the static asserts. Those are all we need though, thankfully. template void emitMemberFunctionCall(T func, void *thisObject) { - void *functionPtr; + uintptr_t functionPtr; auto thisPtr = reinterpret_cast(thisObject); #if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) @@ -82,24 +77,22 @@ private: uintptr_t arr[2]; std::memcpy(arr, &func, sizeof(T)); // First 8 bytes correspond to the actual pointer to the function - functionPtr = reinterpret_cast(arr[0]); + functionPtr = reinterpret_cast(reinterpret_cast(arr[0])); // Next 8 bytes correspond to the "this" pointer adjustment thisPtr += arr[1]; #endif - // Load this pointer to arg1 - if (thisPtr == reinterpret_cast(this)) { - loadThisPointer(code.rdi); - } else { - loadAddress(code.rdi, reinterpret_cast(thisPtr)); - } - - code.call(functionPtr); + code.mov(code.rdi, thisPtr); + code.mov(code.rax, functionPtr); + code.call(code.rax); } + void SkipSlot(); void SkipSlotConstant(); void BranchTaken(s64 offs); - void BranchTaken(const Xbyak::Reg &offs); + void BranchTaken(const Xbyak::Reg64 &offs); + void BranchAbsTaken(s64 addr); + void BranchAbsTaken(const Xbyak::Reg64 &addr); #define check_address_error(mask, vaddr) \ (((!regs.cop0.is64BitAddressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0)) @@ -118,8 +111,9 @@ private: void addiu(u32); void andi(u32); void and_(u32); - void branch_constant(bool cond, s64 address); - void branch_likely_constant(bool cond, s64 address); + void branch_constant(bool cond, s64 offset); + void branch_likely_constant(bool cond, s64 offset); + void branch_abs_constant(bool cond, s64 address); void bltz(u32); void bgez(u32); void bltzl(u32); @@ -188,17 +182,17 @@ private: void mthi(u32); void mtlo(u32); void nor(u32); - void sb(u32); - void sc(u32); - void scd(u32); - void sd(u32); - void sdc1(u32); - void sdl(u32); - void sdr(u32); - void sh(u32); + void sb(u32) {} + void sc(u32) {} + void scd(u32) {} + void sd(u32) {} + void sdc1(u32) {} + void sdl(u32) {} + void sdr(u32) {} + void sh(u32) {} void sw(u32); - void swl(u32); - void swr(u32); + void swl(u32) {} + void swr(u32) {} void slti(u32); void sltiu(u32); void slt(u32); @@ -207,12 +201,12 @@ private: void sllv(u32); void sub(u32); void subu(u32); - void swc1(u32); + void swc1(u32) {} void sra(u32); void srav(u32); void srl(u32); void srlv(u32); - void trap(bool); + void trap(bool) {} void or_(u32); void ori(u32); void xor_(u32); diff --git a/src/backend/core/Mem.cpp b/src/backend/core/Mem.cpp index 1d9a0314..403d461a 100644 --- a/src/backend/core/Mem.cpp +++ b/src/backend/core/Mem.cpp @@ -316,19 +316,6 @@ u64 Mem::Read(Registers ®s, const u32 paddr) { } } -template <> -void Mem::WriteJIT(Registers ®s, const u32 paddr, const u32 val) { - if (jit) - jit->InvalidateBlock(paddr); - - WriteInterpreter(regs, paddr, val); -} - -template <> -void Mem::Write(Registers ®s, const u32 paddr, const u32 val) { - WriteInterpreter(regs, paddr, val); -} - template <> void Mem::WriteInterpreter(Registers ®s, u32 paddr, u32 val) { SI &si = mmio.si; @@ -371,16 +358,15 @@ void Mem::WriteInterpreter(Registers ®s, u32 paddr, u32 val) { } template <> -void Mem::WriteJIT(Registers ®s, const u32 paddr, const u32 val) { +void Mem::WriteJIT(Registers ®s, const u32 paddr, const u32 val) { + WriteInterpreter(regs, paddr, val); if (jit) jit->InvalidateBlock(paddr); - - WriteInterpreter(regs, paddr, val); } template <> -void Mem::Write(Registers ®s, const u32 paddr, const u32 val) { - WriteInterpreter(regs, paddr, val); +void Mem::Write(Registers ®s, const u32 paddr, const u32 val) { + WriteInterpreter(regs, paddr, val); } template <> @@ -425,16 +411,15 @@ void Mem::WriteInterpreter(Registers ®s, u32 paddr, u32 val) { } template <> -void Mem::WriteJIT(Registers ®s, const u32 paddr, const u32 val) { +void Mem::WriteJIT(Registers ®s, const u32 paddr, const u32 val) { + WriteInterpreter(regs, paddr, val); if (jit) jit->InvalidateBlock(paddr); - - WriteInterpreter(regs, paddr, val); } template <> -void Mem::Write(Registers ®s, const u32 paddr, const u32 val) { - WriteInterpreter(regs, paddr, val); +void Mem::Write(Registers ®s, const u32 paddr, const u32 val) { + WriteInterpreter(regs, paddr, val); } template <> @@ -475,11 +460,22 @@ void Mem::WriteInterpreter(Registers ®s, const u32 paddr, const u32 val) } } -void Mem::WriteJIT(const Registers ®s, const u32 paddr, const u64 val) { +template <> +void Mem::WriteJIT(Registers ®s, const u32 paddr, const u32 val) { + WriteInterpreter(regs, paddr, val); if (jit) jit->InvalidateBlock(paddr); +} +template <> +void Mem::Write(Registers ®s, const u32 paddr, const u32 val) { + WriteInterpreter(regs, paddr, val); +} + +void Mem::WriteJIT(const Registers ®s, const u32 paddr, const u64 val) { WriteInterpreter(regs, paddr, val); + if (jit) + jit->InvalidateBlock(paddr); } void Mem::Write(const Registers ®s, const u32 paddr, const u64 val) { WriteInterpreter(regs, paddr, val); } diff --git a/src/backend/core/Mem.hpp b/src/backend/core/Mem.hpp index 49603449..9f9fa035 100644 --- a/src/backend/core/Mem.hpp +++ b/src/backend/core/Mem.hpp @@ -143,6 +143,7 @@ private: friend struct PI; friend struct AI; friend struct RSP; + friend struct JIT; friend struct Core; std::array isviewer{}; std::string sramPath{}; diff --git a/src/backend/core/interpreter/instructions.cpp b/src/backend/core/interpreter/instructions.cpp index 35755853..035b9ada 100644 --- a/src/backend/core/interpreter/instructions.cpp +++ b/src/backend/core/interpreter/instructions.cpp @@ -602,10 +602,8 @@ void Interpreter::jal(const u32 instr) { } void Interpreter::jalr(const u32 instr) { - const u64 addr = regs.Read(RS(instr)); - const s64 currentNextPC = regs.nextPC; - branch(true, addr); - regs.Write(RD(instr), currentNextPC); + regs.Write(RD(instr), regs.nextPC); + jr(instr); } void Interpreter::jr(const u32 instr) { diff --git a/src/backend/core/jit/helpers.hpp b/src/backend/core/jit/helpers.hpp index f577104c..8e8b5cb9 100644 --- a/src/backend/core/jit/helpers.hpp +++ b/src/backend/core/jit/helpers.hpp @@ -20,24 +20,11 @@ static bool SpecialEndsBlock(const u32 instr) { } } -static bool RegimmEndsBlock(const u32 instr) { - switch (instr >> 16 & 0x1F) { - case BLTZL: - case BGEZL: - case BLTZALL: - case BGEZALL: - return false; - default: - return true; - } -} - static bool InstrEndsBlock(const u32 instr) { switch (instr >> 26 & 0x3f) { case SPECIAL: return SpecialEndsBlock(instr); case REGIMM: - return RegimmEndsBlock(instr); case J: case JAL: case BEQ: @@ -49,4 +36,37 @@ static bool InstrEndsBlock(const u32 instr) { return false; } } + +static bool IsBranchLikely(const u32 instr) { + switch (instr >> 26 & 0x1F) { + case BEQL: + case BNEL: + case BLEZL: + case BGTZL: + return true; + case COP1: + { + const u8 mask_sub = (instr >> 21) & 0x1F; + const u8 mask_branch = (instr >> 16) & 0x1F; + if (mask_sub == 0x08) { + if (mask_branch == 2 || mask_branch == 3) + return true; + + return false; + } + + return false; + } + default: + switch (instr >> 16 & 0x1F) { + case BLTZL: + case BGEZL: + case BLTZALL: + case BGEZALL: + return true; + default: + return false; + } + } +} } // namespace n64 diff --git a/src/backend/core/jit/instructions.cpp b/src/backend/core/jit/instructions.cpp index f2b7de18..df560c11 100644 --- a/src/backend/core/jit/instructions.cpp +++ b/src/backend/core/jit/instructions.cpp @@ -10,7 +10,8 @@ using namespace Xbyak::util; void JIT::lui(const u32 instr) { u64 val = static_cast(static_cast(instr)); val <<= 16; - regs.Write(RT(instr), val, true); + regs.gpr[RT(instr)] = val; + regs.gprIsConstant[RT(instr)] = true; } void JIT::add(const u32 instr) { @@ -57,7 +58,7 @@ void JIT::addu(u32 instr) { const s32 rt = regs.Read(RT(instr)); const s32 result = rs + rt; - regs.Write(RD(instr), result); + regs.Write(RD(instr), result, true); return; } @@ -106,7 +107,7 @@ void JIT::addiu(u32 instr) { if (regs.IsRegConstant(RS(instr))) { auto rs = regs.Read(RS(instr)); u32 result = rs + imm; - regs.Write(RT(instr), s32(result)); + regs.Write(RT(instr), s32(result), true); return; } @@ -119,7 +120,7 @@ void JIT::addiu(u32 instr) { void JIT::andi(u32 instr) { const s64 imm = static_cast(instr); if (regs.IsRegConstant(RS(instr))) { - regs.Write(RT(instr), regs.Read(RS(instr)) & imm); + regs.Write(RT(instr), regs.Read(RS(instr)) & imm, true); return; } @@ -130,7 +131,7 @@ void JIT::andi(u32 instr) { void JIT::and_(u32 instr) { if (regs.IsRegConstant(RS(instr), RT(instr))) { - regs.Write(RD(instr), regs.Read(RS(instr)) & regs.Read(RT(instr))); + regs.Write(RD(instr), regs.Read(RS(instr)) & regs.Read(RT(instr)), true); return; } @@ -156,59 +157,60 @@ void JIT::and_(u32 instr) { regs.Write(RD(instr), code.rdi); } -void JIT::SkipSlot() { - code.mov(code.rax, REG(qword, pc)); - code.mov(REG(qword, oldPC), code.rax); - - code.mov(code.rax, REG(qword, nextPC)); - code.mov(REG(qword, pc), code.rax); - - code.add(code.rax, 4); - code.mov(REG(qword, nextPC), code.rax); -} +void JIT::SkipSlot() { code.jmp("not_taken"); } void JIT::SkipSlotConstant() { blockPC += 4; } void JIT::BranchTaken(const s64 offs) { code.mov(code.rax, REG(qword, pc)); code.add(code.rax, offs); - code.mov(REG(qword, nextPC), code.rax); + code.mov(REG(qword, pc), code.rax); } -void JIT::BranchTaken(const Xbyak::Reg &offs) { - code.mov(code.rax, REG(qword, pc)); - code.add(code.rax, offs); - code.mov(REG(qword, nextPC), code.rax); +void JIT::BranchTaken(const Xbyak::Reg64 &offs) { code.add(REG(qword, pc), offs); } + +void JIT::BranchAbsTaken(const s64 addr) { + code.mov(code.rax, addr); + code.mov(REG(qword, pc), code.rax); } +void JIT::BranchAbsTaken(const Xbyak::Reg64 &addr) { code.mov(REG(qword, nextPC), addr); } + #define branch(offs, cond) \ do { \ - code.mov(code.al, 1); \ - code.mov(REG(byte, delaySlot), code.al); \ code.j##cond("taken"); \ - code.jmp("not taken"); \ + code.mov(code.rax, blockPC); \ + code.mov(REG(qword, pc), code.rax); \ + code.jmp("not_taken"); \ code.L("taken"); \ BranchTaken(offs); \ code.L("not_taken"); \ } \ while (0) +#define branch_abs(addr, cond) \ + do { \ + code.j##cond("taken"); \ + code.mov(code.rax, blockPC); \ + code.mov(REG(qword, pc), code.rax); \ + code.jmp("not_taken"); \ + code.L("taken"); \ + BranchAbsTaken(addr); \ + code.L("not_taken"); \ + } \ + while (0) + #define branch_likely(offs, cond) \ do { \ code.j##cond("taken"); \ SkipSlot(); \ code.jmp("not_taken"); \ code.L("taken"); \ - code.mov(code.al, 1); \ - code.mov(REG(byte, delaySlot), code.al); \ BranchTaken(offs); \ - code.L("not_taken"); \ } \ while (0) void JIT::branch_constant(const bool cond, const s64 offset) { - code.mov(code.al, 1); - code.mov(REG(byte, delaySlot), code.al); if (cond) { BranchTaken(offset); } @@ -216,14 +218,18 @@ void JIT::branch_constant(const bool cond, const s64 offset) { void JIT::branch_likely_constant(const bool cond, const s64 offset) { if (cond) { - code.mov(code.al, 1); - code.mov(REG(byte, delaySlot), code.al); BranchTaken(offset); } else { SkipSlotConstant(); } } +void JIT::branch_abs_constant(const bool cond, const s64 address) { + if (cond) { + BranchAbsTaken(address); + } +} + void JIT::bfc0(u32 instr) { const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; @@ -260,7 +266,7 @@ void JIT::bltz(const u32 instr) { return; } - code.mov(code.rax, GPR(RS(instr))); + regs.Read(RS(instr), code.rax); code.cmp(code.rax, 0); branch(offset, l); } @@ -273,7 +279,7 @@ void JIT::bgez(const u32 instr) { return; } - code.mov(code.rax, GPR(RS(instr))); + regs.Read(RS(instr), code.rax); code.cmp(code.rax, 0); branch(offset, ge); } @@ -286,7 +292,7 @@ void JIT::bltzl(const u32 instr) { return; } - code.mov(code.rax, GPR(RS(instr))); + regs.Read(RS(instr), code.rax); code.cmp(code.rax, 0); branch_likely(offset, l); } @@ -299,18 +305,66 @@ void JIT::bgezl(const u32 instr) { return; } - code.mov(code.rax, GPR(RS(instr))); + regs.Read(RS(instr), code.rax); code.cmp(code.rax, 0); branch_likely(offset, ge); } -void JIT::bltzal(const u32 instr) {} +void JIT::bltzal(const u32 instr) { + const s16 imm = instr; + const s64 offset = u64((s64)imm) << 2; + regs.Write(31, blockPC + 4, true); + if (regs.IsRegConstant(RS(instr))) { + branch_constant(regs.Read(RS(instr)) < 0, offset); + return; + } -void JIT::bgezal(const u32 instr) {} + regs.Read(RS(instr), code.rax); + code.cmp(code.rax, 0); + branch(offset, l); +} -void JIT::bltzall(const u32 instr) {} +void JIT::bgezal(const u32 instr) { + const s16 imm = instr; + const s64 offset = u64((s64)imm) << 2; + regs.Write(31, blockPC + 4, true); + if (regs.IsRegConstant(RS(instr))) { + branch_constant(regs.Read(RS(instr)) >= 0, offset); + return; + } -void JIT::bgezall(const u32 instr) {} + regs.Read(RS(instr), code.rax); + code.cmp(code.rax, 0); + branch(offset, ge); +} + +void JIT::bltzall(const u32 instr) { + const s16 imm = instr; + const s64 offset = u64((s64)imm) << 2; + regs.Write(31, blockPC + 4, true); + if (regs.IsRegConstant(RS(instr))) { + branch_likely_constant(regs.Read(RS(instr)) < 0, offset); + return; + } + + regs.Read(RS(instr), code.rax); + code.cmp(code.rax, 0); + branch_likely(offset, l); +} + +void JIT::bgezall(const u32 instr) { + const s16 imm = instr; + const s64 offset = u64((s64)imm) << 2; + regs.Write(31, blockPC + 4, true); + if (regs.IsRegConstant(RS(instr))) { + branch_likely_constant(regs.Read(RS(instr)) >= 0, offset); + return; + } + + regs.Read(RS(instr), code.rax); + code.cmp(code.rax, 0); + branch_likely(offset, ge); +} void JIT::beq(const u32 instr) { const s16 imm = instr; @@ -321,21 +375,21 @@ void JIT::beq(const u32 instr) { } if (regs.IsRegConstant(RS(instr))) { - code.mov(code.rax, GPR(RT(instr))); + regs.Read(RT(instr), code.rax); code.cmp(code.rax, regs.Read(RS(instr))); branch(offset, e); return; } if (regs.IsRegConstant(RT(instr))) { - code.mov(code.rax, GPR(RS(instr))); + regs.Read(RS(instr), code.rax); code.cmp(code.rax, regs.Read(RT(instr))); branch(offset, e); return; } - code.mov(code.rax, GPR(RS(instr))); - code.mov(code.rdi, GPR(RT(instr))); + regs.Read(RS(instr), code.rax); + regs.Read(RT(instr), code.rdi); code.cmp(code.rax, code.rdi); branch(offset, e); } @@ -349,21 +403,21 @@ void JIT::beql(const u32 instr) { } if (regs.IsRegConstant(RS(instr))) { - code.mov(code.rax, GPR(RT(instr))); + regs.Read(RT(instr), code.rax); code.cmp(code.rax, regs.Read(RS(instr))); branch_likely(offset, e); return; } if (regs.IsRegConstant(RT(instr))) { - code.mov(code.rax, GPR(RS(instr))); + regs.Read(RS(instr), code.rax); code.cmp(code.rax, regs.Read(RT(instr))); branch_likely(offset, e); return; } - code.mov(code.rax, GPR(RS(instr))); - code.mov(code.rdi, GPR(RT(instr))); + regs.Read(RS(instr), code.rax); + regs.Read(RT(instr), code.rdi); code.cmp(code.rax, code.rdi); branch_likely(offset, e); } @@ -372,26 +426,26 @@ void JIT::bne(const u32 instr) { const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; if (regs.IsRegConstant(RS(instr)) && regs.IsRegConstant(RT(instr))) { - branch_constant(regs.Read(RS(instr)) == regs.Read(RT(instr)), offset); + branch_constant(regs.Read(RS(instr)) != regs.Read(RT(instr)), offset); return; } if (regs.IsRegConstant(RS(instr))) { - code.mov(code.rax, GPR(RT(instr))); + regs.Read(RT(instr), code.rax); code.cmp(code.rax, regs.Read(RS(instr))); branch(offset, ne); return; } if (regs.IsRegConstant(RT(instr))) { - code.mov(code.rax, GPR(RS(instr))); + regs.Read(RS(instr), code.rax); code.cmp(code.rax, regs.Read(RT(instr))); branch(offset, ne); return; } - code.mov(code.rax, GPR(RS(instr))); - code.mov(code.rdi, GPR(RT(instr))); + regs.Read(RS(instr), code.rax); + regs.Read(RT(instr), code.rdi); code.cmp(code.rax, code.rdi); branch(offset, ne); } @@ -400,26 +454,26 @@ void JIT::bnel(const u32 instr) { const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; if (regs.IsRegConstant(RS(instr)) && regs.IsRegConstant(RT(instr))) { - branch_likely_constant(regs.Read(RS(instr)) == regs.Read(RT(instr)), offset); + branch_likely_constant(regs.Read(RS(instr)) != regs.Read(RT(instr)), offset); return; } if (regs.IsRegConstant(RS(instr))) { - code.mov(code.rax, GPR(RT(instr))); + regs.Read(RT(instr), code.rax); code.cmp(code.rax, regs.Read(RS(instr))); branch_likely(offset, ne); return; } if (regs.IsRegConstant(RT(instr))) { - code.mov(code.rax, GPR(RS(instr))); + regs.Read(RS(instr), code.rax); code.cmp(code.rax, regs.Read(RT(instr))); branch_likely(offset, ne); return; } - code.mov(code.rax, GPR(RS(instr))); - code.mov(code.rdi, GPR(RT(instr))); + regs.Read(RS(instr), code.rax); + regs.Read(RT(instr), code.rdi); code.cmp(code.rax, code.rdi); branch_likely(offset, ne); } @@ -432,7 +486,7 @@ void JIT::blez(const u32 instr) { return; } - code.mov(code.rax, GPR(RS(instr))); + regs.Read(RS(instr), code.rax); code.cmp(code.rax, 0); branch(offset, le); } @@ -445,7 +499,7 @@ void JIT::blezl(const u32 instr) { return; } - code.mov(code.rax, GPR(RS(instr))); + regs.Read(RS(instr), code.rax); code.cmp(code.rax, 0); branch_likely(offset, le); } @@ -458,7 +512,7 @@ void JIT::bgtz(const u32 instr) { return; } - code.mov(code.rax, GPR(RS(instr))); + regs.Read(RS(instr), code.rax); code.cmp(code.rax, 0); branch(offset, g); } @@ -471,7 +525,7 @@ void JIT::bgtzl(const u32 instr) { return; } - code.mov(code.rax, GPR(RS(instr))); + regs.Read(RS(instr), code.rax); code.cmp(code.rax, 0); branch_likely(offset, g); } @@ -485,7 +539,7 @@ void JIT::dadd(u32 instr) { // regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); Util::panic("[JIT]: Unhandled Overflow exception in DADD!"); } - regs.Write(RD(instr), result); + regs.Write(RD(instr), result, true); } else { Util::panic("[JIT]: Implement non constant DADD!"); } @@ -495,7 +549,7 @@ void JIT::daddu(u32 instr) { if (regs.IsRegConstant(RS(instr), RT(instr))) { auto rs = regs.Read(RS(instr)); auto rt = regs.Read(RT(instr)); - regs.Write(RD(instr), rt + rs); + regs.Write(RD(instr), rt + rs, true); } else { Util::panic("[JIT]: Implement non constant DADD!"); } @@ -510,7 +564,7 @@ void JIT::daddi(u32 instr) { // regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); Util::panic("[JIT]: Unhandled Overflow exception in DADDI!"); } - regs.Write(RT(instr), result); + regs.Write(RT(instr), result, true); } else { Util::panic("[JIT]: Implement non constant DADDI!"); } @@ -520,7 +574,7 @@ void JIT::daddiu(u32 instr) { if (regs.IsRegConstant(RS(instr))) { s16 imm = s16(instr); auto rs = regs.Read(RS(instr)); - regs.Write(RT(instr), imm + rs); + regs.Write(RT(instr), imm + rs, true); } else { Util::panic("[JIT]: Implement non constant DADDI!"); } @@ -654,7 +708,7 @@ void JIT::dsll(u32 instr) { if (regs.IsRegConstant(RT(instr))) { u8 sa = ((instr >> 6) & 0x1f); auto result = regs.Read(RT(instr)) << sa; - regs.Write(RD(instr), result); + regs.Write(RD(instr), result, true); } else { Util::panic("[JIT]: Implement non constant DSLL!"); } @@ -664,7 +718,7 @@ void JIT::dsllv(u32 instr) { if (regs.IsRegConstant(RT(instr), RS(instr))) { auto sa = regs.Read(RS(instr)) & 63; auto result = regs.Read(RT(instr)) << sa; - regs.Write(RD(instr), result); + regs.Write(RD(instr), result, true); } else { Util::panic("[JIT]: Implement non constant DSLLV!"); } @@ -674,7 +728,7 @@ void JIT::dsll32(u32 instr) { if (regs.IsRegConstant(RT(instr))) { u8 sa = ((instr >> 6) & 0x1f); auto result = regs.Read(RT(instr)) << (sa + 32); - regs.Write(RD(instr), result); + regs.Write(RD(instr), result, true); } else { Util::panic("[JIT]: Implement non constant DSLL32!"); } @@ -685,7 +739,7 @@ void JIT::dsra(u32 instr) { auto rt = regs.Read(RT(instr)); u8 sa = ((instr >> 6) & 0x1f); s64 result = rt >> sa; - regs.Write(RD(instr), result); + regs.Write(RD(instr), result, true); } else { Util::panic("[JIT]: Implement non constant DSRA!"); } @@ -697,7 +751,7 @@ void JIT::dsrav(u32 instr) { auto rs = regs.Read(RS(instr)); s64 sa = rs & 63; s64 result = rt >> sa; - regs.Write(RD(instr), result); + regs.Write(RD(instr), result, true); } else { Util::panic("[JIT]: Implement non constant DSRAV!"); } @@ -708,7 +762,7 @@ void JIT::dsra32(u32 instr) { auto rt = regs.Read(RT(instr)); u8 sa = ((instr >> 6) & 0x1f); s64 result = rt >> (sa + 32); - regs.Write(RD(instr), result); + regs.Write(RD(instr), result, true); } else { Util::panic("[JIT]: Implement non constant DSRA32!"); } @@ -719,7 +773,7 @@ void JIT::dsrl(u32 instr) { auto rt = regs.Read(RT(instr)); u8 sa = ((instr >> 6) & 0x1f); u64 result = rt >> sa; - regs.Write(RD(instr), s64(result)); + regs.Write(RD(instr), s64(result), true); } else { Util::panic("[JIT]: Implement non constant DSRL!"); } @@ -730,7 +784,7 @@ void JIT::dsrlv(u32 instr) { u8 amount = regs.Read(RS(instr)) & 63; auto rt = regs.Read(RT(instr)); u64 result = rt >> amount; - regs.Write(RD(instr), s64(result)); + regs.Write(RD(instr), s64(result), true); } else { Util::panic("[JIT]: Implement non constant DSRLV!"); } @@ -741,7 +795,7 @@ void JIT::dsrl32(u32 instr) { auto rt = regs.Read(RT(instr)); u8 sa = ((instr >> 6) & 0x1f); u64 result = rt >> (sa + 32); - regs.Write(RD(instr), s64(result)); + regs.Write(RD(instr), s64(result), true); } else { Util::panic("[JIT]: Implement non constant DSRL32!"); } @@ -756,7 +810,7 @@ void JIT::dsub(u32 instr) { // regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); Util::panic("[JIT]: Unhandled Overflow exception in DSUB!"); } else { - regs.Write(RD(instr), result); + regs.Write(RD(instr), result, true); } } else { Util::panic("[JIT]: Implement non constant DSUB!"); @@ -768,7 +822,7 @@ void JIT::dsubu(u32 instr) { auto rt = regs.Read(RT(instr)); auto rs = regs.Read(RS(instr)); s64 result = rs - rt; - regs.Write(RD(instr), result); + regs.Write(RD(instr), result, true); } else { Util::panic("[JIT]: Implement non constant DSUBU!"); } @@ -779,39 +833,28 @@ void JIT::j(const u32 instr) { code.mov(code.rax, REG(qword, oldPC)); code.and_(code.rax, ~0xfffffff); code.or_(code.rax, target); - code.mov(code.dl, 1); - code.mov(REG(byte, delaySlot), code.dl); - code.mov(code.rdi, target); - code.mov(REG(qword, nextPC), code.rdi); + branch_abs(target, mp); } void JIT::jr(const u32 instr) { if (regs.IsRegConstant(RS(instr))) { const u64 address = regs.Read(RS(instr)); - code.mov(code.dl, 1); - code.mov(REG(byte, delaySlot), code.dl); - code.mov(code.rdi, address); - code.mov(REG(qword, nextPC), code.rdi); + branch_abs_constant(true, address); return; } - code.mov(code.dl, 1); - code.mov(REG(byte, delaySlot), code.dl); - code.mov(code.rdi, GPR(RS(instr))); - code.mov(REG(qword, nextPC), code.rdi); + regs.Read(RS(instr), code.rax); + branch_abs(code.rax, mp); } void JIT::jal(const u32 instr) { - code.mov(code.rax, REG(qword, nextPC)); - code.mov(GPR(31), code.rax); + regs.Write(31, blockPC + 4, true); j(instr); } void JIT::jalr(const u32 instr) { - if (regs.IsRegConstant(RS(instr))) { - const u64 addr = regs.Read(RS(instr)); - return; - } + regs.Write(RD(instr), blockPC + 4, true); + jr(instr); } void JIT::lbu(u32 instr) { @@ -824,7 +867,7 @@ void JIT::lbu(u32 instr) { Util::panic("[JIT]: Unhandled TLBL exception in LBU!"); } else { const u8 value = mem.Read(regs, paddr); - regs.Write(RT(instr), value); + regs.Write(RT(instr), value, true); } } else { Util::panic("[JIT]: Implement non constant LBU!"); @@ -839,7 +882,7 @@ void JIT::lb(u32 instr) { // regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC); Util::panic("[JIT]: Unhandled TLBL exception in LB!"); } else { - regs.Write(RT(instr), (s8)mem.Read(regs, paddr)); + regs.Write(RT(instr), (s8)mem.Read(regs, paddr), true); } } else { Util::panic("[JIT]: Implement non constant LB!"); @@ -863,7 +906,7 @@ void JIT::ld(u32 instr) { Util::panic("[JIT]: Unhandled TLBL exception in LD!"); } else { const s64 value = mem.Read(regs, paddr); - regs.Write(RT(instr), value); + regs.Write(RT(instr), value, true); } } else { Util::panic("[JIT]: Implement non constant LD!"); @@ -901,7 +944,7 @@ void JIT::ldl(u32 instr) { const u64 mask = 0xFFFFFFFFFFFFFFFF << shift; const u64 data = mem.Read(regs, paddr & ~7); const s64 result = (s64)((regs.Read(RT(instr)) & ~mask) | (data << shift)); - regs.Write(RT(instr), result); + regs.Write(RT(instr), result, true); } } else { Util::panic("[JIT]: Implement non constant LDL!"); @@ -921,7 +964,7 @@ void JIT::ldr(u32 instr) { const u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; const u64 data = mem.Read(regs, paddr & ~7); const s64 result = (s64)((regs.Read(RT(instr)) & ~mask) | (data >> shift)); - regs.Write(RT(instr), result); + regs.Write(RT(instr), result, true); } } else { Util::panic("[JIT]: Implement non constant LDR!"); @@ -929,21 +972,32 @@ void JIT::ldr(u32 instr) { } void JIT::lh(u32 instr) { - const u64 address = regs.Read(RS(instr)) + (s16)instr; - if (check_address_error(0b1, address)) { - // regs.cop0.HandleTLBException(address); - // regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC); - // return; - Util::panic("[JIT]: Unhandled ADEL exception in LH!"); + if (regs.IsRegConstant(RS(instr))) { + const u64 address = regs.Read(RS(instr)) + (s16)instr; + if (check_address_error(0b1, address)) { + // regs.cop0.HandleTLBException(address); + // regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + // return; + Util::panic("[JIT]: Unhandled ADEL exception in LH!"); + return; + } + + u32 paddr = 0; + if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { + // regs.cop0.HandleTLBException(address); + // regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC); + Util::panic("[JIT]: Unhandled TLBL exception in LH!"); + return; + } + + code.mov(code.rsi, code.ptr[code.rbp + (reinterpret_cast(®s) - reinterpret_cast(this))]); + code.mov(code.edx, paddr); + emitMemberFunctionCall(&Mem::Read, &mem); + regs.Write(RT(instr), code.rax); + return; } - u32 paddr = 0; - if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { - // regs.cop0.HandleTLBException(address); - // regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC); - } else { - regs.Write(RT(instr), (s16)mem.Read(regs, paddr)); - } + Util::panic("[JIT]: Implement non constant LH!"); } void JIT::lhu(u32) {} @@ -952,7 +1006,35 @@ void JIT::ll(u32) {} void JIT::lld(u32) {} -void JIT::lw(u32) {} +void JIT::lw(u32 instr) { + if (regs.IsRegConstant(RS(instr))) { + const s16 offset = instr; + const u64 address = regs.Read(RS(instr)) + offset; + if (check_address_error(0b11, address)) { + // regs.cop0.HandleTLBException(address); + // regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + // return; + Util::panic("[JIT]: Unhandled ADEL exception in LW!"); + return; + } + + u32 paddr = 0; + if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { + // regs.cop0.HandleTLBException(address); + // regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC); + Util::panic("[JIT]: Unhandled TLBL exception in LW!"); + return; + } + + code.mov(code.rsi, code.ptr[code.rbp + (reinterpret_cast(®s) - reinterpret_cast(this))]); + code.mov(code.edx, paddr); + emitMemberFunctionCall(&Mem::Read, &mem); + regs.Write(RT(instr), code.rax); + return; + } + + Util::panic("[JIT]: Implement non constant LW!"); +} void JIT::lwc1(u32) {} @@ -964,7 +1046,7 @@ void JIT::lwr(u32) {} void JIT::mfhi(u32 instr) { if (regs.hiIsConstant) { - regs.Write(RD(instr), regs.hi); + regs.Write(RD(instr), regs.hi, true); } else { Util::panic("[JIT]: Implement non constant MFHI!"); } @@ -972,7 +1054,7 @@ void JIT::mfhi(u32 instr) { void JIT::mflo(u32 instr) { if (regs.loIsConstant) { - regs.Write(RD(instr), regs.lo); + regs.Write(RD(instr), regs.lo, true); } else { Util::panic("[JIT]: Implement non constant MFLO!"); } @@ -1026,7 +1108,7 @@ void JIT::mtlo(u32 instr) { void JIT::nor(u32 instr) { if (regs.IsRegConstant(RS(instr), RT(instr))) { - regs.Write(RD(instr), ~(regs.Read(RS(instr)) | regs.Read(RT(instr)))); + regs.Write(RD(instr), ~(regs.Read(RS(instr)) | regs.Read(RT(instr))), true); } else { Util::panic("[JIT]: Implement non constant NOR!"); } @@ -1035,7 +1117,7 @@ void JIT::nor(u32 instr) { void JIT::slti(u32 instr) { if (regs.IsRegConstant(RS(instr))) { s16 imm = instr; - regs.Write(RT(instr), regs.Read(RS(instr)) < imm); + regs.Write(RT(instr), regs.Read(RS(instr)) < imm, true); } else { Util::panic("[JIT]: Implement non constant SLTI!"); } @@ -1044,7 +1126,7 @@ void JIT::slti(u32 instr) { void JIT::sltiu(u32 instr) { if (regs.IsRegConstant(RS(instr))) { s16 imm = instr; - regs.Write(RT(instr), regs.Read(RS(instr)) < imm); + regs.Write(RT(instr), regs.Read(RS(instr)) < imm, true); } else { Util::panic("[JIT]: Implement non constant SLTIU!"); } @@ -1052,7 +1134,7 @@ void JIT::sltiu(u32 instr) { void JIT::slt(u32 instr) { if (regs.IsRegConstant(RS(instr), RT(instr))) { - regs.Write(RD(instr), regs.Read(RS(instr)) < regs.Read(RT(instr))); + regs.Write(RD(instr), regs.Read(RS(instr)) < regs.Read(RT(instr)), true); } else { Util::panic("[JIT]: Implement non constant SLT!"); } @@ -1060,7 +1142,7 @@ void JIT::slt(u32 instr) { void JIT::sltu(u32 instr) { if (regs.IsRegConstant(RS(instr), RT(instr))) { - regs.Write(RD(instr), regs.Read(RS(instr)) < regs.Read(RT(instr))); + regs.Write(RD(instr), regs.Read(RS(instr)) < regs.Read(RT(instr)), true); } else { Util::panic("[JIT]: Implement non constant SLT!"); } @@ -1070,7 +1152,7 @@ void JIT::sll(u32 instr) { if (regs.IsRegConstant(RT(instr))) { u8 sa = ((instr >> 6) & 0x1f); s32 result = regs.Read(RT(instr)) << sa; - regs.Write(RD(instr), (s64)result); + regs.Write(RD(instr), (s64)result, true); } else { Util::panic("[JIT]: Implement non constant SLL!"); } @@ -1081,7 +1163,7 @@ void JIT::sllv(u32 instr) { u8 sa = (regs.Read(RS(instr))) & 0x1F; u32 rt = regs.Read(RT(instr)); s32 result = rt << sa; - regs.Write(RD(instr), (s64)result); + regs.Write(RD(instr), (s64)result, true); } else { Util::panic("[JIT]: Implement non constant SLLV!"); } @@ -1095,7 +1177,7 @@ void JIT::sub(u32 instr) { if (check_signed_underflow(rs, rt, result)) { regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); } else { - regs.Write(RD(instr), result); + regs.Write(RD(instr), result, true); } } else { Util::panic("[JIT]: Implement non constant SUB!"); @@ -1107,7 +1189,7 @@ void JIT::subu(u32 instr) { u32 rt = regs.Read(RT(instr)); u32 rs = regs.Read(RS(instr)); u32 result = rs - rt; - regs.Write(RD(instr), (s64)((s32)result)); + regs.Write(RD(instr), (s64)((s32)result), true); } else { Util::panic("[JIT]: Implement non constant SUBU!"); } @@ -1118,7 +1200,7 @@ void JIT::sra(u32 instr) { s64 rt = regs.Read(RT(instr)); u8 sa = ((instr >> 6) & 0x1f); s32 result = rt >> sa; - regs.Write(RD(instr), result); + regs.Write(RD(instr), result, true); } else { Util::panic("[JIT]: Implement non constant SRA!"); } @@ -1130,7 +1212,7 @@ void JIT::srav(u32 instr) { s64 rt = regs.Read(RT(instr)); u8 sa = rs & 0x1f; s32 result = rt >> sa; - regs.Write(RD(instr), result); + regs.Write(RD(instr), result, true); } else { Util::panic("[JIT]: Implement non constant SRAV!"); } @@ -1141,14 +1223,14 @@ void JIT::srl(u32 instr) { u32 rt = regs.Read(RT(instr)); u8 sa = ((instr >> 6) & 0x1f); u32 result = rt >> sa; - regs.Write(RD(instr), (s32)result); + regs.Write(RD(instr), (s32)result, true); } else { Util::panic("[JIT]: Implement non constant SRL!"); } } void JIT::sw(const u32 instr) { - if (regs.IsRegConstant(RS(instr)) && regs.IsRegConstant(RT(instr))) { + if (regs.IsRegConstant(RS(instr), RT(instr))) { const s16 offset = instr; const u64 address = regs.Read(RS(instr)) + offset; if (check_address_error(0b11, address)) { @@ -1164,7 +1246,7 @@ void JIT::sw(const u32 instr) { // regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC); Util::panic("[JIT]: Unhandled TLBS exception in SW!"); } else { - code.mov(code.rsi, reinterpret_cast(®s)); + code.lea(code.rsi, code.ptr[code.rbp + (reinterpret_cast(®s) - reinterpret_cast(this))]); code.mov(code.edx, physical); code.mov(code.rcx, regs.Read(RT(instr))); emitMemberFunctionCall(&Mem::WriteJIT, &mem); @@ -1189,9 +1271,9 @@ void JIT::sw(const u32 instr) { // regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC); Util::panic("[JIT]: Unhandled TLBS exception in SW!"); } else { - code.mov(code.rsi, reinterpret_cast(®s)); + code.mov(code.rsi, code.ptr[code.rbp + (reinterpret_cast(®s) - reinterpret_cast(this))]); code.mov(code.edx, physical); - code.mov(code.rcx, GPR(RT(instr))); + regs.Read(RT(instr), code.rcx); emitMemberFunctionCall(&Mem::WriteJIT, &mem); } @@ -1200,7 +1282,7 @@ void JIT::sw(const u32 instr) { if (regs.IsRegConstant(RT(instr))) { const s16 offset = instr; - code.mov(code.rdx, GPR(RS(instr))); + regs.Read(RS(instr), code.rdx); code.add(code.rdx, offset); code.mov(code.esi, Cop0::STORE); @@ -1209,7 +1291,7 @@ void JIT::sw(const u32 instr) { code.mov(code.rcx, reinterpret_cast(&physical)); emitMemberFunctionCall(&Cop0::MapVAddr, ®s.cop0); - code.mov(code.rsi, reinterpret_cast(®s)); + code.mov(code.rsi, code.ptr[code.rbp + (reinterpret_cast(®s) - reinterpret_cast(this))]); code.mov(code.edx, physical); code.mov(code.rcx, regs.Read(RT(instr))); emitMemberFunctionCall(&Mem::WriteJIT, &mem); @@ -1218,7 +1300,7 @@ void JIT::sw(const u32 instr) { } const s16 offset = instr; - code.mov(code.rdx, GPR(RS(instr))); + regs.Read(RS(instr), code.rdx); code.add(code.rdx, offset); code.mov(code.esi, Cop0::STORE); @@ -1227,9 +1309,9 @@ void JIT::sw(const u32 instr) { code.mov(code.rcx, reinterpret_cast(&physical)); emitMemberFunctionCall(&Cop0::MapVAddr, ®s.cop0); - code.mov(code.rsi, reinterpret_cast(®s)); + code.mov(code.rsi, code.ptr[code.rbp + (reinterpret_cast(®s) - reinterpret_cast(this))]); code.mov(code.edx, physical); - code.mov(code.rcx, GPR(RT(instr))); + regs.Read(RT(instr), code.rcx); emitMemberFunctionCall(&Mem::WriteJIT, &mem); } @@ -1238,7 +1320,7 @@ void JIT::srlv(u32 instr) { u8 sa = (regs.Read(RS(instr)) & 0x1F); u32 rt = regs.Read(RT(instr)); s32 result = rt >> sa; - regs.Write(RD(instr), (s64)result); + regs.Write(RD(instr), (s64)result, true); } else { Util::panic("[JIT]: Implement non constant SRLV!"); } @@ -1246,7 +1328,7 @@ void JIT::srlv(u32 instr) { void JIT::or_(u32 instr) { if (regs.IsRegConstant(RS(instr), RT(instr))) { - regs.Write(RD(instr), regs.Read(RS(instr)) | regs.Read(RT(instr))); + regs.Write(RD(instr), regs.Read(RS(instr)) | regs.Read(RT(instr)), true); } else { Util::panic("[JIT]: Implement non constant OR!"); } @@ -1256,19 +1338,22 @@ void JIT::ori(u32 instr) { if (RT(instr) == 0) return; + s64 imm = (u16)instr; if (regs.IsRegConstant(RS(instr))) { - s64 imm = (u16)instr; s64 result = imm | regs.Read(RS(instr)); - code.mov(GPR(RT(instr)), result); - } else { - Util::panic("[JIT]: Implement non constant ORI!"); + regs.Write(RT(instr), result, true); + return; } + + regs.Read(RS(instr), code.rax); + code.or_(code.rax, imm); + regs.Write(RT(instr), code.rax); } void JIT::xori(u32 instr) { if (regs.IsRegConstant(RS(instr))) { s64 imm = (u16)instr; - regs.Write(RT(instr), regs.Read(RS(instr)) ^ imm); + regs.Write(RT(instr), regs.Read(RS(instr)) ^ imm, true); } else { Util::panic("[JIT]: Implement non constant XORI!"); } @@ -1276,7 +1361,7 @@ void JIT::xori(u32 instr) { void JIT::xor_(u32 instr) { if (regs.IsRegConstant(RS(instr), RT(instr))) { - regs.Write(RD(instr), regs.Read(RT(instr)) ^ regs.Read(RS(instr))); + regs.Write(RD(instr), regs.Read(RT(instr)) ^ regs.Read(RS(instr)), true); } else { Util::panic("[JIT]: Implement non constant XOR!"); } diff --git a/src/backend/core/registers/Registers.cpp b/src/backend/core/registers/Registers.cpp index 80c01f9b..fa201f98 100644 --- a/src/backend/core/registers/Registers.cpp +++ b/src/backend/core/registers/Registers.cpp @@ -40,6 +40,41 @@ u64 Registers::Read(size_t idx) { return idx == 0 ? 0 : gpr[idx]; } +template <> +s64 Registers::Read(const size_t idx) { + return static_cast(Read(idx)); +} + +template <> +u32 Registers::Read(size_t idx) { + return idx == 0 ? 0 : gpr[idx]; +} + +template <> +s32 Registers::Read(size_t idx) { + return static_cast(Read(idx)); +} + +template <> +u16 Registers::Read(size_t idx) { + return idx == 0 ? 0 : gpr[idx]; +} + +template <> +s16 Registers::Read(size_t idx) { + return static_cast(Read(idx)); +} + +template <> +u8 Registers::Read(size_t idx) { + return idx == 0 ? 0 : gpr[idx]; +} + +template <> +s8 Registers::Read(size_t idx) { + return static_cast(Read(idx)); +} + template <> void Registers::Read(size_t idx, Xbyak::Reg reg) { jit->code.mov(reg.cvt64(), jit->GPR(idx)); @@ -80,41 +115,6 @@ void Registers::Read(size_t idx, Xbyak::Reg reg) { jit->code.mov(reg.cvt8(), jit->GPR(idx)); } -template <> -s64 Registers::Read(const size_t idx) { - return static_cast(Read(idx)); -} - -template <> -u32 Registers::Read(size_t idx) { - return idx == 0 ? 0 : gpr[idx]; -} - -template <> -s32 Registers::Read(size_t idx) { - return static_cast(Read(idx)); -} - -template <> -u16 Registers::Read(size_t idx) { - return idx == 0 ? 0 : gpr[idx]; -} - -template <> -s16 Registers::Read(size_t idx) { - return static_cast(Read(idx)); -} - -template <> -u8 Registers::Read(size_t idx) { - return idx == 0 ? 0 : gpr[idx]; -} - -template <> -s8 Registers::Read(size_t idx) { - return static_cast(Read(idx)); -} - template <> void Registers::WriteJIT(size_t idx, bool v) { jit->code.mov(jit->code.al, v); @@ -126,10 +126,11 @@ void Registers::Write(size_t idx, bool v, bool isConstant) { if (idx == 0) return; + bool oldIsConstant = gprIsConstant[idx]; gprIsConstant[idx] = isConstant; if (jit) { - if (isConstant) { + if (oldIsConstant) { gpr[idx] = v; return; } @@ -152,10 +153,11 @@ void Registers::Write(size_t idx, u64 v, bool isConstant) { if (idx == 0) return; + bool oldIsConstant = gprIsConstant[idx]; gprIsConstant[idx] = isConstant; if (jit) { - if (isConstant) { + if (oldIsConstant) { gpr[idx] = v; return; } @@ -183,10 +185,11 @@ void Registers::Write(size_t idx, u32 v, bool isConstant) { if (idx == 0) return; + bool oldIsConstant = gprIsConstant[idx]; gprIsConstant[idx] = isConstant; if (jit) { - if (isConstant) { + if (oldIsConstant) { gpr[idx] = v; return; } @@ -210,10 +213,11 @@ void Registers::Write(size_t idx, s32 v, bool isConstant) { if (idx == 0) return; + bool oldIsConstant = gprIsConstant[idx]; gprIsConstant[idx] = isConstant; if (jit) { - if (isConstant) { + if (oldIsConstant) { gpr[idx] = v; return; } @@ -236,10 +240,11 @@ void Registers::Write(size_t idx, u16 v, bool isConstant) { if (idx == 0) return; + bool oldIsConstant = gprIsConstant[idx]; gprIsConstant[idx] = isConstant; if (jit) { - if (isConstant) { + if (oldIsConstant) { gpr[idx] = v; return; } @@ -263,10 +268,11 @@ void Registers::Write(size_t idx, s16 v, bool isConstant) { if (idx == 0) return; + bool oldIsConstant = gprIsConstant[idx]; gprIsConstant[idx] = isConstant; if (jit) { - if (isConstant) { + if (oldIsConstant) { gpr[idx] = v; return; } @@ -289,10 +295,11 @@ void Registers::Write(size_t idx, u8 v, bool isConstant) { if (idx == 0) return; + bool oldIsConstant = gprIsConstant[idx]; gprIsConstant[idx] = isConstant; if (jit) { - if (isConstant) { + if (oldIsConstant) { gpr[idx] = v; return; } @@ -316,10 +323,11 @@ void Registers::Write(size_t idx, s8 v, bool isConstant) { if (idx == 0) return; + bool oldIsConstant = gprIsConstant[idx]; gprIsConstant[idx] = isConstant; if (jit) { - if (isConstant) { + if (oldIsConstant) { gpr[idx] = v; return; } diff --git a/src/backend/core/registers/Registers.hpp b/src/backend/core/registers/Registers.hpp index 964c33ad..f7d3020a 100644 --- a/src/backend/core/registers/Registers.hpp +++ b/src/backend/core/registers/Registers.hpp @@ -29,7 +29,7 @@ struct Registers { Cop1 cop1; s64 oldPC{}, pc{}, nextPC{}; s64 hi{}, lo{}; - bool prevDelaySlot{}, delaySlot{}, block_delaySlot{}; + bool prevDelaySlot{}, delaySlot{}; u32 steps = 0; u32 extraCycles = 0; diff --git a/src/utils/File.hpp b/src/utils/File.hpp index 079656e8..d72d9d64 100644 --- a/src/utils/File.hpp +++ b/src/utils/File.hpp @@ -14,6 +14,12 @@ FORCE_INLINE void WriteFileBinary(const std::vector &data, const std::string std::copy(data.begin(), data.end(), std::ostreambuf_iterator{file}); } +FORCE_INLINE void WriteFileBinary(const u8 *data, const size_t size, const std::string &path) { + FILE *out = fopen(path.c_str(), "wb"); + fwrite(data, size, 1, out); + fclose(out); +} + template FORCE_INLINE void WriteFileBinary(const std::array &data, const std::string &path) { std::ofstream file(path, std::ios::binary);