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
@@ -4,90 +4,90 @@
namespace n64 {
void Cop0::mtc0(const Instruction instr) {
Registers& regs = Core::GetRegs();
SetReg32(instr.rd(), regs.Read<u32>(instr.rt()));
Registers &regs = Core::GetRegs();
SetReg32(instr.rd(), regs.Read<u32>(instr.rt()));
}
void Cop0::dmtc0(const Instruction instr) {
Registers& regs = Core::GetRegs();
SetReg64(instr.rd(), regs.Read<u64>(instr.rt()));
void Cop0::dmtc0(const Instruction instr) {
Registers &regs = Core::GetRegs();
SetReg64(instr.rd(), regs.Read<u64>(instr.rt()));
}
void Cop0::mfc0(const Instruction instr) {
Registers& regs = Core::GetRegs();
regs.Write(instr.rt(), s32(GetReg32(instr.rd())));
void Cop0::mfc0(const Instruction instr) {
Registers &regs = Core::GetRegs();
regs.Write(instr.rt(), s32(GetReg32(instr.rd())));
}
void Cop0::dmfc0(const Instruction instr) const {
Registers& regs = Core::GetRegs();
regs.Write(instr.rt(), s64(GetReg64(instr.rd())));
void Cop0::dmfc0(const Instruction instr) const {
Registers &regs = Core::GetRegs();
regs.Write(instr.rt(), s64(GetReg64(instr.rd())));
}
void Cop0::eret() {
Registers& regs = Core::GetRegs();
if (!regs.cop0.kernelMode) {
FireException(ExceptionCode::CoprocessorUnusable, 0, regs.oldPC);
return;
}
if (status.erl) {
regs.SetPC64(ErrorEPC);
status.erl = false;
} else {
regs.SetPC64(EPC);
status.exl = false;
}
regs.cop0.Update();
llbit = false;
Registers &regs = Core::GetRegs();
if (!regs.cop0.kernelMode) {
FireException(Cop0::ExceptionCode::CoprocessorUnusable, 0, regs.oldPC);
return;
}
if (status.erl) {
regs.SetPC64(ErrorEPC);
status.erl = false;
} else {
regs.SetPC64(EPC);
status.exl = false;
}
regs.cop0.Update();
llbit = false;
}
void Cop0::tlbr() {
if (index.i >= 32) {
panic("TLBR with TLB index {}", index.i);
}
if (index.i >= 32) {
panic("TLBR with TLB index {}", index.i);
}
const TLBEntry entry = tlb[index.i];
const TLBEntry entry = tlb[index.i];
entryHi.raw = entry.entryHi.raw;
entryLo0.raw = entry.entryLo0.raw & 0x3FFFFFFF;
entryLo1.raw = entry.entryLo1.raw & 0x3FFFFFFF;
entryHi.raw = entry.entryHi.raw;
entryLo0.raw = entry.entryLo0.raw & 0x3FFFFFFF;
entryLo1.raw = entry.entryLo1.raw & 0x3FFFFFFF;
entryLo0.g = entry.global;
entryLo1.g = entry.global;
pageMask.raw = entry.pageMask.raw;
entryLo0.g = entry.global;
entryLo1.g = entry.global;
pageMask.raw = entry.pageMask.raw;
}
void Cop0::tlbw(const int index_) {
PageMask page_mask{};
page_mask = pageMask;
const u32 top = page_mask.mask & 0xAAA;
page_mask.mask = top | (top >> 1);
PageMask page_mask{};
page_mask = pageMask;
const u32 top = page_mask.mask & 0xAAA;
page_mask.mask = top | (top >> 1);
if (index_ >= 32) {
panic("TLBWI with TLB index {}", index_);
}
if (index_ >= 32) {
panic("TLBWI with TLB index {}", index_);
}
tlb[index_].entryHi.raw = entryHi.raw;
tlb[index_].entryHi.vpn2 &= ~page_mask.mask;
tlb[index_].entryHi.raw = entryHi.raw;
tlb[index_].entryHi.vpn2 &= ~page_mask.mask;
tlb[index_].entryLo0.raw = entryLo0.raw & 0x03FFFFFE;
tlb[index_].entryLo1.raw = entryLo1.raw & 0x03FFFFFE;
tlb[index_].pageMask.raw = page_mask.raw;
tlb[index_].entryLo0.raw = entryLo0.raw & 0x03FFFFFE;
tlb[index_].entryLo1.raw = entryLo1.raw & 0x03FFFFFE;
tlb[index_].pageMask.raw = page_mask.raw;
tlb[index_].global = entryLo0.g && entryLo1.g;
tlb[index_].initialized = true;
tlb[index_].global = entryLo0.g && entryLo1.g;
tlb[index_].initialized = true;
}
void Cop0::tlbp() {
int match = -1;
const TLBEntry *entry = TLBTryMatch(entryHi.raw, match);
if (match >= 0) {
index.raw = match;
return;
}
int match = -1;
const TLBEntry *entry = TLBTryMatch(entryHi.raw, match);
if (match >= 0) {
index.raw = match;
return;
}
index.raw = 0;
index.p = 1;
index.raw = 0;
index.p = 1;
}
} // namespace n64
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