From b6452880a95ce722aa7d2ec5391053894660d908 Mon Sep 17 00:00:00 2001 From: iris Date: Fri, 22 May 2026 16:46:29 +0200 Subject: [PATCH] start implementing cached interpreter --- src/backend/core/Interpreter.cpp | 66 +++++++++++++++---- src/backend/core/Interpreter.hpp | 24 +++++-- src/backend/core/interpreter/decode.cpp | 2 +- src/backend/core/interpreter/instructions.cpp | 8 +-- src/utils/Instruction.hpp | 1 + 5 files changed, 79 insertions(+), 22 deletions(-) diff --git a/src/backend/core/Interpreter.cpp b/src/backend/core/Interpreter.cpp index 4bdcceb..29eadd6 100644 --- a/src/backend/core/Interpreter.cpp +++ b/src/backend/core/Interpreter.cpp @@ -21,7 +21,19 @@ void Interpreter::CheckCompareInterrupt() const { } } -u32 Interpreter::Step() { +bool Interpreter::Fetch(Instruction &instr) { + u32 paddr = 0; + if (!regs.cop0.MapVAddr(Cop0::LOAD, regs.pc, paddr)) { + regs.cop0.HandleTLBException(regs.pc); + regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.pc); + return false; + } + + instr = mem.Read(paddr); + return true; +} + +bool Interpreter::MaybeAdvance() { CheckCompareInterrupt(); regs.prevDelaySlot = regs.delaySlot; @@ -30,29 +42,57 @@ u32 Interpreter::Step() { if (check_address_error(0b11, u64(regs.pc))) [[unlikely]] { regs.cop0.HandleTLBException(regs.pc); regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.pc); - return 1; + return false; } - u32 paddr = 0; - if (!regs.cop0.MapVAddr(Cop0::LOAD, regs.pc, paddr)) { - regs.cop0.HandleTLBException(regs.pc); - regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.pc); - return 1; - } - - const u32 instruction = mem.Read(paddr); - if (ShouldServiceInterrupt()) { regs.cop0.FireException(Cop0::ExceptionCode::Interrupt, 0, regs.pc); - return 1; + return false; } regs.oldPC = regs.pc; regs.pc = regs.nextPC; regs.nextPC += 4; - Exec(instruction); + return true; +} + +bool Interpreter::FetchThenMaybeAdvance(Instruction &instr) { + 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(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.pc); + return false; + } + + if (!Fetch(instr)) + return false; + + if (ShouldServiceInterrupt()) { + regs.cop0.FireException(Cop0::ExceptionCode::Interrupt, 0, regs.pc); + return false; + } + + regs.oldPC = regs.pc; + regs.pc = regs.nextPC; + regs.nextPC += 4; + + return true; +} + +u32 Interpreter::Step() { + Instruction instr; + if (!FetchThenMaybeAdvance(instr)) + return 1; + + DecodeExecute(instr); return 1; } + +u32 Interpreter::ExecuteCached() {} } // namespace n64 diff --git a/src/backend/core/Interpreter.hpp b/src/backend/core/Interpreter.hpp index a90dd10..e73c915 100644 --- a/src/backend/core/Interpreter.hpp +++ b/src/backend/core/Interpreter.hpp @@ -5,23 +5,39 @@ namespace n64 { struct Core; +static constexpr u32 MAX_INSTRUCTION_PER_LINE = 128; + +struct CachedLine { + std::array code; + u32 cycles = 0; + u32 len = 0; +}; + +struct CachedBlock { + std::vector lines; +}; + struct Interpreter final { explicit Interpreter(Mem &, Registers &); ~Interpreter() = default; u32 Step(); + u32 ExecuteCached(); + bool FetchThenMaybeAdvance(Instruction &); + bool MaybeAdvance(); void Reset() { cop2Latch = {}; } private: + friend struct Cop1; InstructionCache icache; DataCache dcache; Registers ®s; Mem &mem; u64 cop2Latch{}; - friend struct Cop1; - void cache_type_data(u8, u64, u32, u32); - void cache_type_instruction(u8, u64, u32, u32); + bool Fetch(Instruction &); + void CacheTypeData(u8, u64, u32, u32); + void CacheTypeInstruction(u8, u64, u32, u32); #define check_address_error(mask, vaddr) \ (((!regs.cop0.is64BitAddressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0)) [[nodiscard]] bool ShouldServiceInterrupt() const; @@ -30,7 +46,7 @@ struct Interpreter final { void cop2Decode(Instruction); void special(Instruction); void regimm(Instruction); - void Exec(Instruction); + void DecodeExecute(Instruction); void add(Instruction); void addu(Instruction); void addi(Instruction); diff --git a/src/backend/core/interpreter/decode.cpp b/src/backend/core/interpreter/decode.cpp index abf8c52..ee5765b 100644 --- a/src/backend/core/interpreter/decode.cpp +++ b/src/backend/core/interpreter/decode.cpp @@ -249,7 +249,7 @@ void Interpreter::cop2Decode(const Instruction instr) { } } -void Interpreter::Exec(const Instruction instr) { +void Interpreter::DecodeExecute(const Instruction instr) { // 00rr_rccc switch (instr.opcode()) { case Instruction::SPECIAL: diff --git a/src/backend/core/interpreter/instructions.cpp b/src/backend/core/interpreter/instructions.cpp index 983b8a8..227bf14 100644 --- a/src/backend/core/interpreter/instructions.cpp +++ b/src/backend/core/interpreter/instructions.cpp @@ -869,12 +869,12 @@ void Interpreter::cache(const Instruction instr) { panic("Unknown cache type {}", type); if (type == 0) - return cache_type_instruction(op, vaddr, paddr, ptag); + return CacheTypeInstruction(op, vaddr, paddr, ptag); - return cache_type_data(op, vaddr, paddr, ptag); + return CacheTypeData(op, vaddr, paddr, ptag); } -void Interpreter::cache_type_instruction(const u8 op, const u64 vaddr, const u32 paddr, const u32 ptag) { +void Interpreter::CacheTypeInstruction(const u8 op, const u64 vaddr, const u32 paddr, const u32 ptag) { switch (op) { case 0: icache.InvalidateIndex(vaddr); @@ -899,7 +899,7 @@ void Interpreter::cache_type_instruction(const u8 op, const u64 vaddr, const u32 } } -void Interpreter::cache_type_data(const u8 op, const u64 vaddr, const u32 paddr, const u32 ptag) { +void Interpreter::CacheTypeData(const u8 op, const u64 vaddr, const u32 paddr, const u32 ptag) { switch (op) { case 0: dcache.WriteBack(vaddr, paddr); diff --git a/src/utils/Instruction.hpp b/src/utils/Instruction.hpp index ef0c028..2104ff2 100644 --- a/src/utils/Instruction.hpp +++ b/src/utils/Instruction.hpp @@ -4,6 +4,7 @@ namespace n64 { struct Instruction { + Instruction() = default; Instruction(u32 v) { instr.raw = v; } void operator=(u32 v) { instr.raw = v; } operator u32() const { return instr.raw; }