Cop0 tidy

This commit is contained in:
irisz64
2025-09-02 15:23:10 +02:00
parent 4a98610f3c
commit 509f52664c
2 changed files with 83 additions and 129 deletions

View File

@@ -422,164 +422,117 @@ ExceptionCode Cop0::GetTLBExceptionCode(const TLBError error, const TLBAccessTyp
void Cop0::decode(const Instruction instr) {
Registers& regs = Core::GetRegs();
switch (instr.cop_rs()) {
case 0x00:
mfc0(u32(instr));
break;
case 0x01:
dmfc0(u32(instr));
break;
case 0x04:
mtc0(u32(instr));
break;
case 0x05:
dmtc0(u32(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();
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;
default:
panic("Unimplemented COP0 function {} ({:08X}) ({:016X})", instr.cop_funct(), u32(instr),
regs.oldPC);
}
break;
default:
panic("Unimplemented COP0 function {} ({:08X}) ({:016X})", instr.cop_funct(), u32(instr),
regs.oldPC);
}
break;
default:
panic("Unimplemented COP0 instruction {}", instr.cop_rs());
panic("Unimplemented COP0 instruction {}", instr.cop_rs());
}
}
bool Cop0::MapVAddr(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
if(supervisorMode)
panic("Supervisor mode memory access, 64 bit mode");
if (is64BitAddressing) [[unlikely]] {
if (kernelMode) [[likely]] {
return MapVAddr64(accessType, vaddr, paddr);
}
if (kernelMode) [[likely]] return MapVAddr64(accessType, vaddr, paddr);
if (userMode) return UserMapVAddr64(accessType, vaddr, paddr);
if (userMode) {
return UserMapVAddr64(accessType, vaddr, paddr);
}
if (supervisorMode) {
panic("Supervisor mode memory access, 64 bit mode");
} else {
panic("Unknown mode! This should never happen!");
}
} else {
if (kernelMode) [[likely]] {
return MapVAddr32(accessType, vaddr, paddr);
}
if (userMode) {
return UserMapVAddr32(accessType, vaddr, paddr);
}
if (supervisorMode) {
panic("Supervisor mode memory access, 32 bit mode");
} else {
panic("Unknown mode! This should never happen!");
}
panic("Unknown mode! This should never happen!");
}
if (kernelMode) [[likely]] return MapVAddr32(accessType, vaddr, paddr);
if (userMode) return UserMapVAddr32(accessType, vaddr, paddr);
panic("Unknown mode! This should never happen!");
}
bool Cop0::UserMapVAddr32(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
switch (vaddr) {
case VREGION_KUSEG:
if(Util::IsInsideRange(vaddr, START_VREGION_KUSEG, END_VREGION_KUSEG))
return ProbeTLB(accessType, s64(s32(vaddr)), paddr);
default:
tlbError = DISALLOWED_ADDRESS;
return false;
}
tlbError = DISALLOWED_ADDRESS;
return false;
}
bool Cop0::MapVAddr32(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
switch (static_cast<u32>(vaddr) >> 29 & 7) {
case 0 ... 3:
case 7:
u8 segment = static_cast<u32>(vaddr) >> 29 & 7;
if(Util::IsInsideRange(segment, 0, 3) || segment == 7)
return ProbeTLB(accessType, static_cast<s32>(vaddr), paddr);
case 4 ... 5:
if(Util::IsInsideRange(segment, 4, 5)) {
paddr = vaddr & 0x1FFFFFFF;
return true;
case 6:
panic("Unimplemented virtual mapping in KSSEG! ({:08X})", vaddr);
default:
panic("Should never end up in default case in map_vaddr! ({:08X})", vaddr);
}
if(segment == 6)
panic("Unimplemented virtual mapping in KSSEG! ({:08X})", vaddr);
return false;
}
bool Cop0::UserMapVAddr64(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
switch (vaddr) {
case VREGION_XKUSEG:
if(Util::IsInsideRange(vaddr, 0x0000000000000000, 0x000000FFFFFFFFFF))
return ProbeTLB(accessType, vaddr, paddr);
default:
tlbError = DISALLOWED_ADDRESS;
return false;
}
tlbError = DISALLOWED_ADDRESS;
return false;
}
bool Cop0::MapVAddr64(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
switch (vaddr) {
case VREGION_XKUSEG:
case VREGION_XKSSEG:
if(Util::IsInsideRange(vaddr, 0x0000000000000000, 0x000000FFFFFFFFFF) ||
Util::IsInsideRange(vaddr, 0x4000000000000000, 0x400000FFFFFFFFFF) ||
Util::IsInsideRange(vaddr, 0xC000000000000000, 0xC00000FF7FFFFFFF) ||
Util::IsInsideRange(vaddr, 0xFFFFFFFFE0000000, 0xFFFFFFFFFFFFFFFF))
return ProbeTLB(accessType, vaddr, paddr);
case VREGION_XKPHYS:
{
if (!kernelMode) {
panic("Access to XKPHYS address 0x{:016X} when outside kernel mode!", vaddr);
}
if (const u8 high_two_bits = (vaddr >> 62) & 0b11; high_two_bits != 0b10) {
panic("Access to XKPHYS address 0x{:016X} with high two bits != 0b10!", vaddr);
}
const u8 subsegment = (vaddr >> 59) & 0b11;
bool cached = subsegment != 2; // do something with this eventually
// If any bits in the range of 58:32 are set, the address is invalid.
if (const bool valid = (vaddr & 0x07FFFFFF00000000) == 0; !valid) {
tlbError = DISALLOWED_ADDRESS;
return false;
}
paddr = vaddr & 0xFFFFFFFF;
return true;
if(Util::IsInsideRange(vaddr, 0x8000000000000000, 0xBFFFFFFFFFFFFFFF)) {
if (!kernelMode) panic("Access to XKPHYS address 0x{:016X} when outside kernel mode!", vaddr);
if (((vaddr >> 62) & 0b11) != 0b10) panic("Access to XKPHYS address 0x{:016X} with high two bits != 0b10!", vaddr);
const u8 subsegment = (vaddr >> 59) & 0b11;
bool cached = subsegment != 2; // do something with this eventually
// If any bits in the range of 58:32 are set, the address is invalid.
if ((vaddr & 0x07FFFFFF00000000) != 0) {
tlbError = DISALLOWED_ADDRESS;
return false;
}
case VREGION_XKSEG:
return ProbeTLB(accessType, vaddr, paddr);
case VREGION_CKSEG0:
// Identical to kseg0 in 32 bit mode.
// Unmapped translation. Subtract the base address of the space to get the physical address.
paddr = vaddr - START_VREGION_KSEG0; // Implies cutting off the high 32 bits
trace("CKSEG0: Translated 0x{:016X} to 0x{:08X}", vaddr, paddr);
paddr = vaddr & 0xFFFFFFFF;
return true;
case VREGION_CKSEG1:
// Identical to kseg1 in 32 bit mode.
// Unmapped translation. Subtract the base address of the space to get the physical address.
paddr = vaddr - START_VREGION_KSEG1; // Implies cutting off the high 32 bits
trace("KSEG1: Translated 0x{:016X} to 0x{:08X}", vaddr, paddr);
return true;
case VREGION_CKSSEG:
panic("Resolving virtual address 0x{:016X} (VREGION_CKSSEG) in 64 bit mode", vaddr);
case VREGION_CKSEG3:
return ProbeTLB(accessType, vaddr, paddr);
case VREGION_XBAD1:
case VREGION_XBAD2:
case VREGION_XBAD3:
tlbError = DISALLOWED_ADDRESS;
return false;
default:
panic("Resolving virtual address 0x{:016X} in 64 bit mode", vaddr);
}
if(Util::IsInsideRange(vaddr, 0xFFFFFFFF80000000, 0xFFFFFFFF9FFFFFFF) ||
Util::IsInsideRange(vaddr, 0xFFFFFFFFA0000000, 0xFFFFFFFFBFFFFFFF)) {
u32 cut = u32(vaddr) >> 28;
u32 num = cut == 0xA;
// Identical to ksegX in 32 bit mode.
// Unmapped translation. Subtract the base address of the space to get the physical address.
paddr = vaddr - (cut << 28); // Implies cutting off the high 32 bits
trace("CKSEG{}: Translated 0x{:016X} to 0x{:08X}", num, vaddr, paddr);
return true;
}
if(Util::IsInsideRange(vaddr, 0x0000010000000000, 0x3FFFFFFFFFFFFFFF) ||
Util::IsInsideRange(vaddr, 0x4000010000000000, 0x7FFFFFFFFFFFFFFF) ||
Util::IsInsideRange(vaddr, 0xC00000FF80000000, 0xFFFFFFFF7FFFFFFF)) {
tlbError = DISALLOWED_ADDRESS;
return false;
}
panic("Resolving virtual address 0x{:016X} in 64 bit mode", vaddr);
return false;
}
} // namespace n64

View File

@@ -256,10 +256,6 @@ struct Cop0 {
bool ProbeTLB(TLBAccessType accessType, u64 vaddr, u32 &paddr);
void FireException(ExceptionCode code, int cop, s64 pc);
bool MapVAddr(TLBAccessType accessType, u64 vaddr, u32 &paddr);
bool UserMapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr);
bool MapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr);
bool UserMapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr);
bool MapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr);
TLBEntry *TLBTryMatch(u64 vaddr, int &index);
TLBEntry *TLBTryMatch(u64 vaddr);
@@ -280,5 +276,10 @@ private:
void tlbr();
void tlbw(int);
void tlbp();
bool UserMapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr);
bool MapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr);
bool UserMapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr);
bool MapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr);
};
} // namespace n64