From b3fd9f00b8f2eaddd9aa9e64dc763ed484addd02 Mon Sep 17 00:00:00 2001 From: iris Date: Thu, 18 Jun 2026 15:49:06 +0200 Subject: [PATCH] start implementing Supervisor accesses I guess --- src/backend/core/mmio/PI.cpp | 81 +++++++++++++---------------- src/backend/core/registers/Cop0.cpp | 69 +++++++++++++++++------- src/backend/core/registers/Cop0.hpp | 4 +- 3 files changed, 89 insertions(+), 65 deletions(-) diff --git a/src/backend/core/mmio/PI.cpp b/src/backend/core/mmio/PI.cpp index d4f167f..932b5ce 100644 --- a/src/backend/core/mmio/PI.cpp +++ b/src/backend/core/mmio/PI.cpp @@ -26,24 +26,23 @@ void PI::Reset() { } bool PI::WriteLatch(u32 value) { - if (ioBusy) { + if (ioBusy) return false; - } else { - ioBusy = true; - latch = value; - Scheduler::GetInstance().EnqueueRelative(100, PI_BUS_WRITE_COMPLETE); - return true; - } + + ioBusy = true; + latch = value; + Scheduler::GetInstance().EnqueueRelative(100, PI_BUS_WRITE_COMPLETE); + return true; } bool PI::ReadLatch() { n64::Registers ®s = n64::Core::GetRegs(); - if (ioBusy) [[unlikely]] { - ioBusy = false; - regs.CpuStall(Scheduler::GetInstance().Remove(PI_BUS_WRITE_COMPLETE)); - return false; - } - return true; + if (!ioBusy) [[likely]] + return true; + + ioBusy = false; + regs.CpuStall(Scheduler::GetInstance().Remove(PI_BUS_WRITE_COMPLETE)); + return false; } template <> @@ -91,9 +90,8 @@ auto PI::BusRead(u32 addr) -> u8 { template <> auto PI::BusRead(u32 addr) -> u8 { n64::Mem &mem = n64::Core::GetMem(); - if (!ReadLatch()) [[unlikely]] { + if (!ReadLatch()) [[unlikely]] return latch >> 24; - } switch (addr) { case REGION_PI_UNKNOWN: @@ -168,9 +166,8 @@ template <> void PI::BusWrite(u32 addr, u32 val) { u8 latch_shift = 24 - (addr & 1) * 8; - if (!WriteLatch(val << latch_shift) && addr != 0x05000020) [[unlikely]] { + if (!WriteLatch(val << latch_shift) && addr != 0x05000020) [[unlikely]] return; - } BusWrite(addr, val); } @@ -178,9 +175,8 @@ void PI::BusWrite(u32 addr, u32 val) { template <> auto PI::BusRead(u32 addr) -> u16 { n64::Mem &mem = n64::Core::GetMem(); - if (!ReadLatch()) [[unlikely]] { + if (!ReadLatch()) [[unlikely]] return latch >> 16; - } switch (addr) { case REGION_PI_UNKNOWN: @@ -224,9 +220,8 @@ auto PI::BusRead(u32 addr) -> u16 { template <> void PI::BusWrite(u32 addr, u32 val) { - if (!WriteLatch(val << 16)) [[unlikely]] { + if (!WriteLatch(val << 16)) [[unlikely]] return; - } switch (addr) { case REGION_PI_UNKNOWN: @@ -257,9 +252,8 @@ void PI::BusWrite(u32 addr, u32 val) { template <> auto PI::BusRead(u32 addr) -> u32 { n64::Mem &mem = n64::Core::GetMem(); - if (!ReadLatch()) [[unlikely]] { + if (!ReadLatch()) [[unlikely]] return latch; - } switch (addr) { case REGION_PI_UNKNOWN: @@ -319,29 +313,29 @@ void PI::BusWrite(u32 addr, u32 val) { n64::Mem &mem = n64::Core::GetMem(); switch (addr) { case REGION_PI_UNKNOWN: - if (!WriteLatch(val)) [[unlikely]] { + if (!WriteLatch(val)) [[unlikely]] return; - } + ircolib::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr); return; case REGION_PI_64DD_REG: - if (!WriteLatch(val)) [[unlikely]] { + if (!WriteLatch(val)) [[unlikely]] return; - } + ircolib::warn( "Writing word 0x{:08X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", val, addr); return; case REGION_PI_64DD_ROM: - if (!WriteLatch(val)) [[unlikely]] { + if (!WriteLatch(val)) [[unlikely]] return; - } + ircolib::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr); return; case REGION_PI_SRAM: - if (!WriteLatch(val)) [[unlikely]] { + if (!WriteLatch(val)) [[unlikely]] return; - } + mem.BackupWrite(addr - SREGION_PI_SRAM, val); return; case REGION_PI_ROM: @@ -350,19 +344,17 @@ void PI::BusWrite(u32 addr, u32 val) { ircolib::write_access(mem.isviewer, addr - SREGION_CART_ISVIEWER_BUFFER, std::byteswap(val)); break; case CART_ISVIEWER_FLUSH: - { - if (val < CART_ISVIEWER_SIZE) { - std::string message(val, 0); - std::copy_n(mem.isviewer.begin(), val, message.begin()); - mem.isviewer_sink << message; - mem.isviewer_sink.flush(); - } else { - ircolib::panic( - "ISViewer buffer size is emulated at {} bytes, but received a flush command for {} bytes!", - CART_ISVIEWER_SIZE, val); - } - break; + if (val < CART_ISVIEWER_SIZE) { + std::string message(val, 0); + std::copy_n(mem.isviewer.begin(), val, message.begin()); + mem.isviewer_sink << message; + mem.isviewer_sink.flush(); + } else { + ircolib::panic( + "ISViewer buffer size is emulated at {} bytes, but received a flush command for {} bytes!", + CART_ISVIEWER_SIZE, val); } + break; default: if (!WriteLatch(val)) [[unlikely]] { ircolib::warn("Couldn't latch PI bus, ignoring write to REGION_PI_ROM"); @@ -385,9 +377,8 @@ void PI::BusWrite(u32 addr, u32 val) { template <> auto PI::BusRead(u32 addr) -> u64 { n64::Mem &mem = n64::Core::GetMem(); - if (!ReadLatch()) [[unlikely]] { + if (!ReadLatch()) [[unlikely]] return static_cast(latch) << 32; - } switch (addr) { case REGION_PI_UNKNOWN: diff --git a/src/backend/core/registers/Cop0.cpp b/src/backend/core/registers/Cop0.cpp index b07f3f3..ac8826c 100644 --- a/src/backend/core/registers/Cop0.cpp +++ b/src/backend/core/registers/Cop0.cpp @@ -463,9 +463,8 @@ void Cop0::decode(const Instruction instr) { } } - template <> -bool Cop0::MapVirtualAddress(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) { +bool Cop0::MapVirtualAddress(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) { if (ircolib::is_inside_range(vaddr, START_VREGION_KUSEG, END_VREGION_KUSEG)) return ProbeTLB(accessType, s64(s32(vaddr)), paddr); @@ -474,26 +473,52 @@ bool Cop0::MapVirtualAddress(const TLBAccessType accessType, const u6 } template <> -bool Cop0::MapVirtualAddress(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) { +bool Cop0::MapVirtualAddress(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) { u8 segment = static_cast(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(vaddr), paddr); - if (ircolib::is_inside_range(segment, 4, 5)) { - paddr = vaddr & 0x1FFFFFFF; - return true; + if (ircolib::is_inside_range(segment, 4, 5) || segment == 7) { + tlbError = DISALLOWED_ADDRESS; + 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); return false; } template <> -bool Cop0::MapVirtualAddress(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) { +bool Cop0::MapVirtualAddress(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) { + u8 segment = static_cast(vaddr) >> 29 & 7; + if (ircolib::is_inside_range(segment, 0, 3) || segment == 7 || segment == 6) + return ProbeTLB(accessType, static_cast(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(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(vaddr), paddr); +} + +template <> +bool Cop0::MapVirtualAddress(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) { if (ircolib::is_inside_range(vaddr, 0x0000000000000000, 0x000000FFFFFFFFFF)) return ProbeTLB(accessType, vaddr, paddr); @@ -502,7 +527,7 @@ bool Cop0::MapVirtualAddress(const TLBAccessType accessType, const u6 } template <> -bool Cop0::MapVirtualAddress(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) { +bool Cop0::MapVirtualAddress(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) { if (ircolib::is_inside_range(vaddr, 0x0000000000000000, 0x000000FFFFFFFFFF) || // VREGION_XKUSEG ircolib::is_inside_range(vaddr, 0x4000000000000000, 0x400000FFFFFFFFFF) || // VREGION_XKSSEG ircolib::is_inside_range(vaddr, 0xC000000000000000, 0xC00000FF7FFFFFFF) || // VREGION_XKSEG @@ -553,23 +578,29 @@ bool Cop0::MapVirtualAddress(const TLBAccessType accessType, const u } bool Cop0::MapVAddr(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) { - if (supervisorMode) - ircolib::panic("Supervisor mode memory access"); - if (is64BitAddressing) [[unlikely]] { if (kernelMode) [[likely]] - return MapVirtualAddress(accessType, vaddr, paddr); + return MapVirtualAddress(accessType, vaddr, paddr); + + if (supervisorMode) + return MapVirtualAddress(accessType, vaddr, paddr); + if (userMode) - return MapVirtualAddress(accessType, vaddr, paddr); + return MapVirtualAddress(accessType, vaddr, paddr); ircolib::panic("Unknown mode! This should never happen!"); } if (kernelMode) [[likely]] - return MapVirtualAddress(accessType, vaddr, paddr); + return MapVirtualAddress(accessType, vaddr, paddr); + + if (supervisorMode) + return MapVirtualAddress(accessType, vaddr, paddr); + if (userMode) - return MapVirtualAddress(accessType, vaddr, paddr); + return MapVirtualAddress(accessType, vaddr, paddr); ircolib::panic("Unknown mode! This should never happen!"); + return false; } } // namespace n64 diff --git a/src/backend/core/registers/Cop0.hpp b/src/backend/core/registers/Cop0.hpp index ba9475e..4cd6868 100644 --- a/src/backend/core/registers/Cop0.hpp +++ b/src/backend/core/registers/Cop0.hpp @@ -288,7 +288,9 @@ struct Cop0 { void tlbw(int); void tlbp(); - template + enum MemoryMapType { User, Supervisor, Kernel }; + + template bool MapVirtualAddress(TLBAccessType accessType, u64 vaddr, u32 &paddr); }; } // namespace n64