From b8d691efb87f7c142a93c6577a8fd7cfd7933e1d Mon Sep 17 00:00:00 2001 From: irisz64 Date: Fri, 29 Aug 2025 10:57:01 +0200 Subject: [PATCH] This rewrite is working (tested with Super Mario 64) --- src/backend/Core.hpp | 15 +- src/backend/core/CpuDefinitions.hpp | 6 - src/backend/core/JIT.hpp | 210 ++--- .../core/interpreter/cop0instructions.cpp | 16 +- .../core/interpreter/cop1instructions.cpp | 474 +++++----- src/backend/core/interpreter/decode.cpp | 36 +- src/backend/core/interpreter/instructions.cpp | 488 +++++----- src/backend/core/jit/decode.cpp | 266 +++--- src/backend/core/jit/helpers.hpp | 78 +- src/backend/core/jit/instructions.cpp | 850 +++++++++--------- src/backend/core/registers/Cop0.cpp | 2 +- src/backend/core/registers/Cop0.hpp | 8 +- src/backend/core/registers/Cop1.cpp | 27 - src/backend/core/registers/Cop1.hpp | 8 +- src/utils/Instruction.hpp | 11 +- 15 files changed, 1240 insertions(+), 1255 deletions(-) delete mode 100644 src/backend/core/CpuDefinitions.hpp diff --git a/src/backend/Core.hpp b/src/backend/Core.hpp index 2588ba82..38e4cb48 100644 --- a/src/backend/Core.hpp +++ b/src/backend/Core.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace n64 { struct Core { @@ -28,20 +29,6 @@ struct Core { return *GetInstance().mem; } - static Interpreter& GetInterpreter() { - if(GetInstance().cpuType == Interpreted) - return *dynamic_cast(GetInstance().cpu.get()); - - panic("Tried to get interpreter when other cpu type is used."); - } - - static JIT& GetDynamicRecompiler() { - if(GetInstance().cpuType == DynamicRecompiler) - return *dynamic_cast(GetInstance().cpu.get()); - - panic("Tried to get interpreter when other cpu type is used."); - } - int StepCPU(); void StepRSP(int cpuCycles); void Stop(); diff --git a/src/backend/core/CpuDefinitions.hpp b/src/backend/core/CpuDefinitions.hpp deleted file mode 100644 index 59777073..00000000 --- a/src/backend/core/CpuDefinitions.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once -#include - -namespace n64 { - -} // namespace n64 diff --git a/src/backend/core/JIT.hpp b/src/backend/core/JIT.hpp index 91240f58..9776c2f5 100644 --- a/src/backend/core/JIT.hpp +++ b/src/backend/core/JIT.hpp @@ -109,163 +109,163 @@ private: void CheckCompareInterrupt(); u32 FetchInstruction(); - void Emit(u32); - void special(u32); - void regimm(u32); - void add(u32); - void addu(u32); - void addi(u32); - void addiu(u32); - void andi(u32); - void and_(u32); + void Emit(const Instruction); + void special(const Instruction); + void regimm(const Instruction); + void add(const Instruction); + void addu(const Instruction); + void addi(const Instruction); + void addiu(const Instruction); + void andi(const Instruction); + void and_(const Instruction); 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); - void bgezl(u32); - void bltzal(u32); - void bgezal(u32); - void bltzall(u32); - void bgezall(u32); - void beq(u32); - void beql(u32); - void bne(u32); - void bnel(u32); - void blez(u32); - void blezl(u32); - void bgtz(u32); - void bgtzl(u32); - void bfc1(u32 instr); - void blfc1(u32 instr); - void bfc0(u32 instr); - void blfc0(u32 instr); - void dadd(u32); - void daddu(u32); - void daddi(u32); - void daddiu(u32); - void ddiv(u32); - void ddivu(u32); - void div(u32); - void divu(u32); - void dmult(u32); - void dmultu(u32); - void dsll(u32); - void dsllv(u32); - void dsll32(u32); - void dsra(u32); - void dsrav(u32); - void dsra32(u32); - void dsrl(u32); - void dsrlv(u32); - void dsrl32(u32); - void dsub(u32); - void dsubu(u32); - void j(u32); - void jr(u32); - void jal(u32); - void jalr(u32); - void lui(u32); - void lbu(u32); - void lb(u32); - void ld(u32); - void ldc1(u32); - void ldl(u32); - void ldr(u32); - void lh(u32); - void lhu(u32); - void ll(u32); - void lld(u32); - void lw(u32); - void lwc1(u32); - void lwl(u32); - void lwu(u32); - void lwr(u32); - void mfhi(u32); - void mflo(u32); - void mult(u32); - void multu(u32); - void mthi(u32); - void mtlo(u32); - void nor(u32); - void sb(u32) { + void bltz(const Instruction); + void bgez(const Instruction); + void bltzl(const Instruction); + void bgezl(const Instruction); + void bltzal(const Instruction); + void bgezal(const Instruction); + void bltzall(const Instruction); + void bgezall(const Instruction); + void beq(const Instruction); + void beql(const Instruction); + void bne(const Instruction); + void bnel(const Instruction); + void blez(const Instruction); + void blezl(const Instruction); + void bgtz(const Instruction); + void bgtzl(const Instruction); + void bfc1(const Instruction); + void blfc1(const Instruction); + void bfc0(const Instruction); + void blfc0(const Instruction); + void dadd(const Instruction); + void daddu(const Instruction); + void daddi(const Instruction); + void daddiu(const Instruction); + void ddiv(const Instruction); + void ddivu(const Instruction); + void div(const Instruction); + void divu(const Instruction); + void dmult(const Instruction); + void dmultu(const Instruction); + void dsll(const Instruction); + void dsllv(const Instruction); + void dsll32(const Instruction); + void dsra(const Instruction); + void dsrav(const Instruction); + void dsra32(const Instruction); + void dsrl(const Instruction); + void dsrlv(const Instruction); + void dsrl32(const Instruction); + void dsub(const Instruction); + void dsubu(const Instruction); + void j(const Instruction); + void jr(const Instruction); + void jal(const Instruction); + void jalr(const Instruction); + void lui(const Instruction); + void lbu(const Instruction); + void lb(const Instruction); + void ld(const Instruction); + void ldc1(const Instruction); + void ldl(const Instruction); + void ldr(const Instruction); + void lh(const Instruction); + void lhu(const Instruction); + void ll(const Instruction); + void lld(const Instruction); + void lw(const Instruction); + void lwc1(const Instruction); + void lwl(const Instruction); + void lwu(const Instruction); + void lwr(const Instruction); + void mfhi(const Instruction); + void mflo(const Instruction); + void mult(const Instruction); + void multu(const Instruction); + void mthi(const Instruction); + void mtlo(const Instruction); + void nor(const Instruction); + void sb(const Instruction) { Util::Error::GetInstance().Throw( {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION}, blockPC, {}, "[JIT]: Unhandled 'sb'!"); } - void sc(u32) { + void sc(const Instruction) { Util::Error::GetInstance().Throw( {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION}, blockPC, {}, "[JIT]: Unhandled 'sc'!"); } - void scd(u32) { + void scd(const Instruction) { Util::Error::GetInstance().Throw( {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION}, blockPC, {}, "[JIT]: Unhandled 'scd'!"); } - void sd(u32) { + void sd(const Instruction) { Util::Error::GetInstance().Throw( {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION}, blockPC, {}, "[JIT]: Unhandled 'sd'!"); } - void sdc1(u32) { + void sdc1(const Instruction) { Util::Error::GetInstance().Throw( {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION}, blockPC, {}, "[JIT]: Unhandled 'sdc1'!"); } - void sdl(u32) { + void sdl(const Instruction) { Util::Error::GetInstance().Throw( {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION}, blockPC, {}, "[JIT]: Unhandled 'sdl'!"); } - void sdr(u32) { + void sdr(const Instruction) { Util::Error::GetInstance().Throw( {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION}, blockPC, {}, "[JIT]: Unhandled 'sdr'!"); } - void sh(u32) { + void sh(const Instruction) { Util::Error::GetInstance().Throw( {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION}, blockPC, {}, "[JIT]: Unhandled 'sh'!"); } - void sw(u32); - void swl(u32) { + void sw(const Instruction); + void swl(const Instruction) { Util::Error::GetInstance().Throw( {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION}, blockPC, {}, "[JIT]: Unhandled 'swl'!"); } - void swr(u32) { + void swr(const Instruction) { Util::Error::GetInstance().Throw( {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION}, blockPC, {}, "[JIT]: Unhandled 'swr'!"); } - void slti(u32); - void sltiu(u32); - void slt(u32); - void sltu(u32); - void sll(u32); - void sllv(u32); - void sub(u32); - void subu(u32); - void swc1(u32) { + void slti(const Instruction); + void sltiu(const Instruction); + void slt(const Instruction); + void sltu(const Instruction); + void sll(const Instruction); + void sllv(const Instruction); + void sub(const Instruction); + void subu(const Instruction); + void swc1(const Instruction) { Util::Error::GetInstance().Throw( {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::JIT_BRANCH_INSIDE_DELAY_SLOT}, blockPC, {}, "[JIT]: Unhandled case of branch from delay slot!"); } - void sra(u32); - void srav(u32); - void srl(u32); - void srlv(u32); + void sra(const Instruction); + void srav(const Instruction); + void srl(const Instruction); + void srlv(const Instruction); void trap(bool) { Util::Error::GetInstance().Throw( {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::JIT_BRANCH_INSIDE_DELAY_SLOT}, blockPC, {}, "[JIT]: Unhandled case of branch from delay slot!"); } - void or_(u32); - void ori(u32); - void xor_(u32); - void xori(u32); + void or_(const Instruction); + void ori(const Instruction); + void xor_(const Instruction); + void xori(const Instruction); }; #endif } // namespace n64 diff --git a/src/backend/core/interpreter/cop0instructions.cpp b/src/backend/core/interpreter/cop0instructions.cpp index b6246c51..1a6ef6e7 100644 --- a/src/backend/core/interpreter/cop0instructions.cpp +++ b/src/backend/core/interpreter/cop0instructions.cpp @@ -3,24 +3,24 @@ #include namespace n64 { -void Cop0::mtc0(const u32 instr) { +void Cop0::mtc0(const Instruction instr) { Registers& regs = Core::GetRegs(); - SetReg32(RD(instr), regs.Read(RT(instr))); + SetReg32(instr.rd(), regs.Read(instr.rt())); } -void Cop0::dmtc0(const u32 instr) { +void Cop0::dmtc0(const Instruction instr) { Registers& regs = Core::GetRegs(); - SetReg64(RD(instr), regs.Read(RT(instr))); + SetReg64(instr.rd(), regs.Read(instr.rt())); } -void Cop0::mfc0(const u32 instr) { +void Cop0::mfc0(const Instruction instr) { Registers& regs = Core::GetRegs(); - regs.Write(RT(instr), s32(GetReg32(RD(instr)))); + regs.Write(instr.rt(), s32(GetReg32(instr.rd()))); } -void Cop0::dmfc0(const u32 instr) const { +void Cop0::dmfc0(const Instruction instr) const { Registers& regs = Core::GetRegs(); - regs.Write(RT(instr), s64(GetReg64(RD(instr)))); + regs.Write(instr.rt(), s64(GetReg64(instr.rd()))); } void Cop0::eret() { diff --git a/src/backend/core/interpreter/cop1instructions.cpp b/src/backend/core/interpreter/cop1instructions.cpp index 9e6fdec5..1f7dff88 100644 --- a/src/backend/core/interpreter/cop1instructions.cpp +++ b/src/backend/core/interpreter/cop1instructions.cpp @@ -444,109 +444,109 @@ bool Cop1::SetCauseInvalid() { #define CHECK_FPE_CONV(type, res, operation) CHECK_FPE_IMPL(type, res, operation, true) #define CHECK_FPE_CONV_CONST(type, res, operation) CHECK_FPE_IMPL_CONST(type, res, operation, true) -void Cop1::absd(const u32 instr) { +void Cop1::absd(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckArg(fs)) return; auto fd = std::abs(fs); if (!CheckResult(fd)) return; - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::abss(const u32 instr) { +void Cop1::abss(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckArg(fs)) return; auto fd = std::abs(fs); if (!CheckResult(fd)) return; - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::adds(const u32 instr) { +void Cop1::adds(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); - const auto ft = FGR_T(regs.cop0.status, FT(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); + const auto ft = FGR_T(regs.cop0.status, instr.ft()); if (!CheckArgs(fs, ft)) return; CHECK_FPE(float, fd, fs + ft) if (!CheckResult(fd)) return; - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::addd(const u32 instr) { +void Cop1::addd(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); - const auto ft = FGR_T(regs.cop0.status, FT(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); + const auto ft = FGR_T(regs.cop0.status, instr.ft()); if (!CheckArgs(fs, ft)) return; CHECK_FPE(double, fd, fs + ft) if (!CheckResult(fd)) return; - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::ceills(const u32 instr) { +void Cop1::ceills(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckCVTArg(fs)) return; CHECK_FPE_CONST(s64, fd, Util::roundCeil(fs)); - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::ceilld(const u32 instr) { +void Cop1::ceilld(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckCVTArg(fs)) return; CHECK_FPE_CONST(s64, fd, Util::roundCeil(fs)) - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::ceilws(const u32 instr) { +void Cop1::ceilws(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckCVTArg(fs)) return; CHECK_FPE_CONV_CONST(s32, fd, Util::roundCeil(fs)) - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::ceilwd(const u32 instr) { +void Cop1::ceilwd(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckCVTArg(fs)) return; CHECK_FPE_CONV_CONST(s32, fd, Util::roundCeil(fs)) - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::cfc1(const u32 instr) { +void Cop1::cfc1(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const u8 fd = RD(instr); + const u8 fd = instr.rd(); s32 val = 0; switch (fd) { case 0: @@ -558,15 +558,15 @@ void Cop1::cfc1(const u32 instr) { default: panic("Undefined CFC1 with rd != 0 or 31"); } - regs.Write(RT(instr), val); + regs.Write(instr.rt(), val); } -void Cop1::ctc1(const u32 instr) { +void Cop1::ctc1(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const u8 fs = RD(instr); - const u32 val = regs.Read(RT(instr)); + const u8 fs = instr.rd(); + const u32 val = regs.Read(instr.rt()); switch (fs) { case 0: break; @@ -609,48 +609,48 @@ void Cop1::ctc1(const u32 instr) { } } -void Cop1::cvtds(const u32 instr) { +void Cop1::cvtds(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckArg(fs)) return; CHECK_FPE(double, fd, fs) if (!CheckResult(fd)) return; - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::cvtsd(const u32 instr) { +void Cop1::cvtsd(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckArg(fs)) return; CHECK_FPE(float, fd, static_cast(fs)) if (!CheckResult(fd)) return; - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::cvtsw(const u32 instr) { +void Cop1::cvtsw(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); CHECK_FPE(float, fd, fs) if (!CheckResult(fd)) return; - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::cvtsl(const u32 instr) { +void Cop1::cvtsl(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (fs >= 0x0080000000000000 || fs < static_cast(0xff80000000000000)) { SetCauseUnimplemented(); regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); @@ -659,59 +659,59 @@ void Cop1::cvtsl(const u32 instr) { CHECK_FPE(float, fd, fs) if (!CheckResult(fd)) return; - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::cvtwd(const u32 instr) { +void Cop1::cvtwd(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckCVTArg(fs)) return; CHECK_FPE_CONV_CONST(s32, fd, Util::roundCurrent(fs)) - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::cvtws(const u32 instr) { +void Cop1::cvtws(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckCVTArg(fs)) return; CHECK_FPE_CONV_CONST(s32, fd, Util::roundCurrent(fs)) - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::cvtls(const u32 instr) { +void Cop1::cvtls(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckCVTArg(fs)) return; CHECK_FPE_CONST(s64, fd, Util::roundCurrent(fs)) - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::cvtdw(const u32 instr) { +void Cop1::cvtdw(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); CHECK_FPE(double, fd, fs) if (!CheckResult(fd)) return; - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::cvtdl(const u32 instr) { +void Cop1::cvtdl(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (fs >= 0x0080000000000000 || fs < static_cast(0xff80000000000000)) { SetCauseUnimplemented(); @@ -721,18 +721,18 @@ void Cop1::cvtdl(const u32 instr) { CHECK_FPE(double, fd, fs) if (!CheckResult(fd)) return; - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::cvtld(const u32 instr) { +void Cop1::cvtld(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckCVTArg(fs)) return; CHECK_FPE_CONST(s64, fd, Util::roundCurrent(fs)) - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } template @@ -758,377 +758,377 @@ bool Cop1::XORDERED(const T fs, const T ft) { #define UNORDERED(type, cf) XORDERED template -void Cop1::cf(const u32 instr) { +void Cop1::cf(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const T fs = FGR_S(regs.cop0.status, FS(instr)); - if (const T ft = FGR_T(regs.cop0.status, FT(instr)); !UNORDERED(T, 0)(fs, ft)) + const T fs = FGR_S(regs.cop0.status, instr.fs()); + if (const T ft = FGR_T(regs.cop0.status, instr.ft()); !UNORDERED(T, 0)(fs, ft)) return; fcr31.compare = 0; } template -void Cop1::cun(const u32 instr) { +void Cop1::cun(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const T fs = FGR_S(regs.cop0.status, FS(instr)); - if (const T ft = FGR_T(regs.cop0.status, FT(instr)); !UNORDERED(T, 1)(fs, ft)) + const T fs = FGR_S(regs.cop0.status, instr.fs()); + if (const T ft = FGR_T(regs.cop0.status, instr.ft()); !UNORDERED(T, 1)(fs, ft)) return; fcr31.compare = 0; } template -void Cop1::ceq(const u32 instr) { +void Cop1::ceq(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const T fs = FGR_S(regs.cop0.status, FS(instr)); - const T ft = FGR_T(regs.cop0.status, FT(instr)); + const T fs = FGR_S(regs.cop0.status, instr.fs()); + const T ft = FGR_T(regs.cop0.status, instr.ft()); if (!UNORDERED(T, 0)(fs, ft)) return; fcr31.compare = fs == ft; } template -void Cop1::cueq(const u32 instr) { +void Cop1::cueq(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const T fs = FGR_S(regs.cop0.status, FS(instr)); - const T ft = FGR_T(regs.cop0.status, FT(instr)); + const T fs = FGR_S(regs.cop0.status, instr.fs()); + const T ft = FGR_T(regs.cop0.status, instr.ft()); if (!UNORDERED(T, 1)(fs, ft)) return; fcr31.compare = fs == ft; } template -void Cop1::colt(const u32 instr) { +void Cop1::colt(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const T fs = FGR_S(regs.cop0.status, FS(instr)); - const T ft = FGR_T(regs.cop0.status, FT(instr)); + const T fs = FGR_S(regs.cop0.status, instr.fs()); + const T ft = FGR_T(regs.cop0.status, instr.ft()); if (!UNORDERED(T, 0)(fs, ft)) return; fcr31.compare = fs < ft; } template -void Cop1::cult(const u32 instr) { +void Cop1::cult(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const T fs = FGR_S(regs.cop0.status, FS(instr)); - const T ft = FGR_T(regs.cop0.status, FT(instr)); + const T fs = FGR_S(regs.cop0.status, instr.fs()); + const T ft = FGR_T(regs.cop0.status, instr.ft()); if (!UNORDERED(T, 1)(fs, ft)) return; fcr31.compare = fs < ft; } template -void Cop1::cole(const u32 instr) { +void Cop1::cole(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const T fs = FGR_S(regs.cop0.status, FS(instr)); - const T ft = FGR_T(regs.cop0.status, FT(instr)); + const T fs = FGR_S(regs.cop0.status, instr.fs()); + const T ft = FGR_T(regs.cop0.status, instr.ft()); if (!UNORDERED(T, 0)(fs, ft)) return; fcr31.compare = fs <= ft; } template -void Cop1::cule(const u32 instr) { +void Cop1::cule(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const T fs = FGR_S(regs.cop0.status, FS(instr)); - const T ft = FGR_T(regs.cop0.status, FT(instr)); + const T fs = FGR_S(regs.cop0.status, instr.fs()); + const T ft = FGR_T(regs.cop0.status, instr.ft()); if (!UNORDERED(T, 1)(fs, ft)) return; fcr31.compare = fs <= ft; } template -void Cop1::csf(const u32 instr) { +void Cop1::csf(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const T fs = FGR_S(regs.cop0.status, FS(instr)); - if (const T ft = FGR_T(regs.cop0.status, FT(instr)); !ORDERED(T, 0)(fs, ft)) + const T fs = FGR_S(regs.cop0.status, instr.fs()); + if (const T ft = FGR_T(regs.cop0.status, instr.ft()); !ORDERED(T, 0)(fs, ft)) return; fcr31.compare = 0; } template -void Cop1::cngle(const u32 instr) { +void Cop1::cngle(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const T fs = FGR_S(regs.cop0.status, FS(instr)); - if (const T ft = FGR_T(regs.cop0.status, FT(instr)); !ORDERED(T, 1)(fs, ft)) + const T fs = FGR_S(regs.cop0.status, instr.fs()); + if (const T ft = FGR_T(regs.cop0.status, instr.ft()); !ORDERED(T, 1)(fs, ft)) return; fcr31.compare = 0; } template -void Cop1::cseq(const u32 instr) { +void Cop1::cseq(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const T fs = FGR_S(regs.cop0.status, FS(instr)); - const T ft = FGR_T(regs.cop0.status, FT(instr)); + const T fs = FGR_S(regs.cop0.status, instr.fs()); + const T ft = FGR_T(regs.cop0.status, instr.ft()); if (!ORDERED(T, 0)(fs, ft)) return; fcr31.compare = fs == ft; } template -void Cop1::cngl(const u32 instr) { +void Cop1::cngl(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const T fs = FGR_S(regs.cop0.status, FS(instr)); - const T ft = FGR_T(regs.cop0.status, FT(instr)); + const T fs = FGR_S(regs.cop0.status, instr.fs()); + const T ft = FGR_T(regs.cop0.status, instr.ft()); if (!ORDERED(T, 1)(fs, ft)) return; fcr31.compare = fs == ft; } template -void Cop1::clt(const u32 instr) { +void Cop1::clt(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const T fs = FGR_S(regs.cop0.status, FS(instr)); - const T ft = FGR_T(regs.cop0.status, FT(instr)); + const T fs = FGR_S(regs.cop0.status, instr.fs()); + const T ft = FGR_T(regs.cop0.status, instr.ft()); if (!ORDERED(T, 0)(fs, ft)) return; fcr31.compare = fs < ft; } template -void Cop1::cnge(const u32 instr) { +void Cop1::cnge(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const T fs = FGR_S(regs.cop0.status, FS(instr)); - const T ft = FGR_T(regs.cop0.status, FT(instr)); + const T fs = FGR_S(regs.cop0.status, instr.fs()); + const T ft = FGR_T(regs.cop0.status, instr.ft()); if (!ORDERED(T, 1)(fs, ft)) return; fcr31.compare = fs < ft; } template -void Cop1::cle(const u32 instr) { +void Cop1::cle(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const T fs = FGR_S(regs.cop0.status, FS(instr)); - const T ft = FGR_T(regs.cop0.status, FT(instr)); + const T fs = FGR_S(regs.cop0.status, instr.fs()); + const T ft = FGR_T(regs.cop0.status, instr.ft()); if (!ORDERED(T, 0)(fs, ft)) return; fcr31.compare = fs <= ft; } template -void Cop1::cngt(const u32 instr) { +void Cop1::cngt(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const T fs = FGR_S(regs.cop0.status, FS(instr)); - const T ft = FGR_T(regs.cop0.status, FT(instr)); + const T fs = FGR_S(regs.cop0.status, instr.fs()); + const T ft = FGR_T(regs.cop0.status, instr.ft()); if (!ORDERED(T, 1)(fs, ft)) return; fcr31.compare = fs <= ft; } -template void Cop1::cf(u32 instr); -template void Cop1::cun(u32 instr); -template void Cop1::ceq(u32 instr); -template void Cop1::cueq(u32 instr); -template void Cop1::colt(u32 instr); -template void Cop1::cult(u32 instr); -template void Cop1::cole(u32 instr); -template void Cop1::cule(u32 instr); -template void Cop1::csf(u32 instr); -template void Cop1::cngle(u32 instr); -template void Cop1::cseq(u32 instr); -template void Cop1::cngl(u32 instr); -template void Cop1::clt(u32 instr); -template void Cop1::cnge(u32 instr); -template void Cop1::cle(u32 instr); -template void Cop1::cngt(u32 instr); -template void Cop1::cf(u32 instr); -template void Cop1::cun(u32 instr); -template void Cop1::ceq(u32 instr); -template void Cop1::cueq(u32 instr); -template void Cop1::colt(u32 instr); -template void Cop1::cult(u32 instr); -template void Cop1::cole(u32 instr); -template void Cop1::cule(u32 instr); -template void Cop1::csf(u32 instr); -template void Cop1::cngle(u32 instr); -template void Cop1::cseq(u32 instr); -template void Cop1::cngl(u32 instr); -template void Cop1::clt(u32 instr); -template void Cop1::cnge(u32 instr); -template void Cop1::cle(u32 instr); -template void Cop1::cngt(u32 instr); +template void Cop1::cf(Instruction instr); +template void Cop1::cun(Instruction instr); +template void Cop1::ceq(Instruction instr); +template void Cop1::cueq(Instruction instr); +template void Cop1::colt(Instruction instr); +template void Cop1::cult(Instruction instr); +template void Cop1::cole(Instruction instr); +template void Cop1::cule(Instruction instr); +template void Cop1::csf(Instruction instr); +template void Cop1::cngle(Instruction instr); +template void Cop1::cseq(Instruction instr); +template void Cop1::cngl(Instruction instr); +template void Cop1::clt(Instruction instr); +template void Cop1::cnge(Instruction instr); +template void Cop1::cle(Instruction instr); +template void Cop1::cngt(Instruction instr); +template void Cop1::cf(Instruction instr); +template void Cop1::cun(Instruction instr); +template void Cop1::ceq(Instruction instr); +template void Cop1::cueq(Instruction instr); +template void Cop1::colt(Instruction instr); +template void Cop1::cult(Instruction instr); +template void Cop1::cole(Instruction instr); +template void Cop1::cule(Instruction instr); +template void Cop1::csf(Instruction instr); +template void Cop1::cngle(Instruction instr); +template void Cop1::cseq(Instruction instr); +template void Cop1::cngl(Instruction instr); +template void Cop1::clt(Instruction instr); +template void Cop1::cnge(Instruction instr); +template void Cop1::cle(Instruction instr); +template void Cop1::cngt(Instruction instr); -void Cop1::divs(const u32 instr) { +void Cop1::divs(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); - const auto ft = FGR_T(regs.cop0.status, FT(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); + const auto ft = FGR_T(regs.cop0.status, instr.ft()); if (!CheckArgs(fs, ft)) return; CHECK_FPE(float, fd, fs / ft) if (!CheckResult(fd)) return; - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::divd(const u32 instr) { +void Cop1::divd(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); - const auto ft = FGR_T(regs.cop0.status, FT(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); + const auto ft = FGR_T(regs.cop0.status, instr.ft()); if (!CheckArgs(fs, ft)) return; CHECK_FPE(double, fd, fs / ft) if (!CheckResult(fd)) return; - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::muls(const u32 instr) { +void Cop1::muls(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); - const auto ft = FGR_T(regs.cop0.status, FT(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); + const auto ft = FGR_T(regs.cop0.status, instr.ft()); if (!CheckArgs(fs, ft)) return; CHECK_FPE(float, fd, fs *ft) if (!CheckResult(fd)) return; - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::muld(const u32 instr) { +void Cop1::muld(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); - const auto ft = FGR_T(regs.cop0.status, FT(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); + const auto ft = FGR_T(regs.cop0.status, instr.ft()); if (!CheckArgs(fs, ft)) return; CHECK_FPE(double, fd, fs *ft) if (!CheckResult(fd)) return; - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::subs(const u32 instr) { +void Cop1::subs(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); - const auto ft = FGR_T(regs.cop0.status, FT(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); + const auto ft = FGR_T(regs.cop0.status, instr.ft()); if (!CheckArgs(fs, ft)) return; CHECK_FPE(float, fd, fs - ft) if (!CheckResult(fd)) return; - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::subd(const u32 instr) { +void Cop1::subd(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); - const auto ft = FGR_T(regs.cop0.status, FT(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); + const auto ft = FGR_T(regs.cop0.status, instr.ft()); if (!CheckArgs(fs, ft)) return; CHECK_FPE(double, fd, fs - ft) if (!CheckResult(fd)) return; - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::movs(const u32 instr) { movd(instr); } +void Cop1::movs(const Instruction instr) { movd(instr); } -void Cop1::movd(const u32 instr) { +void Cop1::movd(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - FGR_D(regs.cop0.status, FD(instr)) = FGR_S(regs.cop0.status, FS(instr)); + FGR_D(regs.cop0.status, instr.fd()) = FGR_S(regs.cop0.status, instr.fs()); } -void Cop1::negs(const u32 instr) { +void Cop1::negs(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckArg(fs)) return; CHECK_FPE(float, fd, -fs) if (!CheckResult(fd)) return; - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::negd(const u32 instr) { +void Cop1::negd(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckArg(fs)) return; CHECK_FPE(double, fd, -fs) if (!CheckResult(fd)) return; - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::sqrts(const u32 instr) { +void Cop1::sqrts(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckArg(fs)) return; CHECK_FPE(float, fd, sqrtf(fs)) if (!CheckResult(fd)) return; - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::sqrtd(const u32 instr) { +void Cop1::sqrtd(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckArg(fs)) return; CHECK_FPE(double, fd, sqrt(fs)) if (!CheckResult(fd)) return; - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::roundls(const u32 instr) { +void Cop1::roundls(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckCVTArg(fs)) return; CHECK_FPE_CONST(s64, fd, Util::roundNearest(fs)) @@ -1136,14 +1136,14 @@ void Cop1::roundls(const u32 instr) { regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return; } - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::roundld(const u32 instr) { +void Cop1::roundld(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckCVTArg(fs)) return; CHECK_FPE_CONST(s64, fd, Util::roundNearest(fs)) @@ -1151,14 +1151,14 @@ void Cop1::roundld(const u32 instr) { regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return; } - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::roundws(const u32 instr) { +void Cop1::roundws(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckCVTArg(fs)) return; CHECK_FPE_CONV_CONST(s32, fd, Util::roundNearest(fs)) @@ -1166,14 +1166,14 @@ void Cop1::roundws(const u32 instr) { regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return; } - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::roundwd(const u32 instr) { +void Cop1::roundwd(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckCVTArg(fs)) return; CHECK_FPE_CONV_CONST(s32, fd, Util::roundNearest(fs)) @@ -1181,58 +1181,58 @@ void Cop1::roundwd(const u32 instr) { regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return; } - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::floorls(const u32 instr) { +void Cop1::floorls(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckCVTArg(fs)) return; CHECK_FPE_CONST(s64, fd, Util::roundFloor(fs)) - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::floorld(const u32 instr) { +void Cop1::floorld(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckCVTArg(fs)) return; CHECK_FPE_CONST(s64, fd, Util::roundFloor(fs)) - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::floorws(const u32 instr) { +void Cop1::floorws(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckCVTArg(fs)) return; CHECK_FPE_CONV_CONST(s32, fd, Util::roundFloor(fs)) - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::floorwd(const u32 instr) { +void Cop1::floorwd(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckCVTArg(fs)) return; CHECK_FPE_CONV_CONST(s32, fd, Util::roundFloor(fs)) - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::truncws(const u32 instr) { +void Cop1::truncws(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckCVTArg(fs)) return; CHECK_FPE_CONV_CONST(s32, fd, Util::roundTrunc(fs)) @@ -1240,14 +1240,14 @@ void Cop1::truncws(const u32 instr) { regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return; } - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::truncwd(const u32 instr) { +void Cop1::truncwd(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckCVTArg(fs)) return; CHECK_FPE_CONV_CONST(s32, fd, Util::roundTrunc(fs)) @@ -1255,14 +1255,14 @@ void Cop1::truncwd(const u32 instr) { regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return; } - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::truncls(const u32 instr) { +void Cop1::truncls(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckCVTArg(fs)) return; CHECK_FPE_CONST(s64, fd, Util::roundTrunc(fs)) @@ -1270,14 +1270,14 @@ void Cop1::truncls(const u32 instr) { regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return; } - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::truncld(const u32 instr) { +void Cop1::truncld(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - const auto fs = FGR_S(regs.cop0.status, FS(instr)); + const auto fs = FGR_S(regs.cop0.status, instr.fs()); if (!CheckCVTArg(fs)) return; CHECK_FPE_CONST(s64, fd, Util::roundTrunc(fs)) @@ -1285,60 +1285,60 @@ void Cop1::truncld(const u32 instr) { regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return; } - FGR_D(regs.cop0.status, FD(instr)) = fd; + FGR_D(regs.cop0.status, instr.fd()) = fd; } -void Cop1::lwc1(u32 instr) { +void Cop1::lwc1(const Instruction instr) { Mem& mem = Core::GetMem(); Registers& regs = Core::GetRegs(); - const u64 addr = static_cast(static_cast(instr)) + regs.Read(BASE(instr)); + const u64 addr = static_cast(static_cast(instr)) + regs.Read(instr.base()); if (u32 physical; !regs.cop0.MapVAddr(Cop0::LOAD, addr, physical)) { regs.cop0.HandleTLBException(addr); regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC); } else { const u32 data = mem.Read(physical); - FGR_T(regs.cop0.status, FT(instr)) = data; + FGR_T(regs.cop0.status, instr.ft()) = data; } } -void Cop1::swc1(u32 instr) { +void Cop1::swc1(const Instruction instr) { Mem& mem = Core::GetMem(); Registers& regs = Core::GetRegs(); - const u64 addr = static_cast(static_cast(instr)) + regs.Read(BASE(instr)); + const u64 addr = static_cast(static_cast(instr)) + regs.Read(instr.base()); if (u32 physical; !regs.cop0.MapVAddr(Cop0::STORE, addr, physical)) { regs.cop0.HandleTLBException(addr); regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC); } else { - mem.Write(physical, FGR_T(regs.cop0.status, FT(instr))); + mem.Write(physical, FGR_T(regs.cop0.status, instr.ft())); } } -void Cop1::ldc1(u32 instr) { +void Cop1::ldc1(const Instruction instr) { Mem& mem = Core::GetMem(); Registers& regs = Core::GetRegs(); - const u64 addr = static_cast(static_cast(instr)) + regs.Read(BASE(instr)); + const u64 addr = static_cast(static_cast(instr)) + regs.Read(instr.base()); if (u32 physical; !regs.cop0.MapVAddr(Cop0::LOAD, addr, physical)) { regs.cop0.HandleTLBException(addr); regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC); } else { const u64 data = mem.Read(physical); - FGR_T(regs.cop0.status, FT(instr)) = data; + FGR_T(regs.cop0.status, instr.ft()) = data; } } -void Cop1::sdc1(u32 instr) { +void Cop1::sdc1(const Instruction instr) { Mem& mem = Core::GetMem(); Registers& regs = Core::GetRegs(); - const u64 addr = static_cast(static_cast(instr)) + regs.Read(BASE(instr)); + const u64 addr = static_cast(static_cast(instr)) + regs.Read(instr.base()); if (u32 physical; !regs.cop0.MapVAddr(Cop0::STORE, addr, physical)) { regs.cop0.HandleTLBException(addr); regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC); } else { - mem.Write(physical, FGR_T(regs.cop0.status, FT(instr))); + mem.Write(physical, FGR_T(regs.cop0.status, instr.ft())); } } @@ -1350,31 +1350,31 @@ void Cop1::unimplemented() { regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); } -void Cop1::mfc1(const u32 instr) { +void Cop1::mfc1(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - regs.Write(RT(instr), FGR_T(regs.cop0.status, FS(instr))); + regs.Write(instr.rt(), FGR_T(regs.cop0.status, instr.fs())); } -void Cop1::dmfc1(const u32 instr) { +void Cop1::dmfc1(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - regs.Write(RT(instr), FGR_S(regs.cop0.status, FS(instr))); + regs.Write(instr.rt(), FGR_S(regs.cop0.status, instr.fs())); } -void Cop1::mtc1(const u32 instr) { +void Cop1::mtc1(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - FGR_T(regs.cop0.status, FS(instr)) = regs.Read(RT(instr)); + FGR_T(regs.cop0.status, instr.fs()) = regs.Read(instr.rt()); } -void Cop1::dmtc1(const u32 instr) { +void Cop1::dmtc1(const Instruction instr) { Registers& regs = Core::GetRegs(); if (!CheckFPUUsable()) return; - FGR_S(regs.cop0.status, FS(instr)) = regs.Read(RT(instr)); + FGR_S(regs.cop0.status, instr.fs()) = regs.Read(instr.rt()); } } // namespace n64 diff --git a/src/backend/core/interpreter/decode.cpp b/src/backend/core/interpreter/decode.cpp index 3aa84433..aaa44558 100644 --- a/src/backend/core/interpreter/decode.cpp +++ b/src/backend/core/interpreter/decode.cpp @@ -1,12 +1,11 @@ #include -#include #include #include namespace n64 { void Interpreter::special(const Instruction instr) { // 00rr_rccc - switch (instr.instr.opcode.special) { + switch (instr.special()) { case Instruction::SLL: if (instr.instr.raw != 0) { sll(instr); @@ -172,7 +171,7 @@ void Interpreter::special(const Instruction instr) { void Interpreter::regimm(const Instruction instr) { // 000r_rccc - switch (instr.instr.opcode.regimm) { + switch (instr.regimm()) { case Instruction::BLTZ: b(instr, regs.Read(instr.rs()) < 0); break; @@ -217,7 +216,7 @@ void Interpreter::regimm(const Instruction instr) { break; default: panic("Unimplemented regimm {} {} ({:08X}) (pc: {:016X})", instr.instr.opcode.regimm_hi, - instr.instr.opcode.regimm_lo, instr, static_cast(regs.oldPC)); + instr.instr.opcode.regimm_lo, u32(instr), static_cast(regs.oldPC)); } } @@ -252,7 +251,7 @@ void Interpreter::cop2Decode(const u32 instr) { void Interpreter::Exec(const Instruction instr) { // 00rr_rccc - switch (instr.instr.opcode.op) { + switch (instr.opcode()) { case Instruction::SPECIAL: special(instr); break; @@ -305,6 +304,33 @@ void Interpreter::Exec(const Instruction instr) { regs.cop0.decode(instr); break; case Instruction::COP1: + if(instr.cop_rs() == 0x08) { + switch (instr.cop_rt()) { + case 0: + if (!regs.cop1.CheckFPUUsable()) + return; + b(instr, !regs.cop1.fcr31.compare); + break; + case 1: + if (!regs.cop1.CheckFPUUsable()) + return; + b(instr, regs.cop1.fcr31.compare); + break; + case 2: + if (!regs.cop1.CheckFPUUsable()) + return; + bl(instr, !regs.cop1.fcr31.compare); + break; + case 3: + if (!regs.cop1.CheckFPUUsable()) + return; + bl(instr, regs.cop1.fcr31.compare); + break; + default: + panic("Undefined BC COP1 {:02X}", instr.cop_rt()); + } + break; + } regs.cop1.decode(instr); break; case Instruction::COP2: diff --git a/src/backend/core/interpreter/instructions.cpp b/src/backend/core/interpreter/instructions.cpp index 8a669ee0..94d50332 100644 --- a/src/backend/core/interpreter/instructions.cpp +++ b/src/backend/core/interpreter/instructions.cpp @@ -4,76 +4,76 @@ #define check_signed_underflow(op1, op2, res) (((((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1) namespace n64 { -void Interpreter::add(const u32 instr) { - const u32 rs = regs.Read(RS(instr)); - const u32 rt = regs.Read(RT(instr)); +void Interpreter::add(const Instruction instr) { + const u32 rs = regs.Read(instr.rs()); + const u32 rt = regs.Read(instr.rt()); if (const u32 result = rs + rt; check_signed_overflow(rs, rt, result)) { regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); } else { - regs.Write(RD(instr), static_cast(result)); + regs.Write(instr.rd(), static_cast(result)); } } -void Interpreter::addu(const u32 instr) { - const s32 rs = regs.Read(RS(instr)); - const s32 rt = regs.Read(RT(instr)); +void Interpreter::addu(const Instruction instr) { + const s32 rs = regs.Read(instr.rs()); + const s32 rt = regs.Read(instr.rt()); const s32 result = rs + rt; - regs.Write(RD(instr), result); + regs.Write(instr.rd(), result); } -void Interpreter::addi(const u32 instr) { - const u32 rs = regs.Read(RS(instr)); +void Interpreter::addi(const Instruction instr) { + const u32 rs = regs.Read(instr.rs()); const u32 imm = static_cast(static_cast(instr)); if (const u32 result = rs + imm; check_signed_overflow(rs, imm, result)) { regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); } else { - regs.Write(RT(instr), static_cast(result)); + regs.Write(instr.rt(), static_cast(result)); } } -void Interpreter::addiu(const u32 instr) { - const s32 rs = regs.Read(RS(instr)); +void Interpreter::addiu(const Instruction instr) { + const s32 rs = regs.Read(instr.rs()); const s16 imm = static_cast(instr); const s32 result = rs + imm; - regs.Write(RT(instr), result); + regs.Write(instr.rt(), result); } -void Interpreter::dadd(const u32 instr) { - const u64 rs = regs.Read(RS(instr)); - const u64 rt = regs.Read(RT(instr)); +void Interpreter::dadd(const Instruction instr) { + const u64 rs = regs.Read(instr.rs()); + const u64 rt = regs.Read(instr.rt()); if (const u64 result = rt + rs; check_signed_overflow(rs, rt, result)) { regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); } else { - regs.Write(RD(instr), result); + regs.Write(instr.rd(), result); } } -void Interpreter::daddu(const u32 instr) { - const s64 rs = regs.Read(RS(instr)); - const s64 rt = regs.Read(RT(instr)); - regs.Write(RD(instr), rs + rt); +void Interpreter::daddu(const Instruction instr) { + const s64 rs = regs.Read(instr.rs()); + const s64 rt = regs.Read(instr.rt()); + regs.Write(instr.rd(), rs + rt); } -void Interpreter::daddi(const u32 instr) { +void Interpreter::daddi(const Instruction instr) { const u64 imm = s64(s16(instr)); - const u64 rs = regs.Read(RS(instr)); + const u64 rs = regs.Read(instr.rs()); if (const u64 result = imm + rs; check_signed_overflow(rs, imm, result)) { regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); } else { - regs.Write(RT(instr), result); + regs.Write(instr.rt(), result); } } -void Interpreter::daddiu(const u32 instr) { +void Interpreter::daddiu(const Instruction instr) { const s16 imm = static_cast(instr); - const s64 rs = regs.Read(RS(instr)); - regs.Write(RT(instr), rs + imm); + const s64 rs = regs.Read(instr.rs()); + regs.Write(instr.rt(), rs + imm); } -void Interpreter::div(const u32 instr) { - const s64 dividend = regs.Read(RS(instr)); +void Interpreter::div(const Instruction instr) { + const s64 dividend = regs.Read(instr.rs()); - if (const s64 divisor = regs.Read(RT(instr)); divisor == 0) { + if (const s64 divisor = regs.Read(instr.rt()); divisor == 0) { regs.hi = dividend; if (dividend >= 0) { regs.lo = static_cast(-1); @@ -88,9 +88,9 @@ void Interpreter::div(const u32 instr) { } } -void Interpreter::divu(const u32 instr) { - const u32 dividend = regs.Read(RS(instr)); - if (const u32 divisor = regs.Read(RT(instr)); divisor == 0) { +void Interpreter::divu(const Instruction instr) { + const u32 dividend = regs.Read(instr.rs()); + if (const u32 divisor = regs.Read(instr.rt()); divisor == 0) { regs.lo = -1; regs.hi = (s32)dividend; } else { @@ -101,9 +101,9 @@ void Interpreter::divu(const u32 instr) { } } -void Interpreter::ddiv(const u32 instr) { - const s64 dividend = regs.Read(RS(instr)); - const s64 divisor = regs.Read(RT(instr)); +void Interpreter::ddiv(const Instruction instr) { + const s64 dividend = regs.Read(instr.rs()); + const s64 divisor = regs.Read(instr.rt()); if (dividend == 0x8000000000000000 && divisor == 0xFFFFFFFFFFFFFFFF) { regs.lo = dividend; regs.hi = 0; @@ -122,9 +122,9 @@ void Interpreter::ddiv(const u32 instr) { } } -void Interpreter::ddivu(const u32 instr) { - const u64 dividend = regs.Read(RS(instr)); - const u64 divisor = regs.Read(RT(instr)); +void Interpreter::ddivu(const Instruction instr) { + const u64 dividend = regs.Read(instr.rs()); + const u64 divisor = regs.Read(instr.rt()); if (divisor == 0) { regs.lo = -1; regs.hi = (s64)dividend; @@ -152,14 +152,14 @@ void Interpreter::branch_likely(const bool cond, const s64 address) { } } -void Interpreter::b(const u32 instr, const bool cond) { +void Interpreter::b(const Instruction instr, const bool cond) { const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; const s64 address = regs.pc + offset; branch(cond, address); } -void Interpreter::blink(const u32 instr, const bool cond) { +void Interpreter::blink(const Instruction instr, const bool cond) { regs.Write(31, regs.nextPC); const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; @@ -167,14 +167,14 @@ void Interpreter::blink(const u32 instr, const bool cond) { branch(cond, address); } -void Interpreter::bl(const u32 instr, const bool cond) { +void Interpreter::bl(const Instruction instr, const bool cond) { const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; const s64 address = regs.pc + offset; branch_likely(cond, address); } -void Interpreter::bllink(const u32 instr, const bool cond) { +void Interpreter::bllink(const Instruction instr, const bool cond) { regs.Write(31, regs.nextPC); const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; @@ -182,24 +182,24 @@ void Interpreter::bllink(const u32 instr, const bool cond) { branch_likely(cond, address); } -void Interpreter::lui(const u32 instr) { +void Interpreter::lui(const Instruction instr) { u64 val = s64((s16)instr); val <<= 16; - regs.Write(RT(instr), val); + regs.Write(instr.rt(), val); } -void Interpreter::lb(const u32 instr) { - const u64 address = regs.Read(RS(instr)) + (s16)instr; +void Interpreter::lb(const Instruction instr) { + const u64 address = regs.Read(instr.rs()) + (s16)instr; if (u32 paddr = 0; !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), (s8)mem.Read(paddr)); + regs.Write(instr.rt(), (s8)mem.Read(paddr)); } } -void Interpreter::lh(const u32 instr) { - const u64 address = regs.Read(RS(instr)) + (s16)instr; +void Interpreter::lh(const Instruction instr) { + const u64 address = regs.Read(instr.rs()) + (s16)instr; if (check_address_error(0b1, address)) { regs.cop0.HandleTLBException(address); regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC); @@ -211,13 +211,13 @@ void Interpreter::lh(const u32 instr) { 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(paddr)); + regs.Write(instr.rt(), (s16)mem.Read(paddr)); } } -void Interpreter::lw(const u32 instr) { +void Interpreter::lw(const Instruction instr) { const s16 offset = instr; - const u64 address = regs.Read(RS(instr)) + offset; + const u64 address = regs.Read(instr.rs()) + offset; if (check_address_error(0b11, address)) { regs.cop0.HandleTLBException(address); regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC); @@ -229,12 +229,12 @@ void Interpreter::lw(const u32 instr) { regs.cop0.HandleTLBException(address); regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC); } else { - regs.Write(RT(instr), (s32)mem.Read(physical)); + regs.Write(instr.rt(), (s32)mem.Read(physical)); } } -void Interpreter::ll(const u32 instr) { - const u64 address = regs.Read(RS(instr)) + (s16)instr; +void Interpreter::ll(const Instruction instr) { + const u64 address = regs.Read(instr.rs()) + (s16)instr; u32 physical; if (!regs.cop0.MapVAddr(Cop0::LOAD, address, physical)) { regs.cop0.HandleTLBException(address); @@ -246,15 +246,15 @@ void Interpreter::ll(const u32 instr) { return; } - regs.Write(RT(instr), result); + regs.Write(instr.rt(), result); regs.cop0.llbit = true; regs.cop0.LLAddr = physical >> 4; } } -void Interpreter::lwl(const u32 instr) { - const u64 address = regs.Read(RS(instr)) + (s16)instr; +void Interpreter::lwl(const Instruction instr) { + const u64 address = regs.Read(instr.rs()) + (s16)instr; u32 paddr = 0; if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { regs.cop0.HandleTLBException(address); @@ -263,13 +263,13 @@ void Interpreter::lwl(const u32 instr) { const u32 shift = 8 * ((address ^ 0) & 3); const u32 mask = 0xFFFFFFFF << shift; const u32 data = mem.Read(paddr & ~3); - const s32 result = s32((regs.Read(RT(instr)) & ~mask) | (data << shift)); - regs.Write(RT(instr), result); + const s32 result = s32((regs.Read(instr.rt()) & ~mask) | (data << shift)); + regs.Write(instr.rt(), result); } } -void Interpreter::lwr(const u32 instr) { - const u64 address = regs.Read(RS(instr)) + (s16)instr; +void Interpreter::lwr(const Instruction instr) { + const u64 address = regs.Read(instr.rs()) + (s16)instr; u32 paddr = 0; if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { regs.cop0.HandleTLBException(address); @@ -278,13 +278,13 @@ void Interpreter::lwr(const u32 instr) { const u32 shift = 8 * ((address ^ 3) & 3); const u32 mask = 0xFFFFFFFF >> shift; const u32 data = mem.Read(paddr & ~3); - const s32 result = s32((regs.Read(RT(instr)) & ~mask) | (data >> shift)); - regs.Write(RT(instr), result); + const s32 result = s32((regs.Read(instr.rt()) & ~mask) | (data >> shift)); + regs.Write(instr.rt(), result); } } -void Interpreter::ld(const u32 instr) { - const s64 address = regs.Read(RS(instr)) + (s16)instr; +void Interpreter::ld(const Instruction instr) { + const s64 address = regs.Read(instr.rs()) + (s16)instr; if (check_address_error(0b111, address)) { regs.cop0.HandleTLBException(address); regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC); @@ -297,17 +297,17 @@ void Interpreter::ld(const u32 instr) { regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC); } else { const s64 value = mem.Read(paddr); - regs.Write(RT(instr), value); + regs.Write(instr.rt(), value); } } -void Interpreter::lld(const u32 instr) { +void Interpreter::lld(const Instruction instr) { if (!regs.cop0.is64BitAddressing && !regs.cop0.kernelMode) { regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC); return; } - const u64 address = regs.Read(RS(instr)) + (s16)instr; + const u64 address = regs.Read(instr.rs()) + (s16)instr; u32 paddr; if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { regs.cop0.HandleTLBException(address); @@ -316,15 +316,15 @@ void Interpreter::lld(const u32 instr) { if (check_address_error(0b111, address)) { regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC); } else { - regs.Write(RT(instr), mem.Read(paddr)); + regs.Write(instr.rt(), mem.Read(paddr)); regs.cop0.llbit = true; regs.cop0.LLAddr = paddr >> 4; } } } -void Interpreter::ldl(const u32 instr) { - const u64 address = regs.Read(RS(instr)) + (s16)instr; +void Interpreter::ldl(const Instruction instr) { + const u64 address = regs.Read(instr.rs()) + (s16)instr; u32 paddr = 0; if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { regs.cop0.HandleTLBException(address); @@ -333,13 +333,13 @@ void Interpreter::ldl(const u32 instr) { const s32 shift = 8 * ((address ^ 0) & 7); const u64 mask = 0xFFFFFFFFFFFFFFFF << shift; const u64 data = mem.Read(paddr & ~7); - const s64 result = (s64)((regs.Read(RT(instr)) & ~mask) | (data << shift)); - regs.Write(RT(instr), result); + const s64 result = (s64)((regs.Read(instr.rt()) & ~mask) | (data << shift)); + regs.Write(instr.rt(), result); } } -void Interpreter::ldr(const u32 instr) { - const u64 address = regs.Read(RS(instr)) + (s16)instr; +void Interpreter::ldr(const Instruction instr) { + const u64 address = regs.Read(instr.rs()) + (s16)instr; u32 paddr; if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { regs.cop0.HandleTLBException(address); @@ -348,25 +348,25 @@ void Interpreter::ldr(const u32 instr) { const s32 shift = 8 * ((address ^ 7) & 7); const u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; const u64 data = mem.Read(paddr & ~7); - const s64 result = (s64)((regs.Read(RT(instr)) & ~mask) | (data >> shift)); - regs.Write(RT(instr), result); + const s64 result = (s64)((regs.Read(instr.rt()) & ~mask) | (data >> shift)); + regs.Write(instr.rt(), result); } } -void Interpreter::lbu(const u32 instr) { - const u64 address = regs.Read(RS(instr)) + (s16)instr; +void Interpreter::lbu(const Instruction instr) { + const u64 address = regs.Read(instr.rs()) + (s16)instr; u32 paddr; 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 { const u8 value = mem.Read(paddr); - regs.Write(RT(instr), value); + regs.Write(instr.rt(), value); } } -void Interpreter::lhu(const u32 instr) { - const s64 address = regs.Read(RS(instr)) + (s16)instr; +void Interpreter::lhu(const Instruction instr) { + const s64 address = regs.Read(instr.rs()) + (s16)instr; if (check_address_error(0b1, address)) { regs.cop0.HandleTLBException(address); regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC); @@ -378,12 +378,12 @@ void Interpreter::lhu(const u32 instr) { regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC); } else { const u16 value = mem.Read(paddr); - regs.Write(RT(instr), value); + regs.Write(instr.rt(), value); } } -void Interpreter::lwu(const u32 instr) { - const s64 address = regs.Read(RS(instr)) + (s16)instr; +void Interpreter::lwu(const Instruction instr) { + const s64 address = regs.Read(instr.rs()) + (s16)instr; if (check_address_error(0b11, address)) { regs.cop0.HandleTLBException(address); regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC); @@ -396,29 +396,29 @@ void Interpreter::lwu(const u32 instr) { regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC); } else { const u32 value = mem.Read(paddr); - regs.Write(RT(instr), value); + regs.Write(instr.rt(), value); } } -void Interpreter::sb(const u32 instr) { - const u64 address = regs.Read(RS(instr)) + (s16)instr; +void Interpreter::sb(const Instruction instr) { + const u64 address = regs.Read(instr.rs()) + (s16)instr; u32 paddr; if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) { regs.cop0.HandleTLBException(address); regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC); } else { - mem.Write(paddr, regs.Read(RT(instr))); + mem.Write(paddr, regs.Read(instr.rt())); } } -void Interpreter::sc(const u32 instr) { - const u64 address = regs.Read(RS(instr)) + (s16)instr; +void Interpreter::sc(const Instruction instr) { + const u64 address = regs.Read(instr.rs()) + (s16)instr; if (regs.cop0.llbit) { regs.cop0.llbit = false; if (check_address_error(0b11, address)) { - regs.Write(RT(instr), 0); + regs.Write(instr.rt(), 0); regs.cop0.HandleTLBException(address); regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC); return; @@ -426,31 +426,31 @@ void Interpreter::sc(const u32 instr) { u32 paddr = 0; if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) { - regs.Write(RT(instr), 0); + regs.Write(instr.rt(), 0); regs.cop0.HandleTLBException(address); regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC); } else { - mem.Write(paddr, regs.Read(RT(instr))); - regs.Write(RT(instr), 1); + mem.Write(paddr, regs.Read(instr.rt())); + regs.Write(instr.rt(), 1); } } else { - regs.Write(RT(instr), 0); + regs.Write(instr.rt(), 0); } } -void Interpreter::scd(const u32 instr) { +void Interpreter::scd(const Instruction instr) { if (!regs.cop0.is64BitAddressing && !regs.cop0.kernelMode) { regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC); return; } - const s64 address = regs.Read(RS(instr)) + (s16)instr; + const s64 address = regs.Read(instr.rs()) + (s16)instr; if (regs.cop0.llbit) { regs.cop0.llbit = false; if (check_address_error(0b111, address)) { - regs.Write(RT(instr), 0); + regs.Write(instr.rt(), 0); regs.cop0.HandleTLBException(address); regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC); return; @@ -458,33 +458,33 @@ void Interpreter::scd(const u32 instr) { u32 paddr = 0; if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) { - regs.Write(RT(instr), 0); + regs.Write(instr.rt(), 0); regs.cop0.HandleTLBException(address); regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC); } else { - mem.Write(paddr, regs.Read(RT(instr))); - regs.Write(RT(instr), 1); + mem.Write(paddr, regs.Read(instr.rt())); + regs.Write(instr.rt(), 1); } } else { - regs.Write(RT(instr), 0); + regs.Write(instr.rt(), 0); } } -void Interpreter::sh(const u32 instr) { - const s64 address = regs.Read(RS(instr)) + (s16)instr; +void Interpreter::sh(const Instruction instr) { + const s64 address = regs.Read(instr.rs()) + (s16)instr; u32 physical; if (!regs.cop0.MapVAddr(Cop0::STORE, address, physical)) { regs.cop0.HandleTLBException(address); regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC); } else { - mem.Write(physical, regs.Read(RT(instr))); + mem.Write(physical, regs.Read(instr.rt())); } } -void Interpreter::sw(const u32 instr) { +void Interpreter::sw(const Instruction instr) { const s16 offset = instr; - const u64 address = regs.Read(RS(instr)) + offset; + const u64 address = regs.Read(instr.rs()) + offset; if (check_address_error(0b11, address)) { regs.cop0.HandleTLBException(address); regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC); @@ -496,12 +496,12 @@ void Interpreter::sw(const u32 instr) { regs.cop0.HandleTLBException(address); regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC); } else { - mem.Write(physical, regs.Read(RT(instr))); + mem.Write(physical, regs.Read(instr.rt())); } } -void Interpreter::sd(const u32 instr) { - const s64 address = regs.Read(RS(instr)) + (s16)instr; +void Interpreter::sd(const Instruction instr) { + const s64 address = regs.Read(instr.rs()) + (s16)instr; if (check_address_error(0b111, address)) { regs.cop0.HandleTLBException(address); regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC); @@ -513,12 +513,12 @@ void Interpreter::sd(const u32 instr) { regs.cop0.HandleTLBException(address); regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC); } else { - mem.Write(physical, regs.Read(RT(instr))); + mem.Write(physical, regs.Read(instr.rt())); } } -void Interpreter::sdl(const u32 instr) { - const u64 address = regs.Read(RS(instr)) + (s16)instr; +void Interpreter::sdl(const Instruction instr) { + const u64 address = regs.Read(instr.rs()) + (s16)instr; u32 paddr; if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) { regs.cop0.HandleTLBException(address); @@ -527,13 +527,13 @@ void Interpreter::sdl(const u32 instr) { const s32 shift = 8 * ((address ^ 0) & 7); const u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; const u64 data = mem.Read(paddr & ~7); - const u64 rt = regs.Read(RT(instr)); + const u64 rt = regs.Read(instr.rt()); mem.Write(paddr & ~7, (data & ~mask) | (rt >> shift)); } } -void Interpreter::sdr(const u32 instr) { - const u64 address = regs.Read(RS(instr)) + (s16)instr; +void Interpreter::sdr(const Instruction instr) { + const u64 address = regs.Read(instr.rs()) + (s16)instr; u32 paddr; if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) { regs.cop0.HandleTLBException(address); @@ -542,13 +542,13 @@ void Interpreter::sdr(const u32 instr) { const s32 shift = 8 * ((address ^ 7) & 7); const u64 mask = 0xFFFFFFFFFFFFFFFF << shift; const u64 data = mem.Read(paddr & ~7); - const u64 rt = regs.Read(RT(instr)); + const u64 rt = regs.Read(instr.rt()); mem.Write(paddr & ~7, (data & ~mask) | (rt << shift)); } } -void Interpreter::swl(const u32 instr) { - const u64 address = regs.Read(RS(instr)) + (s16)instr; +void Interpreter::swl(const Instruction instr) { + const u64 address = regs.Read(instr.rs()) + (s16)instr; u32 paddr; if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) { regs.cop0.HandleTLBException(address); @@ -557,13 +557,13 @@ void Interpreter::swl(const u32 instr) { const u32 shift = 8 * ((address ^ 0) & 3); const u32 mask = 0xFFFFFFFF >> shift; const u32 data = mem.Read(paddr & ~3); - const u32 rt = regs.Read(RT(instr)); + const u32 rt = regs.Read(instr.rt()); mem.Write(paddr & ~3, (data & ~mask) | (rt >> shift)); } } -void Interpreter::swr(const u32 instr) { - const u64 address = regs.Read(RS(instr)) + (s16)instr; +void Interpreter::swr(const Instruction instr) { + const u64 address = regs.Read(instr.rs()) + (s16)instr; u32 paddr; if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) { regs.cop0.HandleTLBException(address); @@ -572,256 +572,256 @@ void Interpreter::swr(const u32 instr) { const u32 shift = 8 * ((address ^ 3) & 3); const u32 mask = 0xFFFFFFFF << shift; const u32 data = mem.Read(paddr & ~3); - const u32 rt = regs.Read(RT(instr)); + const u32 rt = regs.Read(instr.rt()); mem.Write(paddr & ~3, (data & ~mask) | (rt << shift)); } } -void Interpreter::ori(const u32 instr) { +void Interpreter::ori(const Instruction instr) { const s64 imm = (u16)instr; - const s64 result = imm | regs.Read(RS(instr)); - regs.Write(RT(instr), result); + const s64 result = imm | regs.Read(instr.rs()); + regs.Write(instr.rt(), result); } -void Interpreter::or_(const u32 instr) { regs.Write(RD(instr), regs.Read(RS(instr)) | regs.Read(RT(instr))); } +void Interpreter::or_(const Instruction instr) { regs.Write(instr.rd(), regs.Read(instr.rs()) | regs.Read(instr.rt())); } -void Interpreter::nor(const u32 instr) { - regs.Write(RD(instr), ~(regs.Read(RS(instr)) | regs.Read(RT(instr)))); +void Interpreter::nor(const Instruction instr) { + regs.Write(instr.rd(), ~(regs.Read(instr.rs()) | regs.Read(instr.rt()))); } -void Interpreter::j(const u32 instr) { +void Interpreter::j(const Instruction instr) { const s32 target = (instr & 0x3ffffff) << 2; const s64 address = (regs.oldPC & ~0xfffffff) | target; branch(true, address); } -void Interpreter::jal(const u32 instr) { +void Interpreter::jal(const Instruction instr) { regs.Write(31, regs.nextPC); j(instr); } -void Interpreter::jalr(const u32 instr) { - regs.Write(RD(instr), regs.nextPC); +void Interpreter::jalr(const Instruction instr) { + regs.Write(instr.rd(), regs.nextPC); jr(instr); } -void Interpreter::jr(const u32 instr) { - const u64 address = regs.Read(RS(instr)); +void Interpreter::jr(const Instruction instr) { + const u64 address = regs.Read(instr.rs()); branch(true, address); } -void Interpreter::slti(const u32 instr) { +void Interpreter::slti(const Instruction instr) { const s16 imm = instr; - regs.Write(RT(instr), regs.Read(RS(instr)) < imm); + regs.Write(instr.rt(), regs.Read(instr.rs()) < imm); } -void Interpreter::sltiu(const u32 instr) { +void Interpreter::sltiu(const Instruction instr) { const s16 imm = instr; - regs.Write(RT(instr), regs.Read(RS(instr)) < imm); + regs.Write(instr.rt(), regs.Read(instr.rs()) < imm); } -void Interpreter::slt(const u32 instr) { regs.Write(RD(instr), regs.Read(RS(instr)) < regs.Read(RT(instr))); } +void Interpreter::slt(const Instruction instr) { regs.Write(instr.rd(), regs.Read(instr.rs()) < regs.Read(instr.rt())); } -void Interpreter::sltu(const u32 instr) { - regs.Write(RD(instr), regs.Read(RS(instr)) < regs.Read(RT(instr))); +void Interpreter::sltu(const Instruction instr) { + regs.Write(instr.rd(), regs.Read(instr.rs()) < regs.Read(instr.rt())); } -void Interpreter::xori(const u32 instr) { +void Interpreter::xori(const Instruction instr) { const s64 imm = (u16)instr; - regs.Write(RT(instr), regs.Read(RS(instr)) ^ imm); + regs.Write(instr.rt(), regs.Read(instr.rs()) ^ imm); } -void Interpreter::xor_(const u32 instr) { - regs.Write(RD(instr), regs.Read(RT(instr)) ^ regs.Read(RS(instr))); +void Interpreter::xor_(const Instruction instr) { + regs.Write(instr.rd(), regs.Read(instr.rt()) ^ regs.Read(instr.rs())); } -void Interpreter::andi(const u32 instr) { +void Interpreter::andi(const Instruction instr) { const s64 imm = (u16)instr; - regs.Write(RT(instr), regs.Read(RS(instr)) & imm); + regs.Write(instr.rt(), regs.Read(instr.rs()) & imm); } -void Interpreter::and_(const u32 instr) { - regs.Write(RD(instr), regs.Read(RS(instr)) & regs.Read(RT(instr))); +void Interpreter::and_(const Instruction instr) { + regs.Write(instr.rd(), regs.Read(instr.rs()) & regs.Read(instr.rt())); } -void Interpreter::sll(const u32 instr) { +void Interpreter::sll(const Instruction instr) { const u8 sa = ((instr >> 6) & 0x1f); - const s32 result = regs.Read(RT(instr)) << sa; - regs.Write(RD(instr), (s64)result); + const s32 result = regs.Read(instr.rt()) << sa; + regs.Write(instr.rd(), (s64)result); } -void Interpreter::sllv(const u32 instr) { - const u8 sa = (regs.Read(RS(instr))) & 0x1F; - const u32 rt = regs.Read(RT(instr)); +void Interpreter::sllv(const Instruction instr) { + const u8 sa = (regs.Read(instr.rs())) & 0x1F; + const u32 rt = regs.Read(instr.rt()); const s32 result = rt << sa; - regs.Write(RD(instr), (s64)result); + regs.Write(instr.rd(), (s64)result); } -void Interpreter::dsll32(const u32 instr) { +void Interpreter::dsll32(const Instruction instr) { const u8 sa = ((instr >> 6) & 0x1f); - const s64 result = regs.Read(RT(instr)) << (sa + 32); - regs.Write(RD(instr), result); + const s64 result = regs.Read(instr.rt()) << (sa + 32); + regs.Write(instr.rd(), result); } -void Interpreter::dsll(const u32 instr) { +void Interpreter::dsll(const Instruction instr) { const u8 sa = ((instr >> 6) & 0x1f); - const s64 result = regs.Read(RT(instr)) << sa; - regs.Write(RD(instr), result); + const s64 result = regs.Read(instr.rt()) << sa; + regs.Write(instr.rd(), result); } -void Interpreter::dsllv(const u32 instr) { - const s64 sa = regs.Read(RS(instr)) & 63; - const s64 result = regs.Read(RT(instr)) << sa; - regs.Write(RD(instr), result); +void Interpreter::dsllv(const Instruction instr) { + const s64 sa = regs.Read(instr.rs()) & 63; + const s64 result = regs.Read(instr.rt()) << sa; + regs.Write(instr.rd(), result); } -void Interpreter::srl(const u32 instr) { - const u32 rt = regs.Read(RT(instr)); +void Interpreter::srl(const Instruction instr) { + const u32 rt = regs.Read(instr.rt()); const u8 sa = ((instr >> 6) & 0x1f); const u32 result = rt >> sa; - regs.Write(RD(instr), (s32)result); + regs.Write(instr.rd(), (s32)result); } -void Interpreter::srlv(const u32 instr) { - const u8 sa = (regs.Read(RS(instr)) & 0x1F); - const u32 rt = regs.Read(RT(instr)); +void Interpreter::srlv(const Instruction instr) { + const u8 sa = (regs.Read(instr.rs()) & 0x1F); + const u32 rt = regs.Read(instr.rt()); const s32 result = rt >> sa; - regs.Write(RD(instr), (s64)result); + regs.Write(instr.rd(), (s64)result); } -void Interpreter::dsrl(const u32 instr) { - const u64 rt = regs.Read(RT(instr)); +void Interpreter::dsrl(const Instruction instr) { + const u64 rt = regs.Read(instr.rt()); const u8 sa = ((instr >> 6) & 0x1f); const u64 result = rt >> sa; - regs.Write(RD(instr), s64(result)); + regs.Write(instr.rd(), s64(result)); } -void Interpreter::dsrlv(const u32 instr) { - const u8 amount = (regs.Read(RS(instr)) & 63); - const u64 rt = regs.Read(RT(instr)); +void Interpreter::dsrlv(const Instruction instr) { + const u8 amount = (regs.Read(instr.rs()) & 63); + const u64 rt = regs.Read(instr.rt()); const u64 result = rt >> amount; - regs.Write(RD(instr), s64(result)); + regs.Write(instr.rd(), s64(result)); } -void Interpreter::dsrl32(const u32 instr) { - const u64 rt = regs.Read(RT(instr)); +void Interpreter::dsrl32(const Instruction instr) { + const u64 rt = regs.Read(instr.rt()); const u8 sa = ((instr >> 6) & 0x1f); const u64 result = rt >> (sa + 32); - regs.Write(RD(instr), s64(result)); + regs.Write(instr.rd(), s64(result)); } -void Interpreter::sra(const u32 instr) { - const s64 rt = regs.Read(RT(instr)); +void Interpreter::sra(const Instruction instr) { + const s64 rt = regs.Read(instr.rt()); const u8 sa = ((instr >> 6) & 0x1f); const s32 result = rt >> sa; - regs.Write(RD(instr), result); + regs.Write(instr.rd(), result); } -void Interpreter::srav(const u32 instr) { - const s64 rs = regs.Read(RS(instr)); - const s64 rt = regs.Read(RT(instr)); +void Interpreter::srav(const Instruction instr) { + const s64 rs = regs.Read(instr.rs()); + const s64 rt = regs.Read(instr.rt()); const u8 sa = rs & 0x1f; const s32 result = rt >> sa; - regs.Write(RD(instr), result); + regs.Write(instr.rd(), result); } -void Interpreter::dsra(const u32 instr) { - const s64 rt = regs.Read(RT(instr)); +void Interpreter::dsra(const Instruction instr) { + const s64 rt = regs.Read(instr.rt()); const u8 sa = ((instr >> 6) & 0x1f); const s64 result = rt >> sa; - regs.Write(RD(instr), result); + regs.Write(instr.rd(), result); } -void Interpreter::dsrav(const u32 instr) { - const s64 rt = regs.Read(RT(instr)); - const s64 rs = regs.Read(RS(instr)); +void Interpreter::dsrav(const Instruction instr) { + const s64 rt = regs.Read(instr.rt()); + const s64 rs = regs.Read(instr.rs()); const s64 sa = rs & 63; const s64 result = rt >> sa; - regs.Write(RD(instr), result); + regs.Write(instr.rd(), result); } -void Interpreter::dsra32(const u32 instr) { - const s64 rt = regs.Read(RT(instr)); +void Interpreter::dsra32(const Instruction instr) { + const s64 rt = regs.Read(instr.rt()); const u8 sa = ((instr >> 6) & 0x1f); const s64 result = rt >> (sa + 32); - regs.Write(RD(instr), result); + regs.Write(instr.rd(), result); } -void Interpreter::dsub(const u32 instr) { - const s64 rt = regs.Read(RT(instr)); - const s64 rs = regs.Read(RS(instr)); +void Interpreter::dsub(const Instruction instr) { + const s64 rt = regs.Read(instr.rt()); + const s64 rs = regs.Read(instr.rs()); if (const s64 result = rs - rt; check_signed_underflow(rs, rt, result)) { regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); } else { - regs.Write(RD(instr), result); + regs.Write(instr.rd(), result); } } -void Interpreter::dsubu(const u32 instr) { - const u64 rt = regs.Read(RT(instr)); - const u64 rs = regs.Read(RS(instr)); +void Interpreter::dsubu(const Instruction instr) { + const u64 rt = regs.Read(instr.rt()); + const u64 rs = regs.Read(instr.rs()); const u64 result = rs - rt; - regs.Write(RD(instr), s64(result)); + regs.Write(instr.rd(), s64(result)); } -void Interpreter::sub(const u32 instr) { - const s32 rt = regs.Read(RT(instr)); - const s32 rs = regs.Read(RS(instr)); +void Interpreter::sub(const Instruction instr) { + const s32 rt = regs.Read(instr.rt()); + const s32 rs = regs.Read(instr.rs()); const s32 result = rs - rt; if (check_signed_underflow(rs, rt, result)) { regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); } else { - regs.Write(RD(instr), result); + regs.Write(instr.rd(), result); } } -void Interpreter::subu(const u32 instr) { - const u32 rt = regs.Read(RT(instr)); - const u32 rs = regs.Read(RS(instr)); +void Interpreter::subu(const Instruction instr) { + const u32 rt = regs.Read(instr.rt()); + const u32 rs = regs.Read(instr.rs()); const u32 result = rs - rt; - regs.Write(RD(instr), (s64)((s32)result)); + regs.Write(instr.rd(), (s64)((s32)result)); } -void Interpreter::dmultu(const u32 instr) { - const u64 rt = regs.Read(RT(instr)); - const u64 rs = regs.Read(RS(instr)); +void Interpreter::dmultu(const Instruction instr) { + const u64 rt = regs.Read(instr.rt()); + const u64 rs = regs.Read(instr.rs()); const u128 result = (u128)rt * (u128)rs; regs.lo = (s64)(result & 0xFFFFFFFFFFFFFFFF); regs.hi = (s64)(result >> 64); } -void Interpreter::dmult(const u32 instr) { - const s64 rt = regs.Read(RT(instr)); - const s64 rs = regs.Read(RS(instr)); +void Interpreter::dmult(const Instruction instr) { + const s64 rt = regs.Read(instr.rt()); + const s64 rs = regs.Read(instr.rs()); const s128 result = (s128)rt * (s128)rs; regs.lo = result & 0xFFFFFFFFFFFFFFFF; regs.hi = result >> 64; } -void Interpreter::multu(const u32 instr) { - const u32 rt = regs.Read(RT(instr)); - const u32 rs = regs.Read(RS(instr)); +void Interpreter::multu(const Instruction instr) { + const u32 rt = regs.Read(instr.rt()); + const u32 rs = regs.Read(instr.rs()); const u64 result = (u64)rt * (u64)rs; regs.lo = (s64)((s32)result); regs.hi = (s64)((s32)(result >> 32)); } -void Interpreter::mult(const u32 instr) { - const s32 rt = regs.Read(RT(instr)); - const s32 rs = regs.Read(RS(instr)); +void Interpreter::mult(const Instruction instr) { + const s32 rt = regs.Read(instr.rt()); + const s32 rs = regs.Read(instr.rs()); const s64 result = (s64)rt * (s64)rs; regs.lo = (s64)((s32)result); regs.hi = (s64)((s32)(result >> 32)); } -void Interpreter::mflo(const u32 instr) { regs.Write(RD(instr), regs.lo); } +void Interpreter::mflo(const Instruction instr) { regs.Write(instr.rd(), regs.lo); } -void Interpreter::mfhi(const u32 instr) { regs.Write(RD(instr), regs.hi); } +void Interpreter::mfhi(const Instruction instr) { regs.Write(instr.rd(), regs.hi); } -void Interpreter::mtlo(const u32 instr) { regs.lo = regs.Read(RS(instr)); } +void Interpreter::mtlo(const Instruction instr) { regs.lo = regs.Read(instr.rs()); } -void Interpreter::mthi(const u32 instr) { regs.hi = regs.Read(RS(instr)); } +void Interpreter::mthi(const Instruction instr) { regs.hi = regs.Read(instr.rs()); } void Interpreter::trap(const bool cond) const { Cop0& cop0 = Core::GetRegs().cop0; @@ -830,18 +830,18 @@ void Interpreter::trap(const bool cond) const { } } -void Interpreter::mtc2(const u32 instr) { cop2Latch = regs.Read(RT(instr)); } +void Interpreter::mtc2(const Instruction instr) { cop2Latch = regs.Read(instr.rt()); } -void Interpreter::mfc2(const u32 instr) { +void Interpreter::mfc2(const Instruction instr) { const s32 value = cop2Latch; - regs.Write(RT(instr), value); + regs.Write(instr.rt(), value); } -void Interpreter::dmtc2(const u32 instr) { cop2Latch = regs.Read(RT(instr)); } +void Interpreter::dmtc2(const Instruction instr) { cop2Latch = regs.Read(instr.rt()); } -void Interpreter::dmfc2(const u32 instr) { regs.Write(RT(instr), cop2Latch); } +void Interpreter::dmfc2(const Instruction instr) { regs.Write(instr.rt(), cop2Latch); } -void Interpreter::ctc2(u32) {} +void Interpreter::ctc2(const Instruction) {} -void Interpreter::cfc2(u32) {} +void Interpreter::cfc2(const Instruction) {} } // namespace n64 diff --git a/src/backend/core/jit/decode.cpp b/src/backend/core/jit/decode.cpp index 07886485..9bf0ea92 100644 --- a/src/backend/core/jit/decode.cpp +++ b/src/backend/core/jit/decode.cpp @@ -1,283 +1,281 @@ #include -#include +#include namespace n64 { -void JIT::special(const u32 instr) { +void JIT::special(const Instruction instr) { // 00rr_rccc - switch (const u8 mask = instr & 0x3F) { - case SLL: + switch (instr.special()) { + case Instruction::SLL: if (instr != 0) { sll(instr); } break; - case SRL: + case Instruction::SRL: srl(instr); break; - case SRA: + case Instruction::SRA: sra(instr); break; - case SLLV: + case Instruction::SLLV: sllv(instr); break; - case SRLV: + case Instruction::SRLV: srlv(instr); break; - case SRAV: + case Instruction::SRAV: srav(instr); break; - case JR: + case Instruction::JR: jr(instr); break; - case JALR: + case Instruction::JALR: jalr(instr); break; - case SYSCALL: + case Instruction::SYSCALL: regs.cop0.FireException(ExceptionCode::Syscall, 0, regs.oldPC); break; - case BREAK: + case Instruction::BREAK: regs.cop0.FireException(ExceptionCode::Breakpoint, 0, regs.oldPC); break; - case SYNC: + case Instruction::SYNC: break; // SYNC - case MFHI: + case Instruction::MFHI: mfhi(instr); break; - case MTHI: + case Instruction::MTHI: mthi(instr); break; - case MFLO: + case Instruction::MFLO: mflo(instr); break; - case MTLO: + case Instruction::MTLO: mtlo(instr); break; - case DSLLV: + case Instruction::DSLLV: dsllv(instr); break; - case DSRLV: + case Instruction::DSRLV: dsrlv(instr); break; - case DSRAV: + case Instruction::DSRAV: dsrav(instr); break; - case MULT: + case Instruction::MULT: mult(instr); break; - case MULTU: + case Instruction::MULTU: multu(instr); break; - case DIV: + case Instruction::DIV: div(instr); break; - case DIVU: + case Instruction::DIVU: divu(instr); break; - case DMULT: + case Instruction::DMULT: dmult(instr); break; - case DMULTU: + case Instruction::DMULTU: dmultu(instr); break; - case DDIV: + case Instruction::DDIV: ddiv(instr); break; - case DDIVU: + case Instruction::DDIVU: ddivu(instr); break; - case ADD: + case Instruction::ADD: add(instr); break; - case ADDU: + case Instruction::ADDU: addu(instr); break; - case SUB: + case Instruction::SUB: sub(instr); break; - case SUBU: + case Instruction::SUBU: subu(instr); break; - case AND: + case Instruction::AND: and_(instr); break; - case OR: + case Instruction::OR: or_(instr); break; - case XOR: + case Instruction::XOR: xor_(instr); break; - case NOR: + case Instruction::NOR: nor(instr); break; - case SLT: + case Instruction::SLT: slt(instr); break; - case SLTU: + case Instruction::SLTU: sltu(instr); break; - case DADD: + case Instruction::DADD: dadd(instr); break; - case DADDU: + case Instruction::DADDU: daddu(instr); break; - case DSUB: + case Instruction::DSUB: dsub(instr); break; - case DSUBU: + case Instruction::DSUBU: dsubu(instr); break; - case TGE: + case Instruction::TGE: trap(regs.Read(RS(instr)) >= regs.Read(RT(instr))); break; - case TGEU: + case Instruction::TGEU: trap(regs.Read(RS(instr)) >= regs.Read(RT(instr))); break; - case TLT: + case Instruction::TLT: trap(regs.Read(RS(instr)) < regs.Read(RT(instr))); break; - case TLTU: + case Instruction::TLTU: trap(regs.Read(RS(instr)) < regs.Read(RT(instr))); break; - case TEQ: + case Instruction::TEQ: trap(regs.Read(RS(instr)) == regs.Read(RT(instr))); break; - case TNE: + case Instruction::TNE: trap(regs.Read(RS(instr)) != regs.Read(RT(instr))); break; - case DSLL: + case Instruction::DSLL: dsll(instr); break; - case DSRL: + case Instruction::DSRL: dsrl(instr); break; - case DSRA: + case Instruction::DSRA: dsra(instr); break; - case DSLL32: + case Instruction::DSLL32: dsll32(instr); break; - case DSRL32: + case Instruction::DSRL32: dsrl32(instr); break; - case DSRA32: + case Instruction::DSRA32: dsra32(instr); break; default: - panic("Unimplemented special {} {} ({:08X}) (pc: {:016X})", (mask >> 3) & 7, mask & 7, instr, + panic("Unimplemented special {} ({:08X}) (pc: {:016X})", instr.special(), u32(instr), static_cast(regs.oldPC)); } } -void JIT::regimm(const u32 instr) { +void JIT::regimm(const Instruction instr) { // 000r_rccc - switch (const u8 mask = instr >> 16 & 0x1F) { - case BLTZ: + switch (instr.regimm()) { + case Instruction::BLTZ: bltz(instr); break; - case BGEZ: + case Instruction::BGEZ: bgez(instr); break; - case BLTZL: + case Instruction::BLTZL: bltzl(instr); break; - case BGEZL: + case Instruction::BGEZL: bgezl(instr); break; - case TGEI: + case Instruction::TGEI: trap(regs.Read(RS(instr)) >= static_cast(static_cast(instr))); break; - case TGEIU: + case Instruction::TGEIU: trap(regs.Read(RS(instr)) >= static_cast(static_cast(static_cast(instr)))); break; - case TLTI: + case Instruction::TLTI: trap(regs.Read(RS(instr)) < static_cast(static_cast(instr))); break; - case TLTIU: + case Instruction::TLTIU: trap(regs.Read(RS(instr)) < static_cast(static_cast(static_cast(instr)))); break; - case TEQI: + case Instruction::TEQI: trap(regs.Read(RS(instr)) == static_cast(static_cast(instr))); break; - case TNEI: + case Instruction::TNEI: trap(regs.Read(RS(instr)) != static_cast(static_cast(instr))); break; - case BLTZAL: + case Instruction::BLTZAL: bltzal(instr); break; - case BGEZAL: + case Instruction::BGEZAL: bgezal(instr); break; - case BLTZALL: + case Instruction::BLTZALL: bltzall(instr); break; - case BGEZALL: + case Instruction::BGEZALL: bgezall(instr); break; default: - panic("Unimplemented regimm {} {} ({:08X}) (pc: {:016X})", (mask >> 3) & 3, mask & 7, instr, + panic("Unimplemented regimm {} ({:08X}) (pc: {:016X})", instr.regimm(), u32(instr), static_cast(regs.oldPC)); } } -void JIT::Emit(const u32 instr) { - switch (const u8 mask = instr >> 26 & 0x3f) { - case SPECIAL: +void JIT::Emit(const Instruction instr) { + switch (instr.opcode()) { + case Instruction::SPECIAL: special(instr); break; - case REGIMM: + case Instruction::REGIMM: regimm(instr); break; - case J: + case Instruction::J: j(instr); break; - case JAL: + case Instruction::JAL: jal(instr); break; - case BEQ: + case Instruction::BEQ: beq(instr); break; - case BNE: + case Instruction::BNE: bne(instr); break; - case BLEZ: + case Instruction::BLEZ: blez(instr); break; - case BGTZ: + case Instruction::BGTZ: bgtz(instr); break; - case ADDI: + case Instruction::ADDI: addi(instr); break; - case ADDIU: + case Instruction::ADDIU: addiu(instr); break; - case SLTI: + case Instruction::SLTI: slti(instr); break; - case SLTIU: + case Instruction::SLTIU: sltiu(instr); break; - case ANDI: + case Instruction::ANDI: andi(instr); break; - case ORI: + case Instruction::ORI: ori(instr); break; - case XORI: + case Instruction::XORI: xori(instr); break; - case LUI: + case Instruction::LUI: lui(instr); break; - case COP0: + case Instruction::COP0: panic("[JIT]: Unimplemented Cop0 decode"); break; - case COP1: + case Instruction::COP1: { - const u8 mask_sub = (instr >> 21) & 0x1F; - const u8 mask_branch = (instr >> 16) & 0x1F; - if (mask_sub == 0x08) { - switch (mask_branch) { + if (instr.cop_rs() == 0x08) { + switch (instr.cop_rt()) { case 0: // if (!regs.cop1.CheckFPUUsable()) // return; @@ -299,121 +297,121 @@ void JIT::Emit(const u32 instr) { blfc1(instr); break; default: - panic("Undefined BC COP1 {:02X}", mask_branch); + panic("Undefined BC COP1 {:02X}", instr.cop_rt()); } break; } regs.cop1.decode(instr); } break; - case COP2: + case Instruction::COP2: break; - case BEQL: + case Instruction::BEQL: beql(instr); break; - case BNEL: + case Instruction::BNEL: bnel(instr); break; - case BLEZL: + case Instruction::BLEZL: blezl(instr); break; - case BGTZL: + case Instruction::BGTZL: bgtzl(instr); break; - case DADDI: + case Instruction::DADDI: daddi(instr); break; - case DADDIU: + case Instruction::DADDIU: daddiu(instr); break; - case LDL: + case Instruction::LDL: ldl(instr); break; - case LDR: + case Instruction::LDR: ldr(instr); break; case 0x1F: regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC); break; - case LB: + case Instruction::LB: lb(instr); break; - case LH: + case Instruction::LH: lh(instr); break; - case LWL: + case Instruction::LWL: lwl(instr); break; - case LW: + case Instruction::LW: lw(instr); break; - case LBU: + case Instruction::LBU: lbu(instr); break; - case LHU: + case Instruction::LHU: lhu(instr); break; - case LWR: + case Instruction::LWR: lwr(instr); break; - case LWU: + case Instruction::LWU: lwu(instr); break; - case SB: + case Instruction::SB: sb(instr); break; - case SH: + case Instruction::SH: sh(instr); break; - case SWL: + case Instruction::SWL: swl(instr); break; - case SW: + case Instruction::SW: sw(instr); break; - case SDL: + case Instruction::SDL: sdl(instr); break; - case SDR: + case Instruction::SDR: sdr(instr); break; - case SWR: + case Instruction::SWR: swr(instr); break; - case CACHE: + case Instruction::CACHE: break; // CACHE - case LL: + case Instruction::LL: ll(instr); break; - case LWC1: + case Instruction::LWC1: lwc1(instr); break; - case LLD: + case Instruction::LLD: lld(instr); break; - case LDC1: + case Instruction::LDC1: ldc1(instr); break; - case LD: + case Instruction::LD: ld(instr); break; - case SC: + case Instruction::SC: sc(instr); break; - case SWC1: + case Instruction::SWC1: swc1(instr); break; - case SCD: + case Instruction::SCD: scd(instr); break; - case SDC1: + case Instruction::SDC1: sdc1(instr); break; - case SD: + case Instruction::SD: sd(instr); break; default: - panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})", mask, instr, static_cast(regs.oldPC)); + panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})", instr.opcode(), u32(instr), static_cast(regs.oldPC)); } } } // namespace n64 diff --git a/src/backend/core/jit/helpers.hpp b/src/backend/core/jit/helpers.hpp index ff0661e5..93d7b9f0 100644 --- a/src/backend/core/jit/helpers.hpp +++ b/src/backend/core/jit/helpers.hpp @@ -1,65 +1,63 @@ #pragma once -#include +#include namespace n64 { -static bool SpecialEndsBlock(const u32 instr) { - switch (instr & 0x3F) { - case JR: - case JALR: - case SYSCALL: - case BREAK: - case TGE: - case TGEU: - case TLT: - case TLTU: - case TEQ: - case TNE: +static bool SpecialEndsBlock(const Instruction instr) { + switch (instr.special()) { + case Instruction::JR: + case Instruction::JALR: + case Instruction::SYSCALL: + case Instruction::BREAK: + case Instruction::TGE: + case Instruction::TGEU: + case Instruction::TLT: + case Instruction::TLTU: + case Instruction::TEQ: + case Instruction::TNE: return true; default: return false; } } -static bool InstrEndsBlock(const u32 instr) { - switch (instr >> 26 & 0x3f) { - case SPECIAL: +static bool InstrEndsBlock(const Instruction instr) { + switch (instr.opcode()) { + case Instruction::SPECIAL: return SpecialEndsBlock(instr); - case REGIMM: - case J: - case JAL: - case BEQ: - case BNE: - case BLEZ: - case BGTZ: + case Instruction::REGIMM: + case Instruction::J: + case Instruction::JAL: + case Instruction::BEQ: + case Instruction::BNE: + case Instruction::BLEZ: + case Instruction::BGTZ: return true; default: return false; } } -static bool IsBranchLikely(const u32 instr) { - switch (instr >> 26 & 0x3F) { - case BEQL: - case BNEL: - case BLEZL: - case BGTZL: +static bool IsBranchLikely(const Instruction instr) { + switch (instr.opcode()) { + case Instruction::BEQL: + case Instruction::BNEL: + case Instruction::BLEZL: + case Instruction::BGTZL: return true; - case REGIMM: - switch (instr >> 16 & 0x1f) { - case BLTZL: - case BGEZL: - case BLTZALL: - case BGEZALL: + case Instruction::REGIMM: + switch (instr.regimm()) { + case Instruction::BLTZL: + case Instruction::BGEZL: + case Instruction::BLTZALL: + case Instruction::BGEZALL: return true; default: return false; } - case COP1: + case Instruction::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) + if (instr.cop_rs() == 0x08) { + if (instr.cop_rt() == 2 || instr.cop_rt() == 3) return true; return false; diff --git a/src/backend/core/jit/instructions.cpp b/src/backend/core/jit/instructions.cpp index 97bc9213..8a652a17 100644 --- a/src/backend/core/jit/instructions.cpp +++ b/src/backend/core/jit/instructions.cpp @@ -6,156 +6,156 @@ namespace n64 { using namespace Xbyak::util; -void JIT::lui(const u32 instr) { +void JIT::lui(const Instruction instr) { u64 val = static_cast(static_cast(instr)); val <<= 16; - regs.Write(RT(instr), val); + regs.Write(instr.rt(), val); } -void JIT::add(const u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - const u32 rs = regs.Read(RS(instr)); - const u32 rt = regs.Read(RT(instr)); +void JIT::add(const Instruction instr) { + if (regs.IsRegConstant(instr.rs(), instr.rt())) { + const u32 rs = regs.Read(instr.rs()); + const u32 rt = regs.Read(instr.rt()); const u32 result = rs + rt; if (check_signed_overflow(rs, rt, result)) { // regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); panic("[JIT]: Unhandled Overflow exception in ADD!"); } - regs.Write(RD(instr), result); + regs.Write(instr.rd(), result); return; } - if (regs.IsRegConstant(RS(instr))) { - const u32 rs = regs.Read(RS(instr)); - regs.Read(RT(instr), code.SCR1.cvt32()); + if (regs.IsRegConstant(instr.rs())) { + const u32 rs = regs.Read(instr.rs()); + regs.Read(instr.rt(), code.SCR1.cvt32()); code.add(code.SCR1.cvt32(), rs); - regs.Write(RD(instr), code.SCR1.cvt32()); + regs.Write(instr.rd(), code.SCR1.cvt32()); return; } - if (regs.IsRegConstant(RT(instr))) { - const u32 rt = regs.Read(RT(instr)); - regs.Read(RS(instr), code.SCR1.cvt32()); + if (regs.IsRegConstant(instr.rt())) { + const u32 rt = regs.Read(instr.rt()); + regs.Read(instr.rs(), code.SCR1.cvt32()); code.add(code.SCR1.cvt32(), rt); - regs.Write(RD(instr), code.SCR1.cvt32()); + regs.Write(instr.rd(), code.SCR1.cvt32()); return; } - regs.Read(RT(instr), code.SCR1.cvt32()); - regs.Read(RS(instr), code.SCR2.cvt32()); + regs.Read(instr.rt(), code.SCR1.cvt32()); + regs.Read(instr.rs(), code.SCR2.cvt32()); code.add(code.SCR1.cvt32(), code.SCR2.cvt32()); - regs.Write(RD(instr), code.SCR1.cvt32()); + regs.Write(instr.rd(), code.SCR1.cvt32()); } -void JIT::addu(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - const s32 rs = regs.Read(RS(instr)); - const s32 rt = regs.Read(RT(instr)); +void JIT::addu(const Instruction instr) { + if (regs.IsRegConstant(instr.rs(), instr.rt())) { + const s32 rs = regs.Read(instr.rs()); + const s32 rt = regs.Read(instr.rt()); const s32 result = rs + rt; - regs.Write(RD(instr), result); + regs.Write(instr.rd(), result); return; } - if (regs.IsRegConstant(RS(instr))) { - const s32 rs = regs.Read(RS(instr)); - regs.Read(RT(instr), code.SCR1.cvt32()); + if (regs.IsRegConstant(instr.rs())) { + const s32 rs = regs.Read(instr.rs()); + regs.Read(instr.rt(), code.SCR1.cvt32()); code.add(code.SCR1.cvt32(), rs); - regs.Write(RD(instr), code.SCR1.cvt32()); + regs.Write(instr.rd(), code.SCR1.cvt32()); return; } - if (regs.IsRegConstant(RT(instr))) { - const s32 rs = regs.Read(RT(instr)); - regs.Read(RS(instr), code.SCR1.cvt32()); + if (regs.IsRegConstant(instr.rt())) { + const s32 rs = regs.Read(instr.rt()); + regs.Read(instr.rs(), code.SCR1.cvt32()); code.add(code.SCR1.cvt32(), rs); - regs.Write(RD(instr), code.SCR1.cvt32()); + regs.Write(instr.rd(), code.SCR1.cvt32()); return; } - regs.Read(RS(instr), code.SCR1.cvt32()); - regs.Read(RT(instr), code.SCR2.cvt32()); + regs.Read(instr.rs(), code.SCR1.cvt32()); + regs.Read(instr.rt(), code.SCR2.cvt32()); code.add(code.SCR1.cvt32(), code.SCR2.cvt32()); - regs.Write(RD(instr), code.SCR1.cvt32()); + regs.Write(instr.rd(), code.SCR1.cvt32()); } -void JIT::addi(u32 instr) { +void JIT::addi(const Instruction instr) { u32 imm = s32(s16(instr)); - if (regs.IsRegConstant(RS(instr))) { - auto rs = regs.Read(RS(instr)); + if (regs.IsRegConstant(instr.rs())) { + auto rs = regs.Read(instr.rs()); u32 result = rs + imm; if (check_signed_overflow(rs, imm, result)) { panic("[JIT]: Unhandled Overflow exception in ADDI!"); } - regs.Write(RT(instr), static_cast(result)); + regs.Write(instr.rt(), static_cast(result)); return; } - regs.Read(RS(instr), code.SCR1.cvt32()); + regs.Read(instr.rs(), code.SCR1.cvt32()); code.add(code.eax, SCR1.cvt32()); - regs.Write(RT(instr), code.SCR1.cvt32()); + regs.Write(instr.rt(), code.SCR1.cvt32()); } -void JIT::addiu(u32 instr) { +void JIT::addiu(const Instruction instr) { u32 imm = s32(s16(instr)); - if (regs.IsRegConstant(RS(instr))) { - auto rs = regs.Read(RS(instr)); + if (regs.IsRegConstant(instr.rs())) { + auto rs = regs.Read(instr.rs()); u32 result = rs + imm; - regs.Write(RT(instr), s32(result)); + regs.Write(instr.rt(), s32(result)); return; } - regs.Read(RS(instr), code.SCR1.cvt32()); + regs.Read(instr.rs(), code.SCR1.cvt32()); code.add(code.SCR1.cvt32(), imm); - regs.Write(RT(instr), code.SCR1.cvt32()); + regs.Write(instr.rt(), code.SCR1.cvt32()); } -void JIT::andi(u32 instr) { +void JIT::andi(const Instruction instr) { const s64 imm = static_cast(instr); - if (regs.IsRegConstant(RS(instr))) { - regs.Write(RT(instr), regs.Read(RS(instr)) & imm); + if (regs.IsRegConstant(instr.rs())) { + regs.Write(instr.rt(), regs.Read(instr.rs()) & imm); return; } - regs.Read(RS(instr), code.SCR1); + regs.Read(instr.rs(), code.SCR1); code.and_(code.SCR1, imm); - regs.Write(RT(instr), code.SCR1); + regs.Write(instr.rt(), code.SCR1); } -void JIT::and_(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - regs.Write(RD(instr), regs.Read(RS(instr)) & regs.Read(RT(instr))); +void JIT::and_(const Instruction instr) { + if (regs.IsRegConstant(instr.rs(), instr.rt())) { + regs.Write(instr.rd(), regs.Read(instr.rs()) & regs.Read(instr.rt())); return; } - if (regs.IsRegConstant(RS(instr))) { - const auto rs = regs.Read(RS(instr)); - regs.Read(RT(instr), code.SCR1); + if (regs.IsRegConstant(instr.rs())) { + const auto rs = regs.Read(instr.rs()); + regs.Read(instr.rt(), code.SCR1); code.and_(code.SCR1, rs); - regs.Write(RD(instr), code.SCR1); + regs.Write(instr.rd(), code.SCR1); return; } - if (regs.IsRegConstant(RT(instr))) { - const auto rt = regs.Read(RT(instr)); - regs.Read(RS(instr), code.SCR1); + if (regs.IsRegConstant(instr.rt())) { + const auto rt = regs.Read(instr.rt()); + regs.Read(instr.rs(), code.SCR1); code.and_(code.SCR1, rt); - regs.Write(RD(instr), code.SCR1); + regs.Write(instr.rd(), code.SCR1); return; } - regs.Read(RS(instr), code.SCR1); - regs.Read(RT(instr), code.SCR2); + regs.Read(instr.rs(), code.SCR1); + regs.Read(instr.rt(), code.SCR2); code.and_(code.SCR2, code.SCR1); - regs.Write(RD(instr), code.SCR2); + regs.Write(instr.rd(), code.SCR2); } -void JIT::bfc0(u32 instr) { +void JIT::bfc0(const Instruction instr) { const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; const s64 address = blockPC + offset; @@ -164,7 +164,7 @@ void JIT::bfc0(u32 instr) { // branch(address, z); } -void JIT::blfc0(u32 instr) { +void JIT::blfc0(const Instruction instr) { const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; const s64 address = blockPC + offset; @@ -173,7 +173,7 @@ void JIT::blfc0(u32 instr) { // branch_likely(address, z); } -void JIT::bfc1(u32 instr) { +void JIT::bfc1(const Instruction instr) { const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; const s64 address = blockPC + offset; @@ -182,7 +182,7 @@ void JIT::bfc1(u32 instr) { // branch(address, nz); } -void JIT::blfc1(u32 instr) { +void JIT::blfc1(const Instruction instr) { const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; const s64 address = blockPC + offset; @@ -264,353 +264,353 @@ void JIT::branch_abs_constant(bool cond, s64 address) { SetPC64(blockNextPC); \ } while(0) -void JIT::bltz(const u32 instr) { +void JIT::bltz(const Instruction instr) { const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; - if (regs.IsRegConstant(RS(instr))) { - branch_constant(regs.Read(RS(instr)) < 0, offset); + if (regs.IsRegConstant(instr.rs())) { + branch_constant(regs.Read(instr.rs()) < 0, offset); return; } - regs.Read(RS(instr), code.rax); + regs.Read(instr.rs(), code.rax); code.cmp(code.rax, 0); branch(offset, l); } -void JIT::bgez(const u32 instr) { +void JIT::bgez(const Instruction instr) { const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; - if (regs.IsRegConstant(RS(instr))) { - branch_constant(regs.Read(RS(instr)) >= 0, offset); + if (regs.IsRegConstant(instr.rs())) { + branch_constant(regs.Read(instr.rs()) >= 0, offset); return; } - regs.Read(RS(instr), code.rax); + regs.Read(instr.rs(), code.rax); code.cmp(code.rax, 0); branch(offset, ge); } -void JIT::bltzl(const u32 instr) { +void JIT::bltzl(const Instruction instr) { panic("Implement branch likely < 0"); const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; - if (regs.IsRegConstant(RS(instr))) { - branch_likely_constant(regs.Read(RS(instr)) < 0, offset); + if (regs.IsRegConstant(instr.rs())) { + branch_likely_constant(regs.Read(instr.rs()) < 0, offset); return; } - regs.Read(RS(instr), code.rax); + regs.Read(instr.rs(), code.rax); code.cmp(code.rax, 0); branch_likely(offset, l); } -void JIT::bgezl(const u32 instr) { +void JIT::bgezl(const Instruction instr) { panic("Implement branch likely >= 0"); const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; - if (regs.IsRegConstant(RS(instr))) { - branch_likely_constant(regs.Read(RS(instr)) >= 0, offset); + if (regs.IsRegConstant(instr.rs())) { + branch_likely_constant(regs.Read(instr.rs()) >= 0, offset); return; } - regs.Read(RS(instr), code.rax); + regs.Read(instr.rs(), code.rax); code.cmp(code.rax, 0); branch_likely(offset, ge); } -void JIT::bltzal(const u32 instr) { +void JIT::bltzal(const Instruction instr) { const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; regs.Write(31, blockNextPC); - if (regs.IsRegConstant(RS(instr))) { - branch_constant(regs.Read(RS(instr)) < 0, offset); + if (regs.IsRegConstant(instr.rs())) { + branch_constant(regs.Read(instr.rs()) < 0, offset); return; } - regs.Read(RS(instr), code.rax); + regs.Read(instr.rs(), code.rax); code.cmp(code.rax, 0); branch(offset, l); } -void JIT::bgezal(const u32 instr) { +void JIT::bgezal(const Instruction instr) { const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; regs.Write(31, blockNextPC); - if (regs.IsRegConstant(RS(instr))) { - branch_constant(regs.Read(RS(instr)) >= 0, offset); + if (regs.IsRegConstant(instr.rs())) { + branch_constant(regs.Read(instr.rs()) >= 0, offset); return; } - regs.Read(RS(instr), code.rax); + regs.Read(instr.rs(), code.rax); code.cmp(code.rax, 0); branch(offset, ge); } -void JIT::bltzall(const u32 instr) { +void JIT::bltzall(const Instruction instr) { panic("Implement branch likely and link < 0"); const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; regs.Write(31, blockNextPC); - if (regs.IsRegConstant(RS(instr))) { - branch_likely_constant(regs.Read(RS(instr)) < 0, offset); + if (regs.IsRegConstant(instr.rs())) { + branch_likely_constant(regs.Read(instr.rs()) < 0, offset); return; } - regs.Read(RS(instr), code.rax); + regs.Read(instr.rs(), code.rax); code.cmp(code.rax, 0); branch_likely(offset, l); } -void JIT::bgezall(const u32 instr) { +void JIT::bgezall(const Instruction instr) { panic("Implement branch likely and link >= 0"); const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; regs.Write(31, blockNextPC); - if (regs.IsRegConstant(RS(instr))) { - branch_likely_constant(regs.Read(RS(instr)) >= 0, offset); + if (regs.IsRegConstant(instr.rs())) { + branch_likely_constant(regs.Read(instr.rs()) >= 0, offset); return; } - regs.Read(RS(instr), code.rax); + regs.Read(instr.rs(), code.rax); code.cmp(code.rax, 0); branch_likely(offset, ge); } -void JIT::beq(const u32 instr) { +void JIT::beq(const Instruction 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); + if (regs.IsRegConstant(instr.rs()) && regs.IsRegConstant(instr.rt())) { + branch_constant(regs.Read(instr.rs()) == regs.Read(instr.rt()), offset); return; } - if (regs.IsRegConstant(RS(instr))) { - regs.Read(RT(instr), code.rax); - code.cmp(code.rax, regs.Read(RS(instr))); + if (regs.IsRegConstant(instr.rs())) { + regs.Read(instr.rt(), code.rax); + code.cmp(code.rax, regs.Read(instr.rs())); branch(offset, e); return; } - if (regs.IsRegConstant(RT(instr))) { - regs.Read(RS(instr), code.rax); - code.cmp(code.rax, regs.Read(RT(instr))); + if (regs.IsRegConstant(instr.rt())) { + regs.Read(instr.rs(), code.rax); + code.cmp(code.rax, regs.Read(instr.rt())); branch(offset, e); return; } - regs.Read(RS(instr), code.rax); - regs.Read(RT(instr), code.rdi); + regs.Read(instr.rs(), code.rax); + regs.Read(instr.rt(), code.rdi); code.cmp(code.rax, code.rdi); branch(offset, e); } -void JIT::beql(const u32 instr) { +void JIT::beql(const Instruction instr) { panic("Implement branch likely =="); 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); + if (regs.IsRegConstant(instr.rs()) && regs.IsRegConstant(instr.rt())) { + branch_likely_constant(regs.Read(instr.rs()) == regs.Read(instr.rt()), offset); return; } - if (regs.IsRegConstant(RS(instr))) { - regs.Read(RT(instr), code.rax); - code.cmp(code.rax, regs.Read(RS(instr))); + if (regs.IsRegConstant(instr.rs())) { + regs.Read(instr.rt(), code.rax); + code.cmp(code.rax, regs.Read(instr.rs())); branch_likely(offset, e); return; } - if (regs.IsRegConstant(RT(instr))) { - regs.Read(RS(instr), code.rax); - code.cmp(code.rax, regs.Read(RT(instr))); + if (regs.IsRegConstant(instr.rt())) { + regs.Read(instr.rs(), code.rax); + code.cmp(code.rax, regs.Read(instr.rt())); branch_likely(offset, e); return; } - regs.Read(RS(instr), code.rax); - regs.Read(RT(instr), code.rdi); + regs.Read(instr.rs(), code.rax); + regs.Read(instr.rt(), code.rdi); code.cmp(code.rax, code.rdi); branch_likely(offset, e); } -void JIT::bne(const u32 instr) { +void JIT::bne(const Instruction 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); + if (regs.IsRegConstant(instr.rs()) && regs.IsRegConstant(instr.rt())) { + branch_constant(regs.Read(instr.rs()) != regs.Read(instr.rt()), offset); return; } - if (regs.IsRegConstant(RS(instr))) { - regs.Read(RT(instr), code.rax); - code.cmp(code.rax, regs.Read(RS(instr))); + if (regs.IsRegConstant(instr.rs())) { + regs.Read(instr.rt(), code.rax); + code.cmp(code.rax, regs.Read(instr.rs())); branch(offset, ne); return; } - if (regs.IsRegConstant(RT(instr))) { - regs.Read(RS(instr), code.rax); - code.cmp(code.rax, regs.Read(RT(instr))); + if (regs.IsRegConstant(instr.rt())) { + regs.Read(instr.rs(), code.rax); + code.cmp(code.rax, regs.Read(instr.rt())); branch(offset, ne); return; } - regs.Read(RS(instr), code.rax); - regs.Read(RT(instr), code.rdi); + regs.Read(instr.rs(), code.rax); + regs.Read(instr.rt(), code.rdi); code.cmp(code.rax, code.rdi); branch(offset, ne); } -void JIT::bnel(const u32 instr) { +void JIT::bnel(const Instruction instr) { panic("Implement branch likely !="); 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); + if (regs.IsRegConstant(instr.rs()) && regs.IsRegConstant(instr.rt())) { + branch_likely_constant(regs.Read(instr.rs()) != regs.Read(instr.rt()), offset); return; } - if (regs.IsRegConstant(RS(instr))) { - regs.Read(RT(instr), code.rax); - code.cmp(code.rax, regs.Read(RS(instr))); + if (regs.IsRegConstant(instr.rs())) { + regs.Read(instr.rt(), code.rax); + code.cmp(code.rax, regs.Read(instr.rs())); branch_likely(offset, ne); return; } - if (regs.IsRegConstant(RT(instr))) { - regs.Read(RS(instr), code.rax); - code.cmp(code.rax, regs.Read(RT(instr))); + if (regs.IsRegConstant(instr.rt())) { + regs.Read(instr.rs(), code.rax); + code.cmp(code.rax, regs.Read(instr.rt())); branch_likely(offset, ne); return; } - regs.Read(RS(instr), code.rax); - regs.Read(RT(instr), code.rdi); + regs.Read(instr.rs(), code.rax); + regs.Read(instr.rt(), code.rdi); code.cmp(code.rax, code.rdi); branch_likely(offset, ne); } -void JIT::blez(const u32 instr) { +void JIT::blez(const Instruction instr) { const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; - if (regs.IsRegConstant(RS(instr))) { - branch_constant(regs.Read(RS(instr)) <= 0, offset); + if (regs.IsRegConstant(instr.rs())) { + branch_constant(regs.Read(instr.rs()) <= 0, offset); return; } - regs.Read(RS(instr), code.rax); + regs.Read(instr.rs(), code.rax); code.cmp(code.rax, 0); branch(offset, le); } -void JIT::blezl(const u32 instr) { +void JIT::blezl(const Instruction instr) { panic("Implement branch likely <= 0"); const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; - if (regs.IsRegConstant(RS(instr))) { - branch_likely_constant(regs.Read(RS(instr)) <= 0, offset); + if (regs.IsRegConstant(instr.rs())) { + branch_likely_constant(regs.Read(instr.rs()) <= 0, offset); return; } - regs.Read(RS(instr), code.rax); + regs.Read(instr.rs(), code.rax); code.cmp(code.rax, 0); branch_likely(offset, le); } -void JIT::bgtz(const u32 instr) { +void JIT::bgtz(const Instruction instr) { const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; - if (regs.IsRegConstant(RS(instr))) { - branch_constant(regs.Read(RS(instr)) > 0, offset); + if (regs.IsRegConstant(instr.rs())) { + branch_constant(regs.Read(instr.rs()) > 0, offset); return; } - regs.Read(RS(instr), code.rax); + regs.Read(instr.rs(), code.rax); code.cmp(code.rax, 0); branch(offset, g); } -void JIT::bgtzl(const u32 instr) { +void JIT::bgtzl(const Instruction instr) { panic("Implement branch likely > 0"); const s16 imm = instr; const s64 offset = u64((s64)imm) << 2; - if (regs.IsRegConstant(RS(instr))) { - branch_likely_constant(regs.Read(RS(instr)) > 0, offset); + if (regs.IsRegConstant(instr.rs())) { + branch_likely_constant(regs.Read(instr.rs()) > 0, offset); return; } - regs.Read(RS(instr), code.rax); + regs.Read(instr.rs(), code.rax); code.cmp(code.rax, 0); branch_likely(offset, g); } -void JIT::dadd(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - auto rs = regs.Read(RS(instr)); - auto rt = regs.Read(RT(instr)); +void JIT::dadd(const Instruction instr) { + if (regs.IsRegConstant(instr.rs(), instr.rt())) { + auto rs = regs.Read(instr.rs()); + auto rt = regs.Read(instr.rt()); u64 result = rt + rs; if (check_signed_overflow(rs, rt, result)) { // regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); panic("[JIT]: Unhandled Overflow exception in DADD!"); } - regs.Write(RD(instr), result); + regs.Write(instr.rd(), result); return; } - if (regs.IsRegConstant(RS(instr))) { - auto rs = regs.Read(RS(instr)); - regs.Read(RT(instr), code.SCR1); + if (regs.IsRegConstant(instr.rs())) { + auto rs = regs.Read(instr.rs()); + regs.Read(instr.rt(), code.SCR1); code.add(code.SCR1, rs); - regs.Write(RD(instr), code.SCR1); + regs.Write(instr.rd(), code.SCR1); return; } - if (regs.IsRegConstant(RT(instr))) { - auto rt = regs.Read(RT(instr)); - regs.Read(RS(instr), code.SCR1); + if (regs.IsRegConstant(instr.rt())) { + auto rt = regs.Read(instr.rt()); + regs.Read(instr.rs(), code.SCR1); code.add(code.SCR1, rt); - regs.Write(RD(instr), code.SCR1); + regs.Write(instr.rd(), code.SCR1); return; } - regs.Read(RS(instr), code.SCR1); - regs.Read(RT(instr), code.SCR2); + regs.Read(instr.rs(), code.SCR1); + regs.Read(instr.rt(), code.SCR2); code.add(code.SCR1, code.SCR2); - regs.Write(RD(instr), code.SCR1); + regs.Write(instr.rd(), code.SCR1); } -void JIT::daddu(u32 instr) { +void JIT::daddu(const Instruction instr) { // TODO: IMPLEMENT DADDU BY ITSELF ACTUALLY dadd(instr); } -void JIT::daddi(u32 instr) { +void JIT::daddi(const Instruction instr) { u64 imm = s64(s16(instr)); - if (regs.IsRegConstant(RS(instr))) { - auto rs = regs.Read(RS(instr)); + if (regs.IsRegConstant(instr.rs())) { + auto rs = regs.Read(instr.rs()); u64 result = imm + rs; if (check_signed_overflow(rs, imm, result)) { // regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); panic("[JIT]: Unhandled Overflow exception in DADDI!"); } - regs.Write(RT(instr), result); + regs.Write(instr.rt(), result); return; } - regs.Read(RS(instr), code.SCR1); + regs.Read(instr.rs(), code.SCR1); code.add(code.SCR1, imm); - regs.Write(RT(instr), code.SCR1); + regs.Write(instr.rt(), code.SCR1); } -void JIT::daddiu(u32 instr) { +void JIT::daddiu(const Instruction instr) { // TODO: IMPLEMENT DADDIU BY ITSELF ACTUALLY daddi(instr); } -void JIT::ddiv(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - auto dividend = regs.Read(RS(instr)); - auto divisor = regs.Read(RT(instr)); +void JIT::ddiv(const Instruction instr) { + if (regs.IsRegConstant(instr.rs(), instr.rt())) { + auto dividend = regs.Read(instr.rs()); + auto divisor = regs.Read(instr.rt()); if (dividend == 0x8000000000000000 && divisor == 0xFFFFFFFFFFFFFFFF) { regs.lo = dividend; regs.hi = 0; @@ -635,10 +635,10 @@ void JIT::ddiv(u32 instr) { } } -void JIT::ddivu(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - auto dividend = regs.Read(RS(instr)); - auto divisor = regs.Read(RT(instr)); +void JIT::ddivu(const Instruction instr) { + if (regs.IsRegConstant(instr.rs(), instr.rt())) { + auto dividend = regs.Read(instr.rs()); + auto divisor = regs.Read(instr.rt()); if (divisor == 0) { regs.lo = -1; regs.hi = (s64)dividend; @@ -656,10 +656,10 @@ void JIT::ddivu(u32 instr) { } } -void JIT::div(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - s64 dividend = regs.Read(RS(instr)); - s64 divisor = regs.Read(RT(instr)); +void JIT::div(const Instruction instr) { + if (regs.IsRegConstant(instr.rs(), instr.rt())) { + s64 dividend = regs.Read(instr.rs()); + s64 divisor = regs.Read(instr.rt()); if (divisor == 0) { regs.hi = dividend; @@ -682,10 +682,10 @@ void JIT::div(u32 instr) { } } -void JIT::divu(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - auto dividend = regs.Read(RS(instr)); - auto divisor = regs.Read(RT(instr)); +void JIT::divu(const Instruction instr) { + if (regs.IsRegConstant(instr.rs(), instr.rt())) { + auto dividend = regs.Read(instr.rs()); + auto divisor = regs.Read(instr.rt()); if (divisor == 0) { regs.lo = -1; regs.hi = (s32)dividend; @@ -703,10 +703,10 @@ void JIT::divu(u32 instr) { } } -void JIT::dmult(u32 instr) { - if (regs.IsRegConstant(RT(instr), RS(instr))) { - auto rt = regs.Read(RT(instr)); - auto rs = regs.Read(RS(instr)); +void JIT::dmult(const Instruction instr) { + if (regs.IsRegConstant(instr.rt(), instr.rs())) { + auto rt = regs.Read(instr.rt()); + auto rs = regs.Read(instr.rs()); s128 result = (s128)rt * (s128)rs; regs.lo = result & 0xFFFFFFFFFFFFFFFF; regs.hi = result >> 64; @@ -717,10 +717,10 @@ void JIT::dmult(u32 instr) { } } -void JIT::dmultu(u32 instr) { - if (regs.IsRegConstant(RT(instr), RS(instr))) { - auto rt = regs.Read(RT(instr)); - auto rs = regs.Read(RS(instr)); +void JIT::dmultu(const Instruction instr) { + if (regs.IsRegConstant(instr.rt(), instr.rs())) { + auto rt = regs.Read(instr.rt()); + auto rs = regs.Read(instr.rs()); u128 result = (u128)rt * (u128)rs; regs.lo = s64(result & 0xFFFFFFFFFFFFFFFF); regs.hi = s64(result >> 64); @@ -731,160 +731,160 @@ void JIT::dmultu(u32 instr) { } } -void JIT::dsll(u32 instr) { - if (regs.IsRegConstant(RT(instr))) { +void JIT::dsll(const Instruction instr) { + if (regs.IsRegConstant(instr.rt())) { u8 sa = ((instr >> 6) & 0x1f); - auto result = regs.Read(RT(instr)) << sa; - regs.Write(RD(instr), result); + auto result = regs.Read(instr.rt()) << sa; + regs.Write(instr.rd(), result); } else { panic("[JIT]: Implement non constant DSLL!"); } } -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); +void JIT::dsllv(const Instruction instr) { + if (regs.IsRegConstant(instr.rt(), instr.rs())) { + auto sa = regs.Read(instr.rs()) & 63; + auto result = regs.Read(instr.rt()) << sa; + regs.Write(instr.rd(), result); } else { panic("[JIT]: Implement non constant DSLLV!"); } } -void JIT::dsll32(u32 instr) { - if (regs.IsRegConstant(RT(instr))) { +void JIT::dsll32(const Instruction instr) { + if (regs.IsRegConstant(instr.rt())) { u8 sa = ((instr >> 6) & 0x1f); - auto result = regs.Read(RT(instr)) << (sa + 32); - regs.Write(RD(instr), result); + auto result = regs.Read(instr.rt()) << (sa + 32); + regs.Write(instr.rd(), result); } else { panic("[JIT]: Implement non constant DSLL32!"); } } -void JIT::dsra(u32 instr) { - if (regs.IsRegConstant(RT(instr))) { - auto rt = regs.Read(RT(instr)); +void JIT::dsra(const Instruction instr) { + if (regs.IsRegConstant(instr.rt())) { + auto rt = regs.Read(instr.rt()); u8 sa = ((instr >> 6) & 0x1f); s64 result = rt >> sa; - regs.Write(RD(instr), result); + regs.Write(instr.rd(), result); } else { panic("[JIT]: Implement non constant DSRA!"); } } -void JIT::dsrav(u32 instr) { - if (regs.IsRegConstant(RT(instr), RS(instr))) { - auto rt = regs.Read(RT(instr)); - auto rs = regs.Read(RS(instr)); +void JIT::dsrav(const Instruction instr) { + if (regs.IsRegConstant(instr.rt(), instr.rs())) { + auto rt = regs.Read(instr.rt()); + auto rs = regs.Read(instr.rs()); s64 sa = rs & 63; s64 result = rt >> sa; - regs.Write(RD(instr), result); + regs.Write(instr.rd(), result); } else { panic("[JIT]: Implement non constant DSRAV!"); } } -void JIT::dsra32(u32 instr) { - if (regs.IsRegConstant(RT(instr))) { - auto rt = regs.Read(RT(instr)); +void JIT::dsra32(const Instruction instr) { + if (regs.IsRegConstant(instr.rt())) { + auto rt = regs.Read(instr.rt()); u8 sa = ((instr >> 6) & 0x1f); s64 result = rt >> (sa + 32); - regs.Write(RD(instr), result); + regs.Write(instr.rd(), result); } else { panic("[JIT]: Implement non constant DSRA32!"); } } -void JIT::dsrl(u32 instr) { - if (regs.IsRegConstant(RT(instr))) { - auto rt = regs.Read(RT(instr)); +void JIT::dsrl(const Instruction instr) { + if (regs.IsRegConstant(instr.rt())) { + auto rt = regs.Read(instr.rt()); u8 sa = ((instr >> 6) & 0x1f); u64 result = rt >> sa; - regs.Write(RD(instr), s64(result)); + regs.Write(instr.rd(), s64(result)); } else { panic("[JIT]: Implement non constant DSRL!"); } } -void JIT::dsrlv(u32 instr) { - if (regs.IsRegConstant(RT(instr), RS(instr))) { - u8 amount = regs.Read(RS(instr)) & 63; - auto rt = regs.Read(RT(instr)); +void JIT::dsrlv(const Instruction instr) { + if (regs.IsRegConstant(instr.rt(), instr.rs())) { + u8 amount = regs.Read(instr.rs()) & 63; + auto rt = regs.Read(instr.rt()); u64 result = rt >> amount; - regs.Write(RD(instr), s64(result)); + regs.Write(instr.rd(), s64(result)); } else { panic("[JIT]: Implement non constant DSRLV!"); } } -void JIT::dsrl32(u32 instr) { - if (regs.IsRegConstant(RT(instr))) { - auto rt = regs.Read(RT(instr)); +void JIT::dsrl32(const Instruction instr) { + if (regs.IsRegConstant(instr.rt())) { + auto rt = regs.Read(instr.rt()); u8 sa = ((instr >> 6) & 0x1f); u64 result = rt >> (sa + 32); - regs.Write(RD(instr), s64(result)); + regs.Write(instr.rd(), s64(result)); } else { panic("[JIT]: Implement non constant DSRL32!"); } } -void JIT::dsub(u32 instr) { - if (regs.IsRegConstant(RT(instr), RS(instr))) { - auto rt = regs.Read(RT(instr)); - auto rs = regs.Read(RS(instr)); +void JIT::dsub(const Instruction instr) { + if (regs.IsRegConstant(instr.rt(), instr.rs())) { + auto rt = regs.Read(instr.rt()); + auto rs = regs.Read(instr.rs()); s64 result = rs - rt; if (check_signed_underflow(rs, rt, result)) { // regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); panic("[JIT]: Unhandled Overflow exception in DSUB!"); } else { - regs.Write(RD(instr), result); + regs.Write(instr.rd(), result); } } else { panic("[JIT]: Implement non constant DSUB!"); } } -void JIT::dsubu(u32 instr) { - if (regs.IsRegConstant(RT(instr), RS(instr))) { - auto rt = regs.Read(RT(instr)); - auto rs = regs.Read(RS(instr)); +void JIT::dsubu(const Instruction instr) { + if (regs.IsRegConstant(instr.rt(), instr.rs())) { + auto rt = regs.Read(instr.rt()); + auto rs = regs.Read(instr.rs()); s64 result = rs - rt; - regs.Write(RD(instr), result); + regs.Write(instr.rd(), result); } else { panic("[JIT]: Implement non constant DSUBU!"); } } -void JIT::j(const u32 instr) { +void JIT::j(const Instruction instr) { const s32 target = (instr & 0x3ffffff) << 2; const s64 address = (blockOldPC & ~0xfffffff) | target; branch_abs_constant(true, address); } -void JIT::jr(const u32 instr) { - if (regs.IsRegConstant(RS(instr))) { - const u64 address = regs.Read(RS(instr)); +void JIT::jr(const Instruction instr) { + if (regs.IsRegConstant(instr.rs())) { + const u64 address = regs.Read(instr.rs()); branch_abs_constant(true, address); return; } - regs.Read(RS(instr), code.rax); + regs.Read(instr.rs(), code.rax); branch_abs(code.rax, mp); } -void JIT::jal(const u32 instr) { +void JIT::jal(const Instruction instr) { regs.Write(31, blockNextPC); j(instr); } -void JIT::jalr(const u32 instr) { - regs.Write(RD(instr), blockNextPC); +void JIT::jalr(const Instruction instr) { + regs.Write(instr.rd(), blockNextPC); jr(instr); } -void JIT::lbu(u32 instr) { - if (regs.IsRegConstant(RS(instr))) { - const u64 address = regs.Read(RS(instr)) + (s16)instr; +void JIT::lbu(const Instruction instr) { + if (regs.IsRegConstant(instr.rs())) { + const u64 address = regs.Read(instr.rs()) + (s16)instr; u32 paddr; if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { // regs.cop0.HandleTLBException(address); @@ -895,16 +895,16 @@ void JIT::lbu(u32 instr) { code.ptr[code.rbp + (reinterpret_cast(®s) - reinterpret_cast(this))]); code.mov(code.ARG3, paddr); emitMemberFunctionCall(&Mem::Read, &mem); - regs.Write(RT(instr), code.rax); + regs.Write(instr.rt(), code.rax); } } else { panic("[JIT]: Implement non constant LBU!"); } } -void JIT::lb(u32 instr) { - if (regs.IsRegConstant(RS(instr))) { - const u64 address = regs.Read(RS(instr)) + (s16)instr; +void JIT::lb(const Instruction instr) { + if (regs.IsRegConstant(instr.rs())) { + const u64 address = regs.Read(instr.rs()) + (s16)instr; if (u32 paddr = 0; !regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { // regs.cop0.HandleTLBException(address); // regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC); @@ -914,16 +914,16 @@ void JIT::lb(u32 instr) { code.ptr[code.rbp + (reinterpret_cast(®s) - reinterpret_cast(this))]); code.mov(code.ARG3, paddr); emitMemberFunctionCall(&Mem::Read, &mem); - regs.Write(RT(instr), code.rax); + regs.Write(instr.rt(), code.rax); } } else { panic("[JIT]: Implement non constant LB!"); } } -void JIT::ld(u32 instr) { - if (regs.IsRegConstant(RS(instr))) { - const s64 address = regs.Read(RS(instr)) + (s16)instr; +void JIT::ld(const Instruction instr) { + if (regs.IsRegConstant(instr.rs())) { + const s64 address = regs.Read(instr.rs()) + (s16)instr; if (check_address_error(0b111, address)) { // regs.cop0.HandleTLBException(address); // regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC); @@ -941,14 +941,14 @@ void JIT::ld(u32 instr) { code.ptr[code.rbp + (reinterpret_cast(®s) - reinterpret_cast(this))]); code.mov(code.ARG3, paddr); emitMemberFunctionCall(&Mem::Read, &mem); - regs.Write(RT(instr), code.rax); + regs.Write(instr.rt(), code.rax); } } else { panic("[JIT]: Implement non constant LD!"); } } -void JIT::ldc1(u32 instr) { +void JIT::ldc1(const Instruction instr) { if (regs.IsRegConstant(BASE(instr))) { const u64 addr = static_cast(static_cast(instr)) + regs.Read(BASE(instr)); @@ -966,9 +966,9 @@ void JIT::ldc1(u32 instr) { } } -void JIT::ldl(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - const u64 address = regs.Read(RS(instr)) + (s16)instr; +void JIT::ldl(const Instruction instr) { + if (regs.IsRegConstant(instr.rs(), instr.rt())) { + const u64 address = regs.Read(instr.rs()) + (s16)instr; u32 paddr = 0; if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { // regs.cop0.HandleTLBException(address); @@ -979,17 +979,17 @@ void JIT::ldl(u32 instr) { const s32 shift = 8 * ((address ^ 0) & 7); const u64 mask = 0xFFFFFFFFFFFFFFFF << shift; const u64 data = mem.Read(paddr & ~7); - const s64 result = (s64)((regs.Read(RT(instr)) & ~mask) | (data << shift)); - regs.Write(RT(instr), result); + const s64 result = (s64)((regs.Read(instr.rt()) & ~mask) | (data << shift)); + regs.Write(instr.rt(), result); } } else { panic("[JIT]: Implement non constant LDL!"); } } -void JIT::ldr(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - const u64 address = regs.Read(RS(instr)) + (s16)instr; +void JIT::ldr(const Instruction instr) { + if (regs.IsRegConstant(instr.rs(), instr.rt())) { + const u64 address = regs.Read(instr.rs()) + (s16)instr; u32 paddr; if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { // regs.cop0.HandleTLBException(address); @@ -999,17 +999,17 @@ void JIT::ldr(u32 instr) { const s32 shift = 8 * ((address ^ 7) & 7); const u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; const u64 data = mem.Read(paddr & ~7); - const s64 result = (s64)((regs.Read(RT(instr)) & ~mask) | (data >> shift)); - regs.Write(RT(instr), result); + const s64 result = (s64)((regs.Read(instr.rt()) & ~mask) | (data >> shift)); + regs.Write(instr.rt(), result); } } else { panic("[JIT]: Implement non constant LDR!"); } } -void JIT::lh(u32 instr) { - if (regs.IsRegConstant(RS(instr))) { - const u64 address = regs.Read(RS(instr)) + (s16)instr; +void JIT::lh(const Instruction instr) { + if (regs.IsRegConstant(instr.rs())) { + const u64 address = regs.Read(instr.rs()) + (s16)instr; if (check_address_error(0b1, address)) { // regs.cop0.HandleTLBException(address); // regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC); @@ -1029,17 +1029,17 @@ void JIT::lh(u32 instr) { code.mov(code.ARG2, code.ptr[code.rbp + (reinterpret_cast(®s) - reinterpret_cast(this))]); code.mov(code.ARG3, paddr); emitMemberFunctionCall(&Mem::Read, &mem); - regs.Write(RT(instr), code.rax); + regs.Write(instr.rt(), code.rax); return; } panic("[JIT]: Implement non constant LH!"); } -void JIT::lhu(u32 instr) { +void JIT::lhu(const Instruction instr) { u32 paddr; - if (regs.IsRegConstant(RS(instr))) { - const s64 address = regs.Read(RS(instr)) + (s16)instr; + if (regs.IsRegConstant(instr.rs())) { + const s64 address = regs.Read(instr.rs()) + (s16)instr; if (check_address_error(0b1, address)) { regs.cop0.HandleTLBException(address); regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC); @@ -1055,11 +1055,11 @@ void JIT::lhu(u32 instr) { code.mov(code.ARG2, code.ptr[code.rbp + (reinterpret_cast(®s) - reinterpret_cast(this))]); code.mov(code.ARG3, paddr); emitMemberFunctionCall(&Mem::Read, &mem); - regs.Write(RT(instr), code.rax); + regs.Write(instr.rt(), code.rax); } code.mov(code.ARG2, Cop0::LOAD); - regs.Read(RS(instr), code.ARG3); + regs.Read(instr.rs(), code.ARG3); code.add(code.ARG3, s16(instr)); code.mov(code.ARG4, reinterpret_cast(&paddr)); emitMemberFunctionCall(&Cop0::MapVAddr, ®s.cop0); @@ -1067,18 +1067,18 @@ void JIT::lhu(u32 instr) { code.mov(code.ARG2, code.ptr[code.rbp + (reinterpret_cast(®s) - reinterpret_cast(this))]); code.mov(code.ARG3, code.qword[code.ARG4]); emitMemberFunctionCall(&Mem::Read, &mem); - regs.Write(RT(instr), code.rax); + regs.Write(instr.rt(), code.rax); } -void JIT::ll(u32) { panic("[JIT]: Implement constant LL!"); } +void JIT::ll(const Instruction) { panic("[JIT]: Implement constant LL!"); } -void JIT::lld(u32) { panic("[JIT]: Implement constant LLD!"); } +void JIT::lld(const Instruction) { panic("[JIT]: Implement constant LLD!"); } -void JIT::lw(u32 instr) { +void JIT::lw(const Instruction instr) { const s16 offset = instr; u32 paddr = 0; - if (regs.IsRegConstant(RS(instr))) { - const u64 address = regs.Read(RS(instr)) + offset; + if (regs.IsRegConstant(instr.rs())) { + const u64 address = regs.Read(instr.rs()) + offset; if (check_address_error(0b11, address)) { // regs.cop0.HandleTLBException(address); // regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC); @@ -1097,13 +1097,13 @@ void JIT::lw(u32 instr) { code.mov(code.ARG2, code.ptr[code.rbp + (reinterpret_cast(®s) - reinterpret_cast(this))]); code.mov(code.ARG3, paddr); emitMemberFunctionCall(&Mem::Read, &mem); - regs.Write(RT(instr), code.rax); + regs.Write(instr.rt(), code.rax); return; } code.mov(code.ARG2, Cop0::LOAD); - regs.Read(RS(instr), code.ARG3); + regs.Read(instr.rs(), code.ARG3); code.add(code.ARG3, offset); code.mov(code.ARG4, reinterpret_cast(&paddr)); @@ -1112,39 +1112,39 @@ void JIT::lw(u32 instr) { code.mov(code.ARG2, code.ptr[code.rbp + (reinterpret_cast(®s) - reinterpret_cast(this))]); code.mov(code.ARG3, code.qword[code.ARG4]); emitMemberFunctionCall(&Mem::Read, &mem); - regs.Write(RT(instr), code.rax); + regs.Write(instr.rt(), code.rax); } -void JIT::lwc1(u32) { panic("[JIT]: Implement constant LWC1!"); } +void JIT::lwc1(const Instruction) { panic("[JIT]: Implement constant LWC1!"); } -void JIT::lwl(u32) { panic("[JIT]: Implement constant LWL!"); } +void JIT::lwl(const Instruction) { panic("[JIT]: Implement constant LWL!"); } -void JIT::lwu(u32) { panic("[JIT]: Implement constant LWU!"); } +void JIT::lwu(const Instruction) { panic("[JIT]: Implement constant LWU!"); } -void JIT::lwr(u32) { panic("[JIT]: Implement constant LWR!"); } +void JIT::lwr(const Instruction) { panic("[JIT]: Implement constant LWR!"); } -void JIT::mfhi(u32 instr) { +void JIT::mfhi(const Instruction instr) { if (regs.GetHIConstant()) { - regs.Write(RD(instr), regs.hi); + regs.Write(instr.rd(), regs.hi); } else { code.mov(code.SCR1, REG(qword, hi)); - regs.Write(RD(instr), code.SCR1); + regs.Write(instr.rd(), code.SCR1); } } -void JIT::mflo(u32 instr) { +void JIT::mflo(const Instruction instr) { if (regs.GetLOConstant()) { - regs.Write(RD(instr), regs.lo); + regs.Write(instr.rd(), regs.lo); } else { code.mov(code.SCR1, REG(qword, lo)); - regs.Write(RD(instr), code.SCR1); + regs.Write(instr.rd(), code.SCR1); } } -void JIT::mult(u32 instr) { - if (regs.IsRegConstant(RT(instr), RS(instr))) { - auto rt = regs.Read(RT(instr)); - auto rs = regs.Read(RS(instr)); +void JIT::mult(const Instruction instr) { + if (regs.IsRegConstant(instr.rt(), instr.rs())) { + auto rt = regs.Read(instr.rt()); + auto rs = regs.Read(instr.rs()); s64 result = (s64)rt * (s64)rs; regs.lo = (s64)((s32)result); regs.SetLOConstant(); @@ -1155,10 +1155,10 @@ void JIT::mult(u32 instr) { } } -void JIT::multu(u32 instr) { - if (regs.IsRegConstant(RT(instr), RS(instr))) { - auto rt = regs.Read(RT(instr)); - auto rs = regs.Read(RS(instr)); +void JIT::multu(const Instruction instr) { + if (regs.IsRegConstant(instr.rt(), instr.rs())) { + auto rt = regs.Read(instr.rt()); + auto rs = regs.Read(instr.rs()); u64 result = (u64)rt * (u64)rs; regs.lo = (s64)((s32)result); regs.SetLOConstant(); @@ -1169,182 +1169,182 @@ void JIT::multu(u32 instr) { } } -void JIT::mthi(u32 instr) { - if (regs.IsRegConstant(RS(instr))) { - regs.hi = regs.Read(RS(instr)); +void JIT::mthi(const Instruction instr) { + if (regs.IsRegConstant(instr.rs())) { + regs.hi = regs.Read(instr.rs()); regs.SetHIConstant(); } else { - regs.Read(RS(instr), code.SCR1); + regs.Read(instr.rs(), code.SCR1); code.mov(REG(qword, hi), code.SCR1); regs.UnsetHIConstant(); } } -void JIT::mtlo(u32 instr) { - if (regs.IsRegConstant(RS(instr))) { - regs.lo = regs.Read(RS(instr)); +void JIT::mtlo(const Instruction instr) { + if (regs.IsRegConstant(instr.rs())) { + regs.lo = regs.Read(instr.rs()); regs.SetLOConstant(); } else { - regs.Read(RS(instr), code.SCR1); + regs.Read(instr.rs(), code.SCR1); code.mov(REG(qword, lo), code.SCR1); regs.UnsetLOConstant(); } } -void JIT::nor(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - regs.Write(RD(instr), ~(regs.Read(RS(instr)) | regs.Read(RT(instr)))); +void JIT::nor(const Instruction instr) { + if (regs.IsRegConstant(instr.rs(), instr.rt())) { + regs.Write(instr.rd(), ~(regs.Read(instr.rs()) | regs.Read(instr.rt()))); } else { panic("[JIT]: Implement non constant NOR!"); } } -void JIT::slti(u32 instr) { - if (regs.IsRegConstant(RS(instr))) { +void JIT::slti(const Instruction instr) { + if (regs.IsRegConstant(instr.rs())) { s16 imm = instr; - regs.Write(RT(instr), regs.Read(RS(instr)) < imm); + regs.Write(instr.rt(), regs.Read(instr.rs()) < imm); return; } panic("[JIT]: Implement non constant SLTI!"); } -void JIT::sltiu(u32 instr) { - if (regs.IsRegConstant(RS(instr))) { +void JIT::sltiu(const Instruction instr) { + if (regs.IsRegConstant(instr.rs())) { s16 imm = instr; - regs.Write(RT(instr), regs.Read(RS(instr)) < imm); + regs.Write(instr.rt(), regs.Read(instr.rs()) < imm); } else { panic("[JIT]: Implement non constant SLTIU!"); } } -void JIT::slt(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - regs.Write(RD(instr), regs.Read(RS(instr)) < regs.Read(RT(instr))); +void JIT::slt(const Instruction instr) { + if (regs.IsRegConstant(instr.rs(), instr.rt())) { + regs.Write(instr.rd(), regs.Read(instr.rs()) < regs.Read(instr.rt())); return; } - if (regs.IsRegConstant(RT(instr))) { - s64 rt = regs.Read(RT(instr)); - regs.Read(RS(instr), code.SCR1); + if (regs.IsRegConstant(instr.rt())) { + s64 rt = regs.Read(instr.rt()); + regs.Read(instr.rs(), code.SCR1); code.cmp(code.SCR1, rt); code.setl(code.SCR1.cvt8()); - regs.Write(RD(instr), code.SCR1.cvt8()); + regs.Write(instr.rd(), code.SCR1.cvt8()); return; } - if (regs.IsRegConstant(RS(instr))) { - s64 rs = regs.Read(RS(instr)); - regs.Read(RT(instr), code.SCR1); + if (regs.IsRegConstant(instr.rs())) { + s64 rs = regs.Read(instr.rs()); + regs.Read(instr.rt(), code.SCR1); code.cmp(code.SCR1, rs); code.setge(code.SCR1.cvt8()); - regs.Write(RD(instr), code.SCR1.cvt8()); + regs.Write(instr.rd(), code.SCR1.cvt8()); return; } - regs.Read(RS(instr), code.SCR1); - regs.Read(RT(instr), code.SCR2); + regs.Read(instr.rs(), code.SCR1); + regs.Read(instr.rt(), code.SCR2); code.cmp(code.SCR1, code.SCR2); code.setl(code.SCR1.cvt8()); - regs.Write(RD(instr), code.SCR1.cvt8()); + regs.Write(instr.rd(), code.SCR1.cvt8()); } -void JIT::sltu(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - regs.Write(RD(instr), regs.Read(RS(instr)) < regs.Read(RT(instr))); +void JIT::sltu(const Instruction instr) { + if (regs.IsRegConstant(instr.rs(), instr.rt())) { + regs.Write(instr.rd(), regs.Read(instr.rs()) < regs.Read(instr.rt())); } else { panic("[JIT]: Implement non constant SLT!"); } } -void JIT::sll(u32 instr) { +void JIT::sll(const Instruction instr) { const u8 sa = ((instr >> 6) & 0x1f); - if (regs.IsRegConstant(RT(instr))) { - const s32 result = regs.Read(RT(instr)) << sa; - regs.Write(RD(instr), (s64)result); + if (regs.IsRegConstant(instr.rt())) { + const s32 result = regs.Read(instr.rt()) << sa; + regs.Write(instr.rd(), (s64)result); } else { - regs.Read(RT(instr), code.SCR1); + regs.Read(instr.rt(), code.SCR1); code.sal(code.SCR1, sa); - regs.Write(RD(instr), code.SCR1.cvt32()); + regs.Write(instr.rd(), code.SCR1.cvt32()); } } -void JIT::sllv(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - u8 sa = (regs.Read(RS(instr))) & 0x1F; - u32 rt = regs.Read(RT(instr)); +void JIT::sllv(const Instruction instr) { + if (regs.IsRegConstant(instr.rs(), instr.rt())) { + u8 sa = (regs.Read(instr.rs())) & 0x1F; + u32 rt = regs.Read(instr.rt()); s32 result = rt << sa; - regs.Write(RD(instr), (s64)result); + regs.Write(instr.rd(), (s64)result); } else { panic("[JIT]: Implement non constant SLLV!"); } } -void JIT::sub(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - s32 rt = regs.Read(RT(instr)); - s32 rs = regs.Read(RS(instr)); +void JIT::sub(const Instruction instr) { + if (regs.IsRegConstant(instr.rs(), instr.rt())) { + s32 rt = regs.Read(instr.rt()); + s32 rs = regs.Read(instr.rs()); s32 result = rs - rt; if (check_signed_underflow(rs, rt, result)) { regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); } else { - regs.Write(RD(instr), result); + regs.Write(instr.rd(), result); } } else { panic("[JIT]: Implement non constant SUB!"); } } -void JIT::subu(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - u32 rt = regs.Read(RT(instr)); - u32 rs = regs.Read(RS(instr)); +void JIT::subu(const Instruction instr) { + if (regs.IsRegConstant(instr.rs(), instr.rt())) { + u32 rt = regs.Read(instr.rt()); + u32 rs = regs.Read(instr.rs()); u32 result = rs - rt; - regs.Write(RD(instr), (s64)((s32)result)); + regs.Write(instr.rd(), (s64)((s32)result)); } else { panic("[JIT]: Implement non constant SUBU!"); } } -void JIT::sra(u32 instr) { - if (regs.IsRegConstant(RT(instr))) { - s64 rt = regs.Read(RT(instr)); +void JIT::sra(const Instruction instr) { + if (regs.IsRegConstant(instr.rt())) { + s64 rt = regs.Read(instr.rt()); u8 sa = ((instr >> 6) & 0x1f); s32 result = rt >> sa; - regs.Write(RD(instr), result); + regs.Write(instr.rd(), result); } else { panic("[JIT]: Implement non constant SRA!"); } } -void JIT::srav(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - s64 rs = regs.Read(RS(instr)); - s64 rt = regs.Read(RT(instr)); +void JIT::srav(const Instruction instr) { + if (regs.IsRegConstant(instr.rs(), instr.rt())) { + s64 rs = regs.Read(instr.rs()); + s64 rt = regs.Read(instr.rt()); u8 sa = rs & 0x1f; s32 result = rt >> sa; - regs.Write(RD(instr), result); + regs.Write(instr.rd(), result); } else { panic("[JIT]: Implement non constant SRAV!"); } } -void JIT::srl(u32 instr) { - if (regs.IsRegConstant(RT(instr))) { - u32 rt = regs.Read(RT(instr)); +void JIT::srl(const Instruction instr) { + if (regs.IsRegConstant(instr.rt())) { + u32 rt = regs.Read(instr.rt()); u8 sa = ((instr >> 6) & 0x1f); u32 result = rt >> sa; - regs.Write(RD(instr), (s32)result); + regs.Write(instr.rd(), (s32)result); } else { panic("[JIT]: Implement non constant SRL!"); } } -void JIT::sw(const u32 instr) { +void JIT::sw(const Instruction instr) { u32 physical; - if (regs.IsRegConstant(RS(instr), RT(instr))) { + if (regs.IsRegConstant(instr.rs(), instr.rt())) { const s16 offset = instr; - const u64 address = regs.Read(RS(instr)) + offset; + const u64 address = regs.Read(instr.rs()) + offset; if (check_address_error(0b11, address)) { // regs.cop0.HandleTLBException(address); // regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC); @@ -1360,16 +1360,16 @@ void JIT::sw(const u32 instr) { code.lea(code.ARG2, code.ptr[code.rbp + (reinterpret_cast(®s) - reinterpret_cast(this))]); code.mov(code.ARG3, physical); - regs.Read(RT(instr), code.ARG4); + regs.Read(instr.rt(), code.ARG4); emitMemberFunctionCall(&Mem::WriteJIT, &mem); } return; } - if (regs.IsRegConstant(RS(instr))) { + if (regs.IsRegConstant(instr.rs())) { const s16 offset = instr; - const u64 address = regs.Read(RS(instr)) + offset; + const u64 address = regs.Read(instr.rs()) + offset; if (check_address_error(0b11, address)) { // regs.cop0.HandleTLBException(address); // regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC); @@ -1385,18 +1385,18 @@ void JIT::sw(const u32 instr) { code.mov(code.ARG2, code.ptr[code.rbp + (reinterpret_cast(®s) - reinterpret_cast(this))]); code.mov(code.ARG3, physical); - regs.Read(RT(instr), code.ARG4); + regs.Read(instr.rt(), code.ARG4); emitMemberFunctionCall(&Mem::WriteJIT, &mem); } return; } - if (regs.IsRegConstant(RT(instr))) { + if (regs.IsRegConstant(instr.rt())) { const s16 offset = instr; code.mov(code.ARG2, Cop0::STORE); - regs.Read(RS(instr), code.ARG3); + regs.Read(instr.rs(), code.ARG3); code.add(code.ARG3, offset); code.mov(code.ARG4, reinterpret_cast(&physical)); @@ -1404,7 +1404,7 @@ void JIT::sw(const u32 instr) { code.mov(code.ARG2, code.ptr[code.rbp + (reinterpret_cast(®s) - reinterpret_cast(this))]); code.mov(code.ARG3, code.qword[code.ARG4]); - regs.Read(RT(instr), code.ARG4); + regs.Read(instr.rt(), code.ARG4); emitMemberFunctionCall(&Mem::WriteJIT, &mem); return; @@ -1413,7 +1413,7 @@ void JIT::sw(const u32 instr) { const s16 offset = instr; code.mov(code.ARG2, Cop0::STORE); - regs.Read(RS(instr), code.ARG3); + regs.Read(instr.rs(), code.ARG3); code.add(code.ARG3, offset); code.mov(code.ARG4, reinterpret_cast(&physical)); @@ -1421,54 +1421,54 @@ void JIT::sw(const u32 instr) { code.mov(code.ARG2, code.ptr[code.rbp + (reinterpret_cast(®s) - reinterpret_cast(this))]); code.mov(code.ARG3, code.qword[code.ARG4]); - regs.Read(RT(instr), code.ARG4); + regs.Read(instr.rt(), code.ARG4); emitMemberFunctionCall(&Mem::WriteJIT, &mem); } -void JIT::srlv(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - u8 sa = (regs.Read(RS(instr)) & 0x1F); - u32 rt = regs.Read(RT(instr)); +void JIT::srlv(const Instruction instr) { + if (regs.IsRegConstant(instr.rs(), instr.rt())) { + u8 sa = (regs.Read(instr.rs()) & 0x1F); + u32 rt = regs.Read(instr.rt()); s32 result = rt >> sa; - regs.Write(RD(instr), (s64)result); + regs.Write(instr.rd(), (s64)result); } else { panic("[JIT]: Implement non constant SRLV!"); } } -void JIT::or_(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - regs.Write(RD(instr), regs.Read(RS(instr)) | regs.Read(RT(instr))); +void JIT::or_(const Instruction instr) { + if (regs.IsRegConstant(instr.rs(), instr.rt())) { + regs.Write(instr.rd(), regs.Read(instr.rs()) | regs.Read(instr.rt())); } else { panic("[JIT]: Implement non constant OR!"); } } -void JIT::ori(u32 instr) { +void JIT::ori(const Instruction instr) { s64 imm = (u16)instr; - if (regs.IsRegConstant(RS(instr))) { - s64 result = imm | regs.Read(RS(instr)); - regs.Write(RT(instr), result); + if (regs.IsRegConstant(instr.rs())) { + s64 result = imm | regs.Read(instr.rs()); + regs.Write(instr.rt(), result); return; } - regs.Read(RS(instr), code.SCR1); + regs.Read(instr.rs(), code.SCR1); code.or_(code.SCR1, imm); - regs.Write(RT(instr), code.SCR1); + regs.Write(instr.rt(), code.SCR1); } -void JIT::xori(u32 instr) { - if (regs.IsRegConstant(RS(instr))) { +void JIT::xori(const Instruction instr) { + if (regs.IsRegConstant(instr.rs())) { s64 imm = (u16)instr; - regs.Write(RT(instr), regs.Read(RS(instr)) ^ imm); + regs.Write(instr.rt(), regs.Read(instr.rs()) ^ imm); } else { panic("[JIT]: Implement non constant XORI!"); } } -void JIT::xor_(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - regs.Write(RD(instr), regs.Read(RT(instr)) ^ regs.Read(RS(instr))); +void JIT::xor_(const Instruction instr) { + if (regs.IsRegConstant(instr.rs(), instr.rt())) { + regs.Write(instr.rd(), regs.Read(instr.rt()) ^ regs.Read(instr.rs())); } else { panic("[JIT]: Implement non constant XOR!"); } diff --git a/src/backend/core/registers/Cop0.cpp b/src/backend/core/registers/Cop0.cpp index 330c7537..dabc5175 100644 --- a/src/backend/core/registers/Cop0.cpp +++ b/src/backend/core/registers/Cop0.cpp @@ -489,7 +489,7 @@ void Cop0::decode(const Instruction instr) { } break; default: - panic("Unimplemented COP0 instruction {} {}", mask_cop >> 4, mask_cop & 7); + panic("Unimplemented COP0 instruction {}", instr.cop_rs()); } } diff --git a/src/backend/core/registers/Cop0.hpp b/src/backend/core/registers/Cop0.hpp index 0bbd5c42..f8906a6f 100644 --- a/src/backend/core/registers/Cop0.hpp +++ b/src/backend/core/registers/Cop0.hpp @@ -271,10 +271,10 @@ private: [[nodiscard]] FORCE_INLINE u32 GetWired() const { return wired & 0x3F; } [[nodiscard]] FORCE_INLINE u32 GetCount() const { return u32(u64(count >> 1)); } - void mtc0(u32); - void dmtc0(u32); - void mfc0(u32); - void dmfc0(u32) const; + void mtc0(const Instruction); + void dmtc0(const Instruction); + void mfc0(const Instruction); + void dmfc0(const Instruction) const; void eret(); void tlbr(); diff --git a/src/backend/core/registers/Cop1.cpp b/src/backend/core/registers/Cop1.cpp index b2d12a96..98626c11 100644 --- a/src/backend/core/registers/Cop1.cpp +++ b/src/backend/core/registers/Cop1.cpp @@ -11,7 +11,6 @@ void Cop1::Reset() { } void Cop1::decode(const Instruction instr) { - auto cpu = Core::GetInstance().cpuType == Core::Interpreted ? Core::GetInterpreter() : Core::GetDynamicRecompiler(); switch (instr.cop_rs()) { // 000r_rccc case 0x00: @@ -38,32 +37,6 @@ void Cop1::decode(const Instruction instr) { case 0x07: unimplemented(); break; - case 0x08: - switch (instr.cop_rt()) { - case 0: - if (!regs.cop1.CheckFPUUsable()) - return; - cpu.b(instr, !regs.cop1.fcr31.compare); - break; - case 1: - if (!regs.cop1.CheckFPUUsable()) - return; - cpu.b(instr, regs.cop1.fcr31.compare); - break; - case 2: - if (!regs.cop1.CheckFPUUsable()) - return; - cpu.bl(instr, !regs.cop1.fcr31.compare); - break; - case 3: - if (!regs.cop1.CheckFPUUsable()) - return; - cpu.bl(instr, regs.cop1.fcr31.compare); - break; - default: - panic("Undefined BC COP1 {:02X}", instr.cop_rt()); - } - break; case 0x10: // s switch (instr.cop_funct()) { case 0x00: diff --git a/src/backend/core/registers/Cop1.hpp b/src/backend/core/registers/Cop1.hpp index e6da8259..4d3402c2 100644 --- a/src/backend/core/registers/Cop1.hpp +++ b/src/backend/core/registers/Cop1.hpp @@ -230,10 +230,10 @@ private: void negd(const Instruction instr); void sqrts(const Instruction instr); void sqrtd(const Instruction instr); - void lwc1(u32); - void swc1(u32); - void ldc1(u32); - void sdc1(u32); + void lwc1(const Instruction instr); + void swc1(const Instruction instr); + void ldc1(const Instruction instr); + void sdc1(const Instruction instr); void mfc1(const Instruction instr); void dmfc1(const Instruction instr); diff --git a/src/utils/Instruction.hpp b/src/utils/Instruction.hpp index df8a355d..ba3fb380 100644 --- a/src/utils/Instruction.hpp +++ b/src/utils/Instruction.hpp @@ -6,14 +6,21 @@ namespace n64 { struct Instruction { Instruction(u32 v) { instr.raw = v; } void operator=(u32 v) { instr.raw = v; } - auto operator u32() { return instr.raw; } + operator u32() const { return instr.raw; } inline u8 rs() const { return instr.rtype.rs; } inline u8 rt() const { return instr.rtype.rt; } inline u8 rd() const { return instr.rtype.rd; } inline u8 sa() const { return instr.rtype.sa; } + inline u8 fs() const { return rd(); } + inline u8 ft() const { return rt(); } + inline u8 fd() const { return sa(); } + inline u8 base() const { return rs(); } inline u16 imm() const { return instr.itype.imm; } inline u32 target() const { return instr.jtype.target; } + inline u8 opcode() const { return instr.opcode.op; } + inline u8 special() const { return instr.opcode.special; } + inline u8 regimm() const { return instr.opcode.regimm; } inline u8 cop_rs() const { return instr.opcode.cop_rs; } inline u8 cop_rt() const { return instr.opcode.cop_rt; } inline u8 cop_funct() const { return instr.opcode.funct; } @@ -76,6 +83,8 @@ struct Instruction { unsigned cop_rs:5; unsigned:6; }; + + u32 raw; } opcode; u32 raw;