From a9ba5bce0f7d0a55ccd2d49ff174052ccbfc913f Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Thu, 21 Aug 2025 02:18:07 +0300 Subject: [PATCH] Disassembly: Merge li a0 + syscall --- src/core/disr3000a.cc | 47 +++++++++++++++++++++++++++++++++---- src/core/disr3000a.h | 5 ++++ src/gui/widgets/assembly.cc | 5 ++++ src/gui/widgets/assembly.h | 1 + 4 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/core/disr3000a.cc b/src/core/disr3000a.cc index 4cfd2edce..facaf4e78 100644 --- a/src/core/disr3000a.cc +++ b/src/core/disr3000a.cc @@ -57,6 +57,19 @@ const char *PCSX::Disasm::s_disRNameCP0[] = { "TagLo", "TagHi", "ErrorEPC", "*RES*", // 1c }; +const char *PCSX::Disasm::getSyscallName(uint32_t index) { + switch (index) { + case 0: + return "NOP"; + case 1: + return "EnterCriticalSection"; + case 2: + return "ExitCriticalSection"; + default: + return "DeliverEvent"; + } +} + #undef declare #undef _Funct_ #undef _Rd_ @@ -226,6 +239,7 @@ struct StringDisasm : public PCSX::Disasm { } } } + virtual void SyscallName(const char *name) final { append(name); } virtual void reset() final { m_buf[0] = 0; m_len = 0; @@ -281,8 +295,9 @@ declare(disADDI) { declare(disADDIU) { if (_Rs_ == 0) { // this is the common pseudo-instruction to load an immediate 16 bits value - dOpCode("li"); - GPR(_Rt_); + if (disLI(_Rt_, _Im_, nextCode, skipNext, delaySlotNext)) { + return; + } } else { dOpCode("addiu"); GPR(_Rt_); @@ -299,8 +314,9 @@ declare(disANDI) { declare(disORI) { if (_Rs_ == 0) { // while rare, this can also be used to load an immediate 16-bits value - dOpCode("li"); - GPR(_Rt_); + if (disLI(_Rt_, _Im_, nextCode, skipNext, delaySlotNext)) { + return; + } } else { dOpCode("ori"); GPR(_Rt_); @@ -680,6 +696,27 @@ declare(disLUI) { } } +bool PCSX::Disasm::disLI(uint32_t reg, uint32_t imm, uint32_t nextCode, bool *skipNext, bool *delaySlotNext) { + // Merge syscalls, which usually have the pattern + // li $a0, syscallNumber + // syscall 0x0000 + uint8_t nextIns = nextCode >> 26; + uint8_t nextSubfunc = nextCode & 0x3f; + + if (skipNext && reg == 4 && nextIns == 0 && nextSubfunc == 0xC) { + dOpCode("syscall"); + SyscallName(getSyscallName(imm)); + + *skipNext = true; + return true; + } else { + dOpCode("li"); + GPR(reg); + + return false; + } +} + /********************************************************* * Move from HI/LO to GPR * * Format: OP rd * @@ -969,7 +1006,7 @@ declare(disCTC0) { } /********************************************************* - * Unknow instruction (would generate an exception) * + * Unknown instruction (would generate an exception) * * Format: ? * *********************************************************/ declare(disNULL) { diff --git a/src/core/disr3000a.h b/src/core/disr3000a.h index 07d0b4825..6dfda853e 100644 --- a/src/core/disr3000a.h +++ b/src/core/disr3000a.h @@ -36,6 +36,7 @@ class Disasm { static const char *s_disRNameCP2D[]; static const char *s_disRNameCP2C[]; static const char *s_disRNameCP0[]; + static const char *getSyscallName(uint32_t index); #define declare(n) \ void n(uint32_t code, uint32_t nextCode, uint32_t pc, bool *skipNext = nullptr, bool *delaySlotNext = nullptr) @@ -72,6 +73,7 @@ class Disasm { virtual void OfB(int16_t offset, uint8_t reg, int size) = 0; virtual void BranchDest(uint32_t offset) = 0; virtual void Offset(uint32_t offset, int size) = 0; + virtual void SyscallName(const char *) = 0; private: // Type definition of our functions @@ -188,6 +190,9 @@ class Disasm { declare(disGPL); declare(disNCCT); #undef declare + + // li has a slightly different signature, being a pseudoinstruction + bool disLI(uint32_t reg, uint32_t imm, uint32_t nextCode, bool *skipNext = nullptr, bool *delaySlotNext = nullptr); }; } // namespace PCSX diff --git a/src/gui/widgets/assembly.cc b/src/gui/widgets/assembly.cc index 1eb539693..5823b1d84 100644 --- a/src/gui/widgets/assembly.cc +++ b/src/gui/widgets/assembly.cc @@ -104,6 +104,7 @@ class DummyAsm : public PCSX::Disasm { virtual void OfB(int16_t offset, uint8_t reg, int size) final {} virtual void BranchDest(uint32_t offset) final {} virtual void Offset(uint32_t offset, int size) final {} + virtual void SyscallName(const char*) final {} }; } // namespace @@ -310,6 +311,10 @@ void PCSX::Widgets::Assembly::Target(uint32_t value) { } ImGui::PopStyleVar(); } +void PCSX::Widgets::Assembly::SyscallName(const char* name) { + sameLine(); + ImGui::TextUnformatted(name); +} void PCSX::Widgets::Assembly::Sa(uint8_t value) { comma(); sameLine(); diff --git a/src/gui/widgets/assembly.h b/src/gui/widgets/assembly.h index f3ef27843..b817f2148 100644 --- a/src/gui/widgets/assembly.h +++ b/src/gui/widgets/assembly.h @@ -92,6 +92,7 @@ class Assembly : private Disasm { virtual void OfB(int16_t offset, uint8_t reg, int size) final; virtual void BranchDest(uint32_t value) final; virtual void Offset(uint32_t addr, int size) final; + virtual void SyscallName(const char*) final; bool m_gotArg = false; bool m_notch = false; bool m_notchAfterSkip[2] = {false, false};