Does not quite fully work yet...
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
#include <Core.hpp>
|
||||
#include <Scheduler.hpp>
|
||||
#include "jit/helpers.hpp"
|
||||
|
||||
namespace n64 {
|
||||
Interpreter::Interpreter(Mem &mem, Registers ®s) : regs(regs), mem(mem) {}
|
||||
@@ -21,11 +23,11 @@ void Interpreter::CheckCompareInterrupt() const {
|
||||
}
|
||||
}
|
||||
|
||||
bool Interpreter::Fetch(Instruction &instr) {
|
||||
bool Interpreter::Fetch(Instruction &instr, u64 vaddr) {
|
||||
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);
|
||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, vaddr, paddr)) {
|
||||
regs.cop0.HandleTLBException(vaddr);
|
||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, vaddr);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -69,7 +71,7 @@ bool Interpreter::FetchThenMaybeAdvance(Instruction &instr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Fetch(instr))
|
||||
if (!Fetch(instr, regs.pc))
|
||||
return false;
|
||||
|
||||
if (ShouldServiceInterrupt()) {
|
||||
@@ -94,18 +96,94 @@ u32 Interpreter::Step() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
u32 DivideAddr(u32 addr, u32& offset) {
|
||||
offset = (addr & (MAX_LINES_PER_BLOCK - 1)) / 4;
|
||||
u32 DivideAddr(u32 addr, u32 &offset) {
|
||||
offset = (addr & (MAX_LINES_PER_BLOCK - 1)) / 4;
|
||||
return addr / MAX_LINES_PER_BLOCK;
|
||||
}
|
||||
|
||||
CachedLine* GetLine(CachedState& cachedState, u32 addr) {
|
||||
CachedLine *CachedState::GetLine(u64 addr) {
|
||||
u32 offset;
|
||||
u32 page = DivideAddr(addr, offset);
|
||||
return cachedState.blocks[page][offset].lines[0];
|
||||
if (blocks[page] && blocks[page]->valid)
|
||||
return &blocks[page]->lines[offset];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CachedState::InsertLine(u64 addr, const CachedLine &line) {
|
||||
u32 offset;
|
||||
u32 page = DivideAddr(addr, offset);
|
||||
|
||||
if (!blocks[page])
|
||||
blocks[page] = std::make_unique<CachedBlock>();
|
||||
|
||||
blocks[page]->valid = true;
|
||||
blocks[page]->lines[offset] = line;
|
||||
}
|
||||
|
||||
void CachedState::EvictLine(u64 addr) {
|
||||
u32 offset;
|
||||
u32 page = DivideAddr(addr, offset);
|
||||
|
||||
if (blocks[page] && blocks[page]->valid)
|
||||
blocks[page]->valid = false;
|
||||
}
|
||||
|
||||
u32 Interpreter::ExecuteCached() {
|
||||
auto addr = regs.pc;
|
||||
auto block_addr = addr;
|
||||
auto line = cachedState.GetLine(addr);
|
||||
|
||||
if (line) {
|
||||
for (u32 i = 0; i < line->len; i++) {
|
||||
if (!MaybeAdvance())
|
||||
return i + 1;
|
||||
|
||||
Instruction instr = line->code[i];
|
||||
DecodeExecute(instr);
|
||||
if (IsBranchLikely(instr) && !regs.delaySlot) {
|
||||
line->len -= 1; // Branch likely with false condition, it wasn't taken so don't execute the delay slot
|
||||
// and remove it from the cache
|
||||
if (line->len <= 0)
|
||||
line->len = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (line->cycles == 0)
|
||||
Scheduler::GetInstance().SkipToNext();
|
||||
|
||||
return line->cycles;
|
||||
}
|
||||
|
||||
std::array<Instruction, MAX_INSTRUCTION_PER_LINE> code;
|
||||
|
||||
u32 i;
|
||||
bool fetchDelaySlot = false;
|
||||
for (i = 0; i < MAX_INSTRUCTION_PER_LINE; i++) {
|
||||
Instruction instr;
|
||||
if (!Fetch(instr, addr))
|
||||
return i + 1;
|
||||
|
||||
addr += 4;
|
||||
code[i] = instr;
|
||||
|
||||
if (fetchDelaySlot) {
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (InstrEndsBlock(instr)) {
|
||||
if (InstrHasDelaySlot(instr) && !fetchDelaySlot) {
|
||||
fetchDelaySlot = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cachedState.InsertLine(block_addr, {code, i, i});
|
||||
|
||||
return ExecuteCached();
|
||||
}
|
||||
} // namespace n64
|
||||
|
||||
Reference in New Issue
Block a user