From ff4cd66bdb7cf4e71f032dfed2b8193ca52df0d9 Mon Sep 17 00:00:00 2001 From: SimoZ64 Date: Tue, 29 Jul 2025 22:46:34 +0200 Subject: [PATCH] Things to neat up that I noticed with Hazel <3 --- src/backend/Core.cpp | 5 +++ src/backend/Core.hpp | 1 + src/backend/core/BaseCPU.hpp | 1 - src/backend/core/Disassembler.cpp | 45 ++++++++++++++----- src/backend/core/Disassembler.hpp | 19 ++++---- src/backend/core/Interpreter.cpp | 8 ---- src/backend/core/Interpreter.hpp | 2 - src/backend/core/JIT.cpp | 32 ++++++++----- src/backend/core/JIT.hpp | 3 -- src/backend/core/Mem.cpp | 3 +- .../core/interpreter/cop0instructions.cpp | 2 +- src/frontend/Debugger.cpp | 44 +++++++++++------- src/frontend/EmuThread.cpp | 8 +--- src/frontend/EmuThread.hpp | 3 +- 14 files changed, 104 insertions(+), 72 deletions(-) diff --git a/src/backend/Core.cpp b/src/backend/Core.cpp index 346027bb..e9368fdd 100644 --- a/src/backend/Core.cpp +++ b/src/backend/Core.cpp @@ -22,7 +22,12 @@ Core::Core() { void Core::Stop() { pause = true; romLoaded = false; + Reset(); +} + +void Core::Reset() { cpu->Reset(); + cpu->GetMem().mmio.si.pif.Execute(); } bool Core::LoadTAS(const fs::path &path) const { return cpu->GetMem().mmio.si.pif.movie.Load(path); } diff --git a/src/backend/Core.hpp b/src/backend/Core.hpp index ab88f865..f7a48c75 100644 --- a/src/backend/Core.hpp +++ b/src/backend/Core.hpp @@ -20,6 +20,7 @@ struct Core { } void Stop(); + void Reset(); void LoadROM(const std::string &); [[nodiscard]] bool LoadTAS(const fs::path &) const; void Run(float volumeL, float volumeR); diff --git a/src/backend/core/BaseCPU.hpp b/src/backend/core/BaseCPU.hpp index 62181a4d..a2607c19 100644 --- a/src/backend/core/BaseCPU.hpp +++ b/src/backend/core/BaseCPU.hpp @@ -10,6 +10,5 @@ struct BaseCPU { virtual void Reset() = 0; virtual Mem &GetMem() = 0; virtual Registers &GetRegs() = 0; - [[nodiscard]] virtual Disassembler::DisassemblyResult Disassemble(u32) = 0; }; } // namespace n64 diff --git a/src/backend/core/Disassembler.cpp b/src/backend/core/Disassembler.cpp index 082b8c16..2e284eed 100644 --- a/src/backend/core/Disassembler.cpp +++ b/src/backend/core/Disassembler.cpp @@ -1,8 +1,9 @@ #include +#include Disassembler::DisassemblyResult Disassembler::DisassembleSimple(const u32 address, const u32 instruction) const { cs_insn *insn; - const auto bytes = Util::IntegralToBuffer(instruction); + const auto bytes = Util::IntegralToBuffer(std::byteswap(instruction)); const auto count = cs_disasm(handle, bytes.data(), bytes.size(), address, 0, &insn); if (count <= 0) @@ -15,9 +16,21 @@ Disassembler::DisassemblyResult Disassembler::DisassembleSimple(const u32 addres return result; } +[[nodiscard]] Disassembler::DisassemblyResult Disassembler::Disassemble(const u32 address) const { + n64::Core& core = n64::Core::GetInstance(); + n64::Mem& mem = core.cpu->GetMem(); + u32 paddr; + if(!core.cpu->GetRegs().cop0.MapVAddr(n64::Cop0::TLBAccessType::LOAD, address, paddr)) + return DisassemblyResult{false, ""}; + + u32 instruction = mem.Read(paddr); + + return details ? DisassembleDetailed(address, instruction) : DisassembleSimple(address, instruction); +} + Disassembler::DisassemblyResult Disassembler::DisassembleDetailed(const u32 address, const u32 instruction) const { cs_insn *insn; - const auto bytes = Util::IntegralToBuffer(instruction); + const auto bytes = Util::IntegralToBuffer(std::byteswap(instruction)); const auto count = cs_disasm(handle, bytes.data(), bytes.size(), address, 0, &insn); if (count <= 0) @@ -29,29 +42,41 @@ Disassembler::DisassemblyResult Disassembler::DisassembleDetailed(const u32 addr result.full += std::format("0x{:016X}", result.address) + ":\t"; result.full += result.mnemonic + "\t"; + result.comment = "// "; const cs_detail *details = insn[0].detail; auto formatOperand = [&](const cs_mips_op &operand) { switch (operand.type) { case MIPS_OP_IMM: - return std::format("#{:X}", operand.is_unsigned ? operand.uimm : operand.imm); + return DisassemblyResult::Operand{ + 0xffcbf1ae, + std::format("#{:X}", operand.is_unsigned ? operand.uimm : operand.imm) + }; case MIPS_OP_MEM: - return std::format("{}(0x{:X})", cs_reg_name(handle, operand.mem.base), operand.mem.disp); + return DisassemblyResult::Operand{ + 0xffaef1c3, + std::format("{}(0x{:X})", cs_reg_name(handle, operand.mem.base), operand.mem.disp) + }; case MIPS_OP_REG: - return std::format("{}", cs_reg_name(handle, operand.reg)); + return DisassemblyResult::Operand{ + 0xffaef1eb, + std::format("{}", cs_reg_name(handle, operand.reg)) + }; default: - return std::string{""}; + return DisassemblyResult::Operand { 0xff808080, "" }; } }; + auto formatComment = [&](const cs_mips_op &operand) { + return ""; + }; + for (u8 i = 0; i < details->mips.op_count && i < 3; i++) { result.ops[i] = formatOperand(details->mips.operands[i]); - result.full += result.ops[i] + "\t"; + result.full += result.ops[i].str + "\t"; } - result.full += "\t// "; - - // TODO: generate a comment + result.full += result.comment; cs_free(insn, count); diff --git a/src/backend/core/Disassembler.hpp b/src/backend/core/Disassembler.hpp index 85f84c63..74e4acad 100644 --- a/src/backend/core/Disassembler.hpp +++ b/src/backend/core/Disassembler.hpp @@ -10,24 +10,25 @@ struct Disassembler { std::string full; u64 address; std::string mnemonic; - std::array ops{}; + struct Operand { + u32 color; + std::string str; + }; + std::array ops{}; + std::string comment; }; + ~Disassembler() { cs_close(&handle); } + static Disassembler &GetInstance(bool rsp = false) { static Disassembler ret(rsp); return ret; } - [[nodiscard]] DisassemblyResult Disassemble(const u32 address, const u32 instruction) const { - return details ? DisassembleDetailed(address, instruction) : DisassembleSimple(address, instruction); - } - - ~Disassembler() { cs_close(&handle); } - -private: + [[nodiscard]] DisassemblyResult Disassemble(const u32 address) const; [[nodiscard]] DisassemblyResult DisassembleDetailed(u32 address, u32 instruction) const; [[nodiscard]] DisassemblyResult DisassembleSimple(u32 address, u32 instruction) const; - +private: explicit Disassembler(const bool rsp) : rsp(rsp) { if (cs_open(CS_ARCH_MIPS, static_cast((rsp ? CS_MODE_32 : CS_MODE_64) | CS_MODE_BIG_ENDIAN), &handle) != CS_ERR_OK) { diff --git a/src/backend/core/Interpreter.cpp b/src/backend/core/Interpreter.cpp index 92cc8586..5cf28d0d 100644 --- a/src/backend/core/Interpreter.cpp +++ b/src/backend/core/Interpreter.cpp @@ -21,14 +21,6 @@ void Interpreter::CheckCompareInterrupt() { } } -Disassembler::DisassemblyResult Interpreter::Disassemble(const u32 address) { - u32 paddr; - if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { - return {}; - } - return Disassembler::GetInstance().Disassemble(address, mem.Read(paddr)); -} - int Interpreter::Step() { CheckCompareInterrupt(); diff --git a/src/backend/core/Interpreter.hpp b/src/backend/core/Interpreter.hpp index 243a2d7e..1673b73a 100644 --- a/src/backend/core/Interpreter.hpp +++ b/src/backend/core/Interpreter.hpp @@ -20,8 +20,6 @@ struct Interpreter : BaseCPU { Mem &GetMem() override { return mem; } Registers &GetRegs() override { return regs; } - [[nodiscard]] Disassembler::DisassemblyResult Disassemble(u32) override; - private: Registers regs; Mem mem; diff --git a/src/backend/core/JIT.cpp b/src/backend/core/JIT.cpp index c969a5e1..a2be902b 100644 --- a/src/backend/core/JIT.cpp +++ b/src/backend/core/JIT.cpp @@ -107,8 +107,26 @@ int JIT::Step() { trace("\tMIPS code (guest PC = 0x{:016X}):", blockPC); while (!instrEndsBlock) { // CheckCompareInterrupt(); + paddr = 0; - instruction = FetchInstruction(); + if (check_address_error(0b11, u64(blockPC))) [[unlikely]] { + /*regs.cop0.HandleTLBException(blockPC); + regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, blockPC); + return 1;*/ + + panic("[JIT]: Unhandled exception ADL due to unaligned PC virtual value! (0x{:016X})", blockPC); + } + + if (!regs.cop0.MapVAddr(Cop0::LOAD, blockPC, paddr)) { + /*regs.cop0.HandleTLBException(blockPC); + regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, blockPC); + return 1;*/ + panic( + "[JIT]: Unhandled exception TLB exception {} when retrieving PC physical address! (virtual: 0x{:016X})", + static_cast(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD)), static_cast(blockPC)); + } + + instruction = mem.Read(paddr); instructionsInBlock++; blockOldPC = blockPC; @@ -118,17 +136,9 @@ int JIT::Step() { if((instrEndsBlock = InstrEndsBlock(instruction))) continue; - /*u32 bswapped = std::byteswap(instruction); - auto count = cs_disasm(disassemblerMips, reinterpret_cast(&bswapped), 4, blockPC, 0, &insn); + trace("{}", Disassembler::GetInstance().DisassembleSimple(paddr, instruction).full); - if (count > 0) { - trace("\t\t0x{:016X}:\t{}\t\t{}\n", insn->address, insn->mnemonic, insn->op_str); - cs_free(insn, count); - } else { - trace("\t\tCould not disassemble 0x{:08X} due to error {}\n", instruction, (int)cs_errno(disassemblerMips)); - } - - if(ShouldServiceInterrupt()) { + /*if(ShouldServiceInterrupt()) { regs.cop0.FireException(ExceptionCode::Interrupt, 0, blockPC); return 1; }*/ diff --git a/src/backend/core/JIT.hpp b/src/backend/core/JIT.hpp index e317cc6b..1c991266 100644 --- a/src/backend/core/JIT.hpp +++ b/src/backend/core/JIT.hpp @@ -39,9 +39,6 @@ struct JIT : BaseCPU { Mem &GetMem() override { return mem; } Registers &GetRegs() override { return regs; } - - [[nodiscard]] Disassembler::DisassemblyResult Disassemble(u32) override { return {}; } - private: Xbyak::CodeGenerator code{kCodeCacheAllocSize}; Registers regs; diff --git a/src/backend/core/Mem.cpp b/src/backend/core/Mem.cpp index 05692b8a..7b9b8fc7 100644 --- a/src/backend/core/Mem.cpp +++ b/src/backend/core/Mem.cpp @@ -13,7 +13,6 @@ Mem::Mem(JIT *jit) : flash(saveData), jit(jit) { } void Mem::Reset() { - std::ranges::fill(rom.cart, 0); std::ranges::fill(isviewer, 0); flash.Reset(); if (saveData.is_mapped()) { @@ -454,7 +453,7 @@ void Mem::Write(const u32 paddr, const u32 val) { } #ifndef __aarch64__ -void Mem::WriteJIT(const const u32 paddr, const u64 val) { +void Mem::WriteJIT(const u32 paddr, const u64 val) { WriteInterpreter(paddr, val); if (jit) jit->InvalidateBlock(paddr); diff --git a/src/backend/core/interpreter/cop0instructions.cpp b/src/backend/core/interpreter/cop0instructions.cpp index 482b8e3b..0708d020 100644 --- a/src/backend/core/interpreter/cop0instructions.cpp +++ b/src/backend/core/interpreter/cop0instructions.cpp @@ -76,7 +76,7 @@ void Cop0::tlbw(const int index_) { void Cop0::tlbp() { int match = -1; - if (const TLBEntry *entry = TLBTryMatch(entryHi.raw, match); entry && match >= 0) { + if (const TLBEntry *entry = TLBTryMatch(entryHi.raw, match); match >= 0) { index.raw = match; } else { index.raw = 0; diff --git a/src/frontend/Debugger.cpp b/src/frontend/Debugger.cpp index 58e793e7..3f055482 100644 --- a/src/frontend/Debugger.cpp +++ b/src/frontend/Debugger.cpp @@ -14,28 +14,17 @@ bool Debugger::render() { ImGui::SameLine(); ImGui::Checkbox("Follow program counter:", &followPC); if(followPC) - startAddr = core.cpu->GetRegs().oldPC - 64; // TODO: arbitrary??? + startAddr = core.cpu->GetRegs().pc - 128; // TODO: arbitrary??? if(ImGui::BeginTable("Disassembly", 3, ImGuiTableFlags_RowBg)) { ImGui::TableSetupColumn("Address"); - ImGui::TableSetupColumn("Mnemonic"); + ImGui::TableSetupColumn("Instruction"); ImGui::TableSetupColumn("Comment"); ImGui::TableHeadersRow(); for(u64 addr = startAddr; addr < startAddr + MAX_LINES_OF_DISASM * sizeof(u32); addr += sizeof(u32)) { - auto disasm = core.cpu->Disassemble(addr); - std::string op_str; - for(int i = 0; i < 3; i++) { - if(i < 2) { - if(!disasm.ops[i].empty()) { - op_str += disasm.ops[i]; - if(!disasm.ops[i+1].empty()) op_str += ", "; - } - } else { - if(!disasm.ops[i].empty()) op_str += disasm.ops[i]; - } - } - auto isPc = addr == core.cpu->GetRegs().oldPC; + auto disasm = Disassembler::GetInstance().Disassemble(addr); + auto isPc = addr == core.cpu->GetRegs().pc; if(isPc) { ImGui::PushStyleColor(ImGuiCol_TableRowBg, 0x809a9ade); ImGui::PushStyleColor(ImGuiCol_TableRowBgAlt, 0x807777bf); @@ -45,9 +34,25 @@ bool Debugger::render() { ImGui::TableSetColumnIndex(0); ImGui::TextColored(ImColor(0xffeaefb6), "%s", std::format("{:016X}:", disasm.address).c_str()); ImGui::TableSetColumnIndex(1); - ImGui::TextColored(ImColor(0xffcbf1ae), "%s", std::format("{} {}", disasm.mnemonic, op_str).c_str()); + ImGui::TextColored(ImColor(0xffcbf1ae), "%s", std::format("{} ", disasm.mnemonic).c_str()); + ImGui::SameLine(0, 0); + for(int i = 0; i < 3; i++) { + if(i < 2) { + if(!disasm.ops[i].str.empty()) { + std::string op_str = disasm.ops[i].str; + if(!disasm.ops[i+1].str.empty()) op_str += ", "; + ImGui::TextColored(ImColor(disasm.ops[i].color), "%s", op_str.c_str()); + ImGui::SameLine(0, 0); + } + } else { + if(!disasm.ops[i].str.empty()) { + ImGui::TextColored(ImColor(disasm.ops[i].color), "%s", disasm.ops[i].str.c_str()); + ImGui::SameLine(0, 0); + } + } + } ImGui::TableSetColumnIndex(2); - ImGui::TextColored(ImColor(0xff71efe5), "%s", std::format("{}", "// no comments for now!").c_str()); + ImGui::TextColored(ImColor(0xff71efe5), "%s", std::format("{}", disasm.comment).c_str()); } else { ImGui::TableSetColumnIndex(0); ImGui::TextColored(ImColor(0xffeaefb6), "????????????????"); @@ -61,6 +66,11 @@ bool Debugger::render() { ImGui::PopStyleColor(); } } + + if(ImGui::TableGetHoveredColumn() == 2) { + // do the thing with the little fucking hover popup that shows the memory view + } + ImGui::EndTable(); } ImGui::End(); diff --git a/src/frontend/EmuThread.cpp b/src/frontend/EmuThread.cpp index 6a73c51e..0a83ce74 100644 --- a/src/frontend/EmuThread.cpp +++ b/src/frontend/EmuThread.cpp @@ -2,9 +2,7 @@ #include #include -EmuThread::EmuThread(double &fps, RenderWidget &renderWidget, - SettingsWindow &settings) noexcept : - renderWidget(renderWidget), settings(settings), fps(fps) {} +EmuThread::EmuThread(double &fps, SettingsWindow &settings) noexcept : settings(settings), fps(fps) {} void EmuThread::run() const noexcept { n64::Core& core = n64::Core::GetInstance(); @@ -45,9 +43,7 @@ void EmuThread::TogglePause() const noexcept { } void EmuThread::Reset() const noexcept { - n64::Core& core = n64::Core::GetInstance(); - core.Stop(); - core.LoadROM(core.rom); + n64::Core::GetInstance().Reset(); } void EmuThread::Stop() const noexcept { diff --git a/src/frontend/EmuThread.hpp b/src/frontend/EmuThread.hpp index 0829e380..6172867a 100644 --- a/src/frontend/EmuThread.hpp +++ b/src/frontend/EmuThread.hpp @@ -8,10 +8,9 @@ struct Core; } class EmuThread final { - RenderWidget &renderWidget; bool started = false; public: - explicit EmuThread(double &, RenderWidget &, SettingsWindow &) noexcept; + explicit EmuThread(double &, SettingsWindow &) noexcept; ~EmuThread() = default; void run() const noexcept; void TogglePause() const noexcept;