start implementing Supervisor accesses I guess

This commit is contained in:
2026-06-18 15:49:06 +02:00
parent 0c831f22d0
commit b3fd9f00b8
3 changed files with 89 additions and 65 deletions
+36 -45
View File
@@ -26,24 +26,23 @@ void PI::Reset() {
} }
bool PI::WriteLatch(u32 value) { bool PI::WriteLatch(u32 value) {
if (ioBusy) { if (ioBusy)
return false; return false;
} else {
ioBusy = true; ioBusy = true;
latch = value; latch = value;
Scheduler::GetInstance().EnqueueRelative(100, PI_BUS_WRITE_COMPLETE); Scheduler::GetInstance().EnqueueRelative(100, PI_BUS_WRITE_COMPLETE);
return true; return true;
}
} }
bool PI::ReadLatch() { bool PI::ReadLatch() {
n64::Registers &regs = n64::Core::GetRegs(); n64::Registers &regs = n64::Core::GetRegs();
if (ioBusy) [[unlikely]] { if (!ioBusy) [[likely]]
ioBusy = false; return true;
regs.CpuStall(Scheduler::GetInstance().Remove(PI_BUS_WRITE_COMPLETE));
return false; ioBusy = false;
} regs.CpuStall(Scheduler::GetInstance().Remove(PI_BUS_WRITE_COMPLETE));
return true; return false;
} }
template <> template <>
@@ -91,9 +90,8 @@ auto PI::BusRead<u8, true>(u32 addr) -> u8 {
template <> template <>
auto PI::BusRead<u8, false>(u32 addr) -> u8 { auto PI::BusRead<u8, false>(u32 addr) -> u8 {
n64::Mem &mem = n64::Core::GetMem(); n64::Mem &mem = n64::Core::GetMem();
if (!ReadLatch()) [[unlikely]] { if (!ReadLatch()) [[unlikely]]
return latch >> 24; return latch >> 24;
}
switch (addr) { switch (addr) {
case REGION_PI_UNKNOWN: case REGION_PI_UNKNOWN:
@@ -168,9 +166,8 @@ template <>
void PI::BusWrite<u8, false>(u32 addr, u32 val) { void PI::BusWrite<u8, false>(u32 addr, u32 val) {
u8 latch_shift = 24 - (addr & 1) * 8; u8 latch_shift = 24 - (addr & 1) * 8;
if (!WriteLatch(val << latch_shift) && addr != 0x05000020) [[unlikely]] { if (!WriteLatch(val << latch_shift) && addr != 0x05000020) [[unlikely]]
return; return;
}
BusWrite<u8, true>(addr, val); BusWrite<u8, true>(addr, val);
} }
@@ -178,9 +175,8 @@ void PI::BusWrite<u8, false>(u32 addr, u32 val) {
template <> template <>
auto PI::BusRead<u16, false>(u32 addr) -> u16 { auto PI::BusRead<u16, false>(u32 addr) -> u16 {
n64::Mem &mem = n64::Core::GetMem(); n64::Mem &mem = n64::Core::GetMem();
if (!ReadLatch()) [[unlikely]] { if (!ReadLatch()) [[unlikely]]
return latch >> 16; return latch >> 16;
}
switch (addr) { switch (addr) {
case REGION_PI_UNKNOWN: case REGION_PI_UNKNOWN:
@@ -224,9 +220,8 @@ auto PI::BusRead<u16, true>(u32 addr) -> u16 {
template <> template <>
void PI::BusWrite<u16, false>(u32 addr, u32 val) { void PI::BusWrite<u16, false>(u32 addr, u32 val) {
if (!WriteLatch(val << 16)) [[unlikely]] { if (!WriteLatch(val << 16)) [[unlikely]]
return; return;
}
switch (addr) { switch (addr) {
case REGION_PI_UNKNOWN: case REGION_PI_UNKNOWN:
@@ -257,9 +252,8 @@ void PI::BusWrite<u16, true>(u32 addr, u32 val) {
template <> template <>
auto PI::BusRead<u32, false>(u32 addr) -> u32 { auto PI::BusRead<u32, false>(u32 addr) -> u32 {
n64::Mem &mem = n64::Core::GetMem(); n64::Mem &mem = n64::Core::GetMem();
if (!ReadLatch()) [[unlikely]] { if (!ReadLatch()) [[unlikely]]
return latch; return latch;
}
switch (addr) { switch (addr) {
case REGION_PI_UNKNOWN: case REGION_PI_UNKNOWN:
@@ -319,29 +313,29 @@ void PI::BusWrite<u32, false>(u32 addr, u32 val) {
n64::Mem &mem = n64::Core::GetMem(); n64::Mem &mem = n64::Core::GetMem();
switch (addr) { switch (addr) {
case REGION_PI_UNKNOWN: case REGION_PI_UNKNOWN:
if (!WriteLatch(val)) [[unlikely]] { if (!WriteLatch(val)) [[unlikely]]
return; return;
}
ircolib::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr); ircolib::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr);
return; return;
case REGION_PI_64DD_REG: case REGION_PI_64DD_REG:
if (!WriteLatch(val)) [[unlikely]] { if (!WriteLatch(val)) [[unlikely]]
return; return;
}
ircolib::warn( ircolib::warn(
"Writing word 0x{:08X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", val, "Writing word 0x{:08X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", val,
addr); addr);
return; return;
case REGION_PI_64DD_ROM: case REGION_PI_64DD_ROM:
if (!WriteLatch(val)) [[unlikely]] { if (!WriteLatch(val)) [[unlikely]]
return; return;
}
ircolib::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr); ircolib::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr);
return; return;
case REGION_PI_SRAM: case REGION_PI_SRAM:
if (!WriteLatch(val)) [[unlikely]] { if (!WriteLatch(val)) [[unlikely]]
return; return;
}
mem.BackupWrite<u32>(addr - SREGION_PI_SRAM, val); mem.BackupWrite<u32>(addr - SREGION_PI_SRAM, val);
return; return;
case REGION_PI_ROM: case REGION_PI_ROM:
@@ -350,19 +344,17 @@ void PI::BusWrite<u32, false>(u32 addr, u32 val) {
ircolib::write_access<u32>(mem.isviewer, addr - SREGION_CART_ISVIEWER_BUFFER, std::byteswap(val)); ircolib::write_access<u32>(mem.isviewer, addr - SREGION_CART_ISVIEWER_BUFFER, std::byteswap(val));
break; break;
case CART_ISVIEWER_FLUSH: case CART_ISVIEWER_FLUSH:
{ if (val < CART_ISVIEWER_SIZE) {
if (val < CART_ISVIEWER_SIZE) { std::string message(val, 0);
std::string message(val, 0); std::copy_n(mem.isviewer.begin(), val, message.begin());
std::copy_n(mem.isviewer.begin(), val, message.begin()); mem.isviewer_sink << message;
mem.isviewer_sink << message; mem.isviewer_sink.flush();
mem.isviewer_sink.flush(); } else {
} else { ircolib::panic(
ircolib::panic( "ISViewer buffer size is emulated at {} bytes, but received a flush command for {} bytes!",
"ISViewer buffer size is emulated at {} bytes, but received a flush command for {} bytes!", CART_ISVIEWER_SIZE, val);
CART_ISVIEWER_SIZE, val);
}
break;
} }
break;
default: default:
if (!WriteLatch(val)) [[unlikely]] { if (!WriteLatch(val)) [[unlikely]] {
ircolib::warn("Couldn't latch PI bus, ignoring write to REGION_PI_ROM"); ircolib::warn("Couldn't latch PI bus, ignoring write to REGION_PI_ROM");
@@ -385,9 +377,8 @@ void PI::BusWrite<u32, true>(u32 addr, u32 val) {
template <> template <>
auto PI::BusRead<u64, false>(u32 addr) -> u64 { auto PI::BusRead<u64, false>(u32 addr) -> u64 {
n64::Mem &mem = n64::Core::GetMem(); n64::Mem &mem = n64::Core::GetMem();
if (!ReadLatch()) [[unlikely]] { if (!ReadLatch()) [[unlikely]]
return static_cast<u64>(latch) << 32; return static_cast<u64>(latch) << 32;
}
switch (addr) { switch (addr) {
case REGION_PI_UNKNOWN: case REGION_PI_UNKNOWN:
+50 -19
View File
@@ -463,9 +463,8 @@ void Cop0::decode(const Instruction instr) {
} }
} }
template <> template <>
bool Cop0::MapVirtualAddress<u32, true>(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) { bool Cop0::MapVirtualAddress<u32, Cop0::User>(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
if (ircolib::is_inside_range(vaddr, START_VREGION_KUSEG, END_VREGION_KUSEG)) if (ircolib::is_inside_range(vaddr, START_VREGION_KUSEG, END_VREGION_KUSEG))
return ProbeTLB(accessType, s64(s32(vaddr)), paddr); return ProbeTLB(accessType, s64(s32(vaddr)), paddr);
@@ -474,26 +473,52 @@ bool Cop0::MapVirtualAddress<u32, true>(const TLBAccessType accessType, const u6
} }
template <> template <>
bool Cop0::MapVirtualAddress<u32, false>(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) { bool Cop0::MapVirtualAddress<u32, Cop0::Supervisor>(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
u8 segment = static_cast<u32>(vaddr) >> 29 & 7; u8 segment = static_cast<u32>(vaddr) >> 29 & 7;
if (ircolib::is_inside_range(segment, 0, 3) || segment == 7) if (ircolib::is_inside_range(segment, 0, 3) || segment == 6)
return ProbeTLB(accessType, static_cast<s32>(vaddr), paddr); return ProbeTLB(accessType, static_cast<s32>(vaddr), paddr);
if (ircolib::is_inside_range(segment, 4, 5)) { if (ircolib::is_inside_range(segment, 4, 5) || segment == 7) {
paddr = vaddr & 0x1FFFFFFF; tlbError = DISALLOWED_ADDRESS;
return true; return false;
} }
if (segment == 6)
ircolib::panic("Unimplemented virtual mapping in KSSEG! ({:08X})", vaddr);
ircolib::panic("Should never end up in base case in MapVirtualAddress! ({:08X})", vaddr); ircolib::panic("Should never end up in base case in MapVirtualAddress! ({:08X})", vaddr);
return false; return false;
} }
template <> template <>
bool Cop0::MapVirtualAddress<u64, true>(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) { bool Cop0::MapVirtualAddress<u32, Cop0::Kernel>(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
u8 segment = static_cast<u32>(vaddr) >> 29 & 7;
if (ircolib::is_inside_range(segment, 0, 3) || segment == 7 || segment == 6)
return ProbeTLB(accessType, static_cast<s32>(vaddr), paddr);
if (ircolib::is_inside_range(segment, 4, 5)) {
paddr = vaddr & 0x1FFFFFFF;
return true;
}
ircolib::panic("Should never end up in base case in MapVirtualAddress! ({:08X})", vaddr);
return false;
}
template <>
bool Cop0::MapVirtualAddress<u64, Cop0::Supervisor>(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
bool unused1 = ircolib::is_inside_range(vaddr, 0x0000'0100'0000'0000ull, 0x3fff'ffff'ffff'ffffull);
bool unused2 = ircolib::is_inside_range(vaddr, 0x4000'0100'0000'0000ull, 0xffff'ffff'bfff'ffffull);
bool unused3 = ircolib::is_inside_range(vaddr, 0xffff'ffff'e000'0000ull, 0xffff'ffff'ffff'ffffull);
if (unused1 || unused2 || unused3) {
tlbError = DISALLOWED_ADDRESS;
return false;
}
return ProbeTLB(accessType, static_cast<s32>(vaddr), paddr);
}
template <>
bool Cop0::MapVirtualAddress<u64, Cop0::User>(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
if (ircolib::is_inside_range(vaddr, 0x0000000000000000, 0x000000FFFFFFFFFF)) if (ircolib::is_inside_range(vaddr, 0x0000000000000000, 0x000000FFFFFFFFFF))
return ProbeTLB(accessType, vaddr, paddr); return ProbeTLB(accessType, vaddr, paddr);
@@ -502,7 +527,7 @@ bool Cop0::MapVirtualAddress<u64, true>(const TLBAccessType accessType, const u6
} }
template <> template <>
bool Cop0::MapVirtualAddress<u64, false>(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) { bool Cop0::MapVirtualAddress<u64, Cop0::Kernel>(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
if (ircolib::is_inside_range(vaddr, 0x0000000000000000, 0x000000FFFFFFFFFF) || // VREGION_XKUSEG if (ircolib::is_inside_range(vaddr, 0x0000000000000000, 0x000000FFFFFFFFFF) || // VREGION_XKUSEG
ircolib::is_inside_range(vaddr, 0x4000000000000000, 0x400000FFFFFFFFFF) || // VREGION_XKSSEG ircolib::is_inside_range(vaddr, 0x4000000000000000, 0x400000FFFFFFFFFF) || // VREGION_XKSSEG
ircolib::is_inside_range(vaddr, 0xC000000000000000, 0xC00000FF7FFFFFFF) || // VREGION_XKSEG ircolib::is_inside_range(vaddr, 0xC000000000000000, 0xC00000FF7FFFFFFF) || // VREGION_XKSEG
@@ -553,23 +578,29 @@ bool Cop0::MapVirtualAddress<u64, false>(const TLBAccessType accessType, const u
} }
bool Cop0::MapVAddr(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) { bool Cop0::MapVAddr(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
if (supervisorMode)
ircolib::panic("Supervisor mode memory access");
if (is64BitAddressing) [[unlikely]] { if (is64BitAddressing) [[unlikely]] {
if (kernelMode) [[likely]] if (kernelMode) [[likely]]
return MapVirtualAddress<u64, false>(accessType, vaddr, paddr); return MapVirtualAddress<u64, Cop0::Kernel>(accessType, vaddr, paddr);
if (supervisorMode)
return MapVirtualAddress<u64, Cop0::Supervisor>(accessType, vaddr, paddr);
if (userMode) if (userMode)
return MapVirtualAddress<u64, true>(accessType, vaddr, paddr); return MapVirtualAddress<u64, Cop0::User>(accessType, vaddr, paddr);
ircolib::panic("Unknown mode! This should never happen!"); ircolib::panic("Unknown mode! This should never happen!");
} }
if (kernelMode) [[likely]] if (kernelMode) [[likely]]
return MapVirtualAddress<u32, false>(accessType, vaddr, paddr); return MapVirtualAddress<u32, Cop0::Kernel>(accessType, vaddr, paddr);
if (supervisorMode)
return MapVirtualAddress<u32, Cop0::Supervisor>(accessType, vaddr, paddr);
if (userMode) if (userMode)
return MapVirtualAddress<u32, true>(accessType, vaddr, paddr); return MapVirtualAddress<u32, Cop0::User>(accessType, vaddr, paddr);
ircolib::panic("Unknown mode! This should never happen!"); ircolib::panic("Unknown mode! This should never happen!");
return false;
} }
} // namespace n64 } // namespace n64
+3 -1
View File
@@ -288,7 +288,9 @@ struct Cop0 {
void tlbw(int); void tlbw(int);
void tlbp(); void tlbp();
template <typename T, bool User> enum MemoryMapType { User, Supervisor, Kernel };
template <typename T, MemoryMapType mapType>
bool MapVirtualAddress(TLBAccessType accessType, u64 vaddr, u32 &paddr); bool MapVirtualAddress(TLBAccessType accessType, u64 vaddr, u32 &paddr);
}; };
} // namespace n64 } // namespace n64