Let's try doing this again

This commit is contained in:
Simone Coco
2024-05-21 09:30:13 +01:00
parent 7479ad46a6
commit 24f4f0270d
5 changed files with 242 additions and 1 deletions

View File

@@ -5,7 +5,7 @@
namespace n64 { namespace n64 {
struct Core; struct Core;
struct Interpreter final : BaseCPU { struct Interpreter : BaseCPU {
explicit Interpreter(ParallelRDP&); explicit Interpreter(ParallelRDP&);
~Interpreter() override = default; ~Interpreter() override = default;
int Step() override; int Step() override;

84
src/backend/core/JIT.cpp Normal file
View File

@@ -0,0 +1,84 @@
#include <Core.hpp>
#include <jit/helpers.hpp>
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<u32>(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<u32>(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<u8> JIT::Serialize() {
std::vector<u8> res{};
res.resize(sizeof(Registers));
memcpy(res.data(), &regs, sizeof(Registers));
return res;
}
void JIT::Deserialize(const std::vector<u8> &data) {
memcpy(&regs, data.data(), sizeof(Registers));
}
}

132
src/backend/core/JIT.hpp Normal file
View File

@@ -0,0 +1,132 @@
#pragma once
#include <Mem.hpp>
#include <vector>
#include <BaseCPU.hpp>
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<u8> Serialize() override;
void Deserialize(const std::vector<u8>&) 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);
};
}

View File

@@ -0,0 +1,23 @@
#include <CpuDefinitions.hpp>
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:
}
}
}

View File

@@ -7,7 +7,9 @@ struct Registers {
void Reset(); void Reset();
void SetPC64(s64); void SetPC64(s64);
void SetPC32(s32); void SetPC32(s32);
s64 gpr[32]{}; s64 gpr[32]{};
bool gprIsConstant[32]{};
Cop0 cop0; Cop0 cop0;
Cop1 cop1; Cop1 cop1;
s64 oldPC{}, pc{}, nextPC{}; s64 oldPC{}, pc{}, nextPC{};