From 4d9cb49b732f701436e8602bfb34f509921aa9a1 Mon Sep 17 00:00:00 2001 From: iris Date: Wed, 27 May 2026 12:44:01 +0200 Subject: [PATCH] aaaaaaaaa --- src/backend/Core.cpp | 7 + src/backend/Scheduler.cpp | 3 - src/backend/Scheduler.hpp | 2 +- src/backend/core/Interpreter.cpp | 24 +- src/backend/core/Interpreter.hpp | 7 +- src/backend/core/RDP.cpp | 341 +++++++++--------- .../core/interpreter/cop1instructions.cpp | 2 + src/backend/core/jit/helpers.hpp | 12 + 8 files changed, 202 insertions(+), 196 deletions(-) diff --git a/src/backend/Core.cpp b/src/backend/Core.cpp index f553bd2..446e265 100644 --- a/src/backend/Core.cpp +++ b/src/backend/Core.cpp @@ -82,6 +82,12 @@ u32 Core::StepCPU() { void Core::StepRSP(const u32 cpuCycles) { MMIO &mmio = mem->mmio; + if (mmio.rsp.spStatus.halt) { + regs.steps = 0; + mmio.rsp.steps = 0; + return; + } + static constexpr u32 cpuRatio = 3, rspRatio = 2; regs.steps += cpuCycles; @@ -113,6 +119,7 @@ void Core::Run(const float volumeL, const float volumeR) { const u32 taken = StepCPU(); cycles += taken; frameCycles += taken; + StepRSP(taken); Scheduler::GetInstance().Tick(taken); } } diff --git a/src/backend/Scheduler.cpp b/src/backend/Scheduler.cpp index 8356a98..119e676 100644 --- a/src/backend/Scheduler.cpp +++ b/src/backend/Scheduler.cpp @@ -39,9 +39,6 @@ void Scheduler::HandleEvents() { while (ticks >= events.top().time) { switch (const auto type = events.top().type) { - case RSP_STEP: - n64::Core::GetInstance().StepRSP(1); - break; case SI_DMA: si.DMA(); break; diff --git a/src/backend/Scheduler.hpp b/src/backend/Scheduler.hpp index 0808a57..51e43d5 100644 --- a/src/backend/Scheduler.hpp +++ b/src/backend/Scheduler.hpp @@ -3,7 +3,7 @@ #include #include -enum EventType { NONE, RSP_STEP, PI_BUS_WRITE_COMPLETE, PI_DMA_COMPLETE, SI_DMA, IMPOSSIBLE }; +enum EventType { NONE, PI_BUS_WRITE_COMPLETE, PI_DMA_COMPLETE, SI_DMA, IMPOSSIBLE }; struct Event { u64 time; diff --git a/src/backend/core/Interpreter.cpp b/src/backend/core/Interpreter.cpp index e248a1c..324ae43 100644 --- a/src/backend/core/Interpreter.cpp +++ b/src/backend/core/Interpreter.cpp @@ -93,14 +93,6 @@ u32 Interpreter::Step() { DecodeExecute(instr); - if (!mem.mmio.rsp.spStatus.halt) { - rspSyncCount++; - if (rspSyncCount >= 3) - Scheduler::GetInstance().EnqueueRelative(0, RSP_STEP); - } - - Scheduler::GetInstance().HandleEvents(); - return 1; } @@ -132,8 +124,10 @@ void CachedState::EvictLine(u64 addr) { u32 offset; u32 page = DivideAddr(addr, offset); - if (blocks[page]) - blocks[page] = nullptr; + if (blocks[page]) { + blocks[page]->lines[offset].reset(); + blocks[page].reset(); + } } u32 Interpreter::ExecuteCached() { @@ -149,7 +143,6 @@ u32 Interpreter::ExecuteCached() { Instruction instr = line->code[i]; DecodeExecute(instr); - Scheduler::GetInstance().HandleEvents(); // Branch likely with false condition, it wasn't taken so don't execute the delay slot if (IsBranchLikely(instr) && !regs.delaySlot) break; @@ -187,15 +180,6 @@ u32 Interpreter::ExecuteCached() { } } - if (!mem.mmio.rsp.spStatus.halt) { - for (int j = 1; j <= (int)std::floor((double)i / 3); j++) { - Scheduler::GetInstance().EnqueueRelative(j * 3, RSP_STEP); - } - } else { - regs.steps = 0; - mem.mmio.rsp.steps = 0; - } - cachedState.InsertLine(blockAddr, std::make_shared(code, i, i)); return ExecuteCached(); diff --git a/src/backend/core/Interpreter.hpp b/src/backend/core/Interpreter.hpp index 1f525d5..16ebd41 100644 --- a/src/backend/core/Interpreter.hpp +++ b/src/backend/core/Interpreter.hpp @@ -5,8 +5,8 @@ namespace n64 { struct Core; -static constexpr u32 MAX_INSTRUCTION_PER_LINE = 128; static constexpr u32 MAX_LINES_PER_BLOCK = 1 << 12; +static constexpr u32 MAX_INSTRUCTION_PER_LINE = MAX_LINES_PER_BLOCK >> 2; struct CachedLine { std::array code = {}; @@ -51,14 +51,15 @@ struct Interpreter final { cachedState.Reset(); } + + CachedState cachedState; + private: friend struct Cop1; friend struct Mem; void MaybeIdleSkip(); - CachedState cachedState; - InstructionCache icache; DataCache dcache; Registers ®s; diff --git a/src/backend/core/RDP.cpp b/src/backend/core/RDP.cpp index d503eb4..ea2df52 100644 --- a/src/backend/core/RDP.cpp +++ b/src/backend/core/RDP.cpp @@ -4,75 +4,79 @@ namespace n64 { RDP::RDP() { - rdram.resize(RDRAM_SIZE); - Reset(); + rdram.resize(RDRAM_SIZE); + Reset(); } void RDP::Reset() { - dpc = {}; - dpc.status.raw = 0x80; - std::ranges::fill(rdram, 0); - std::ranges::fill(cmd_buf, 0); + dpc = {}; + dpc.status.raw = 0x80; + std::ranges::fill(rdram, 0); + std::ranges::fill(cmd_buf, 0); } template <> void RDP::WriteRDRAM(const size_t idx, const u8 v) { - if (const size_t real = BYTE_ADDRESS(idx); real < RDRAM_SIZE) [[likely]] { - rdram[real] = v; - } + if (const size_t real = BYTE_ADDRESS(idx); real < RDRAM_SIZE) [[likely]] { + rdram[real] = v; + Core::GetInstance().interpreter.cachedState.EvictLine(idx); + } } template <> void RDP::WriteRDRAM(const size_t idx, const u16 v) { - if (const size_t real = HALF_ADDRESS(idx); real < RDRAM_SIZE) [[likely]] { - ircolib::WriteAccess(rdram, real, v); - } + if (const size_t real = HALF_ADDRESS(idx); real < RDRAM_SIZE) [[likely]] { + ircolib::WriteAccess(rdram, real, v); + Core::GetInstance().interpreter.cachedState.EvictLine(idx); + } } template <> void RDP::WriteRDRAM(const size_t idx, const u32 v) { - if (idx < RDRAM_SIZE) [[likely]] { - ircolib::WriteAccess(rdram, idx, v); - } + if (idx < RDRAM_SIZE) [[likely]] { + ircolib::WriteAccess(rdram, idx, v); + Core::GetInstance().interpreter.cachedState.EvictLine(idx); + } } template <> void RDP::WriteRDRAM(const size_t idx, const u64 v) { - if (idx < RDRAM_SIZE) [[likely]] { - ircolib::WriteAccess(rdram, idx, v); - } + if (idx < RDRAM_SIZE) [[likely]] { + ircolib::WriteAccess(rdram, idx, v); + Core::GetInstance().interpreter.cachedState.EvictLine(idx); + } } template <> u8 RDP::ReadRDRAM(const size_t idx) { - if (const size_t real = BYTE_ADDRESS(idx); real < RDRAM_SIZE) [[likely]] - return rdram[real]; + if (const size_t real = BYTE_ADDRESS(idx); real < RDRAM_SIZE) [[likely]] + return rdram[real]; - return 0; + return 0; } template <> u16 RDP::ReadRDRAM(const size_t idx) { - if (const size_t real = HALF_ADDRESS(idx); real < RDRAM_SIZE) [[likely]] - return ircolib::ReadAccess(rdram, real); + if (const size_t real = HALF_ADDRESS(idx); real < RDRAM_SIZE) [[likely]] + return ircolib::ReadAccess(rdram, real); - return 0; + return 0; } template <> u32 RDP::ReadRDRAM(const size_t idx) { - if (idx < RDRAM_SIZE) [[likely]] - return ircolib::ReadAccess(rdram, idx); + if (idx < RDRAM_SIZE) [[likely]] + return ircolib::ReadAccess(rdram, idx); - return 0; + return 0; } template <> u64 RDP::ReadRDRAM(const size_t idx) { - if (idx < RDRAM_SIZE) [[likely]] - return ircolib::ReadAccess(rdram, idx); + if (idx < RDRAM_SIZE) [[likely]] + return ircolib::ReadAccess(rdram, idx); - return 0; + return 0; } static const int cmd_lens[64] = {2, 2, 2, 2, 2, 2, 2, 2, 8, 12, 24, 28, 24, 28, 40, 44, 2, 2, 2, 2, 2, 2, @@ -80,79 +84,78 @@ static const int cmd_lens[64] = {2, 2, 2, 2, 2, 2, 2, 2, 8, 12, 24, 28, 24, 28, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; auto RDP::Read(const u32 addr) const -> u32 { - switch (addr) { - case 0x04100000: - return dpc.start; - case 0x04100004: - return dpc.end; - case 0x04100008: - return dpc.current; - case 0x0410000C: - return dpc.status.raw; - case 0x04100010: - return dpc.clock; - case 0x04100014: - return dpc.status.cmdBusy; - case 0x04100018: - return dpc.status.pipeBusy; - case 0x0410001C: - return dpc.tmem; - default: - panic("Unhandled DP Command Registers read (addr: {:08X})", addr); - } + switch (addr) { + case 0x04100000: + return dpc.start; + case 0x04100004: + return dpc.end; + case 0x04100008: + return dpc.current; + case 0x0410000C: + return dpc.status.raw; + case 0x04100010: + return dpc.clock; + case 0x04100014: + return dpc.status.cmdBusy; + case 0x04100018: + return dpc.status.pipeBusy; + case 0x0410001C: + return dpc.tmem; + default: + panic("Unhandled DP Command Registers read (addr: {:08X})", addr); + } - return 0; + return 0; } void RDP::Write(const u32 addr, const u32 val) { - switch (addr) { - case 0x04100000: - WriteStart(val); - break; - case 0x04100004: - WriteEnd(val); - break; - case 0x0410000C: - WriteStatus(val); - break; - default: - panic("Unhandled DP Command Registers write (addr: {:08X}, val: {:08X})", addr, val); - } + switch (addr) { + case 0x04100000: + WriteStart(val); + break; + case 0x04100004: + WriteEnd(val); + break; + case 0x0410000C: + WriteStatus(val); + break; + default: + panic("Unhandled DP Command Registers write (addr: {:08X}, val: {:08X})", addr, val); + } } - void RDP::WriteStatus(const u32 val) { - DPCStatusWrite temp{}; - temp.raw = val; - bool unfrozen = false; + DPCStatusWrite temp{}; + temp.raw = val; + bool unfrozen = false; #define CLEAR_SET(val, clear, set) \ - do { \ - if ((clear)) \ - (val) = 0; \ - if ((set)) \ - (val) = 1; \ - } \ - while (0) + do { \ + if ((clear)) \ + (val) = 0; \ + if ((set)) \ + (val) = 1; \ + } \ + while (0) - CLEAR_SET(dpc.status.xbusDmemDma, temp.clearXbusDmemDma, temp.setXbusDmemDma); - if (temp.clearFreeze) { - dpc.status.freeze = false; - unfrozen = true; - } + CLEAR_SET(dpc.status.xbusDmemDma, temp.clearXbusDmemDma, temp.setXbusDmemDma); + if (temp.clearFreeze) { + dpc.status.freeze = false; + unfrozen = true; + } - if (temp.setFreeze) { - dpc.status.freeze = true; - } - CLEAR_SET(dpc.status.flush, temp.clearFlush, temp.setFlush); - CLEAR_SET(dpc.status.tmemBusy, temp.clearTmem, false); - CLEAR_SET(dpc.status.pipeBusy, temp.clearPipe, false); - CLEAR_SET(dpc.status.cmdBusy, temp.clearCmd, false); - CLEAR_SET(dpc.clock, temp.clearClock, false); + if (temp.setFreeze) { + dpc.status.freeze = true; + } + CLEAR_SET(dpc.status.flush, temp.clearFlush, temp.setFlush); + CLEAR_SET(dpc.status.tmemBusy, temp.clearTmem, false); + CLEAR_SET(dpc.status.pipeBusy, temp.clearPipe, false); + CLEAR_SET(dpc.status.cmdBusy, temp.clearCmd, false); + CLEAR_SET(dpc.clock, temp.clearClock, false); - if (!unfrozen) { - RunCommand(); - } + if (!unfrozen) { + RunCommand(); + } } /* FORCE_INLINE void logCommand(u8 cmd) { @@ -197,102 +200,102 @@ FORCE_INLINE void logCommand(u8 cmd) { */ void RDP::RunCommand() { - n64::Mem& mem = n64::Core::GetMem(); - ParallelRDP& parallel = n64::Core::GetInstance().parallel; - if (dpc.status.freeze) { - return; - } - dpc.status.pipeBusy = true; - dpc.status.startGclk = true; - if (dpc.end > dpc.current) { - dpc.status.freeze = true; - - static int remaining_cmds = 0; - - const u32 current = dpc.current & 0xFFFFF8; - const u32 end = dpc.end & 0xFFFFF8; - - const auto len = static_cast(end) - static_cast(current); - if (len <= 0) - return; - - if (len + remaining_cmds * 4 > COMMAND_BUFFER_SIZE) { - panic("Too many RDP commands"); - return; - } - - if (dpc.status.xbusDmemDma) { - for (int i = 0; i < len; i += 4) { - const u32 cmd = ircolib::ReadAccess(mem.mmio.rsp.dmem, current + i & 0xFFF); - cmd_buf[remaining_cmds + (i >> 2)] = cmd; - } - } else { - if (end > 0x7FFFFFF || current > 0x7FFFFFF) { // if (end > RDRAM_DSIZE || current > RDRAM_DSIZE) + n64::Mem &mem = n64::Core::GetMem(); + ParallelRDP ¶llel = n64::Core::GetInstance().parallel; + if (dpc.status.freeze) { return; - } - - for (int i = 0; i < len; i += 4) { - const u32 cmd = ircolib::ReadAccess(rdram, current + i); - cmd_buf[remaining_cmds + (i >> 2)] = cmd; - } } + dpc.status.pipeBusy = true; + dpc.status.startGclk = true; + if (dpc.end > dpc.current) { + dpc.status.freeze = true; - const int word_len = (len >> 2) + remaining_cmds; - int buf_index = 0; + static int remaining_cmds = 0; - bool processed_all = true; + const u32 current = dpc.current & 0xFFFFF8; + const u32 end = dpc.end & 0xFFFFF8; - while (buf_index < word_len) { - const u8 cmd = cmd_buf[buf_index] >> 24 & 0x3F; + const auto len = static_cast(end) - static_cast(current); + if (len <= 0) + return; - const int cmd_len = cmd_lens[cmd]; - if ((buf_index + cmd_len) * 4 > len + remaining_cmds * 4) { - remaining_cmds = word_len - buf_index; - - u32 tmp[remaining_cmds]; - for (int i = 0; i < remaining_cmds; i++) { - tmp[i] = cmd_buf[buf_index + i]; + if (len + remaining_cmds * 4 > COMMAND_BUFFER_SIZE) { + panic("Too many RDP commands"); + return; } - for (int i = 0; i < remaining_cmds; i++) { - cmd_buf[i] = tmp[i]; + if (dpc.status.xbusDmemDma) { + for (int i = 0; i < len; i += 4) { + const u32 cmd = ircolib::ReadAccess(mem.mmio.rsp.dmem, current + i & 0xFFF); + cmd_buf[remaining_cmds + (i >> 2)] = cmd; + } + } else { + if (end > 0x7FFFFFF || current > 0x7FFFFFF) { // if (end > RDRAM_DSIZE || current > RDRAM_DSIZE) + return; + } + + for (int i = 0; i < len; i += 4) { + const u32 cmd = ircolib::ReadAccess(rdram, current + i); + cmd_buf[remaining_cmds + (i >> 2)] = cmd; + } } - processed_all = false; - break; - } + const int word_len = (len >> 2) + remaining_cmds; + int buf_index = 0; - if (cmd >= 8) { - parallel.EnqueueCommand(cmd_len, &cmd_buf[buf_index]); - } + bool processed_all = true; - if (cmd == 0x29) { - OnFullSync(); - } + while (buf_index < word_len) { + const u8 cmd = cmd_buf[buf_index] >> 24 & 0x3F; - buf_index += cmd_len; + const int cmd_len = cmd_lens[cmd]; + if ((buf_index + cmd_len) * 4 > len + remaining_cmds * 4) { + remaining_cmds = word_len - buf_index; + + u32 tmp[remaining_cmds]; + for (int i = 0; i < remaining_cmds; i++) { + tmp[i] = cmd_buf[buf_index + i]; + } + + for (int i = 0; i < remaining_cmds; i++) { + cmd_buf[i] = tmp[i]; + } + + processed_all = false; + break; + } + + if (cmd >= 8) { + parallel.EnqueueCommand(cmd_len, &cmd_buf[buf_index]); + } + + if (cmd == 0x29) { + OnFullSync(); + } + + buf_index += cmd_len; + } + + if (processed_all) { + remaining_cmds = 0; + } + + dpc.current = end; + dpc.end = end; + dpc.status.freeze = false; } - - if (processed_all) { - remaining_cmds = 0; - } - - dpc.current = end; - dpc.end = end; - dpc.status.freeze = false; - } - dpc.status.cbufReady = true; + dpc.status.cbufReady = true; } void RDP::OnFullSync() { - n64::Mem& mem = n64::Core::GetMem(); - ParallelRDP& parallel = n64::Core::GetInstance().parallel; + n64::Mem &mem = n64::Core::GetMem(); + ParallelRDP ¶llel = n64::Core::GetInstance().parallel; - parallel.OnFullSync(); + parallel.OnFullSync(); - dpc.status.pipeBusy = false; - dpc.status.startGclk = false; - dpc.status.cbufReady = false; - mem.mmio.mi.InterruptRaise(MI::Interrupt::DP); + dpc.status.pipeBusy = false; + dpc.status.startGclk = false; + dpc.status.cbufReady = false; + mem.mmio.mi.InterruptRaise(MI::Interrupt::DP); } } // namespace n64 diff --git a/src/backend/core/interpreter/cop1instructions.cpp b/src/backend/core/interpreter/cop1instructions.cpp index 3f702ac..4281edc 100644 --- a/src/backend/core/interpreter/cop1instructions.cpp +++ b/src/backend/core/interpreter/cop1instructions.cpp @@ -1311,6 +1311,7 @@ void Cop1::swc1(const Instruction instr) { regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC); } else { mem.Write(physical, FGR_T(regs.cop0.status, instr.ft())); + Core::GetInstance().interpreter.cachedState.EvictLine(addr); } } @@ -1338,6 +1339,7 @@ void Cop1::sdc1(const Instruction instr) { regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC); } else { mem.Write(physical, FGR_T(regs.cop0.status, instr.ft())); + Core::GetInstance().interpreter.cachedState.EvictLine(addr); } } diff --git a/src/backend/core/jit/helpers.hpp b/src/backend/core/jit/helpers.hpp index cd62a25..98ce5dc 100644 --- a/src/backend/core/jit/helpers.hpp +++ b/src/backend/core/jit/helpers.hpp @@ -69,6 +69,18 @@ static bool InstrEndsBlock(const Instruction instr) { return true; return false; + case Instruction::COP0: + switch (instr.cop_rs()) { + case 0x10 ... 0x1F: + switch (instr.cop_funct()) { + case 0x18: // eret + return true; + default: + return false; + } + default: + return false; + } default: return false; }