From 16778c55494e3fa5f54c3192e8da030fe8d9a153 Mon Sep 17 00:00:00 2001 From: iris Date: Thu, 28 May 2026 11:03:57 +0200 Subject: [PATCH] AAAAAAAAAAAAAAAAAAAAAAAAA --- src/backend/core/Interpreter.cpp | 64 +++++++++++++++++++---------- src/backend/core/Interpreter.hpp | 30 ++++++++++---- src/backend/core/registers/Cop0.cpp | 2 + 3 files changed, 66 insertions(+), 30 deletions(-) diff --git a/src/backend/core/Interpreter.cpp b/src/backend/core/Interpreter.cpp index addd948..aca6837 100644 --- a/src/backend/core/Interpreter.cpp +++ b/src/backend/core/Interpreter.cpp @@ -99,39 +99,59 @@ u32 Interpreter::Step() { u32 Interpreter::ExecuteCached() { auto addr = regs.pc; auto blockAddr = addr; - auto page = (addr >> 12) & 0xfffff; - auto offset = addr & 0xfff; - auto &blocks = cachedState.blocks; + auto page = CACHE_GET_PAGE(addr); + auto offset = CACHE_GET_BLOCK(addr); + auto &lines = cachedState.lines; + auto &blocks = lines[page].blocks; + + if (lines[page].blocks[offset].len > 0) { + info("Executing block @ pc 0x{:016X}", (u64)addr); + auto &block = lines[page].blocks[offset]; + // i copy the block cycles here in case the block evicts itself when executing which would set the cycles to + // 0, making so the emulator halts cause the outer loop won't advance + const auto blockCycles = block.cycles; + for (u32 i = 0; i < block.len; i++) { + u32 paddr = 0; + if (!regs.cop0.MapVAddr(Cop0::LOAD, blockAddr, paddr)) { + regs.cop0.HandleTLBException(blockAddr); + regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, blockAddr); + return i + 1; + } + + blockAddr += 4; - if (blocks[page].code.size() >= offset) { - const auto &block = blocks[page]; - for (u32 i = 0; i < block.code.size(); i++) { if (!MaybeAdvance()) return i + 1; Instruction instr = block.code[i]; DecodeExecute(instr); + if (block.exception) { + block.exception = false; + return i + 1; + } + // Branch likely with false condition, it wasn't taken so don't execute the delay slot if (IsBranchLikely(instr) && !regs.delaySlot) break; } - if (block.cycles == 0) + if (blockCycles == 0) Scheduler::GetInstance().SkipToNext(); - return block.cycles; + return blockCycles; } - auto &block = blocks[page]; - block.code.resize(MAX_INSTRUCTION_PER_BLOCK); + auto &block = lines[page].blocks[offset]; + block.code.resize(MAX_INSTRUCTIONS_PER_BLOCK); + + info("Compiling block @ pc 0x{:016X}", (u64)addr); u32 i; bool fetchDelaySlot = false; - for (i = 0; i < MAX_INSTRUCTION_PER_BLOCK; i++) { + for (i = 0; i < MAX_INSTRUCTIONS_PER_BLOCK; i++) { Instruction instr; - if (!Fetch(instr, addr)) - return i + 1; + Fetch(instr, addr); addr += 4; block.code[i] = instr; @@ -141,17 +161,19 @@ u32 Interpreter::ExecuteCached() { break; } - if (InstrEndsBlock(instr)) { - if (InstrHasDelaySlot(instr) && !fetchDelaySlot) { - fetchDelaySlot = true; - continue; - } - break; + if (!InstrEndsBlock(instr)) + continue; + + if (InstrHasDelaySlot(instr) && !fetchDelaySlot) { + fetchDelaySlot = true; + continue; } + + break; } - blocks[page].cycles = i; - blocks[page].len = i; + block.cycles = i; + block.len = i; return ExecuteCached(); } diff --git a/src/backend/core/Interpreter.hpp b/src/backend/core/Interpreter.hpp index 6000029..89df54a 100644 --- a/src/backend/core/Interpreter.hpp +++ b/src/backend/core/Interpreter.hpp @@ -5,24 +5,33 @@ namespace n64 { struct Core; -static constexpr u32 MAX_BLOCKS = 1 << 20; -static constexpr u32 MAX_INSTRUCTION_PER_BLOCK = 1 << 12; +static constexpr u32 CACHE_OUTER_SHIFT = 12; +static constexpr u32 MAX_LINES = 1 << (32 - CACHE_OUTER_SHIFT); +static constexpr u32 MAX_INSTRUCTIONS_PER_BLOCK = 256 / sizeof(Instruction); +static constexpr u32 MAX_BLOCKS_PER_LINE = + ((1 << CACHE_OUTER_SHIFT) / sizeof(Instruction)) / MAX_INSTRUCTIONS_PER_BLOCK; + +#define CACHE_GET_PAGE(addr) ((addr >> CACHE_OUTER_SHIFT) & (MAX_LINES - 1)) +#define CACHE_GET_BLOCK(addr) ((addr & 0xF00) >> 8) struct CachedBlock { std::vector code = {}; u32 len = 0; u32 cycles = 0; + bool exception = false; } __attribute__((__packed__)); +struct CachedLine { + std::array blocks = {}; +}; + struct CachedState { - CachedState() { blocks.resize(MAX_BLOCKS); } - std::vector blocks = {}; - bool exception = false; + CachedState() { lines.resize(MAX_LINES); } + std::vector lines = {}; void Reset() { - blocks = {}; - blocks.resize(MAX_BLOCKS); - exception = false; + lines = {}; + lines.resize(MAX_LINES); } }; @@ -34,7 +43,10 @@ struct Interpreter final { bool FetchThenMaybeAdvance(Instruction &); bool MaybeAdvance(); - void EvictCachedBlock(u64 addr) { cachedState.blocks[(addr >> 12) & 0xfffff] = {}; } + void SignalException(u64 addr) { + cachedState.lines[CACHE_GET_PAGE(addr)].blocks[CACHE_GET_BLOCK(addr)].exception = true; + } + void EvictCachedBlock(u64 addr) { cachedState.lines[CACHE_GET_PAGE(addr)].blocks[CACHE_GET_BLOCK(addr)] = {}; } void Reset() { cop2Latch = {}; diff --git a/src/backend/core/registers/Cop0.cpp b/src/backend/core/registers/Cop0.cpp index d919752..16f3ba4 100644 --- a/src/backend/core/registers/Cop0.cpp +++ b/src/backend/core/registers/Cop0.cpp @@ -363,6 +363,8 @@ bool Cop0::ProbeTLB(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) void Cop0::FireException(const ExceptionCode code, const int cop, s64 pc) { Registers ®s = Core::GetRegs(); + Core::GetInstance().interpreter.SignalException(pc); + u16 vectorOffset = 0x0180; if (tlbError == MISS && (code == ExceptionCode::TLBLoad || code == ExceptionCode::TLBStore)) { if (!status.exl) {