AAAAAAAAAAAAAAAAAAAAAAAAA

This commit is contained in:
2026-05-28 11:03:57 +02:00
parent 5ae2af0f33
commit 16778c5549
3 changed files with 66 additions and 30 deletions
+43 -21
View File
@@ -99,39 +99,59 @@ u32 Interpreter::Step() {
u32 Interpreter::ExecuteCached() { u32 Interpreter::ExecuteCached() {
auto addr = regs.pc; auto addr = regs.pc;
auto blockAddr = addr; auto blockAddr = addr;
auto page = (addr >> 12) & 0xfffff; auto page = CACHE_GET_PAGE(addr);
auto offset = addr & 0xfff; auto offset = CACHE_GET_BLOCK(addr);
auto &blocks = cachedState.blocks; 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()) if (!MaybeAdvance())
return i + 1; return i + 1;
Instruction instr = block.code[i]; Instruction instr = block.code[i];
DecodeExecute(instr); 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 // Branch likely with false condition, it wasn't taken so don't execute the delay slot
if (IsBranchLikely(instr) && !regs.delaySlot) if (IsBranchLikely(instr) && !regs.delaySlot)
break; break;
} }
if (block.cycles == 0) if (blockCycles == 0)
Scheduler::GetInstance().SkipToNext(); Scheduler::GetInstance().SkipToNext();
return block.cycles; return blockCycles;
} }
auto &block = blocks[page]; auto &block = lines[page].blocks[offset];
block.code.resize(MAX_INSTRUCTION_PER_BLOCK); block.code.resize(MAX_INSTRUCTIONS_PER_BLOCK);
info("Compiling block @ pc 0x{:016X}", (u64)addr);
u32 i; u32 i;
bool fetchDelaySlot = false; bool fetchDelaySlot = false;
for (i = 0; i < MAX_INSTRUCTION_PER_BLOCK; i++) { for (i = 0; i < MAX_INSTRUCTIONS_PER_BLOCK; i++) {
Instruction instr; Instruction instr;
if (!Fetch(instr, addr)) Fetch(instr, addr);
return i + 1;
addr += 4; addr += 4;
block.code[i] = instr; block.code[i] = instr;
@@ -141,17 +161,19 @@ u32 Interpreter::ExecuteCached() {
break; break;
} }
if (InstrEndsBlock(instr)) { if (!InstrEndsBlock(instr))
if (InstrHasDelaySlot(instr) && !fetchDelaySlot) { continue;
fetchDelaySlot = true;
continue; if (InstrHasDelaySlot(instr) && !fetchDelaySlot) {
} fetchDelaySlot = true;
break; continue;
} }
break;
} }
blocks[page].cycles = i; block.cycles = i;
blocks[page].len = i; block.len = i;
return ExecuteCached(); return ExecuteCached();
} }
+21 -9
View File
@@ -5,24 +5,33 @@
namespace n64 { namespace n64 {
struct Core; struct Core;
static constexpr u32 MAX_BLOCKS = 1 << 20; static constexpr u32 CACHE_OUTER_SHIFT = 12;
static constexpr u32 MAX_INSTRUCTION_PER_BLOCK = 1 << 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 { struct CachedBlock {
std::vector<Instruction> code = {}; std::vector<Instruction> code = {};
u32 len = 0; u32 len = 0;
u32 cycles = 0; u32 cycles = 0;
bool exception = false;
} __attribute__((__packed__)); } __attribute__((__packed__));
struct CachedLine {
std::array<CachedBlock, MAX_BLOCKS_PER_LINE> blocks = {};
};
struct CachedState { struct CachedState {
CachedState() { blocks.resize(MAX_BLOCKS); } CachedState() { lines.resize(MAX_LINES); }
std::vector<CachedBlock> blocks = {}; std::vector<CachedLine> lines = {};
bool exception = false;
void Reset() { void Reset() {
blocks = {}; lines = {};
blocks.resize(MAX_BLOCKS); lines.resize(MAX_LINES);
exception = false;
} }
}; };
@@ -34,7 +43,10 @@ struct Interpreter final {
bool FetchThenMaybeAdvance(Instruction &); bool FetchThenMaybeAdvance(Instruction &);
bool MaybeAdvance(); 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() { void Reset() {
cop2Latch = {}; cop2Latch = {};
+2
View File
@@ -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) { void Cop0::FireException(const ExceptionCode code, const int cop, s64 pc) {
Registers &regs = Core::GetRegs(); Registers &regs = Core::GetRegs();
Core::GetInstance().interpreter.SignalException(pc);
u16 vectorOffset = 0x0180; u16 vectorOffset = 0x0180;
if (tlbError == MISS && (code == ExceptionCode::TLBLoad || code == ExceptionCode::TLBStore)) { if (tlbError == MISS && (code == ExceptionCode::TLBLoad || code == ExceptionCode::TLBStore)) {
if (!status.exl) { if (!status.exl) {