diff --git a/src/backend/Core.cpp b/src/backend/Core.cpp index 40a399f8..cfce2be4 100644 --- a/src/backend/Core.cpp +++ b/src/backend/Core.cpp @@ -3,7 +3,7 @@ #include namespace n64 { -Core::Core() : cpu(std::make_unique(parallel)) {} +Core::Core() : cpu(std::make_unique(parallel)) {} void Core::Stop() { render = false; @@ -23,8 +23,7 @@ void Core::LoadROM(const std::string &rom_) { std::string archive_types[] = {".zip", ".7z", ".rar", ".tar"}; auto extension = fs::path(rom).extension().string(); - const bool isArchive = std::ranges::any_of(archive_types, - [&extension](const auto &e) { return e == extension; }); + const bool isArchive = std::ranges::any_of(archive_types, [&extension](const auto &e) { return e == extension; }); cpu->GetMem().LoadROM(isArchive, rom); GameDB::match(cpu->GetMem()); diff --git a/src/backend/core/JIT.cpp b/src/backend/core/JIT.cpp index fcf549f9..f07325dd 100644 --- a/src/backend/core/JIT.cpp +++ b/src/backend/core/JIT.cpp @@ -2,7 +2,7 @@ #include namespace n64 { -JIT::JIT(ParallelRDP ¶llel) : regs(this), mem(regs, parallel) {} +JIT::JIT(ParallelRDP ¶llel) : regs(this), mem(regs, parallel, this) { blockCache.resize(kUpperSize); } bool JIT::ShouldServiceInterrupt() const { const bool interrupts_pending = (regs.cop0.status.im & regs.cop0.cause.interruptPending) != 0; @@ -23,18 +23,26 @@ void JIT::CheckCompareInterrupt() { } int JIT::Step() { - u32 instruction = 0; - s64 pc = regs.pc; + blockPC = regs.pc; + + if (!blockCache[blockPC >> 8].empty()) { + if (blockCache[blockPC >> 8][blockPC >> 20]) { + return blockCache[blockPC >> 8][blockPC >> 20](); + } + } else { + blockCache[blockPC >> 8].resize(kLowerSize); + } + + regs.block_delaySlot = false; + + u32 instruction; do { // CheckCompareInterrupt(); - // regs.prevDelaySlot = regs.delaySlot; - // regs.delaySlot = false; - - if (check_address_error(0b11, u64(pc))) [[unlikely]] { - /*regs.cop0.HandleTLBException(pc); - regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, pc); + if (check_address_error(0b11, u64(blockPC))) [[unlikely]] { + /*regs.cop0.HandleTLBException(blockPC); + regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, blockPC); return 1;*/ Util::panic("[JIT]: Unhandled exception ADL due to unaligned PC virtual value! (0x{:016lX})", @@ -42,9 +50,10 @@ int JIT::Step() { } u32 paddr = 0; - if (!regs.cop0.MapVAddr(Cop0::LOAD, pc, paddr)) { - /*regs.cop0.HandleTLBException(pc); - regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, pc); + + 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})", @@ -58,15 +67,15 @@ int JIT::Step() { return 1; }*/ - pc += 4; + blockPC += 4; Emit(instruction); } while (!InstrEndsBlock(instruction)); // emit code to store the value of pc - - return 1; + blockCache[regs.pc >> 8][regs.pc >> 20] = code.getCurr(); + return blockCache[regs.pc >> 8][regs.pc >> 20](); } std::vector JIT::Serialize() { diff --git a/src/backend/core/JIT.hpp b/src/backend/core/JIT.hpp index ac252d40..632d770b 100644 --- a/src/backend/core/JIT.hpp +++ b/src/backend/core/JIT.hpp @@ -9,13 +9,10 @@ struct Core; static constexpr u32 kAddressSpaceSize = 0x8000'0000; // >> 20 = 0x800 static constexpr u32 kLowerSize = kAddressSpaceSize >> 20; // 0x800 -static constexpr u32 kUpperSize = 1 << 20; // 0x100000 +static constexpr u32 kUpperSize = kAddressSpaceSize >> 8; // 0x100000 static constexpr u32 kCodeCacheSize = 32_mb; static constexpr u32 kCodeCacheAllocSize = kCodeCacheSize + 4096; - -struct CodeGenerator : Xbyak::CodeGenerator { - CodeGenerator() : Xbyak::CodeGenerator{kCodeCacheSize} {} -}; +#define REG(acc, x) code.acc[reinterpret_cast(®s.x)] struct JIT : BaseCPU { explicit JIT(ParallelRDP &); @@ -27,6 +24,8 @@ struct JIT : BaseCPU { mem.Reset(); } + void InvalidateBlock(u32); + Mem &GetMem() override { return mem; } Registers &GetRegs() override { return regs; } @@ -34,23 +33,31 @@ struct JIT : BaseCPU { [[nodiscard]] Disassembler::DisassemblyResult Disassemble(u32, u32) const override { return {}; } private: - CodeGenerator code; + Xbyak::CodeGenerator code{kCodeCacheSize}; Registers regs; Mem mem; u64 cop2Latch{}; + u64 blockPC = 0; friend struct Cop1; + friend struct Registers; + using BlockFn = int (*)(); + std::vector> blockCache; template - AddressFrame GPR(size_t index) { - if constexpr(sizeof(T) == 1) { - return code.byte[offsetof(JIT, regs) + offsetof(Registers, gpr) + 8 * x]; - } else if constexpr(sizeof(T) == 2) { - return code.word[offsetof(JIT, regs) + offsetof(Registers, gpr) + 8 * x]; - } else if constexpr(sizeof(T) == 4) { - return code.dword[offsetof(JIT, regs) + offsetof(Registers, gpr) + 8 * x]; - } else if constexpr(sizeof(T) == 8) { - return code.qword[offsetof(JIT, regs) + offsetof(Registers, gpr) + 8 * x]; + Xbyak::Address GPR(const size_t index) const { + if constexpr (sizeof(T) == 1) { + return code.byte[reinterpret_cast(®s.gpr[index])]; + } else if constexpr (sizeof(T) == 2) { + return code.word[reinterpret_cast(®s.gpr[index])]; + } else if constexpr (sizeof(T) == 4) { + return code.dword[reinterpret_cast(®s.gpr[index])]; + } else if constexpr (sizeof(T) == 8) { + return code.qword[reinterpret_cast(®s.gpr[index])]; } + + Util::panic("[JIT]: Invalid register addressing"); + // never actually hit, but just to silence the warning "not all control paths return a value" + return Xbyak::Address{0}; } // Credits to PCSX-Redux: https://github.com/grumpycoders/pcsx-redux @@ -90,6 +97,7 @@ private: code.call(functionPtr); } void SkipSlot(); + void SkipSlotConstant(); void BranchTaken(s64 offs); void BranchTaken(const Xbyak::Reg &offs); @@ -110,8 +118,8 @@ private: void addiu(u32); void andi(u32); void and_(u32); - void branch_constant(const bool cond, const s64 address); - void branch_likely_constant(const bool cond, const s64 address); + void branch_constant(bool cond, s64 address); + void branch_likely_constant(bool cond, s64 address); void bltz(u32); void bgez(u32); void bltzl(u32); diff --git a/src/backend/core/Mem.cpp b/src/backend/core/Mem.cpp index fd5e0130..1d9a0314 100644 --- a/src/backend/core/Mem.cpp +++ b/src/backend/core/Mem.cpp @@ -2,12 +2,11 @@ #include #include #include -#include -#include +#include #include namespace n64 { -Mem::Mem(Registers ®s, ParallelRDP ¶llel) : mmio(*this, regs, parallel), flash(saveData) { +Mem::Mem(Registers ®s, ParallelRDP ¶llel, JIT *jit) : mmio(*this, regs, parallel), flash(saveData), jit(jit) { rom.cart.resize(CART_SIZE); std::ranges::fill(rom.cart, 0); } @@ -318,7 +317,20 @@ u64 Mem::Read(Registers ®s, const u32 paddr) { } template <> -void Mem::Write(Registers ®s, u32 paddr, u32 val) { +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; switch (paddr) { @@ -359,7 +371,20 @@ void Mem::Write(Registers ®s, u32 paddr, u32 val) { } template <> -void Mem::Write(Registers ®s, u32 paddr, u32 val) { +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; switch (paddr) { @@ -399,8 +424,21 @@ void Mem::Write(Registers ®s, u32 paddr, u32 val) { } } +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, const u32 paddr, const u32 val) { SI &si = mmio.si; switch (paddr) { @@ -437,7 +475,16 @@ void Mem::Write(Registers ®s, const u32 paddr, const u32 val) { } } -void Mem::Write(const Registers ®s, const u32 paddr, u64 val) { +void Mem::WriteJIT(const Registers ®s, const u32 paddr, const u64 val) { + if (jit) + jit->InvalidateBlock(paddr); + + WriteInterpreter(regs, paddr, val); +} + +void Mem::Write(const Registers ®s, const u32 paddr, const u64 val) { WriteInterpreter(regs, paddr, val); } + +void Mem::WriteInterpreter(const Registers ®s, const u32 paddr, u64 val) { SI &si = mmio.si; switch (paddr) { diff --git a/src/backend/core/Mem.hpp b/src/backend/core/Mem.hpp index 517e3c25..49603449 100644 --- a/src/backend/core/Mem.hpp +++ b/src/backend/core/Mem.hpp @@ -79,7 +79,7 @@ struct Flash { struct Mem { ~Mem() = default; - Mem(Registers &, ParallelRDP &); + Mem(Registers &, ParallelRDP &, JIT * = nullptr); void Reset(); void LoadSRAM(SaveType, fs::path); static std::vector OpenROM(const std::string &, size_t &); @@ -131,6 +131,14 @@ struct Mem { Flash flash; private: + template + void WriteInterpreter(Registers &, u32, u32); + void WriteInterpreter(const Registers &, u32, u64); + template + void WriteJIT(Registers &, u32, u32); + void WriteJIT(const Registers &, u32, u64); + + JIT *jit = nullptr; friend struct SI; friend struct PI; friend struct AI; diff --git a/src/backend/core/jit/helpers.hpp b/src/backend/core/jit/helpers.hpp index 10bee975..f577104c 100644 --- a/src/backend/core/jit/helpers.hpp +++ b/src/backend/core/jit/helpers.hpp @@ -20,27 +20,33 @@ 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: case BNE: case BLEZ: case BGTZ: - case BEQL: - case BNEL: - case BLEZL: - case BGTZL: return true; default: return false; } } - -#define REG(acc, x) code.acc[offsetof(JIT, regs) + offsetof(Registers, x)] -#define GPR_constant_marker(x) code.byte[offsetof(JIT, regs) + offsetof(Registers, gprIsConstant) + x] } // namespace n64 diff --git a/src/backend/core/jit/instructions.cpp b/src/backend/core/jit/instructions.cpp index 5849c017..f2b7de18 100644 --- a/src/backend/core/jit/instructions.cpp +++ b/src/backend/core/jit/instructions.cpp @@ -8,19 +8,12 @@ namespace n64 { using namespace Xbyak::util; void JIT::lui(const u32 instr) { - if (RT(instr) == 0) - return; - u64 val = static_cast(static_cast(instr)); val <<= 16; - code.mov(GPR(RT(instr)), val); - code.mov(GPR_constant_marker(RT(instr)), 1); + regs.Write(RT(instr), val, true); } void JIT::add(const u32 instr) { - if (RD(instr) == 0) - return; - if (regs.IsRegConstant(RS(instr), RT(instr))) { const u32 rs = regs.Read(RS(instr)); const u32 rt = regs.Read(RT(instr)); @@ -30,117 +23,137 @@ void JIT::add(const u32 instr) { Util::panic("[JIT]: Unhandled Overflow exception in ADD!"); } - code.mov(code.eax, static_cast(result)); - code.movsxd(code.rax, code.eax); - code.mov(GPR(RD(instr)), code.rax); - + regs.Write(RD(instr), result, true); return; } if (regs.IsRegConstant(RS(instr))) { const u32 rs = regs.Read(RS(instr)); - code.mov(code.eax, GPR(RT(instr))); + regs.Read(RT(instr), code.eax); code.add(code.eax, rs); - code.movsxd(code.rax, code.eax); - code.mov(GPR(RD(instr)), code.rax); + regs.Write(RD(instr), code.eax); return; } if (regs.IsRegConstant(RT(instr))) { const u32 rt = regs.Read(RT(instr)); - code.mov(code.eax, GPR(RS(instr))); + regs.Read(RS(instr), code.eax); code.add(code.eax, rt); - code.movsxd(code.rax, code.eax); - code.mov(GPR(RD(instr)), code.rax); + regs.Write(RD(instr), code.eax); return; } - code.mov(code.edi, GPR(RT(instr))); - code.mov(code.eax, GPR(RS(instr))); + regs.Read(RT(instr), code.eax); + regs.Read(RS(instr), code.edi); code.add(code.eax, code.edi); - code.movsxd(code.rax, code.eax); - code.mov(GPR(RD(instr)), code.rax); + regs.Write(RD(instr), code.eax); } void JIT::addu(u32 instr) { - if (RD(instr) == 0) - return; - if (regs.IsRegConstant(RS(instr), RT(instr))) { const s32 rs = regs.Read(RS(instr)); const s32 rt = regs.Read(RT(instr)); const s32 result = rs + rt; - code.mov(code.eax, result); - code.movsxd(code.rax, code.eax); - code.mov(GPR(RD(instr)), code.rax); - code.mov(REG(byte, gprIsConstant), 1); + regs.Write(RD(instr), result); return; } - + if (regs.IsRegConstant(RS(instr))) { const s32 rs = regs.Read(RS(instr)); + regs.Read(RT(instr), code.eax); + code.add(code.eax, rs); + regs.Write(RD(instr), code.eax); return; } + + if (regs.IsRegConstant(RT(instr))) { + const s32 rs = regs.Read(RT(instr)); + regs.Read(RS(instr), code.eax); + code.add(code.eax, rs); + regs.Write(RD(instr), code.eax); + return; + } + + regs.Read(RS(instr), code.eax); + regs.Read(RT(instr), code.edi); + code.add(code.eax, code.edi); + regs.Write(RD(instr), code.eax); } void JIT::addi(u32 instr) { - if (RT(instr) == 0) - return; - + u32 imm = s32(s16(instr)); if (regs.IsRegConstant(RS(instr))) { auto rs = regs.Read(RS(instr)); - u32 imm = s32(s16(instr)); u32 result = rs + imm; if (check_signed_overflow(rs, imm, result)) { Util::panic("[JIT]: Unhandled Overflow exception in ADDI!"); - } else { - code.mov(code.eax, static_cast(result)); - code.movsxd(code.rax, code.eax); - code.mov(GPR(RT(instr)), code.rax); } - } else { - Util::panic("[JIT]: Implement non constant ADDI!"); + + regs.Write(RT(instr), static_cast(result), true); + return; } + + regs.Read(RS(instr), code.eax); + code.add(code.eax, imm); + regs.Write(RT(instr), code.eax); } void JIT::addiu(u32 instr) { - if (RT(instr) == 0) - return; - + u32 imm = s32(s16(instr)); if (regs.IsRegConstant(RS(instr))) { auto rs = regs.Read(RS(instr)); - u32 imm = s32(s16(instr)); u32 result = rs + imm; regs.Write(RT(instr), s32(result)); - } else { - Util::panic("[JIT]: Implement non constant ADDIU!"); + + return; } + + regs.Read(RS(instr), code.eax); + code.add(code.eax, imm); + regs.Write(RT(instr), code.eax); } void JIT::andi(u32 instr) { - if (RT(instr) == 0) - return; - - s64 imm = (u16)instr; + const s64 imm = static_cast(instr); if (regs.IsRegConstant(RS(instr))) { regs.Write(RT(instr), regs.Read(RS(instr)) & imm); - } else { - Util::panic("[JIT]: Implement non constant ANDI!"); + return; } + + regs.Read(RS(instr), code.rax); + code.and_(code.rax, imm); + regs.Write(RT(instr), code.rax); } void JIT::and_(u32 instr) { - if (RD(instr) == 0) - return; - if (regs.IsRegConstant(RS(instr), RT(instr))) { regs.Write(RD(instr), regs.Read(RS(instr)) & regs.Read(RT(instr))); - } else { - Util::panic("[JIT]: Implement non constant AND!"); + return; } + + if (regs.IsRegConstant(RS(instr))) { + const auto rs = regs.Read(RS(instr)); + regs.Read(RT(instr), code.rax); + code.and_(code.rax, rs); + regs.Write(RD(instr), code.rax); + return; + } + + if (regs.IsRegConstant(RT(instr))) { + const auto rt = regs.Read(RT(instr)); + regs.Read(RS(instr), code.rax); + code.and_(code.rax, rt); + regs.Write(RD(instr), code.rax); + return; + } + + regs.Read(RS(instr), code.rax); + regs.Read(RT(instr), code.rdi); + code.and_(code.rdi, code.rax); + regs.Write(RD(instr), code.rdi); } void JIT::SkipSlot() { @@ -154,6 +167,8 @@ void JIT::SkipSlot() { code.mov(REG(qword, nextPC), code.rax); } +void JIT::SkipSlotConstant() { blockPC += 4; } + void JIT::BranchTaken(const s64 offs) { code.mov(code.rax, REG(qword, pc)); code.add(code.rax, offs); @@ -205,7 +220,7 @@ void JIT::branch_likely_constant(const bool cond, const s64 offset) { code.mov(REG(byte, delaySlot), code.al); BranchTaken(offset); } else { - SkipSlot(); + SkipSlotConstant(); } } @@ -245,7 +260,7 @@ void JIT::bltz(const u32 instr) { return; } - code.mov(code.rax, GPR(RS(instr))); + code.mov(code.rax, GPR(RS(instr))); code.cmp(code.rax, 0); branch(offset, l); } @@ -353,7 +368,7 @@ void JIT::beql(const u32 instr) { branch_likely(offset, e); } -void JIT::bne(const u32 instr) { +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))) { @@ -409,7 +424,7 @@ void JIT::bnel(const u32 instr) { branch_likely(offset, ne); } -void JIT::blez(const u32 instr) { +void JIT::blez(const u32 instr) { const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; if (regs.IsRegConstant(RS(instr))) { @@ -462,9 +477,6 @@ void JIT::bgtzl(const u32 instr) { } void JIT::dadd(u32 instr) { - if (RD(instr) == 0) - return; - if (regs.IsRegConstant(RS(instr), RT(instr))) { auto rs = regs.Read(RS(instr)); auto rt = regs.Read(RT(instr)); @@ -1155,7 +1167,7 @@ void JIT::sw(const u32 instr) { code.mov(code.rsi, reinterpret_cast(®s)); code.mov(code.edx, physical); code.mov(code.rcx, regs.Read(RT(instr))); - emitMemberFunctionCall(&Mem::Write, &mem); + emitMemberFunctionCall(&Mem::WriteJIT, &mem); } return; @@ -1180,7 +1192,7 @@ void JIT::sw(const u32 instr) { code.mov(code.rsi, reinterpret_cast(®s)); code.mov(code.edx, physical); code.mov(code.rcx, GPR(RT(instr))); - emitMemberFunctionCall(&Mem::Write, &mem); + emitMemberFunctionCall(&Mem::WriteJIT, &mem); } return; @@ -1200,7 +1212,7 @@ void JIT::sw(const u32 instr) { code.mov(code.rsi, reinterpret_cast(®s)); code.mov(code.edx, physical); code.mov(code.rcx, regs.Read(RT(instr))); - emitMemberFunctionCall(&Mem::Write, &mem); + emitMemberFunctionCall(&Mem::WriteJIT, &mem); return; } @@ -1218,7 +1230,7 @@ void JIT::sw(const u32 instr) { code.mov(code.rsi, reinterpret_cast(®s)); code.mov(code.edx, physical); code.mov(code.rcx, GPR(RT(instr))); - emitMemberFunctionCall(&Mem::Write, &mem); + emitMemberFunctionCall(&Mem::WriteJIT, &mem); } void JIT::srlv(u32 instr) { diff --git a/src/backend/core/registers/Registers.cpp b/src/backend/core/registers/Registers.cpp index 40497ec0..80c01f9b 100644 --- a/src/backend/core/registers/Registers.cpp +++ b/src/backend/core/registers/Registers.cpp @@ -1,8 +1,11 @@ +#include "jit/helpers.hpp" + + #include #include namespace n64 { -Registers::Registers(JIT* jit) : jit(jit), cop0(*this), cop1(*this) { Reset(); } +Registers::Registers(JIT *jit) : jit(jit), cop0(*this), cop1(*this) { Reset(); } void Registers::Reset() { hi = 0; @@ -11,6 +14,7 @@ void Registers::Reset() { prevDelaySlot = false; gpr.fill(0); gprIsConstant.fill(false); + gprIsConstant[0] = true; cop0.Reset(); cop1.Reset(); @@ -37,8 +41,48 @@ u64 Registers::Read(size_t idx) { } template <> -s64 Registers::Read(size_t idx) { - return s64(Read(idx)); +void Registers::Read(size_t idx, Xbyak::Reg reg) { + jit->code.mov(reg.cvt64(), jit->GPR(idx)); +} + +template <> +void Registers::Read(size_t idx, Xbyak::Reg reg) { + jit->code.mov(reg.cvt64(), jit->GPR(idx)); +} + +template <> +void Registers::Read(size_t idx, Xbyak::Reg reg) { + jit->code.mov(reg.cvt32(), jit->GPR(idx)); +} + +template <> +void Registers::Read(size_t idx, Xbyak::Reg reg) { + jit->code.mov(reg.cvt32(), jit->GPR(idx)); +} + +template <> +void Registers::Read(size_t idx, Xbyak::Reg reg) { + jit->code.mov(reg.cvt16(), jit->GPR(idx)); +} + +template <> +void Registers::Read(size_t idx, Xbyak::Reg reg) { + jit->code.mov(reg.cvt16(), jit->GPR(idx)); +} + +template <> +void Registers::Read(size_t idx, Xbyak::Reg reg) { + jit->code.mov(reg.cvt8(), jit->GPR(idx)); +} + +template <> +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 <> @@ -48,7 +92,7 @@ u32 Registers::Read(size_t idx) { template <> s32 Registers::Read(size_t idx) { - return s32(Read(idx)); + return static_cast(Read(idx)); } template <> @@ -58,7 +102,7 @@ u16 Registers::Read(size_t idx) { template <> s16 Registers::Read(size_t idx) { - return s16(Read(idx)); + return static_cast(Read(idx)); } template <> @@ -68,150 +112,321 @@ u8 Registers::Read(size_t idx) { template <> s8 Registers::Read(size_t idx) { - return s8(Read(idx)); + return static_cast(Read(idx)); } template <> -void Registers::Write(size_t idx, bool v) { +void Registers::WriteJIT(size_t idx, bool v) { + jit->code.mov(jit->code.al, v); + jit->code.mov(jit->GPR(idx), jit->code.al); +} + +template <> +void Registers::Write(size_t idx, bool v, bool isConstant) { if (idx == 0) return; - if(jit) { - jit->code.mov(jit->code.rax, v); - jit->code.mov(GPR(idx), jit->code.rax); - jit->code.mov(jit->code.rax, 1); - jit->code.mov(GPR_constant_marker(idx), jit->code.rax); + gprIsConstant[idx] = isConstant; + + if (jit) { + if (isConstant) { + gpr[idx] = v; + return; + } + + WriteJIT(idx, v); return; } gpr[idx] = v; - gprIsConstant[idx] = true; } template <> -void Registers::Write(size_t idx, u64 v) { +void Registers::WriteJIT(size_t idx, u64 v) { + jit->code.mov(jit->code.rax, v); + jit->code.mov(jit->GPR(idx), jit->code.rax); +} + +template <> +void Registers::Write(size_t idx, u64 v, bool isConstant) { if (idx == 0) return; - if(jit) { - jit->code.mov(jit->code.rax, v); - jit->code.mov(GPR(idx), jit->code.rax); - jit->code.mov(jit->code.rax, 1); - jit->code.mov(GPR_constant_marker(idx), jit->code.rax); + gprIsConstant[idx] = isConstant; + + if (jit) { + if (isConstant) { + gpr[idx] = v; + return; + } + + WriteJIT(idx, v); return; } gpr[idx] = v; - gprIsConstant[idx] = true; } template <> -void Registers::Write(size_t idx, s64 v) { +void Registers::Write(size_t idx, s64 v, bool isConstant) { + Write(idx, v, isConstant); +} + +template <> +void Registers::WriteJIT(size_t idx, u32 v) { + jit->code.mov(jit->code.eax, v); + jit->code.mov(jit->GPR(idx), jit->code.eax); +} + +template <> +void Registers::Write(size_t idx, u32 v, bool isConstant) { + if (idx == 0) + return; + + gprIsConstant[idx] = isConstant; + + if (jit) { + if (isConstant) { + gpr[idx] = v; + return; + } + + WriteJIT(idx, v); + return; + } + + gpr[idx] = v; +} + +template <> +void Registers::WriteJIT(size_t idx, s32 v) { + jit->code.mov(jit->code.eax, v); + jit->code.movsxd(jit->code.rax, jit->code.eax); + jit->code.mov(jit->GPR(idx), jit->code.rax); +} + +template <> +void Registers::Write(size_t idx, s32 v, bool isConstant) { + if (idx == 0) + return; + + gprIsConstant[idx] = isConstant; + + if (jit) { + if (isConstant) { + gpr[idx] = v; + return; + } + + WriteJIT(idx, v); + return; + } + + gpr[idx] = v; +} + +template <> +void Registers::WriteJIT(size_t idx, u16 v) { + jit->code.mov(jit->code.ax, v); + jit->code.mov(jit->GPR(idx), jit->code.ax); +} + +template <> +void Registers::Write(size_t idx, u16 v, bool isConstant) { + if (idx == 0) + return; + + gprIsConstant[idx] = isConstant; + + if (jit) { + if (isConstant) { + gpr[idx] = v; + return; + } + + WriteJIT(idx, v); + return; + } + + gpr[idx] = v; +} + +template <> +void Registers::WriteJIT(size_t idx, s16 v) { + jit->code.mov(jit->code.ax, v); + jit->code.movsx(jit->code.rax, jit->code.ax); + jit->code.mov(jit->GPR(idx), jit->code.rax); +} + +template <> +void Registers::Write(size_t idx, s16 v, bool isConstant) { + if (idx == 0) + return; + + gprIsConstant[idx] = isConstant; + + if (jit) { + if (isConstant) { + gpr[idx] = v; + return; + } + + WriteJIT(idx, v); + return; + } + + gpr[idx] = v; +} + +template <> +void Registers::WriteJIT(size_t idx, u8 v) { + jit->code.mov(jit->code.al, v); + jit->code.mov(jit->GPR(idx), jit->code.al); +} + +template <> +void Registers::Write(size_t idx, u8 v, bool isConstant) { + if (idx == 0) + return; + + gprIsConstant[idx] = isConstant; + + if (jit) { + if (isConstant) { + gpr[idx] = v; + return; + } + + WriteJIT(idx, v); + return; + } + + gpr[idx] = v; +} + +template <> +void Registers::WriteJIT(size_t idx, s8 v) { + jit->code.mov(jit->code.al, v); + jit->code.movsx(jit->code.rax, jit->code.al); + jit->code.mov(jit->GPR(idx), jit->code.rax); +} + +template <> +void Registers::Write(size_t idx, s8 v, bool isConstant) { + if (idx == 0) + return; + + gprIsConstant[idx] = isConstant; + + if (jit) { + if (isConstant) { + gpr[idx] = v; + return; + } + + WriteJIT(idx, v); + return; + } + + gpr[idx] = v; +} + +template <> +void Registers::Write(size_t idx, Xbyak::Reg v) { + if (idx == 0) + return; + + gprIsConstant[idx] = false; + + if (!jit) + Util::panic("Did you try to call Registers::Write(size_t, *Xbyak::Reg*) from the interpreter?"); + + jit->code.movsx(v.cvt64(), v.cvt8()); + jit->code.mov(jit->GPR(idx), v); +} + +template <> +void Registers::Write(size_t idx, Xbyak::Reg v) { + if (idx == 0) + return; + + gprIsConstant[idx] = false; + + if (!jit) + Util::panic("Did you try to call Registers::Write(size_t, *Xbyak::Reg*) from the interpreter?"); + + jit->code.mov(jit->GPR(idx), v.cvt8()); +} + +template <> +void Registers::Write(size_t idx, Xbyak::Reg v) { + if (idx == 0) + return; + + gprIsConstant[idx] = false; + + if (!jit) + Util::panic("Did you try to call Registers::Write(size_t, *Xbyak::Reg*) from the interpreter?"); + + jit->code.movsx(v.cvt64(), v.cvt16()); + jit->code.mov(jit->GPR(idx), v.cvt64()); +} + +template <> +void Registers::Write(size_t idx, Xbyak::Reg v) { + if (idx == 0) + return; + + gprIsConstant[idx] = false; + + if (!jit) + Util::panic("Did you try to call Registers::Write(size_t, *Xbyak::Reg*) from the interpreter?"); + + jit->code.mov(jit->GPR(idx), v.cvt16()); +} + +template <> +void Registers::Write(size_t idx, Xbyak::Reg v) { + if (idx == 0) + return; + + gprIsConstant[idx] = false; + + if (!jit) + Util::panic("Did you try to call Registers::Write(size_t, *Xbyak::Reg*) from the interpreter?"); + + jit->code.movsxd(v.cvt64(), v.cvt32()); + jit->code.mov(jit->GPR(idx), v.cvt64()); +} + +template <> +void Registers::Write(size_t idx, Xbyak::Reg v) { + if (idx == 0) + return; + + gprIsConstant[idx] = false; + + if (!jit) + Util::panic("Did you try to call Registers::Write(size_t, *Xbyak::Reg*) from the interpreter?"); + + jit->code.mov(jit->GPR(idx), v.cvt32()); +} + +template <> +void Registers::Write(size_t idx, Xbyak::Reg v) { + if (idx == 0) + return; + + gprIsConstant[idx] = false; + + if (!jit) + Util::panic("Did you try to call Registers::Write(size_t, *Xbyak::Reg*) from the interpreter?"); + + jit->code.mov(jit->GPR(idx), v.cvt64()); +} + +template <> +void Registers::Write(size_t idx, Xbyak::Reg v) { Write(idx, v); } - -template <> -void Registers::Write(size_t idx, u32 v) { - if (idx == 0) - return; - - if(jit) { - jit->code.mov(jit->code.rax, v); - jit->code.mov(GPR(idx), jit->code.rax); - jit->code.mov(jit->code.rax, 1); - jit->code.mov(GPR_constant_marker(idx), jit->code.rax); - return; - } - - gpr[idx] = (u32)v; - gprIsConstant[idx] = true; -} - -template <> -void Registers::Write(size_t idx, s32 v) { - if (idx == 0) - return; - - if(jit) { - jit->code.mov(jit->code.eax, v); - jit->code.movsxd(jit->code.rax, jit->code.eax); - jit->code.mov(GPR(idx), jit->code.rax); - jit->code.mov(jit->code.rax, 1); - jit->code.mov(GPR_constant_marker(idx), jit->code.rax); - return; - } - - gpr[idx] = v; - gprIsConstant[idx] = true; -} - -template <> -void Registers::Write(size_t idx, u16 v) { - if (idx == 0) - return; - - if(jit) { - jit->code.mov(jit->code.rax, v); - jit->code.mov(GPR(idx), jit->code.rax); - jit->code.mov(jit->code.rax, 1); - jit->code.mov(GPR_constant_marker(idx), jit->code.rax); - return; - } - - gpr[idx] = (u16)v; - gprIsConstant[idx] = true; -} - -template <> -void Registers::Write(size_t idx, s16 v) { - if (idx == 0) - return; - - if(jit) { - jit->code.mov(jit->code.ax, v); - jit->code.movsx(jit->code.rax, jit->code.ax); - jit->code.mov(GPR(idx), jit->code.rax); - jit->code.mov(jit->code.rax, 1); - jit->code.mov(GPR_constant_marker(idx), jit->code.rax); - return; - } - - gpr[idx] = v; - gprIsConstant[idx] = true; -} - -template <> -void Registers::Write(size_t idx, u8 v) { - if (idx == 0) - return; - - if(jit) { - jit->code.mov(jit->code.rax, v); - jit->code.mov(GPR(idx), jit->code.rax); - jit->code.mov(jit->code.rax, 1); - jit->code.mov(GPR_constant_marker(idx), jit->code.rax); - return; - } - - gpr[idx] = (u8)v; - gprIsConstant[idx] = true; -} - -template <> -void Registers::Write(size_t idx, s8 v) { - if (idx == 0) - return; - - if(jit) { - jit->code.mov(jit->code.al, v); - jit->code.movsx(jit->code.rax, jit->code.al); - jit->code.mov(GPR(idx), jit->code.rax); - jit->code.mov(jit->code.rax, 1); - jit->code.mov(GPR_constant_marker(idx), jit->code.rax); - return; - } - - gpr[idx] = v; - gprIsConstant[idx] = true; -} } // namespace n64 diff --git a/src/backend/core/registers/Registers.hpp b/src/backend/core/registers/Registers.hpp index 48402bae..964c33ad 100644 --- a/src/backend/core/registers/Registers.hpp +++ b/src/backend/core/registers/Registers.hpp @@ -1,11 +1,12 @@ #pragma once #include +#include #include namespace n64 { struct JIT; struct Registers { - Registers(JIT* jit = nullptr); + Registers(JIT *jit = nullptr); void Reset(); void SetPC64(s64); void SetPC32(s32); @@ -20,7 +21,7 @@ struct Registers { return IsRegConstant(first) && IsRegConstant(second); } - JIT* jit = nullptr; + JIT *jit = nullptr; std::array gprIsConstant{}; bool loIsConstant = false, hiIsConstant = false; @@ -28,7 +29,7 @@ struct Registers { Cop1 cop1; s64 oldPC{}, pc{}, nextPC{}; s64 hi{}, lo{}; - bool prevDelaySlot{}, delaySlot{}; + bool prevDelaySlot{}, delaySlot{}, block_delaySlot{}; u32 steps = 0; u32 extraCycles = 0; @@ -43,9 +44,14 @@ struct Registers { template T Read(size_t); template - void Write(size_t, T); + void Read(size_t, Xbyak::Reg); + template + void Write(size_t, T, bool = false); + template + void Write(size_t, Xbyak::Reg); std::array gpr{}; + private: template void WriteJIT(size_t, T);