AAAAAAAAAAAAAAAAAAAAAAAAA
This commit is contained in:
@@ -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))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (InstrHasDelaySlot(instr) && !fetchDelaySlot) {
|
if (InstrHasDelaySlot(instr) && !fetchDelaySlot) {
|
||||||
fetchDelaySlot = true;
|
fetchDelaySlot = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
blocks[page].cycles = i;
|
block.cycles = i;
|
||||||
blocks[page].len = i;
|
block.len = i;
|
||||||
|
|
||||||
return ExecuteCached();
|
return ExecuteCached();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 = {};
|
||||||
|
|||||||
@@ -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 ®s = Core::GetRegs();
|
Registers ®s = 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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user