diff --git a/src/backend/core/Interpreter.hpp b/src/backend/core/Interpreter.hpp index 2b724985..461558cb 100644 --- a/src/backend/core/Interpreter.hpp +++ b/src/backend/core/Interpreter.hpp @@ -5,7 +5,7 @@ namespace n64 { struct Core; -struct Interpreter final : BaseCPU { +struct Interpreter : BaseCPU { explicit Interpreter(ParallelRDP&); ~Interpreter() override = default; int Step() override; diff --git a/src/backend/core/JIT.cpp b/src/backend/core/JIT.cpp new file mode 100644 index 00000000..a488316b --- /dev/null +++ b/src/backend/core/JIT.cpp @@ -0,0 +1,84 @@ +#include +#include + +namespace n64 { +JIT::JIT(ParallelRDP& parallel) : mem(regs, parallel) { } + +bool JIT::ShouldServiceInterrupt() { + bool interrupts_pending = (regs.cop0.status.im & regs.cop0.cause.interruptPending) != 0; + bool interrupts_enabled = regs.cop0.status.ie == 1; + bool currently_handling_exception = regs.cop0.status.exl == 1; + bool currently_handling_error = regs.cop0.status.erl == 1; + + return interrupts_pending && interrupts_enabled && + !currently_handling_exception && !currently_handling_error; +} + +void JIT::CheckCompareInterrupt() { + regs.cop0.count++; + regs.cop0.count &= 0x1FFFFFFFF; + if(regs.cop0.count == (u64)regs.cop0.compare << 1) { + regs.cop0.cause.ip7 = 1; + mem.mmio.mi.UpdateInterrupt(); + } +} + +int JIT::Step() { + CheckCompareInterrupt(); + + regs.prevDelaySlot = regs.delaySlot; + regs.delaySlot = false; + + if (check_address_error(0b11, u64(regs.pc))) [[unlikely]] { + regs.cop0.HandleTLBException(regs.pc); + regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.pc); + return 1; + } + + u32 paddr = 0; + if (!regs.cop0.MapVAddr(Cop0::LOAD, regs.pc, paddr)) { + regs.cop0.HandleTLBException(regs.pc); + regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.pc); + return 1; + } + + u32 instruction = mem.Read(regs, paddr); + while (!InstrEndsBlock(instr)) { + + if (!regs.cop0.MapVAddr(Cop0::LOAD, regs.pc, paddr)) { + regs.cop0.HandleTLBException(regs.pc); + regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.pc); + return 1; + } + + instruction = mem.Read(regs, paddr); + } + + if(ShouldServiceInterrupt()) { + regs.cop0.FireException(ExceptionCode::Interrupt, 0, regs.pc); + return 1; + } + + regs.oldPC = regs.pc; + regs.pc = regs.nextPC; + regs.nextPC += 4; + + Exec(instruction); + + return 1; +} + +std::vector JIT::Serialize() { + std::vector res{}; + + res.resize(sizeof(Registers)); + + memcpy(res.data(), ®s, sizeof(Registers)); + + return res; +} + +void JIT::Deserialize(const std::vector &data) { + memcpy(®s, data.data(), sizeof(Registers)); +} +} \ No newline at end of file diff --git a/src/backend/core/JIT.hpp b/src/backend/core/JIT.hpp new file mode 100644 index 00000000..7ee88b58 --- /dev/null +++ b/src/backend/core/JIT.hpp @@ -0,0 +1,132 @@ +#pragma once +#include +#include +#include + +namespace n64 { +struct Core; +struct JIT : BaseCPU { + explicit JIT(ParallelRDP&); + ~Interpreter() override = default; + int Step() override; + void Reset() override { + regs.Reset(); + mem.Reset(); + } + + Mem& GetMem() override { + return mem; + } + + Registers& GetRegs() override { + return regs; + } +private: + Registers regs; + Mem mem; + u64 cop2Latch{}; + friend struct Cop1; +#define check_address_error(mask, vaddr) (((!regs.cop0.is64BitAddressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0)) + bool ShouldServiceInterrupt() override; + void CheckCompareInterrupt() override; + std::vector Serialize() override; + void Deserialize(const std::vector&) override; + + void cop2Decode(u32); + void special(u32); + void regimm(u32); + void Exec(u32); + void add(u32); + void addu(u32); + void addi(u32); + void addiu(u32); + void andi(u32); + void and_(u32); + void branch(bool, s64); + void branch_likely(bool, s64); + void b(u32, bool); + void blink(u32, bool); + void bl(u32, bool); + void bllink(u32, bool); + 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 ldl(u32); + void ldr(u32); + void lh(u32); + void lhu(u32); + void ll(u32); + void lld(u32); + void lw(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 sc(u32); + void scd(u32); + void sd(u32); + void sdl(u32); + void sdr(u32); + void sh(u32); + void sw(u32); + void swl(u32); + void swr(u32); + 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 sra(u32); + void srav(u32); + void srl(u32); + void srlv(u32); + void trap(bool); + void or_(u32); + void ori(u32); + void xor_(u32); + void xori(u32); + + void mtc2(u32); + void mfc2(u32); + void dmtc2(u32); + void dmfc2(u32); + void ctc2(u32); + void cfc2(u32); +}; +} diff --git a/src/backend/core/jit/helpers.hpp b/src/backend/core/jit/helpers.hpp new file mode 100644 index 00000000..31b4300a --- /dev/null +++ b/src/backend/core/jit/helpers.hpp @@ -0,0 +1,23 @@ +#include + +namespace n64 { +static inline bool SpecialEndsBlock(u32 instr) { + u8 mask = instr & 0x3F; + switch (mask) { + case JR: case JALR: case SYSCALL: case BREAK: + case TGE: case TGEU: case TLT: case TLTU: + case TEQ: case TNE: return true; + default: return false; + } +} + +static inline bool InstrEndsBlock(u32 instr) { + u8 mask = (instr >> 26) & 0x3f; + switch (mask) { + case SPECIAL: return SpecialEndsBlock(instr); + case REGIMM: case J: case JAL: case BEQ: + case BNE: case BLEZ: case BGTZ: case BEQL: + case BNEL: case BLEZL: case BGTZL: return true: + } +} +} \ No newline at end of file diff --git a/src/backend/core/registers/Registers.hpp b/src/backend/core/registers/Registers.hpp index 71e2220e..aab24af9 100644 --- a/src/backend/core/registers/Registers.hpp +++ b/src/backend/core/registers/Registers.hpp @@ -7,7 +7,9 @@ struct Registers { void Reset(); void SetPC64(s64); void SetPC32(s32); + s64 gpr[32]{}; + bool gprIsConstant[32]{}; Cop0 cop0; Cop1 cop1; s64 oldPC{}, pc{}, nextPC{};