Does not quite fully work yet...
This commit is contained in:
@@ -64,7 +64,7 @@ void Core::LoadROM(const std::string &rom_) {
|
|||||||
|
|
||||||
u32 Core::StepCPU() {
|
u32 Core::StepCPU() {
|
||||||
if (cpuType == Interpreted)
|
if (cpuType == Interpreted)
|
||||||
return interpreter.Step() + regs.PopStalledCycles();
|
return interpreter.ExecuteCached() + regs.PopStalledCycles();
|
||||||
|
|
||||||
#ifdef KAIZEN_JIT_ENABLED
|
#ifdef KAIZEN_JIT_ENABLED
|
||||||
if (cpuType == DynamicRecompiler)
|
if (cpuType == DynamicRecompiler)
|
||||||
@@ -96,11 +96,6 @@ void Core::StepRSP(const u32 cpuCycles) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::MaybeIdleSkip() {
|
|
||||||
if (GetRegs().nextPC == GetRegs().pc)
|
|
||||||
Scheduler::GetInstance().SkipToNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::Run(const float volumeL, const float volumeR) {
|
void Core::Run(const float volumeL, const float volumeR) {
|
||||||
MMIO &mmio = mem->mmio;
|
MMIO &mmio = mem->mmio;
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ struct Core {
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MaybeIdleSkip();
|
|
||||||
static Registers &GetRegs() { return GetInstance().regs; }
|
static Registers &GetRegs() { return GetInstance().regs; }
|
||||||
|
|
||||||
static Mem &GetMem() { return *GetInstance().mem; }
|
static Mem &GetMem() { return *GetInstance().mem; }
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
|
#include <Scheduler.hpp>
|
||||||
|
#include "jit/helpers.hpp"
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
Interpreter::Interpreter(Mem &mem, Registers ®s) : regs(regs), mem(mem) {}
|
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;
|
u32 paddr = 0;
|
||||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, regs.pc, paddr)) {
|
if (!regs.cop0.MapVAddr(Cop0::LOAD, vaddr, paddr)) {
|
||||||
regs.cop0.HandleTLBException(regs.pc);
|
regs.cop0.HandleTLBException(vaddr);
|
||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.pc);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, vaddr);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +71,7 @@ bool Interpreter::FetchThenMaybeAdvance(Instruction &instr) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Fetch(instr))
|
if (!Fetch(instr, regs.pc))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (ShouldServiceInterrupt()) {
|
if (ShouldServiceInterrupt()) {
|
||||||
@@ -99,13 +101,89 @@ u32 DivideAddr(u32 addr, u32& offset) {
|
|||||||
return addr / MAX_LINES_PER_BLOCK;
|
return addr / MAX_LINES_PER_BLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedLine* GetLine(CachedState& cachedState, u32 addr) {
|
CachedLine *CachedState::GetLine(u64 addr) {
|
||||||
u32 offset;
|
u32 offset;
|
||||||
u32 page = DivideAddr(addr, 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() {
|
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
|
} // namespace n64
|
||||||
|
|||||||
@@ -9,21 +9,34 @@ static constexpr u32 MAX_INSTRUCTION_PER_LINE = 128;
|
|||||||
static constexpr u32 MAX_LINES_PER_BLOCK = 1 << 12;
|
static constexpr u32 MAX_LINES_PER_BLOCK = 1 << 12;
|
||||||
|
|
||||||
struct CachedLine {
|
struct CachedLine {
|
||||||
std::array<u32, MAX_INSTRUCTION_PER_LINE> code;
|
std::array<Instruction, MAX_INSTRUCTION_PER_LINE> code = {};
|
||||||
u32 cycles = 0;
|
u32 cycles = 0;
|
||||||
u32 len = 0;
|
u32 len = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CachedBlock {
|
struct CachedBlock {
|
||||||
std::array<CachedLine*, MAX_LINES_PER_BLOCK / 4> lines;
|
std::array<CachedLine, MAX_LINES_PER_BLOCK / 4> lines = {};
|
||||||
|
bool valid = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
using CachedBlocks = std::array<std::vector<CachedBlock>, (u64(std::numeric_limits<u32>::max()) + 1) / MAX_LINES_PER_BLOCK>;
|
using CachedBlocks = std::vector<std::unique_ptr<CachedBlock>>;
|
||||||
|
|
||||||
struct CachedState {
|
struct CachedState {
|
||||||
CachedBlocks blocks;
|
CachedState() { blocks.resize((u64(std::numeric_limits<u32>::max()) + 1) / MAX_LINES_PER_BLOCK); }
|
||||||
CachedLine* lastLine = nullptr;
|
CachedBlocks blocks = {};
|
||||||
bool exception = false;
|
bool exception = false;
|
||||||
|
|
||||||
|
void Reset() {
|
||||||
|
for (auto &block : blocks) {
|
||||||
|
block.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
exception = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CachedLine *GetLine(u64);
|
||||||
|
void InsertLine(u64, const CachedLine &);
|
||||||
|
void EvictLine(u64);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Interpreter final {
|
struct Interpreter final {
|
||||||
@@ -34,10 +47,16 @@ struct Interpreter final {
|
|||||||
bool FetchThenMaybeAdvance(Instruction &);
|
bool FetchThenMaybeAdvance(Instruction &);
|
||||||
bool MaybeAdvance();
|
bool MaybeAdvance();
|
||||||
|
|
||||||
void Reset() { cop2Latch = {}; }
|
void Reset() {
|
||||||
|
cop2Latch = {};
|
||||||
|
cachedState.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend struct Cop1;
|
friend struct Cop1;
|
||||||
|
friend struct Mem;
|
||||||
|
|
||||||
|
void MaybeIdleSkip();
|
||||||
|
|
||||||
CachedState cachedState;
|
CachedState cachedState;
|
||||||
|
|
||||||
@@ -47,7 +66,7 @@ struct Interpreter final {
|
|||||||
Mem &mem;
|
Mem &mem;
|
||||||
u64 cop2Latch{};
|
u64 cop2Latch{};
|
||||||
|
|
||||||
bool Fetch(Instruction &);
|
bool Fetch(Instruction &, u64);
|
||||||
void CacheTypeData(u8, u64, u32, u32);
|
void CacheTypeData(u8, u64, u32, u32);
|
||||||
void CacheTypeInstruction(u8, u64, u32, u32);
|
void CacheTypeInstruction(u8, u64, u32, u32);
|
||||||
#define check_address_error(mask, vaddr) \
|
#define check_address_error(mask, vaddr) \
|
||||||
|
|||||||
@@ -140,7 +140,6 @@ void Interpreter::branch(const bool cond, const s64 address) {
|
|||||||
regs.delaySlot = true;
|
regs.delaySlot = true;
|
||||||
if (cond) {
|
if (cond) {
|
||||||
regs.nextPC = address;
|
regs.nextPC = address;
|
||||||
Core::MaybeIdleSkip();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +147,6 @@ void Interpreter::branch_likely(const bool cond, const s64 address) {
|
|||||||
if (cond) {
|
if (cond) {
|
||||||
regs.delaySlot = true;
|
regs.delaySlot = true;
|
||||||
regs.nextPC = address;
|
regs.nextPC = address;
|
||||||
Core::MaybeIdleSkip();
|
|
||||||
} else {
|
} else {
|
||||||
regs.SetPC64(regs.nextPC);
|
regs.SetPC64(regs.nextPC);
|
||||||
}
|
}
|
||||||
@@ -409,6 +407,7 @@ void Interpreter::sb(const Instruction instr) {
|
|||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
|
cachedState.EvictLine(address);
|
||||||
mem.Write<u8>(paddr, regs.Read<s64>(instr.rt()));
|
mem.Write<u8>(paddr, regs.Read<s64>(instr.rt()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -432,6 +431,7 @@ void Interpreter::sc(const Instruction instr) {
|
|||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
|
cachedState.EvictLine(address);
|
||||||
mem.Write<u32>(paddr, regs.Read<s64>(instr.rt()));
|
mem.Write<u32>(paddr, regs.Read<s64>(instr.rt()));
|
||||||
regs.Write(instr.rt(), 1);
|
regs.Write(instr.rt(), 1);
|
||||||
}
|
}
|
||||||
@@ -464,6 +464,7 @@ void Interpreter::scd(const Instruction instr) {
|
|||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
|
cachedState.EvictLine(address);
|
||||||
mem.Write<u32>(paddr, regs.Read<s64>(instr.rt()));
|
mem.Write<u32>(paddr, regs.Read<s64>(instr.rt()));
|
||||||
regs.Write(instr.rt(), 1);
|
regs.Write(instr.rt(), 1);
|
||||||
}
|
}
|
||||||
@@ -480,6 +481,7 @@ void Interpreter::sh(const Instruction instr) {
|
|||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
|
cachedState.EvictLine(address);
|
||||||
mem.Write<u16>(physical, regs.Read<s64>(instr.rt()));
|
mem.Write<u16>(physical, regs.Read<s64>(instr.rt()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -498,6 +500,7 @@ void Interpreter::sw(const Instruction instr) {
|
|||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
|
cachedState.EvictLine(address);
|
||||||
mem.Write<u32>(physical, regs.Read<s64>(instr.rt()));
|
mem.Write<u32>(physical, regs.Read<s64>(instr.rt()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -515,6 +518,7 @@ void Interpreter::sd(const Instruction instr) {
|
|||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
|
cachedState.EvictLine(address);
|
||||||
mem.Write(physical, regs.Read<s64>(instr.rt()));
|
mem.Write(physical, regs.Read<s64>(instr.rt()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -531,6 +535,7 @@ void Interpreter::sdl(const Instruction instr) {
|
|||||||
const u64 data = mem.Read<u64>(paddr & ~7);
|
const u64 data = mem.Read<u64>(paddr & ~7);
|
||||||
const u64 rt = regs.Read<s64>(instr.rt());
|
const u64 rt = regs.Read<s64>(instr.rt());
|
||||||
mem.Write(paddr & ~7, (data & ~mask) | (rt >> shift));
|
mem.Write(paddr & ~7, (data & ~mask) | (rt >> shift));
|
||||||
|
cachedState.EvictLine(address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -546,6 +551,7 @@ void Interpreter::sdr(const Instruction instr) {
|
|||||||
const u64 data = mem.Read<u64>(paddr & ~7);
|
const u64 data = mem.Read<u64>(paddr & ~7);
|
||||||
const u64 rt = regs.Read<s64>(instr.rt());
|
const u64 rt = regs.Read<s64>(instr.rt());
|
||||||
mem.Write(paddr & ~7, (data & ~mask) | (rt << shift));
|
mem.Write(paddr & ~7, (data & ~mask) | (rt << shift));
|
||||||
|
cachedState.EvictLine(address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -561,6 +567,7 @@ void Interpreter::swl(const Instruction instr) {
|
|||||||
const u32 data = mem.Read<u32>(paddr & ~3);
|
const u32 data = mem.Read<u32>(paddr & ~3);
|
||||||
const u32 rt = regs.Read<s64>(instr.rt());
|
const u32 rt = regs.Read<s64>(instr.rt());
|
||||||
mem.Write<u32>(paddr & ~3, (data & ~mask) | (rt >> shift));
|
mem.Write<u32>(paddr & ~3, (data & ~mask) | (rt >> shift));
|
||||||
|
cachedState.EvictLine(address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -576,6 +583,7 @@ void Interpreter::swr(const Instruction instr) {
|
|||||||
const u32 data = mem.Read<u32>(paddr & ~3);
|
const u32 data = mem.Read<u32>(paddr & ~3);
|
||||||
const u32 rt = regs.Read<s64>(instr.rt());
|
const u32 rt = regs.Read<s64>(instr.rt());
|
||||||
mem.Write<u32>(paddr & ~3, (data & ~mask) | (rt << shift));
|
mem.Write<u32>(paddr & ~3, (data & ~mask) | (rt << shift));
|
||||||
|
cachedState.EvictLine(address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,34 @@ static bool SpecialEndsBlock(const Instruction instr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool InstrHasDelaySlot(const Instruction instr) {
|
||||||
|
switch (instr.opcode()) {
|
||||||
|
case Instruction::SPECIAL:
|
||||||
|
if (instr.special() == Instruction::JR || instr.special() == Instruction::JALR)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
case Instruction::REGIMM:
|
||||||
|
case Instruction::J:
|
||||||
|
case Instruction::JAL:
|
||||||
|
case Instruction::BEQ:
|
||||||
|
case Instruction::BNE:
|
||||||
|
case Instruction::BLEZ:
|
||||||
|
case Instruction::BGTZ:
|
||||||
|
case Instruction::BEQL:
|
||||||
|
case Instruction::BNEL:
|
||||||
|
case Instruction::BLEZL:
|
||||||
|
case Instruction::BGTZL:
|
||||||
|
return true;
|
||||||
|
case Instruction::COP1:
|
||||||
|
if (instr.cop_rs() == 8)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool InstrEndsBlock(const Instruction instr) {
|
static bool InstrEndsBlock(const Instruction instr) {
|
||||||
switch (instr.opcode()) {
|
switch (instr.opcode()) {
|
||||||
case Instruction::SPECIAL:
|
case Instruction::SPECIAL:
|
||||||
@@ -31,7 +59,16 @@ static bool InstrEndsBlock(const Instruction instr) {
|
|||||||
case Instruction::BNE:
|
case Instruction::BNE:
|
||||||
case Instruction::BLEZ:
|
case Instruction::BLEZ:
|
||||||
case Instruction::BGTZ:
|
case Instruction::BGTZ:
|
||||||
|
case Instruction::BEQL:
|
||||||
|
case Instruction::BNEL:
|
||||||
|
case Instruction::BLEZL:
|
||||||
|
case Instruction::BGTZL:
|
||||||
return true;
|
return true;
|
||||||
|
case Instruction::COP1:
|
||||||
|
if (instr.cop_rs() == 8)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -55,16 +92,10 @@ static bool IsBranchLikely(const Instruction instr) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
case Instruction::COP1:
|
case Instruction::COP1:
|
||||||
{
|
if (instr.cop_rs() == 8 && (instr.cop_rt() == 2 || instr.cop_rt() == 3))
|
||||||
if (instr.cop_rs() == 0x08) {
|
|
||||||
if (instr.cop_rt() == 2 || instr.cop_rt() == 3)
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,9 +51,10 @@ auto PI::BusRead<u8, true>(u32 addr) -> u8 {
|
|||||||
n64::Mem &mem = n64::Core::GetMem();
|
n64::Mem &mem = n64::Core::GetMem();
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case REGION_PI_UNKNOWN:
|
case REGION_PI_UNKNOWN:
|
||||||
|
mem.DumpRDRAM();
|
||||||
panic("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, "
|
panic("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, "
|
||||||
"returning FF because it is not emulated",
|
"returning FF because it is not emulated (pc: 0x{:016X})",
|
||||||
addr);
|
addr, (u64)Core::GetRegs().oldPC);
|
||||||
case REGION_PI_64DD_REG:
|
case REGION_PI_64DD_REG:
|
||||||
panic("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, "
|
panic("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, "
|
||||||
"returning FF because it is not emulated",
|
"returning FF because it is not emulated",
|
||||||
|
|||||||
@@ -366,10 +366,9 @@ void Cop0::FireException(const ExceptionCode code, const int cop, s64 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) {
|
||||||
|
vectorOffset = 0x0000;
|
||||||
if (is64BitAddressing)
|
if (is64BitAddressing)
|
||||||
vectorOffset = 0x0080;
|
vectorOffset = 0x0080;
|
||||||
else
|
|
||||||
vectorOffset = 0x0000;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user