From 509f52664ca20933613c1009d84c258d2def7bed Mon Sep 17 00:00:00 2001 From: irisz64 Date: Tue, 2 Sep 2025 15:23:10 +0200 Subject: [PATCH] Cop0 tidy --- src/backend/core/registers/Cop0.cpp | 203 +++++++++++----------------- src/backend/core/registers/Cop0.hpp | 9 +- 2 files changed, 83 insertions(+), 129 deletions(-) diff --git a/src/backend/core/registers/Cop0.cpp b/src/backend/core/registers/Cop0.cpp index 0831fa70..0c7f5516 100644 --- a/src/backend/core/registers/Cop0.cpp +++ b/src/backend/core/registers/Cop0.cpp @@ -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) { +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(vaddr) >> 29 & 7) { - case 0 ... 3: - case 7: + u8 segment = static_cast(vaddr) >> 29 & 7; + if(Util::IsInsideRange(segment, 0, 3) || segment == 7) return ProbeTLB(accessType, static_cast(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 diff --git a/src/backend/core/registers/Cop0.hpp b/src/backend/core/registers/Cop0.hpp index f8906a6f..ab6a23f6 100644 --- a/src/backend/core/registers/Cop0.hpp +++ b/src/backend/core/registers/Cop0.hpp @@ -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