Cache instructions implemented but broken lmao. Commented out for now

This commit is contained in:
2026-04-29 12:05:45 +02:00
parent e140a6d124
commit 609fa2fb08
14 changed files with 3721 additions and 3495 deletions
+94
View File
@@ -0,0 +1,94 @@
#include <Core.hpp>
namespace n64 {
void InstructionCache::FillLine(u64 vaddr, u32 paddr) {
int index = GetICacheLineIndex(vaddr);
auto &line = lines[index];
line.valid = true;
line.ptag = paddr & ~0x00000fff;
auto &mmio = Core::GetMem().mmio;
for (int i = 0; i < 8; i++) {
line.data[i] = mmio.rdp.ReadRDRAM<u32>(line.ptag | index);
}
}
void InstructionCache::StoreTag(u64 vaddr, u32 ptag, Cop0 &cop0) {
auto &line = lines[GetICacheLineIndex(vaddr)];
line.valid = (cop0.tagLo.pstate >> 1) & 1;
line.ptag = ptag;
}
void DataCache::StoreTag(u64 vaddr, u32 ptag, Cop0 &cop0) {
auto &line = lines[GetDCacheLineIndex(vaddr)];
line.valid = (cop0.tagLo.pstate >> 1) & 1;
line.dirty = (cop0.tagLo.pstate >> 0) & 1;
line.ptag = ptag;
}
void InstructionCache::LoadTag(u64 vaddr) {
auto &cop0 = Core::GetRegs().cop0;
auto &line = lines[GetICacheLineIndex(vaddr)];
cop0.tagLo.pstate = line.valid << 1;
cop0.tagLo.ptaglo = line.ptag;
}
void DataCache::LoadTag(u64 vaddr) {
auto &cop0 = Core::GetRegs().cop0;
auto &line = lines[GetDCacheLineIndex(vaddr)];
cop0.tagLo.pstate = (line.valid << 1) | line.dirty;
cop0.tagLo.ptaglo = line.ptag;
}
template <>
void DataCache::WriteBack<false>(u64 vaddr, u32 paddr) {
auto &mmio = Core::GetMem().mmio;
DCacheLine &line = lines[GetDCacheLineIndex(vaddr)];
if (!line.valid)
return;
u32 origPhysAddr = (line.ptag << 12) | (paddr & 0xfff);
u32 lineStart = GetDCacheLineStart(origPhysAddr);
for (int i = 0; i < 16; i++) {
mmio.rdp.WriteRDRAM(lineStart + i, line.data[i]);
}
line.dirty = false;
}
template <>
void DataCache::WriteBack<true>(u64 vaddr, u32 paddr) {
WriteBack<false>(vaddr, paddr);
lines[GetDCacheLineIndex(vaddr)].valid = false;
}
template <>
void DataCache::WriteBack<false>(u64 vaddr, u32 paddr, u32 ptag) {
DCacheLine &line = lines[GetDCacheLineIndex(vaddr)];
if (line.ptag == ptag)
WriteBack(vaddr, paddr);
}
template <>
void DataCache::WriteBack<true>(u64 vaddr, u32 paddr, u32 ptag) {
DCacheLine &line = lines[GetDCacheLineIndex(vaddr)];
if (line.ptag == ptag)
WriteBack<true>(vaddr, paddr);
}
void InstructionCache::WriteBack(u64 vaddr, u32 paddr, u32 ptag) {
auto &mmio = Core::GetMem().mmio;
ICacheLine &line = lines[GetICacheLineIndex(vaddr)];
if (line.ptag == ptag && line.valid) {
u32 origPhysAddr = (line.ptag << 12) | (paddr & 0xfff);
u32 lineStart = GetICacheLineStart(origPhysAddr);
for (int i = 0; i < 16; i++) {
mmio.rdp.WriteRDRAM(lineStart + i, line.data[i]);
}
}
}
} // namespace n64
+44 -10
View File
@@ -1,27 +1,61 @@
#pragma once
#include <common.hpp>
#include <array>
namespace n64 {
struct alignas(32) InstructionCache {
struct alignas(32) ICacheLine {
bool valid;
u32 data[8];
u32 ptag;
private:
friend struct Interpreter;
int GetLineIndex(u64 vaddr) { return (vaddr >> 5) & 0x1FF; }
u32 GetLineStart(u64 paddr) { return paddr & ~0x1F; }
};
struct alignas(32) DataCache {
struct alignas(32) DCacheLine {
bool valid, dirty;
u8 data[16];
u32 ptag;
int index;
};
struct Cop0;
inline const u32 GetPhysicalAddressPTag(const u32 paddr) { return paddr >> 12; }
inline const int GetICacheLineIndex(u64 vaddr) { return (vaddr >> 5) & 0x1FF; }
inline const u32 GetICacheLineStart(u64 paddr) { return paddr & ~0x1F; }
inline const int GetDCacheLineIndex(u64 vaddr) { return (vaddr >> 4) & 0x1FF; }
inline const u32 GetDCacheLineStart(u64 paddr) { return paddr & ~0xF; }
struct InstructionCache {
std::array<ICacheLine, 512> lines;
void FillLine(u64, u32);
void InvalidateIndex(u64 vaddr) { lines[GetICacheLineIndex(vaddr)].valid = false; }
void StoreTag(u64, u32, Cop0 &);
void LoadTag(u64 vaddr);
void WriteBack(u64 vaddr, u32 paddr, u32 ptag);
void InvalidateIndex(u64 vaddr, u32 ptag) {
int lineIndex = GetICacheLineIndex(vaddr);
if (lines[lineIndex].valid && lines[lineIndex].ptag == ptag)
lines[lineIndex].valid = false;
}
private:
friend struct Interpreter;
int GetLineIndex(u64 vaddr) { return (vaddr >> 4) & 0x1FF; }
u32 GetLineStart(u64 paddr) { return paddr & ~0xF; }
};
struct DataCache {
std::array<DCacheLine, 512> lines;
void StoreTag(u64, u32, Cop0 &);
void LoadTag(u64 vaddr);
template <bool invalidate = false>
void WriteBack(u64 vaddr, u32 paddr);
template <bool invalidate = false>
void WriteBack(u64 vaddr, u32 paddr, u32 ptag);
void InvalidateIndex(u64 vaddr) { lines[GetDCacheLineIndex(vaddr)].valid = false; }
void InvalidateIndex(u64 vaddr, u32 ptag) {
int lineIndex = GetDCacheLineIndex(vaddr);
if (lines[lineIndex].valid && lines[lineIndex].ptag == ptag)
lines[lineIndex].valid = false;
}
};
} // namespace n64
+3 -3
View File
@@ -1,7 +1,7 @@
#include <Core.hpp>
namespace n64 {
Interpreter::Interpreter(Mem& mem, Registers& regs) : regs(regs), mem(mem) {}
Interpreter::Interpreter(Mem &mem, Registers &regs) : regs(regs), mem(mem) {}
bool Interpreter::ShouldServiceInterrupt() const {
const bool interrupts_pending = (regs.cop0.status.im & regs.cop0.cause.interruptPending) != 0;
@@ -29,7 +29,7 @@ u32 Interpreter::Step() {
if (check_address_error(0b11, u64(regs.pc))) [[unlikely]] {
regs.cop0.HandleTLBException(regs.pc);
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.pc);
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.pc);
return 1;
}
@@ -43,7 +43,7 @@ u32 Interpreter::Step() {
const u32 instruction = mem.Read<u32>(paddr);
if (ShouldServiceInterrupt()) {
regs.cop0.FireException(ExceptionCode::Interrupt, 0, regs.pc);
regs.cop0.FireException(Cop0::ExceptionCode::Interrupt, 0, regs.pc);
return 1;
}
+2 -2
View File
@@ -20,8 +20,8 @@ struct Interpreter final {
u64 cop2Latch{};
friend struct Cop1;
void cache_type_data(u8);
void cache_type_instruction(u8);
void cache_type_data(u8, u64, u32, u32);
void cache_type_instruction(u8, u64, u32, u32);
#define check_address_error(mask, vaddr) \
(((!regs.cop0.is64BitAddressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0))
[[nodiscard]] bool ShouldServiceInterrupt() const;
+1 -1
View File
@@ -43,7 +43,7 @@ std::optional<u32> JIT::FetchInstruction(s64 vaddr) {
if (check_address_error(0b11, vaddr)) [[unlikely]] {
/*regs.cop0.HandleTLBException(blockPC);
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, blockPC);
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, blockPC);
return 1;*/
Util::Error::GetInstance().Throw({Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_EXCEPTION},
blockPC, {},
@@ -4,29 +4,29 @@
namespace n64 {
void Cop0::mtc0(const Instruction instr) {
Registers& regs = Core::GetRegs();
Registers &regs = Core::GetRegs();
SetReg32(instr.rd(), regs.Read<u32>(instr.rt()));
}
void Cop0::dmtc0(const Instruction instr) {
Registers& regs = Core::GetRegs();
Registers &regs = Core::GetRegs();
SetReg64(instr.rd(), regs.Read<u64>(instr.rt()));
}
void Cop0::mfc0(const Instruction instr) {
Registers& regs = Core::GetRegs();
Registers &regs = Core::GetRegs();
regs.Write(instr.rt(), s32(GetReg32(instr.rd())));
}
void Cop0::dmfc0(const Instruction instr) const {
Registers& regs = Core::GetRegs();
Registers &regs = Core::GetRegs();
regs.Write(instr.rt(), s64(GetReg64(instr.rd())));
}
void Cop0::eret() {
Registers& regs = Core::GetRegs();
Registers &regs = Core::GetRegs();
if (!regs.cop0.kernelMode) {
FireException(ExceptionCode::CoprocessorUnusable, 0, regs.oldPC);
FireException(Cop0::ExceptionCode::CoprocessorUnusable, 0, regs.oldPC);
return;
}
if (status.erl) {
File diff suppressed because it is too large Load Diff
+6 -9
View File
@@ -33,10 +33,10 @@ void Interpreter::special(const Instruction instr) {
jalr(instr);
break;
case Instruction::SYSCALL:
regs.cop0.FireException(ExceptionCode::Syscall, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::Syscall, 0, regs.oldPC);
break;
case Instruction::BREAK:
regs.cop0.FireException(ExceptionCode::Breakpoint, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::Breakpoint, 0, regs.oldPC);
break;
case Instruction::SYNC:
break; // SYNC
@@ -222,7 +222,7 @@ void Interpreter::regimm(const Instruction instr) {
void Interpreter::cop2Decode(const Instruction instr) {
if (!regs.cop0.status.cu2) {
regs.cop0.FireException(ExceptionCode::CoprocessorUnusable, 2, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::CoprocessorUnusable, 2, regs.oldPC);
return;
}
switch (instr.rs()) {
@@ -245,7 +245,7 @@ void Interpreter::cop2Decode(const Instruction instr) {
ctc2(instr);
break;
default:
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 2, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::ReservedInstruction, 2, regs.oldPC);
}
}
@@ -361,7 +361,7 @@ void Interpreter::Exec(const Instruction instr) {
ldr(instr);
break;
case 0x1F:
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::ReservedInstruction, 0, regs.oldPC);
break;
case Instruction::LB:
lb(instr);
@@ -409,10 +409,7 @@ void Interpreter::Exec(const Instruction instr) {
swr(instr);
break;
case Instruction::CACHE:
{
panic("CACHE 0b{:05b}, 0x{:04X}({}/r{} = 0x{:08X})", instr.op(), instr.offset(),
Registers::regNames[instr.base()], instr.base(), regs.Read<u64>(instr.base()));
}
// cache(instr);
break;
case Instruction::LL:
ll(instr);
+89 -26
View File
@@ -8,7 +8,7 @@ void Interpreter::add(const Instruction instr) {
const u32 rs = regs.Read<s32>(instr.rs());
const u32 rt = regs.Read<s32>(instr.rt());
if (const u32 result = rs + rt; check_signed_overflow(rs, rt, result)) {
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::Overflow, 0, regs.oldPC);
} else {
regs.Write(instr.rd(), static_cast<s32>(result));
}
@@ -25,7 +25,7 @@ void Interpreter::addi(const Instruction instr) {
const u32 rs = regs.Read<s64>(instr.rs());
const u32 imm = static_cast<s32>(static_cast<s16>(instr));
if (const u32 result = rs + imm; check_signed_overflow(rs, imm, result)) {
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::Overflow, 0, regs.oldPC);
} else {
regs.Write(instr.rt(), static_cast<s32>(result));
}
@@ -42,7 +42,7 @@ void Interpreter::dadd(const Instruction instr) {
const u64 rs = regs.Read<s64>(instr.rs());
const u64 rt = regs.Read<s64>(instr.rt());
if (const u64 result = rt + rs; check_signed_overflow(rs, rt, result)) {
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::Overflow, 0, regs.oldPC);
} else {
regs.Write(instr.rd(), result);
}
@@ -58,7 +58,7 @@ void Interpreter::daddi(const Instruction instr) {
const u64 imm = s64(s16(instr));
const u64 rs = regs.Read<s64>(instr.rs());
if (const u64 result = imm + rs; check_signed_overflow(rs, imm, result)) {
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::Overflow, 0, regs.oldPC);
} else {
regs.Write(instr.rt(), result);
}
@@ -202,7 +202,7 @@ void Interpreter::lh(const Instruction instr) {
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
if (check_address_error(0b1, address)) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
return;
}
@@ -220,7 +220,7 @@ void Interpreter::lw(const Instruction instr) {
const u64 address = regs.Read<s64>(instr.rs()) + offset;
if (check_address_error(0b11, address)) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
return;
}
@@ -242,7 +242,7 @@ void Interpreter::ll(const Instruction instr) {
} else {
const s32 result = mem.Read<u32>(physical);
if (check_address_error(0b11, address)) {
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
return;
}
@@ -287,7 +287,7 @@ void Interpreter::ld(const Instruction instr) {
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
if (check_address_error(0b111, address)) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
return;
}
@@ -303,7 +303,7 @@ void Interpreter::ld(const Instruction instr) {
void Interpreter::lld(const Instruction instr) {
if (!regs.cop0.is64BitAddressing && !regs.cop0.kernelMode) {
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::ReservedInstruction, 0, regs.oldPC);
return;
}
@@ -314,7 +314,7 @@ void Interpreter::lld(const Instruction instr) {
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else {
if (check_address_error(0b111, address)) {
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
} else {
regs.Write(instr.rt(), mem.Read<u64>(paddr));
regs.cop0.llbit = true;
@@ -369,7 +369,7 @@ void Interpreter::lhu(const Instruction instr) {
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
if (check_address_error(0b1, address)) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
return;
}
u32 paddr;
@@ -386,7 +386,7 @@ void Interpreter::lwu(const Instruction instr) {
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
if (check_address_error(0b11, address)) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
return;
}
@@ -420,7 +420,7 @@ void Interpreter::sc(const Instruction instr) {
if (check_address_error(0b11, address)) {
regs.Write(instr.rt(), 0);
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorStore, 0, regs.oldPC);
return;
}
@@ -440,7 +440,7 @@ void Interpreter::sc(const Instruction instr) {
void Interpreter::scd(const Instruction instr) {
if (!regs.cop0.is64BitAddressing && !regs.cop0.kernelMode) {
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::ReservedInstruction, 0, regs.oldPC);
return;
}
@@ -452,7 +452,7 @@ void Interpreter::scd(const Instruction instr) {
if (check_address_error(0b111, address)) {
regs.Write(instr.rt(), 0);
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorStore, 0, regs.oldPC);
return;
}
@@ -487,7 +487,7 @@ void Interpreter::sw(const Instruction instr) {
const u64 address = regs.Read<s64>(instr.rs()) + offset;
if (check_address_error(0b11, address)) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorStore, 0, regs.oldPC);
return;
}
@@ -504,7 +504,7 @@ void Interpreter::sd(const Instruction instr) {
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
if (check_address_error(0b111, address)) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorStore, 0, regs.oldPC);
return;
}
@@ -757,7 +757,7 @@ void Interpreter::dsub(const Instruction instr) {
const s64 rt = regs.Read<s64>(instr.rt());
const s64 rs = regs.Read<s64>(instr.rs());
if (const s64 result = rs - rt; check_signed_underflow(rs, rt, result)) {
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::Overflow, 0, regs.oldPC);
} else {
regs.Write(instr.rd(), result);
}
@@ -775,7 +775,7 @@ void Interpreter::sub(const Instruction instr) {
const s32 rs = regs.Read<s64>(instr.rs());
const s32 result = rs - rt;
if (check_signed_underflow(rs, rt, result)) {
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::Overflow, 0, regs.oldPC);
} else {
regs.Write(instr.rd(), result);
}
@@ -831,7 +831,7 @@ void Interpreter::mthi(const Instruction instr) { regs.hi = regs.Read<s64>(instr
void Interpreter::trap(const bool cond) const {
Cop0 &cop0 = Core::GetRegs().cop0;
if (cond) {
cop0.FireException(ExceptionCode::Trap, 0, regs.oldPC);
cop0.FireException(Cop0::ExceptionCode::Trap, 0, regs.oldPC);
}
}
@@ -852,21 +852,84 @@ void Interpreter::cfc2(const Instruction) {}
void Interpreter::cache(const Instruction instr) {
u8 type = instr.op() & 3;
u8 op = (instr.op() >> 2) & 7;
const u8 op = (instr.op() >> 2) & 7;
u64 vaddr = regs.Read<u64>(instr.rs()) + (s16)instr.offset();
u32 paddr;
if (!regs.cop0.MapVAddr(Cop0::LOAD, vaddr, paddr)) {
regs.cop0.HandleTLBException(vaddr);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
return;
}
u32 ptag = GetPhysicalAddressPTag(paddr);
if (type > 1)
panic("Unknown cache type {}", type);
if (type == 0)
return cache_type_instruction(op);
return cache_type_instruction(op, vaddr, paddr, ptag);
if (type == 1)
return cache_type_data(op);
return cache_type_data(op, vaddr, paddr, ptag);
}
void Interpreter::cache_type_instruction(const u8 op) {
void Interpreter::cache_type_instruction(const u8 op, const u64 vaddr, const u32 paddr, const u32 ptag) {
switch (op) {
case 0:
icache.
icache.InvalidateIndex(vaddr);
break;
case 1:
icache.LoadTag(vaddr);
break;
case 2:
icache.StoreTag(vaddr, regs.cop0.tagLo.ptaglo, regs.cop0);
break;
case 4:
icache.InvalidateIndex(vaddr, ptag);
break;
case 5:
icache.FillLine(vaddr, paddr);
break;
case 6:
icache.WriteBack(vaddr, paddr, ptag);
break;
default:
panic("Unimplemented icache op 0b{:03b}", op);
}
}
void Interpreter::cache_type_data(const u8 op, const u64 vaddr, const u32 paddr, const u32 ptag) {
switch (op) {
case 0:
dcache.WriteBack<true>(vaddr, paddr);
break;
case 1:
dcache.LoadTag(vaddr);
break;
case 2:
dcache.StoreTag(vaddr, regs.cop0.tagLo.ptaglo, regs.cop0);
break;
case 3:
{
auto &line = dcache.lines[GetDCacheLineIndex(vaddr)];
if ((line.ptag != ptag || !line.valid) && line.dirty)
dcache.WriteBack(vaddr, paddr);
line.ptag = ptag;
line.valid = true;
line.dirty = true;
}
break;
case 4:
dcache.InvalidateIndex(vaddr, ptag);
break;
case 5:
dcache.WriteBack<true>(vaddr, paddr, ptag);
break;
case 6:
dcache.WriteBack(vaddr, paddr, ptag);
break;
default:
panic("Unimplemented dcache op 0b{:03b}", op);
}
}
} // namespace n64
+6 -6
View File
@@ -32,10 +32,10 @@ void JIT::special(const Instruction instr) {
jalr(instr);
break;
case Instruction::SYSCALL:
regs.cop0.FireException(ExceptionCode::Syscall, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::Syscall, 0, regs.oldPC);
break;
case Instruction::BREAK:
regs.cop0.FireException(ExceptionCode::Breakpoint, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::Breakpoint, 0, regs.oldPC);
break;
case Instruction::SYNC:
break; // SYNC
@@ -311,8 +311,7 @@ void JIT::Emit(const Instruction instr) {
emitMemberFunctionCall(&Cop0::eret, &regs.cop0);
break;
default:
panic("Unimplemented COP0 function {} ({:08X}) ({:016X})", instr.cop_funct(), u32(instr),
regs.oldPC);
panic("Unimplemented COP0 function {} ({:08X}) ({:016X})", instr.cop_funct(), u32(instr), regs.oldPC);
}
break;
default:
@@ -378,7 +377,7 @@ void JIT::Emit(const Instruction instr) {
ldr(instr);
break;
case 0x1F:
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::ReservedInstruction, 0, regs.oldPC);
break;
case Instruction::LB:
lb(instr);
@@ -459,7 +458,8 @@ void JIT::Emit(const Instruction instr) {
break;
default:
DumpBlockCacheToDisk();
panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})", instr.opcode(), u32(instr), static_cast<u64>(regs.oldPC));
panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})", instr.opcode(), u32(instr),
static_cast<u64>(regs.oldPC));
}
}
} // namespace n64
+31 -29
View File
@@ -18,7 +18,7 @@ void JIT::add(const Instruction instr) {
const u32 rt = regs.Read<s32>(instr.rt());
const u32 result = rs + rt;
if (check_signed_overflow(rs, rt, result)) {
// regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
// regs.cop0.FireException(Cop0::ExceptionCode::Overflow, 0, regs.oldPC);
panic("[JIT]: Unhandled Overflow exception in ADD!");
}
@@ -205,16 +205,12 @@ void JIT::BranchTaken(const Xbyak::Reg64 &offs) {
SetPC64(code.SCR2);
}
void JIT::BranchAbsTaken(const s64 addr) {
SetPC64(addr);
}
void JIT::BranchAbsTaken(const s64 addr) { SetPC64(addr); }
void JIT::BranchAbsTaken(const Xbyak::Reg64 &addr) {
SetPC64(addr);
}
void JIT::BranchAbsTaken(const Xbyak::Reg64 &addr) { SetPC64(addr); }
void JIT::branch_constant(const bool cond, const s64 offset) {
if(cond) {
if (cond) {
regs.delaySlot = true;
BranchTaken(offset);
branch_taken = true;
@@ -222,7 +218,7 @@ void JIT::branch_constant(const bool cond, const s64 offset) {
}
void JIT::branch_abs_constant(const bool cond, const s64 address) {
if(cond) {
if (cond) {
regs.delaySlot = true;
BranchAbsTaken(address);
branch_taken = true;
@@ -230,7 +226,7 @@ void JIT::branch_abs_constant(const bool cond, const s64 address) {
}
void JIT::branch_likely_constant(const bool cond, const s64 offset) {
if(cond) {
if (cond) {
regs.delaySlot = true;
BranchTaken(offset);
branch_taken = true;
@@ -239,29 +235,34 @@ void JIT::branch_likely_constant(const bool cond, const s64 offset) {
}
}
#define branch(offs, cond) do { \
#define branch(offs, cond) \
do { \
Xbyak::Label taken, not_taken; \
code.j## cond(taken); \
code.j##cond(taken); \
code.jmp(not_taken); \
code.L(taken); \
BranchTaken(offs); \
code.mov(code.byte[code.rbp + BRANCH_TAKEN_OFFSET], 1); \
code.L(not_taken); \
} while(0)
} \
while (0)
#define branch_abs(addr, cond) do { \
#define branch_abs(addr, cond) \
do { \
Xbyak::Label taken, not_taken; \
code.j## cond(taken); \
code.j##cond(taken); \
code.jmp(not_taken); \
code.L(taken); \
BranchAbsTaken(addr); \
code.mov(code.byte[code.rbp + BRANCH_TAKEN_OFFSET], 1); \
code.L(not_taken); \
} while(0)
} \
while (0)
#define branch_likely(offs, cond) do { \
#define branch_likely(offs, cond) \
do { \
Xbyak::Label taken, not_taken, end; \
code.j## cond(taken); \
code.j##cond(taken); \
code.jmp(not_taken); \
code.L(taken); \
BranchTaken(offs); \
@@ -270,7 +271,8 @@ void JIT::branch_likely_constant(const bool cond, const s64 offset) {
code.L(not_taken); \
SetPC64(blockNextPC); \
code.L(end); \
} while(0)
} \
while (0)
void JIT::bltz(const Instruction instr) {
const s16 imm = instr;
@@ -558,7 +560,7 @@ void JIT::dadd(const Instruction instr) {
auto rt = regs.Read<u64>(instr.rt());
u64 result = rt + rs;
if (check_signed_overflow(rs, rt, result)) {
// regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
// regs.cop0.FireException(Cop0::ExceptionCode::Overflow, 0, regs.oldPC);
panic("[JIT]: Unhandled Overflow exception in DADD!");
}
regs.Write(instr.rd(), result);
@@ -598,7 +600,7 @@ void JIT::daddi(const Instruction instr) {
auto rs = regs.Read<u64>(instr.rs());
u64 result = imm + rs;
if (check_signed_overflow(rs, imm, result)) {
// regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
// regs.cop0.FireException(Cop0::ExceptionCode::Overflow, 0, regs.oldPC);
panic("[JIT]: Unhandled Overflow exception in DADDI!");
}
regs.Write(instr.rt(), result);
@@ -842,7 +844,7 @@ void JIT::dsub(const Instruction instr) {
auto rs = regs.Read<s64>(instr.rs());
s64 result = rs - rt;
if (check_signed_underflow(rs, rt, result)) {
// regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
// regs.cop0.FireException(Cop0::ExceptionCode::Overflow, 0, regs.oldPC);
panic("[JIT]: Unhandled Overflow exception in DSUB!");
} else {
regs.Write(instr.rd(), result);
@@ -930,7 +932,7 @@ void JIT::ld(const Instruction instr) {
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
if (check_address_error(0b111, address)) {
// regs.cop0.HandleTLBException(address);
// regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
// regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
// return;
panic("[JIT]: Unhandled ADEL exception in LD!");
}
@@ -1014,7 +1016,7 @@ void JIT::lh(const Instruction instr) {
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
if (check_address_error(0b1, address)) {
// regs.cop0.HandleTLBException(address);
// regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
// regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
// return;
panic("[JIT]: Unhandled ADEL exception in LH!");
return;
@@ -1043,7 +1045,7 @@ void JIT::lhu(const Instruction instr) {
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
if (check_address_error(0b1, address)) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
return;
}
@@ -1080,7 +1082,7 @@ void JIT::lw(const Instruction instr) {
const u64 address = regs.Read<s64>(instr.rs()) + offset;
if (check_address_error(0b11, address)) {
// regs.cop0.HandleTLBException(address);
// regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
// regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
// return;
panic("[JIT]: Unhandled ADEL exception in LW!");
return;
@@ -1283,7 +1285,7 @@ void JIT::sub(const Instruction instr) {
s32 rs = regs.Read<s64>(instr.rs());
s32 result = rs - rt;
if (check_signed_underflow(rs, rt, result)) {
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
regs.cop0.FireException(Cop0::ExceptionCode::Overflow, 0, regs.oldPC);
} else {
regs.Write(instr.rd(), result);
}
@@ -1344,7 +1346,7 @@ void JIT::sw(const Instruction instr) {
const u64 address = regs.Read<s64>(instr.rs()) + offset;
if (check_address_error(0b11, address)) {
// regs.cop0.HandleTLBException(address);
// regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
// regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorStore, 0, regs.oldPC);
panic("[JIT]: Unhandled ADES exception in SW!");
return;
}
@@ -1367,7 +1369,7 @@ void JIT::sw(const Instruction instr) {
const u64 address = regs.Read<s64>(instr.rs()) + offset;
if (check_address_error(0b11, address)) {
// regs.cop0.HandleTLBException(address);
// regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
// regs.cop0.FireException(Cop0::ExceptionCode::AddressErrorStore, 0, regs.oldPC);
panic("[JIT]: Unhandled ADES exception in SW!");
return;
}
+63 -40
View File
@@ -34,7 +34,7 @@ void Cop0::Reset() {
LLAddr = {}, WatchLo = {}, WatchHi = {};
xcontext = {};
r21 = {}, r22 = {}, r23 = {}, r24 = {}, r25 = {};
ParityError = {}, CacheError = {}, TagLo = {}, TagHi = {};
ParityError = {}, CacheError = {}, tagLo = {}, TagHi = {};
ErrorEPC = {};
r31 = {};
memset(tlb, 0, sizeof(TLBEntry) * 32);
@@ -89,7 +89,7 @@ u32 Cop0::GetReg32(const u8 addr) {
case COP0_REG_CACHE_ERR:
return CacheError;
case COP0_REG_TAGLO:
return TagLo;
return tagLo.raw;
case COP0_REG_TAGHI:
return TagHi;
case COP0_REG_ERROREPC:
@@ -186,7 +186,7 @@ void Cop0::SetReg32(const u8 addr, const u32 value) {
break;
case COP0_REG_CAUSE:
{
Cop0Cause tmp{};
Cause tmp{};
tmp.raw = value;
cause.ip0 = tmp.ip0;
cause.ip1 = tmp.ip1;
@@ -219,7 +219,7 @@ void Cop0::SetReg32(const u8 addr, const u32 value) {
case COP0_REG_CACHE_ERR:
break;
case COP0_REG_TAGLO:
TagLo = value;
tagLo.raw = value;
break;
case COP0_REG_TAGHI:
TagHi = value;
@@ -263,7 +263,7 @@ void Cop0::SetReg64(const u8 addr, const u64 value) {
break;
case COP0_REG_CAUSE:
{
Cop0Cause tmp{};
Cause tmp{};
tmp.raw = value;
cause.ip0 = tmp.ip0;
cause.ip1 = tmp.ip1;
@@ -292,7 +292,7 @@ static FORCE_INLINE u64 getVPN(const u64 addr, const u64 pageMask) {
return vpn & ~mask;
}
TLBEntry *Cop0::TLBTryMatch(const u64 vaddr, int &index) {
Cop0::TLBEntry *Cop0::TLBTryMatch(const u64 vaddr, int &index) {
for (int i = 0; i < 32; i++) {
TLBEntry *entry = &tlb[i];
if (!entry->initialized)
@@ -304,7 +304,7 @@ TLBEntry *Cop0::TLBTryMatch(const u64 vaddr, int &index) {
const bool vpn_match = entry_vpn == vaddr_vpn;
const bool asid_match = entry->global || entryHi.asid == entry->entryHi.asid;
if(!vpn_match || !asid_match)
if (!vpn_match || !asid_match)
continue;
index = i;
@@ -314,7 +314,7 @@ TLBEntry *Cop0::TLBTryMatch(const u64 vaddr, int &index) {
return nullptr;
}
TLBEntry *Cop0::TLBTryMatch(const u64 vaddr) {
Cop0::TLBEntry *Cop0::TLBTryMatch(const u64 vaddr) {
for (auto &t : tlb) {
TLBEntry *entry = &t;
if (!entry->initialized)
@@ -361,13 +361,15 @@ bool Cop0::ProbeTLB(const TLBAccessType accessType, const u64 vaddr, u32 &paddr)
}
void Cop0::FireException(const ExceptionCode code, const int cop, s64 pc) {
Registers& regs = Core::GetRegs();
Registers &regs = Core::GetRegs();
u16 vectorOffset = 0x0180;
if(tlbError == MISS && (code == ExceptionCode::TLBLoad || code == ExceptionCode::TLBStore)) {
if(!status.exl) {
if(is64BitAddressing) vectorOffset = 0x0080;
else vectorOffset = 0x0000;
if (tlbError == MISS && (code == ExceptionCode::TLBLoad || code == ExceptionCode::TLBStore)) {
if (!status.exl) {
if (is64BitAddressing)
vectorOffset = 0x0080;
else
vectorOffset = 0x0000;
}
}
@@ -402,7 +404,7 @@ void Cop0::HandleTLBException(const u64 vaddr) {
entryHi.r = vaddr >> 62 & 3;
}
ExceptionCode Cop0::GetTLBExceptionCode(const TLBError error, const TLBAccessType accessType) {
Cop0::ExceptionCode Cop0::GetTLBExceptionCode(const TLBError error, const TLBAccessType accessType) {
switch (error) {
case NONE:
panic("Getting TLB exception with error NONE");
@@ -420,22 +422,39 @@ ExceptionCode Cop0::GetTLBExceptionCode(const TLBError error, const TLBAccessTyp
}
void Cop0::decode(const Instruction instr) {
Registers& regs = Core::GetRegs();
Registers &regs = Core::GetRegs();
switch (instr.cop_rs()) {
case 0x00: mfc0(instr); break;
case 0x01: dmfc0(instr); break;
case 0x04: mtc0(instr); break;
case 0x05: dmtc0(instr); break;
case 0x00:
mfc0(instr);
break;
case 0x01:
dmfc0(instr);
break;
case 0x04:
mtc0(instr);
break;
case 0x05:
dmtc0(instr);
break;
case 0x10 ... 0x1F:
switch (instr.cop_funct()) {
case 0x01: tlbr(); break;
case 0x02: tlbw(index.i); break;
case 0x06: tlbw(GetRandom()); break;
case 0x08: tlbp(); break;
case 0x18: eret(); break;
case 0x01:
tlbr();
break;
case 0x02:
tlbw(index.i);
break;
case 0x06:
tlbw(GetRandom());
break;
case 0x08:
tlbp();
break;
case 0x18:
eret();
break;
default:
panic("Unimplemented COP0 function {} ({:08X}) ({:016X})", instr.cop_funct(), u32(instr),
regs.oldPC);
panic("Unimplemented COP0 function {} ({:08X}) ({:016X})", instr.cop_funct(), u32(instr), regs.oldPC);
}
break;
default:
@@ -446,7 +465,7 @@ void Cop0::decode(const Instruction instr) {
template <>
bool Cop0::MapVirtualAddress<u32, true>(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
if(ircolib::IsInsideRange(vaddr, START_VREGION_KUSEG, END_VREGION_KUSEG))
if (ircolib::IsInsideRange(vaddr, START_VREGION_KUSEG, END_VREGION_KUSEG))
return ProbeTLB(accessType, s64(s32(vaddr)), paddr);
tlbError = DISALLOWED_ADDRESS;
@@ -456,15 +475,15 @@ bool Cop0::MapVirtualAddress<u32, true>(const TLBAccessType accessType, const u6
template <>
bool Cop0::MapVirtualAddress<u32, false>(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
u8 segment = static_cast<u32>(vaddr) >> 29 & 7;
if(ircolib::IsInsideRange(segment, 0, 3) || segment == 7)
if (ircolib::IsInsideRange(segment, 0, 3) || segment == 7)
return ProbeTLB(accessType, static_cast<s32>(vaddr), paddr);
if(ircolib::IsInsideRange(segment, 4, 5)) {
if (ircolib::IsInsideRange(segment, 4, 5)) {
paddr = vaddr & 0x1FFFFFFF;
return true;
}
if(segment == 6)
if (segment == 6)
panic("Unimplemented virtual mapping in KSSEG! ({:08X})", vaddr);
panic("Should never end up in base case in MapVirtualAddress! ({:08X})", vaddr);
@@ -474,7 +493,7 @@ bool Cop0::MapVirtualAddress<u32, false>(const TLBAccessType accessType, const u
template <>
bool Cop0::MapVirtualAddress<u64, true>(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
if(ircolib::IsInsideRange(vaddr, 0x0000000000000000, 0x000000FFFFFFFFFF))
if (ircolib::IsInsideRange(vaddr, 0x0000000000000000, 0x000000FFFFFFFFFF))
return ProbeTLB(accessType, vaddr, paddr);
tlbError = DISALLOWED_ADDRESS;
@@ -483,13 +502,13 @@ bool Cop0::MapVirtualAddress<u64, true>(const TLBAccessType accessType, const u6
template <>
bool Cop0::MapVirtualAddress<u64, false>(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
if(ircolib::IsInsideRange(vaddr, 0x0000000000000000, 0x000000FFFFFFFFFF) || // VREGION_XKUSEG
if (ircolib::IsInsideRange(vaddr, 0x0000000000000000, 0x000000FFFFFFFFFF) || // VREGION_XKUSEG
ircolib::IsInsideRange(vaddr, 0x4000000000000000, 0x400000FFFFFFFFFF) || // VREGION_XKSSEG
ircolib::IsInsideRange(vaddr, 0xC000000000000000, 0xC00000FF7FFFFFFF) || // VREGION_XKSEG
ircolib::IsInsideRange(vaddr, 0xFFFFFFFFE0000000, 0xFFFFFFFFFFFFFFFF)) // VREGION_CKSEG3
return ProbeTLB(accessType, vaddr, paddr);
if(ircolib::IsInsideRange(vaddr, 0x8000000000000000, 0xBFFFFFFFFFFFFFFF)) { // VREGION_XKPHYS
if (ircolib::IsInsideRange(vaddr, 0x8000000000000000, 0xBFFFFFFFFFFFFFFF)) { // VREGION_XKPHYS
if (!kernelMode)
panic("Access to XKPHYS address 0x{:016X} when outside kernel mode!", vaddr);
@@ -510,7 +529,7 @@ bool Cop0::MapVirtualAddress<u64, false>(const TLBAccessType accessType, const u
return true;
}
if(ircolib::IsInsideRange(vaddr, 0xFFFFFFFF80000000, 0xFFFFFFFF9FFFFFFF) || // VREGION_CKSEG0
if (ircolib::IsInsideRange(vaddr, 0xFFFFFFFF80000000, 0xFFFFFFFF9FFFFFFF) || // VREGION_CKSEG0
ircolib::IsInsideRange(vaddr, 0xFFFFFFFFA0000000, 0xFFFFFFFFBFFFFFFF)) { // VREGION_CKSEG1
u32 cut = u32(vaddr) >> 28;
u32 num = cut == 0xA;
@@ -521,7 +540,7 @@ bool Cop0::MapVirtualAddress<u64, false>(const TLBAccessType accessType, const u
return true;
}
if(ircolib::IsInsideRange(vaddr, 0x0000010000000000, 0x3FFFFFFFFFFFFFFF) || // VREGION_XBAD1
if (ircolib::IsInsideRange(vaddr, 0x0000010000000000, 0x3FFFFFFFFFFFFFFF) || // VREGION_XBAD1
ircolib::IsInsideRange(vaddr, 0x4000010000000000, 0x7FFFFFFFFFFFFFFF) || // VREGION_XBAD2
ircolib::IsInsideRange(vaddr, 0xC00000FF80000000, 0xFFFFFFFF7FFFFFFF)) { // VREGION_XBAD3
tlbError = DISALLOWED_ADDRESS;
@@ -533,18 +552,22 @@ bool Cop0::MapVirtualAddress<u64, false>(const TLBAccessType accessType, const u
}
bool Cop0::MapVAddr(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
if(supervisorMode)
if (supervisorMode)
panic("Supervisor mode memory access");
if (is64BitAddressing) [[unlikely]] {
if (kernelMode) [[likely]] return MapVirtualAddress<u64, false>(accessType, vaddr, paddr);
if (userMode) return MapVirtualAddress<u64, true>(accessType, vaddr, paddr);
if (kernelMode) [[likely]]
return MapVirtualAddress<u64, false>(accessType, vaddr, paddr);
if (userMode)
return MapVirtualAddress<u64, true>(accessType, vaddr, paddr);
panic("Unknown mode! This should never happen!");
}
if (kernelMode) [[likely]] return MapVirtualAddress<u32, false>(accessType, vaddr, paddr);
if (userMode) return MapVirtualAddress<u32, true>(accessType, vaddr, paddr);
if (kernelMode) [[likely]]
return MapVirtualAddress<u32, false>(accessType, vaddr, paddr);
if (userMode)
return MapVirtualAddress<u32, true>(accessType, vaddr, paddr);
panic("Unknown mode! This should never happen!");
}
+39 -28
View File
@@ -38,7 +38,8 @@ namespace n64 {
#define ENTRY_HI_MASK 0xC00000FFFFFFE0FF
#define PAGEMASK_MASK 0x1FFE000
union Cop0Cause {
struct Cop0 {
union Cause {
u32 raw;
struct {
unsigned : 8;
@@ -62,9 +63,9 @@ union Cop0Cause {
unsigned : 1;
unsigned branchDelay : 1;
} __attribute__((__packed__));
};
};
union Cop0Status {
union Status {
struct {
unsigned ie : 1;
unsigned exl : 1;
@@ -97,9 +98,9 @@ union Cop0Status {
unsigned : 7;
} __attribute__((__packed__));
u32 raw;
} __attribute__((__packed__));
} __attribute__((__packed__));
union EntryLo {
union EntryLo {
u32 raw;
struct {
unsigned g : 1;
@@ -109,9 +110,9 @@ union EntryLo {
unsigned pfn : 20;
unsigned : 6;
};
};
};
union EntryHi {
union EntryHi {
u64 raw;
struct {
u64 asid : 8;
@@ -120,38 +121,38 @@ union EntryHi {
u64 fill : 22;
u64 r : 2;
} __attribute__((__packed__));
};
};
union PageMask {
union PageMask {
u32 raw;
struct {
unsigned : 13;
unsigned mask : 12;
unsigned : 7;
};
};
};
union Index {
union Index {
u32 raw;
struct {
unsigned i : 6;
unsigned : 25;
unsigned p : 1;
};
};
};
struct TLBEntry {
struct TLBEntry {
bool initialized;
EntryLo entryLo0, entryLo1;
EntryHi entryHi;
PageMask pageMask;
bool global;
};
};
enum TLBError : u8 { NONE, MISS, INVALID, MODIFICATION, DISALLOWED_ADDRESS };
enum TLBError : u8 { NONE, MISS, INVALID, MODIFICATION, DISALLOWED_ADDRESS };
enum class ExceptionCode : u8 {
enum class ExceptionCode : u8 {
Interrupt = 0,
TLBModification = 1,
TLBLoad = 2,
@@ -168,18 +169,18 @@ enum class ExceptionCode : u8 {
Trap = 13,
FloatingPointError = 15,
Watch = 23
};
};
union Cop0Context {
union Context {
u64 raw;
struct {
u64 : 4;
u64 badvpn2 : 19;
u64 ptebase : 41;
};
};
};
union Cop0XContext {
union XContext {
u64 raw;
struct {
u64 : 4;
@@ -187,9 +188,18 @@ union Cop0XContext {
u64 r : 2;
u64 ptebase : 31;
} __attribute__((__packed__));
};
};
union TagLo {
u32 raw;
struct {
u64 : 4;
u64 ptaglo : 20;
u64 pstate : 2;
u64 : 6;
} __attribute__((__packed__));
};
struct Cop0 {
Cop0();
bool kernelMode{true};
@@ -199,19 +209,20 @@ struct Cop0 {
bool llbit{};
TLBError tlbError = NONE;
TagLo tagLo;
PageMask pageMask{};
EntryHi entryHi{};
EntryLo entryLo0{}, entryLo1{};
Index index{};
Cop0Context context{};
Context context{};
u32 wired{}, r7{};
u32 compare{};
Cop0Status status{};
Cop0Cause cause{};
Status status{};
Cause cause{};
u32 PRId{}, Config{}, LLAddr{}, WatchLo{}, WatchHi{};
u32 r21{}, r22{}, r23{}, r24{}, r25{}, ParityError{}, CacheError{}, TagLo{}, TagHi{};
u32 r21{}, r22{}, r23{}, r24{}, r25{}, ParityError{}, CacheError{}, TagHi{};
u32 r31{};
Cop0XContext xcontext{};
XContext xcontext{};
u64 badVaddr{}, count{};
s64 EPC{};
s64 ErrorEPC{};
@@ -263,7 +274,7 @@ struct Cop0 {
is64BitAddressing = (kernelMode && status.kx) || (supervisorMode && status.sx) || (userMode && status.ux);
}
private:
private:
friend struct JIT;
[[nodiscard]] FORCE_INLINE u32 GetWired() const { return wired & 0x3F; }
+4 -4
View File
@@ -150,13 +150,13 @@ struct Cop1 {
bool SetCauseOverflow();
bool SetCauseInvalid();
private:
private:
template <typename T>
auto FGR_T(const Cop0Status &, u32) -> T &;
auto FGR_T(const Cop0::Status &, u32) -> T &;
template <typename T>
auto FGR_S(const Cop0Status &, u32) -> T &;
auto FGR_S(const Cop0::Status &, u32) -> T &;
template <typename T>
auto FGR_D(const Cop0Status &, u32) -> T &;
auto FGR_D(const Cop0::Status &, u32) -> T &;
void absd(const Instruction instr);
void abss(const Instruction instr);
void adds(const Instruction instr);