Cop0 tidy
This commit is contained in:
@@ -422,164 +422,117 @@ ExceptionCode Cop0::GetTLBExceptionCode(const TLBError error, const TLBAccessTyp
|
|||||||
void Cop0::decode(const Instruction instr) {
|
void Cop0::decode(const Instruction instr) {
|
||||||
Registers& regs = Core::GetRegs();
|
Registers& regs = Core::GetRegs();
|
||||||
switch (instr.cop_rs()) {
|
switch (instr.cop_rs()) {
|
||||||
case 0x00:
|
case 0x00: mfc0(instr); break;
|
||||||
mfc0(u32(instr));
|
case 0x01: dmfc0(instr); break;
|
||||||
break;
|
case 0x04: mtc0(instr); break;
|
||||||
case 0x01:
|
case 0x05: dmtc0(instr); break;
|
||||||
dmfc0(u32(instr));
|
case 0x10 ... 0x1F:
|
||||||
break;
|
switch (instr.cop_funct()) {
|
||||||
case 0x04:
|
case 0x01: tlbr(); break;
|
||||||
mtc0(u32(instr));
|
case 0x02: tlbw(index.i); break;
|
||||||
break;
|
case 0x06: tlbw(GetRandom()); break;
|
||||||
case 0x05:
|
case 0x08: tlbp(); break;
|
||||||
dmtc0(u32(instr));
|
case 0x18: eret(); break;
|
||||||
break;
|
default:
|
||||||
case 0x10 ... 0x1F:
|
panic("Unimplemented COP0 function {} ({:08X}) ({:016X})", instr.cop_funct(), u32(instr),
|
||||||
switch (instr.cop_funct()) {
|
regs.oldPC);
|
||||||
case 0x01:
|
}
|
||||||
tlbr();
|
|
||||||
break;
|
|
||||||
case 0x02:
|
|
||||||
tlbw(index.i);
|
|
||||||
break;
|
|
||||||
case 0x06:
|
|
||||||
tlbw(GetRandom());
|
|
||||||
break;
|
|
||||||
case 0x08:
|
|
||||||
tlbp();
|
|
||||||
break;
|
|
||||||
case 0x18:
|
|
||||||
eret();
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unimplemented COP0 function {} ({:08X}) ({:016X})", instr.cop_funct(), u32(instr),
|
panic("Unimplemented COP0 instruction {}", instr.cop_rs());
|
||||||
regs.oldPC);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
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 (is64BitAddressing) [[unlikely]] {
|
||||||
if (kernelMode) [[likely]] {
|
if (kernelMode) [[likely]] return MapVAddr64(accessType, vaddr, paddr);
|
||||||
return MapVAddr64(accessType, vaddr, paddr);
|
if (userMode) return UserMapVAddr64(accessType, vaddr, paddr);
|
||||||
}
|
|
||||||
|
|
||||||
if (userMode) {
|
panic("Unknown mode! This should never happen!");
|
||||||
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!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
bool Cop0::UserMapVAddr32(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
|
||||||
switch (vaddr) {
|
if(Util::IsInsideRange(vaddr, START_VREGION_KUSEG, END_VREGION_KUSEG))
|
||||||
case VREGION_KUSEG:
|
|
||||||
return ProbeTLB(accessType, s64(s32(vaddr)), paddr);
|
return ProbeTLB(accessType, s64(s32(vaddr)), paddr);
|
||||||
default:
|
|
||||||
tlbError = DISALLOWED_ADDRESS;
|
tlbError = DISALLOWED_ADDRESS;
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Cop0::MapVAddr32(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
|
bool Cop0::MapVAddr32(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
|
||||||
switch (static_cast<u32>(vaddr) >> 29 & 7) {
|
u8 segment = static_cast<u32>(vaddr) >> 29 & 7;
|
||||||
case 0 ... 3:
|
if(Util::IsInsideRange(segment, 0, 3) || segment == 7)
|
||||||
case 7:
|
|
||||||
return ProbeTLB(accessType, static_cast<s32>(vaddr), paddr);
|
return ProbeTLB(accessType, static_cast<s32>(vaddr), paddr);
|
||||||
case 4 ... 5:
|
|
||||||
|
if(Util::IsInsideRange(segment, 4, 5)) {
|
||||||
paddr = vaddr & 0x1FFFFFFF;
|
paddr = vaddr & 0x1FFFFFFF;
|
||||||
return true;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Cop0::UserMapVAddr64(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
|
bool Cop0::UserMapVAddr64(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
|
||||||
switch (vaddr) {
|
if(Util::IsInsideRange(vaddr, 0x0000000000000000, 0x000000FFFFFFFFFF))
|
||||||
case VREGION_XKUSEG:
|
|
||||||
return ProbeTLB(accessType, vaddr, paddr);
|
return ProbeTLB(accessType, vaddr, paddr);
|
||||||
default:
|
|
||||||
tlbError = DISALLOWED_ADDRESS;
|
tlbError = DISALLOWED_ADDRESS;
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Cop0::MapVAddr64(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
|
bool Cop0::MapVAddr64(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
|
||||||
switch (vaddr) {
|
if(Util::IsInsideRange(vaddr, 0x0000000000000000, 0x000000FFFFFFFFFF) ||
|
||||||
case VREGION_XKUSEG:
|
Util::IsInsideRange(vaddr, 0x4000000000000000, 0x400000FFFFFFFFFF) ||
|
||||||
case VREGION_XKSSEG:
|
Util::IsInsideRange(vaddr, 0xC000000000000000, 0xC00000FF7FFFFFFF) ||
|
||||||
|
Util::IsInsideRange(vaddr, 0xFFFFFFFFE0000000, 0xFFFFFFFFFFFFFFFF))
|
||||||
return ProbeTLB(accessType, vaddr, paddr);
|
return ProbeTLB(accessType, vaddr, paddr);
|
||||||
case VREGION_XKPHYS:
|
|
||||||
{
|
if(Util::IsInsideRange(vaddr, 0x8000000000000000, 0xBFFFFFFFFFFFFFFF)) {
|
||||||
if (!kernelMode) {
|
if (!kernelMode) panic("Access to XKPHYS address 0x{:016X} when outside kernel mode!", vaddr);
|
||||||
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);
|
||||||
}
|
|
||||||
if (const u8 high_two_bits = (vaddr >> 62) & 0b11; high_two_bits != 0b10) {
|
const u8 subsegment = (vaddr >> 59) & 0b11;
|
||||||
panic("Access to XKPHYS address 0x{:016X} with high two bits != 0b10!", vaddr);
|
bool cached = subsegment != 2; // do something with this eventually
|
||||||
}
|
// If any bits in the range of 58:32 are set, the address is invalid.
|
||||||
const u8 subsegment = (vaddr >> 59) & 0b11;
|
if ((vaddr & 0x07FFFFFF00000000) != 0) {
|
||||||
bool cached = subsegment != 2; // do something with this eventually
|
tlbError = DISALLOWED_ADDRESS;
|
||||||
// If any bits in the range of 58:32 are set, the address is invalid.
|
return false;
|
||||||
if (const bool valid = (vaddr & 0x07FFFFFF00000000) == 0; !valid) {
|
|
||||||
tlbError = DISALLOWED_ADDRESS;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
paddr = vaddr & 0xFFFFFFFF;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
case VREGION_XKSEG:
|
paddr = vaddr & 0xFFFFFFFF;
|
||||||
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);
|
|
||||||
return true;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -256,10 +256,6 @@ struct Cop0 {
|
|||||||
bool ProbeTLB(TLBAccessType accessType, u64 vaddr, u32 &paddr);
|
bool ProbeTLB(TLBAccessType accessType, u64 vaddr, u32 &paddr);
|
||||||
void FireException(ExceptionCode code, int cop, s64 pc);
|
void FireException(ExceptionCode code, int cop, s64 pc);
|
||||||
bool MapVAddr(TLBAccessType accessType, u64 vaddr, u32 &paddr);
|
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, int &index);
|
||||||
TLBEntry *TLBTryMatch(u64 vaddr);
|
TLBEntry *TLBTryMatch(u64 vaddr);
|
||||||
@@ -280,5 +276,10 @@ private:
|
|||||||
void tlbr();
|
void tlbr();
|
||||||
void tlbw(int);
|
void tlbw(int);
|
||||||
void tlbp();
|
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
|
} // namespace n64
|
||||||
|
|||||||
Reference in New Issue
Block a user