diff --git a/Source/Core/Common/Assembler/GekkoIRGen.cpp b/Source/Core/Common/Assembler/GekkoIRGen.cpp index 4640ec529e47..6fae04907334 100644 --- a/Source/Core/Common/Assembler/GekkoIRGen.cpp +++ b/Source/Core/Common/Assembler/GekkoIRGen.cpp @@ -681,6 +681,7 @@ void GekkoIRPlugin::EvalTerminalRel(Terminal type, const AssemblerToken& tok) case Terminal::Bin: case Terminal::GPR: case Terminal::FPR: + case Terminal::GQR: case Terminal::SPR: case Terminal::CRField: case Terminal::Lt: @@ -732,6 +733,7 @@ void GekkoIRPlugin::EvalTerminalAbs(Terminal type, const AssemblerToken& tok) case Terminal::Bin: case Terminal::GPR: case Terminal::FPR: + case Terminal::GQR: case Terminal::SPR: case Terminal::CRField: case Terminal::Lt: diff --git a/Source/Core/Common/Assembler/GekkoLexer.cpp b/Source/Core/Common/Assembler/GekkoLexer.cpp index d14270d2b9ca..769e20d93391 100644 --- a/Source/Core/Common/Assembler/GekkoLexer.cpp +++ b/Source/Core/Common/Assembler/GekkoLexer.cpp @@ -187,6 +187,8 @@ std::optional EvalIntegral(TokenType tp, std::string_view val) if (CaseInsensitiveEquals(val, "rtoc")) return T{2}; [[fallthrough]]; + case TokenType::GQR: + return std::accumulate(val.begin() + 2, val.end(), T{0}, dec_step); case TokenType::FPR: return std::accumulate(val.begin() + 1, val.end(), T{0}, dec_step); case TokenType::CRField: @@ -220,6 +222,8 @@ std::string_view TokenTypeToStr(TokenType tp) return "GPR"; case TokenType::FPR: return "FPR"; + case TokenType::GQR: + return "GQR"; case TokenType::SPR: return "SPR"; case TokenType::CRField: @@ -668,6 +672,15 @@ TokenType Lexer::ClassifyAlnum() const { return TokenType::FPR; } + else if (std::tolower(alnum[0]) == 'p' && valid_regnum(alnum.substr(1))) + { + return TokenType::FPR; + } + else if (alnum.length() == 3 && CaseInsensitiveEquals(alnum.substr(0, 2), "qr") && + alnum[2] >= '0' && alnum[2] <= '7') + { + return TokenType::GQR; + } else if (alnum.length() == 3 && CaseInsensitiveEquals(alnum.substr(0, 2), "cr") && alnum[2] >= '0' && alnum[2] <= '7') { diff --git a/Source/Core/Common/Assembler/GekkoLexer.h b/Source/Core/Common/Assembler/GekkoLexer.h index 9ff78c04d030..cb49de585881 100644 --- a/Source/Core/Common/Assembler/GekkoLexer.h +++ b/Source/Core/Common/Assembler/GekkoLexer.h @@ -31,6 +31,7 @@ enum class TokenType FloatLit, GPR, FPR, + GQR, CRField, SPR, Lt, diff --git a/Source/Core/Common/Assembler/GekkoParser.cpp b/Source/Core/Common/Assembler/GekkoParser.cpp index 26b5bb10821e..2ef6de6e9f73 100644 --- a/Source/Core/Common/Assembler/GekkoParser.cpp +++ b/Source/Core/Common/Assembler/GekkoParser.cpp @@ -127,6 +127,9 @@ void ParsePpcBuiltin(ParseState* state) case TokenType::FPR: state->plugin.OnTerminal(Terminal::FPR, tok); break; + case TokenType::GQR: + state->plugin.OnTerminal(Terminal::GQR, tok); + break; case TokenType::SPR: state->plugin.OnTerminal(Terminal::SPR, tok); break; @@ -176,6 +179,7 @@ void ParseBaseexpr(ParseState* state) case TokenType::GPR: case TokenType::FPR: case TokenType::SPR: + case TokenType::GQR: case TokenType::CRField: case TokenType::Lt: case TokenType::Gt: diff --git a/Source/Core/Common/Assembler/GekkoParser.h b/Source/Core/Common/Assembler/GekkoParser.h index 4258b5d582aa..fe0ffdc2dae8 100644 --- a/Source/Core/Common/Assembler/GekkoParser.h +++ b/Source/Core/Common/Assembler/GekkoParser.h @@ -56,6 +56,7 @@ enum class Terminal Id, GPR, FPR, + GQR, SPR, CRField, Lt, diff --git a/Source/Core/Common/GekkoDisassembler.cpp b/Source/Core/Common/GekkoDisassembler.cpp index 46905c8773d1..820f3ea171f2 100644 --- a/Source/Core/Common/GekkoDisassembler.cpp +++ b/Source/Core/Common/GekkoDisassembler.cpp @@ -631,7 +631,7 @@ void GekkoDisassembler::nooper(u32 in, std::string_view name) } } -void GekkoDisassembler::rlw(u32 in, std::string_view name, int i) +void GekkoDisassembler::rlw(u32 in, std::string_view name, int i, bool for_assemble) { int s = (int)PPCGETD(in); int a = (int)PPCGETA(in); @@ -640,8 +640,17 @@ void GekkoDisassembler::rlw(u32 in, std::string_view name, int i) int me = (int)PPCGETM(in); m_opcode = fmt::format("rlw{}{}", name, (in & 1) ? "." : ""); - m_operands = fmt::format("{}, {}, {}{}, {}, {} ({:08x})", regnames[a], regnames[s], regsel[i], - bsh, mb, me, HelperRotateMask(bsh, mb, me)); + if (!for_assemble) + { + m_operands = fmt::format("{}, {}, {}{}, {}, {} ({:08x})", regnames[a], regnames[s], regsel[i], + bsh, mb, me, HelperRotateMask(bsh, mb, me)); + } + else + { + m_operands = fmt::format("{}, {}, {}{}, {}, {}", regnames[a], regnames[s], regsel[i], + bsh, mb, me); + + } } void GekkoDisassembler::ori(u32 in, std::string_view name) @@ -1019,7 +1028,7 @@ void GekkoDisassembler::mtfsb(u32 in, int n) #define IX ((inst >> 7) & 0x7) #define WX ((inst >> 10) & 0x1) -void GekkoDisassembler::ps(u32 inst) +void GekkoDisassembler::ps(u32 inst, bool for_assemble) { switch ((inst >> 1) & 0x1F) { @@ -1035,32 +1044,74 @@ void GekkoDisassembler::ps(u32 inst) case 18: m_opcode = "ps_div"; - m_operands = fmt::format("p{}, p{}/p{}", FD, FA, FB); + if (!for_assemble) + { + m_operands = fmt::format("p{}, p{}/p{}", FD, FA, FB); + } + else + { + m_operands = fmt::format("p{}, p{}, p{}", FD, FA, FB); + } return; case 20: m_opcode = "ps_sub"; - m_operands = fmt::format("p{}, p{}-p{}", FD, FA, FB); + if (!for_assemble) + { + m_operands = fmt::format("p{}, p{}-p{}", FD, FA, FB); + } + else + { + m_operands = fmt::format("p{}, p{}, p{}", FD, FA, FB); + } return; case 21: m_opcode = "ps_add"; - m_operands = fmt::format("p{}, p{}+p{}", FD, FA, FB); + if (!for_assemble) + { + m_operands = fmt::format("p{}, p{}+p{}", FD, FA, FB); + } + else + { + m_operands = fmt::format("p{}, p{}, p{}", FD, FA, FB); + } return; case 23: m_opcode = "ps_sel"; - m_operands = fmt::format("p{}>=0?p{}:p{}", FD, FA, FC); + if (!for_assemble) + { + m_operands = fmt::format("p{}>=0?p{}:p{}", FD, FA, FC); + } + else + { + m_operands = fmt::format("p{}, p{}, p{}", FD, FA, FC); + } return; case 24: m_opcode = "ps_res"; - m_operands = fmt::format("p{}, (1/p{})", FD, FB); + if (!for_assemble) + { + m_operands = fmt::format("p{}, (1/p{})", FD, FB); + } + else + { + m_operands = fmt::format("p{}, p{}", FD, FB); + } return; case 25: m_opcode = "ps_mul"; - m_operands = fmt::format("p{}, p{}*p{}", FD, FA, FC); + if (!for_assemble) + { + m_operands = fmt::format("p{}, p{}*p{}", FD, FA, FC); + } + else + { + m_operands = fmt::format("p{}, p{}, p{}", FD, FA, FC); + } return; case 26: // rsqrte @@ -1070,52 +1121,122 @@ void GekkoDisassembler::ps(u32 inst) case 28: // msub m_opcode = "ps_msub"; - m_operands = fmt::format("p{}, p{}*p{}-p{}", FD, FA, FC, FB); + if (!for_assemble) + { + m_operands = fmt::format("p{}, p{}*p{}-p{}", FD, FA, FC, FB); + } + else + { + m_operands = fmt::format("p{}, p{}, p{}, p{}", FD, FA, FC, FB); + } return; case 29: // madd m_opcode = "ps_madd"; - m_operands = fmt::format("p{}, p{}*p{}+p{}", FD, FA, FC, FB); + if (!for_assemble) + { + m_operands = fmt::format("p{}, p{}*p{}+p{}", FD, FA, FC, FB); + } + else + { + m_operands = fmt::format("p{}, p{}, p{}, p{}", FD, FA, FC, FB); + } return; case 30: // nmsub m_opcode = "ps_nmsub"; - m_operands = fmt::format("p{}, -(p{}*p{}-p{})", FD, FA, FC, FB); + if (!for_assemble) + { + m_operands = fmt::format("p{}, -(p{}*p{}-p{})", FD, FA, FC, FB); + } + else + { + m_operands = fmt::format("p{}, p{}, p{}, p{}", FD, FA, FC, FB); + } return; case 31: // nmadd m_opcode = "ps_nmadd"; - m_operands = fmt::format("p{}, -(p{}*p{}+p{})", FD, FA, FC, FB); + if (!for_assemble) + { + m_operands = fmt::format("p{}, -(p{}*p{}+p{})", FD, FA, FC, FB); + } + else + { + m_operands = fmt::format("p{}, p{}, p{}, p{}", FD, FA, FC, FB); + } return; case 10: m_opcode = "ps_sum0"; - m_operands = fmt::format("p{}, 0=p{}+p{}, 1=p{}", FD, FA, FB, FC); + if (!for_assemble) + { + m_operands = fmt::format("p{}, 0=p{}+p{}, 1=p{}", FD, FA, FB, FC); + } + else + { + m_operands = fmt::format("p{}, p{}, p{}, p{}", FD, FA, FB, FC); + } return; case 11: m_opcode = "ps_sum1"; - m_operands = fmt::format("p{}, 0=p{}, 1=p{}+p{}", FD, FC, FA, FB); + if (!for_assemble) + { + m_operands = fmt::format("p{}, 0=p{}, 1=p{}+p{}", FD, FC, FA, FB); + } + else + { + m_operands = fmt::format("p{}, p{}, p{}, p{}", FD, FC, FA, FB); + } return; case 12: m_opcode = "ps_muls0"; - m_operands = fmt::format("p{}, p{}*p{}[0]", FD, FA, FC); + if (!for_assemble) + { + m_operands = fmt::format("p{}, p{}*p{}[0]", FD, FA, FC); + } + else + { + m_operands = fmt::format("p{}, p{}, p{}", FD, FA, FC); + } return; case 13: m_opcode = "ps_muls1"; - m_operands = fmt::format("p{}, p{}*p{}[1]", FD, FA, FC); + if (!for_assemble) + { + m_operands = fmt::format("p{}, p{}*p{}[1]", FD, FA, FC); + } + else + { + m_operands = fmt::format("p{}, p{}, p{}", FD, FA, FC); + } return; case 14: m_opcode = "ps_madds0"; - m_operands = fmt::format("p{}, p{}*p{}[0]+p{}", FD, FA, FC, FB); + if (!for_assemble) + { + m_operands = fmt::format("p{}, p{}*p{}[0]+p{}", FD, FA, FC, FB); + } + else + { + m_operands = fmt::format("p{}, p{}, p{}, p{}", FD, FA, FC, FB); + } return; case 15: m_opcode = "ps_madds1"; - m_operands = fmt::format("p{}, p{}*p{}[1]+p{}", FD, FA, FC, FB); + if (!for_assemble) + { + m_operands = fmt::format("p{}, p{}*p{}[1]+p{}", FD, FA, FC, FB); + } + else + { + m_operands = fmt::format("p{}, p{}, p{}, p{}", FD, FA, FC, FB); + } return; } @@ -1124,7 +1245,14 @@ void GekkoDisassembler::ps(u32 inst) // 10-bit suckers (?) case 40: // nmadd m_opcode = "ps_neg"; - m_operands = fmt::format("p{}, -p{}", FD, FB); + if (!for_assemble) + { + m_operands = fmt::format("p{}, -p{}", FD, FB); + } + else + { + m_operands = fmt::format("p{}, p{}", FD, FB); + } return; case 72: // nmadd @@ -1134,12 +1262,26 @@ void GekkoDisassembler::ps(u32 inst) case 136: m_opcode = "ps_nabs"; - m_operands = fmt::format("p{}, -|p{}|", FD, FB); + if (!for_assemble) + { + m_operands = fmt::format("p{}, -|p{}|", FD, FB); + } + else + { + m_operands = fmt::format("p{}, p{}", FD, FB); + } return; case 264: m_opcode = "ps_abs"; - m_operands = fmt::format("p{}, |p{}|", FD, FB); + if (!for_assemble) + { + m_operands = fmt::format("p{}, |p{}|", FD, FB); + } + else + { + m_operands = fmt::format("p{}, p{}", FD, FB); + } return; case 0: @@ -1157,22 +1299,50 @@ void GekkoDisassembler::ps(u32 inst) } case 528: m_opcode = "ps_merge00"; - m_operands = fmt::format("p{}, p{}[0], p{}[0]", FD, FA, FB); + if (!for_assemble) + { + m_operands = fmt::format("p{}, p{}[0], p{}[0]", FD, FA, FB); + } + else + { + m_operands = fmt::format("p{}, p{}, p{}", FD, FA, FB); + } return; case 560: m_opcode = "ps_merge01"; - m_operands = fmt::format("p{}, p{}[0], p{}[1]", FD, FA, FB); + if (!for_assemble) + { + m_operands = fmt::format("p{}, p{}[0], p{}[1]", FD, FA, FB); + } + else + { + m_operands = fmt::format("p{}, p{}, p{}", FD, FA, FB); + } return; case 592: m_opcode = "ps_merge10"; - m_operands = fmt::format("p{}, p{}[1], p{}[0]", FD, FA, FB); + if (!for_assemble) + { + m_operands = fmt::format("p{}, p{}[1], p{}[0]", FD, FA, FB); + } + else + { + m_operands = fmt::format("p{}, p{}, p{}", FD, FA, FB); + } return; case 624: m_opcode = "ps_merge11"; - m_operands = fmt::format("p{}, p{}[1], p{}[1]", FD, FA, FB); + if (!for_assemble) + { + m_operands = fmt::format("p{}, p{}[1], p{}[1]", FD, FA, FB); + } + else + { + m_operands = fmt::format("p{}, p{}, p{}", FD, FA, FB); + } return; case 1014: @@ -1217,7 +1387,7 @@ void GekkoDisassembler::ps_mem(u32 inst) // Disassemble PPC instruction and return a pointer to the next // instruction, or nullptr if an error occurred. -u32* GekkoDisassembler::DoDisassembly(bool big_endian) +u32* GekkoDisassembler::DoDisassembly(bool for_assemble, bool big_endian) { u32 in = *m_instr; @@ -1240,7 +1410,7 @@ u32* GekkoDisassembler::DoDisassembly(bool big_endian) break; case 4: - ps(in); + ps(in, for_assemble); break; case 56: @@ -1361,15 +1531,15 @@ u32* GekkoDisassembler::DoDisassembly(bool big_endian) break; case 20: - rlw(in, "imi", 0); // rlwimi + rlw(in, "imi", 0, for_assemble); // rlwimi break; case 21: - rlw(in, "inm", 0); // rlwinm + rlw(in, "inm", 0, for_assemble); // rlwinm break; case 23: - rlw(in, "nm", 1); // rlwnm + rlw(in, "nm", 1, for_assemble); // rlwnm break; case 24: @@ -2275,7 +2445,7 @@ u32* GekkoDisassembler::DoDisassembly(bool big_endian) // simplified interface std::string GekkoDisassembler::Disassemble(u32 opcode, u32 current_instruction_address, - bool big_endian) + bool for_assemble, bool big_endian) { u32 opc = opcode; u32 addr = current_instruction_address; @@ -2283,7 +2453,7 @@ std::string GekkoDisassembler::Disassemble(u32 opcode, u32 current_instruction_a m_instr = (u32*)&opc; m_iaddr = (u32*)&addr; - DoDisassembly(big_endian); + DoDisassembly(for_assemble, big_endian); return m_opcode.append("\t").append(m_operands); } diff --git a/Source/Core/Common/GekkoDisassembler.h b/Source/Core/Common/GekkoDisassembler.h index a40323abf6eb..5495fa1db6cb 100644 --- a/Source/Core/Common/GekkoDisassembler.h +++ b/Source/Core/Common/GekkoDisassembler.h @@ -43,8 +43,8 @@ namespace Common class GekkoDisassembler final { public: - static std::string Disassemble(u32 opcode, u32 current_instruction_address, - bool big_endian = true); + static std::string Disassemble(u32 opcode, u32 current_instruction_address, + bool for_assemble, bool big_endian = true); static const char* GetGPRName(u32 index); static const char* GetFPRName(u32 index); @@ -67,7 +67,7 @@ class GekkoDisassembler final static void mcrf(u32 in, std::string_view suffix); static void crop(u32 in, std::string_view n1, std::string_view n2); static void nooper(u32 in, std::string_view name); - static void rlw(u32 in, std::string_view name, int i); + static void rlw(u32 in, std::string_view name, int i, bool for_assemble); static void ori(u32 in, std::string_view name); static void rld(u32 in, std::string_view name, int i); static void cmp(u32 in); @@ -85,10 +85,10 @@ class GekkoDisassembler final static void fdab(u32 in, std::string_view name); static void fcmp(u32 in, char c); static void mtfsb(u32 in, int n); - static void ps(u32 inst); + static void ps(u32 inst, bool for_assemble); static void ps_mem(u32 inst); - static u32* DoDisassembly(bool big_endian); + static u32* DoDisassembly(bool for_assemble, bool big_endian ); enum Flags { diff --git a/Source/Core/Core/Debugger/DebugInterface.h b/Source/Core/Core/Debugger/DebugInterface.h index cc07d06d3bcc..46efda6a0525 100644 --- a/Source/Core/Core/Debugger/DebugInterface.h +++ b/Source/Core/Core/Debugger/DebugInterface.h @@ -62,7 +62,8 @@ class DebugInterface // Threads virtual Common::Debug::Threads GetThreads(const CPUThreadGuard& guard) const = 0; - virtual std::string Disassemble(const CPUThreadGuard* /*guard*/, u32 /*address*/) const + virtual std::string Disassemble(const CPUThreadGuard* /*guard*/, u32 /*address*/, + bool /*for_assemble*/) const { return "NODEBUGGER"; } diff --git a/Source/Core/Core/Debugger/PPCDebugInterface.cpp b/Source/Core/Core/Debugger/PPCDebugInterface.cpp index 2c840d0ae59b..700fc50b5255 100644 --- a/Source/Core/Core/Debugger/PPCDebugInterface.cpp +++ b/Source/Core/Core/Debugger/PPCDebugInterface.cpp @@ -276,7 +276,7 @@ Common::Debug::Threads PPCDebugInterface::GetThreads(const Core::CPUThreadGuard& return threads; } -std::string PPCDebugInterface::Disassemble(const Core::CPUThreadGuard* guard, u32 address) const +std::string PPCDebugInterface::Disassemble(const Core::CPUThreadGuard* guard, u32 address, bool for_assemble) const { if (guard) { @@ -286,7 +286,7 @@ std::string PPCDebugInterface::Disassemble(const Core::CPUThreadGuard* guard, u3 } const u32 op = PowerPC::MMU::HostRead_Instruction(*guard, address); - std::string disasm = Common::GekkoDisassembler::Disassemble(op, address); + std::string disasm = Common::GekkoDisassembler::Disassemble(op, address,for_assemble); const UGeckoInstruction inst{op}; if (inst.OPCD == 1) diff --git a/Source/Core/Core/Debugger/PPCDebugInterface.h b/Source/Core/Core/Debugger/PPCDebugInterface.h index 797f2d52548c..75f2acc246b4 100644 --- a/Source/Core/Core/Debugger/PPCDebugInterface.h +++ b/Source/Core/Core/Debugger/PPCDebugInterface.h @@ -75,7 +75,7 @@ class PPCDebugInterface final : public Core::DebugInterface // Threads Common::Debug::Threads GetThreads(const Core::CPUThreadGuard& guard) const override; - std::string Disassemble(const Core::CPUThreadGuard* guard, u32 address) const override; + std::string Disassemble(const Core::CPUThreadGuard* guard, u32 address, bool for_assemble = false) const override; std::string GetRawMemoryString(const Core::CPUThreadGuard& guard, int memory, u32 address) const override; bool IsAlive() const override; diff --git a/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp b/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp index b281ac0300bb..de50055ee930 100644 --- a/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp +++ b/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp @@ -454,7 +454,7 @@ void CachedInterpreter::LogGeneratedCode() const std::span{m_code_buffer.data(), code_block.m_num_instructions}) { fmt::print(stream, "0x{:08x}\t\t{}\n", op.address, - Common::GekkoDisassembler::Disassemble(op.inst.hex, op.address)); + Common::GekkoDisassembler::Disassemble(op.inst.hex, op.address,false)); } stream << "\nHost Code:\n"; diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp index 89153f801e52..dcd7d354aecc 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp @@ -97,7 +97,7 @@ void Interpreter::Trace(const UGeckoInstruction& inst) fregs += fmt::format("f{:02d}: {:08x} {:08x} ", i, ps.PS0AsU64(), ps.PS1AsU64()); } - const std::string ppc_inst = Common::GekkoDisassembler::Disassemble(inst.hex, m_ppc_state.pc); + const std::string ppc_inst = Common::GekkoDisassembler::Disassemble(inst.hex, m_ppc_state.pc, false); DEBUG_LOG_FMT(POWERPC, "INTER PC: {:08x} SRR0: {:08x} SRR1: {:08x} CRval: {:016x} " "FPSCR: {:08x} MSR: {:08x} LR: {:08x} {} {:08x} {}", @@ -294,7 +294,7 @@ void Interpreter::unknown_instruction(Interpreter& interpreter, UGeckoInstructio const u32 last_pc = interpreter.m_last_pc; const u32 opcode = PowerPC::MMU::HostRead_U32(guard, last_pc); - const std::string disasm = Common::GekkoDisassembler::Disassemble(opcode, last_pc); + const std::string disasm = Common::GekkoDisassembler::Disassemble(opcode, last_pc, false); NOTICE_LOG_FMT(POWERPC, "Last PC = {:08x} : {}", last_pc, disasm); Dolphin_Debugger::PrintCallstack(guard, Common::Log::LogType::POWERPC, Common::Log::LogLevel::LNOTICE); diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp index b09279d45850..05005c727b31 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp @@ -1177,7 +1177,8 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC) #if defined(_DEBUG) || defined(DEBUGFAST) if (!gpr.SanityCheck() || !fpr.SanityCheck()) { - const std::string ppc_inst = Common::GekkoDisassembler::Disassemble(op.inst.hex, em_address); + const std::string ppc_inst = + Common::GekkoDisassembler::Disassemble(op.inst.hex, em_address, false); NOTICE_LOG_FMT(DYNA_REC, "Unflushed register: {}", ppc_inst); } #endif @@ -1320,7 +1321,7 @@ void Jit64::LogGeneratedCode() const std::span{m_code_buffer.data(), code_block.m_num_instructions}) { fmt::print(stream, "0x{:08x}\t\t{}\n", op.address, - Common::GekkoDisassembler::Disassemble(op.inst.hex, op.address)); + Common::GekkoDisassembler::Disassemble(op.inst.hex, op.address, false)); } const JitBlock* const block = js.curBlock; diff --git a/Source/Core/DolphinQt/Debugger/AssembleInstructionDialog.cpp b/Source/Core/DolphinQt/Debugger/AssembleInstructionDialog.cpp index a130576e0801..0c6eadc00a9d 100644 --- a/Source/Core/DolphinQt/Debugger/AssembleInstructionDialog.cpp +++ b/Source/Core/DolphinQt/Debugger/AssembleInstructionDialog.cpp @@ -38,8 +38,9 @@ QString HtmlFormatErrorLine(const Common::GekkoAssembler::AssemblerError& err) } } // namespace -AssembleInstructionDialog::AssembleInstructionDialog(QWidget* parent, u32 address, u32 value) - : QDialog(parent), m_code(value), m_address(address) +AssembleInstructionDialog::AssembleInstructionDialog(QWidget* parent, u32 address, u32 value, + QString disasm) + : QDialog(parent), m_code(value), m_address(address), m_disassembly(disasm) { setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setWindowModality(Qt::WindowModal); @@ -66,7 +67,7 @@ void AssembleInstructionDialog::CreateWidgets() layout->addWidget(m_error_line_label); layout->addWidget(m_msg_label); layout->addWidget(m_button_box); - m_input_edit->setText(QStringLiteral(".4byte 0x%1").arg(m_code, 8, 16, QLatin1Char('0'))); + m_input_edit->setText(m_disassembly); setLayout(layout); OnEditChanged(); @@ -86,6 +87,31 @@ void AssembleInstructionDialog::OnEditChanged() std::string line = m_input_edit->text().toStdString(); Common::ToLower(&line); + size_t posArrow = line.find("->"); + if (posArrow != std::string::npos) + { + std::string start = line.substr(0, posArrow); + std::string dest = line.substr(posArrow + 2); + u32 destAddress = 0; + size_t posHex = dest.find("0x"); + if (posHex == std::string::npos) + { + destAddress = (u32)strtoul(dest.c_str(), nullptr, 10); + } + else + { + destAddress = (u32)strtoul(dest.substr(posHex + 2).c_str(), nullptr, 16); + } + if (destAddress < m_address) + { + line = start + " -" + std::to_string(m_address - destAddress); + } + else + { + line = start + " " + std::to_string(destAddress - m_address); + } + } + FailureOr> asm_result = Assemble(line, m_address); if (IsFailure(asm_result)) diff --git a/Source/Core/DolphinQt/Debugger/AssembleInstructionDialog.h b/Source/Core/DolphinQt/Debugger/AssembleInstructionDialog.h index de2191e2c79d..5f170d28df56 100644 --- a/Source/Core/DolphinQt/Debugger/AssembleInstructionDialog.h +++ b/Source/Core/DolphinQt/Debugger/AssembleInstructionDialog.h @@ -15,7 +15,7 @@ class AssembleInstructionDialog : public QDialog { Q_OBJECT public: - explicit AssembleInstructionDialog(QWidget* parent, u32 address, u32 value); + explicit AssembleInstructionDialog(QWidget* parent, u32 address, u32 value, QString disasm); u32 GetCode() const; @@ -28,6 +28,7 @@ class AssembleInstructionDialog : public QDialog u32 m_code; u32 m_address; + QString m_disassembly; QLineEdit* m_input_edit; QLabel* m_error_loc_label; QLabel* m_error_line_label; diff --git a/Source/Core/DolphinQt/Debugger/BranchWatchTableModel.cpp b/Source/Core/DolphinQt/Debugger/BranchWatchTableModel.cpp index 2a3f4cb3d144..7319750a371a 100644 --- a/Source/Core/DolphinQt/Debugger/BranchWatchTableModel.cpp +++ b/Source/Core/DolphinQt/Debugger/BranchWatchTableModel.cpp @@ -306,7 +306,7 @@ static QVariant GetValidSymbolStringVariant(const QVariant& symbol_name_v) static QString GetInstructionMnemonic(u32 hex) { - const std::string disas = Common::GekkoDisassembler::Disassemble(hex, 0); + const std::string disas = Common::GekkoDisassembler::Disassemble(hex, 0, false); const std::string::size_type split = disas.find('\t'); // I wish I could disassemble just the mnemonic! if (split == std::string::npos) diff --git a/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp b/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp index 1f5de76ff04b..ae1e036d6d70 100644 --- a/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/CodeViewWidget.cpp @@ -228,7 +228,7 @@ void CodeViewWidget::FontBasedSizing() // Similarly, the longest parameter set is 'rtoc, rtoc, r10, 10, 10 (00000800)' (0x5c425294u), // but one is unlikely to encounter that in practice, so let's use a slightly more reasonable // 'r31, r31, 16, 16, 31 (ffff0000)'. The user can resize the columns as necessary anyway. - const std::string disas = Common::GekkoDisassembler::Disassemble(0x57ff843fu, 0); + const std::string disas = Common::GekkoDisassembler::Disassemble(0x57ff843fu, 0, false); const auto split = disas.find('\t'); const std::string ins = (split == std::string::npos ? disas : disas.substr(0, split)); const std::string param = (split == std::string::npos ? "" : disas.substr(split + 1)); @@ -1030,7 +1030,12 @@ void CodeViewWidget::DoPatchInstruction(bool assemble) if (assemble) { - AssembleInstructionDialog dialog(this, addr, debug_interface.ReadInstruction(guard, addr)); + std::string code_line = + m_system.GetPowerPC().GetDebugInterface().Disassemble(&guard, addr, true); + std::ranges::replace(code_line, '\t', ' '); + + AssembleInstructionDialog dialog(this, addr, debug_interface.ReadInstruction(guard, addr), + QString::fromStdString(code_line)); SetQWidgetWindowDecorations(&dialog); if (dialog.exec() == QDialog::Accepted) { diff --git a/Source/Core/DolphinQt/Debugger/GekkoSyntaxHighlight.cpp b/Source/Core/DolphinQt/Debugger/GekkoSyntaxHighlight.cpp index d29bf100db3e..80b01d18db05 100644 --- a/Source/Core/DolphinQt/Debugger/GekkoSyntaxHighlight.cpp +++ b/Source/Core/DolphinQt/Debugger/GekkoSyntaxHighlight.cpp @@ -55,6 +55,10 @@ class HighlightParsePlugin : public ParsePlugin HighlightCurToken(HighlightFormat::FPR); break; + case Terminal::GQR: + HighlightCurToken(HighlightFormat::GQR); + break; + case Terminal::SPR: HighlightCurToken(HighlightFormat::SPR); break; @@ -221,6 +225,7 @@ void GekkoSyntaxHighlight::HighlightSubstr(int start, int len, HighlightFormat f break; case HighlightFormat::GPR: case HighlightFormat::FPR: + case HighlightFormat::GQR: case HighlightFormat::SPR: case HighlightFormat::CRField: case HighlightFormat::CRFlag: diff --git a/Source/Core/DolphinQt/Debugger/GekkoSyntaxHighlight.h b/Source/Core/DolphinQt/Debugger/GekkoSyntaxHighlight.h index 777f3c45ff35..c5c9a2435fc8 100644 --- a/Source/Core/DolphinQt/Debugger/GekkoSyntaxHighlight.h +++ b/Source/Core/DolphinQt/Debugger/GekkoSyntaxHighlight.h @@ -18,6 +18,7 @@ enum class HighlightFormat Immediate, GPR, FPR, + GQR, SPR, CRField, CRFlag, diff --git a/Source/Core/DolphinQt/Debugger/JITWidget.cpp b/Source/Core/DolphinQt/Debugger/JITWidget.cpp index 39580e5030d1..d58593724ae8 100644 --- a/Source/Core/DolphinQt/Debugger/JITWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/JITWidget.cpp @@ -213,7 +213,7 @@ static void DisassembleCodeBuffer(const JitBlock& block, PPCSymbolDB& ppc_symbol next_address = address; } fmt::print(stream, "0x{:08x}\t{}\n", address, - Common::GekkoDisassembler::Disassemble(inst.hex, address)); + Common::GekkoDisassembler::Disassemble(inst.hex, address, false)); next_address += sizeof(UGeckoInstruction); } } diff --git a/Source/Core/DolphinQt/Debugger/PatchInstructionDialog.cpp b/Source/Core/DolphinQt/Debugger/PatchInstructionDialog.cpp index 9a562863d64b..03949bcdc8e2 100644 --- a/Source/Core/DolphinQt/Debugger/PatchInstructionDialog.cpp +++ b/Source/Core/DolphinQt/Debugger/PatchInstructionDialog.cpp @@ -55,9 +55,9 @@ void PatchInstructionDialog::OnEditChanged() m_button_box->button(QDialogButtonBox::Ok)->setEnabled(good); - m_preview_label->setText( - tr("Instruction: %1") - .arg(QString::fromStdString(Common::GekkoDisassembler::Disassemble(m_code, m_address)))); + m_preview_label->setText(tr("Instruction: %1") + .arg(QString::fromStdString(Common::GekkoDisassembler::Disassemble( + m_code, m_address, false)))); } u32 PatchInstructionDialog::GetCode() const