Things to neat up that I noticed with Hazel <3

This commit is contained in:
SimoZ64
2025-07-29 22:46:34 +02:00
parent 01d05ca8fd
commit ff4cd66bdb
14 changed files with 104 additions and 72 deletions

View File

@@ -22,7 +22,12 @@ Core::Core() {
void Core::Stop() { void Core::Stop() {
pause = true; pause = true;
romLoaded = false; romLoaded = false;
Reset();
}
void Core::Reset() {
cpu->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); } bool Core::LoadTAS(const fs::path &path) const { return cpu->GetMem().mmio.si.pif.movie.Load(path); }

View File

@@ -20,6 +20,7 @@ struct Core {
} }
void Stop(); void Stop();
void Reset();
void LoadROM(const std::string &); void LoadROM(const std::string &);
[[nodiscard]] bool LoadTAS(const fs::path &) const; [[nodiscard]] bool LoadTAS(const fs::path &) const;
void Run(float volumeL, float volumeR); void Run(float volumeL, float volumeR);

View File

@@ -10,6 +10,5 @@ struct BaseCPU {
virtual void Reset() = 0; virtual void Reset() = 0;
virtual Mem &GetMem() = 0; virtual Mem &GetMem() = 0;
virtual Registers &GetRegs() = 0; virtual Registers &GetRegs() = 0;
[[nodiscard]] virtual Disassembler::DisassemblyResult Disassemble(u32) = 0;
}; };
} // namespace n64 } // namespace n64

View File

@@ -1,8 +1,9 @@
#include <Disassembler.hpp> #include <Disassembler.hpp>
#include <Core.hpp>
Disassembler::DisassemblyResult Disassembler::DisassembleSimple(const u32 address, const u32 instruction) const { Disassembler::DisassemblyResult Disassembler::DisassembleSimple(const u32 address, const u32 instruction) const {
cs_insn *insn; 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); const auto count = cs_disasm(handle, bytes.data(), bytes.size(), address, 0, &insn);
if (count <= 0) if (count <= 0)
@@ -15,9 +16,21 @@ Disassembler::DisassemblyResult Disassembler::DisassembleSimple(const u32 addres
return result; 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<u32>(paddr);
return details ? DisassembleDetailed(address, instruction) : DisassembleSimple(address, instruction);
}
Disassembler::DisassemblyResult Disassembler::DisassembleDetailed(const u32 address, const u32 instruction) const { Disassembler::DisassemblyResult Disassembler::DisassembleDetailed(const u32 address, const u32 instruction) const {
cs_insn *insn; 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); const auto count = cs_disasm(handle, bytes.data(), bytes.size(), address, 0, &insn);
if (count <= 0) 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 += std::format("0x{:016X}", result.address) + ":\t";
result.full += result.mnemonic + "\t"; result.full += result.mnemonic + "\t";
result.comment = "// ";
const cs_detail *details = insn[0].detail; const cs_detail *details = insn[0].detail;
auto formatOperand = [&](const cs_mips_op &operand) { auto formatOperand = [&](const cs_mips_op &operand) {
switch (operand.type) { switch (operand.type) {
case MIPS_OP_IMM: 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: 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: 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: 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++) { for (u8 i = 0; i < details->mips.op_count && i < 3; i++) {
result.ops[i] = formatOperand(details->mips.operands[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// "; result.full += result.comment;
// TODO: generate a comment
cs_free(insn, count); cs_free(insn, count);

View File

@@ -10,24 +10,25 @@ struct Disassembler {
std::string full; std::string full;
u64 address; u64 address;
std::string mnemonic; std::string mnemonic;
std::array<std::string, 3> ops{}; struct Operand {
u32 color;
std::string str;
};
std::array<Operand, 3> ops{};
std::string comment;
}; };
~Disassembler() { cs_close(&handle); }
static Disassembler &GetInstance(bool rsp = false) { static Disassembler &GetInstance(bool rsp = false) {
static Disassembler ret(rsp); static Disassembler ret(rsp);
return ret; return ret;
} }
[[nodiscard]] DisassemblyResult Disassemble(const u32 address, const u32 instruction) const { [[nodiscard]] DisassemblyResult Disassemble(const u32 address) const;
return details ? DisassembleDetailed(address, instruction) : DisassembleSimple(address, instruction);
}
~Disassembler() { cs_close(&handle); }
private:
[[nodiscard]] DisassemblyResult DisassembleDetailed(u32 address, u32 instruction) const; [[nodiscard]] DisassemblyResult DisassembleDetailed(u32 address, u32 instruction) const;
[[nodiscard]] DisassemblyResult DisassembleSimple(u32 address, u32 instruction) const; [[nodiscard]] DisassemblyResult DisassembleSimple(u32 address, u32 instruction) const;
private:
explicit Disassembler(const bool rsp) : rsp(rsp) { explicit Disassembler(const bool rsp) : rsp(rsp) {
if (cs_open(CS_ARCH_MIPS, static_cast<cs_mode>((rsp ? CS_MODE_32 : CS_MODE_64) | CS_MODE_BIG_ENDIAN), &handle) != if (cs_open(CS_ARCH_MIPS, static_cast<cs_mode>((rsp ? CS_MODE_32 : CS_MODE_64) | CS_MODE_BIG_ENDIAN), &handle) !=
CS_ERR_OK) { CS_ERR_OK) {

View File

@@ -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<u32>(paddr));
}
int Interpreter::Step() { int Interpreter::Step() {
CheckCompareInterrupt(); CheckCompareInterrupt();

View File

@@ -20,8 +20,6 @@ struct Interpreter : BaseCPU {
Mem &GetMem() override { return mem; } Mem &GetMem() override { return mem; }
Registers &GetRegs() override { return regs; } Registers &GetRegs() override { return regs; }
[[nodiscard]] Disassembler::DisassemblyResult Disassemble(u32) override;
private: private:
Registers regs; Registers regs;
Mem mem; Mem mem;

View File

@@ -107,8 +107,26 @@ int JIT::Step() {
trace("\tMIPS code (guest PC = 0x{:016X}):", blockPC); trace("\tMIPS code (guest PC = 0x{:016X}):", blockPC);
while (!instrEndsBlock) { while (!instrEndsBlock) {
// CheckCompareInterrupt(); // 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<int>(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD)), static_cast<u64>(blockPC));
}
instruction = mem.Read<u32>(paddr);
instructionsInBlock++; instructionsInBlock++;
blockOldPC = blockPC; blockOldPC = blockPC;
@@ -118,17 +136,9 @@ int JIT::Step() {
if((instrEndsBlock = InstrEndsBlock(instruction))) if((instrEndsBlock = InstrEndsBlock(instruction)))
continue; continue;
/*u32 bswapped = std::byteswap(instruction); trace("{}", Disassembler::GetInstance().DisassembleSimple(paddr, instruction).full);
auto count = cs_disasm(disassemblerMips, reinterpret_cast<const u8 *>(&bswapped), 4, blockPC, 0, &insn);
if (count > 0) { /*if(ShouldServiceInterrupt()) {
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()) {
regs.cop0.FireException(ExceptionCode::Interrupt, 0, blockPC); regs.cop0.FireException(ExceptionCode::Interrupt, 0, blockPC);
return 1; return 1;
}*/ }*/

View File

@@ -39,9 +39,6 @@ struct JIT : BaseCPU {
Mem &GetMem() override { return mem; } Mem &GetMem() override { return mem; }
Registers &GetRegs() override { return regs; } Registers &GetRegs() override { return regs; }
[[nodiscard]] Disassembler::DisassemblyResult Disassemble(u32) override { return {}; }
private: private:
Xbyak::CodeGenerator code{kCodeCacheAllocSize}; Xbyak::CodeGenerator code{kCodeCacheAllocSize};
Registers regs; Registers regs;

View File

@@ -13,7 +13,6 @@ Mem::Mem(JIT *jit) : flash(saveData), jit(jit) {
} }
void Mem::Reset() { void Mem::Reset() {
std::ranges::fill(rom.cart, 0);
std::ranges::fill(isviewer, 0); std::ranges::fill(isviewer, 0);
flash.Reset(); flash.Reset();
if (saveData.is_mapped()) { if (saveData.is_mapped()) {
@@ -454,7 +453,7 @@ void Mem::Write<u32>(const u32 paddr, const u32 val) {
} }
#ifndef __aarch64__ #ifndef __aarch64__
void Mem::WriteJIT(const const u32 paddr, const u64 val) { void Mem::WriteJIT(const u32 paddr, const u64 val) {
WriteInterpreter(paddr, val); WriteInterpreter(paddr, val);
if (jit) if (jit)
jit->InvalidateBlock(paddr); jit->InvalidateBlock(paddr);

View File

@@ -76,7 +76,7 @@ void Cop0::tlbw(const int index_) {
void Cop0::tlbp() { void Cop0::tlbp() {
int match = -1; 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; index.raw = match;
} else { } else {
index.raw = 0; index.raw = 0;

View File

@@ -14,28 +14,17 @@ bool Debugger::render() {
ImGui::SameLine(); ImGui::SameLine();
ImGui::Checkbox("Follow program counter:", &followPC); ImGui::Checkbox("Follow program counter:", &followPC);
if(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)) { if(ImGui::BeginTable("Disassembly", 3, ImGuiTableFlags_RowBg)) {
ImGui::TableSetupColumn("Address"); ImGui::TableSetupColumn("Address");
ImGui::TableSetupColumn("Mnemonic"); ImGui::TableSetupColumn("Instruction");
ImGui::TableSetupColumn("Comment"); ImGui::TableSetupColumn("Comment");
ImGui::TableHeadersRow(); ImGui::TableHeadersRow();
for(u64 addr = startAddr; addr < startAddr + MAX_LINES_OF_DISASM * sizeof(u32); addr += sizeof(u32)) { for(u64 addr = startAddr; addr < startAddr + MAX_LINES_OF_DISASM * sizeof(u32); addr += sizeof(u32)) {
auto disasm = core.cpu->Disassemble(addr); auto disasm = Disassembler::GetInstance().Disassemble(addr);
std::string op_str; auto isPc = addr == core.cpu->GetRegs().pc;
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;
if(isPc) { if(isPc) {
ImGui::PushStyleColor(ImGuiCol_TableRowBg, 0x809a9ade); ImGui::PushStyleColor(ImGuiCol_TableRowBg, 0x809a9ade);
ImGui::PushStyleColor(ImGuiCol_TableRowBgAlt, 0x807777bf); ImGui::PushStyleColor(ImGuiCol_TableRowBgAlt, 0x807777bf);
@@ -45,9 +34,25 @@ bool Debugger::render() {
ImGui::TableSetColumnIndex(0); ImGui::TableSetColumnIndex(0);
ImGui::TextColored(ImColor(0xffeaefb6), "%s", std::format("{:016X}:", disasm.address).c_str()); ImGui::TextColored(ImColor(0xffeaefb6), "%s", std::format("{:016X}:", disasm.address).c_str());
ImGui::TableSetColumnIndex(1); 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::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 { } else {
ImGui::TableSetColumnIndex(0); ImGui::TableSetColumnIndex(0);
ImGui::TextColored(ImColor(0xffeaefb6), "????????????????"); ImGui::TextColored(ImColor(0xffeaefb6), "????????????????");
@@ -61,6 +66,11 @@ bool Debugger::render() {
ImGui::PopStyleColor(); ImGui::PopStyleColor();
} }
} }
if(ImGui::TableGetHoveredColumn() == 2) {
// do the thing with the little fucking hover popup that shows the memory view
}
ImGui::EndTable(); ImGui::EndTable();
} }
ImGui::End(); ImGui::End();

View File

@@ -2,9 +2,7 @@
#include <EmuThread.hpp> #include <EmuThread.hpp>
#include <KaizenGui.hpp> #include <KaizenGui.hpp>
EmuThread::EmuThread(double &fps, RenderWidget &renderWidget, EmuThread::EmuThread(double &fps, SettingsWindow &settings) noexcept : settings(settings), fps(fps) {}
SettingsWindow &settings) noexcept :
renderWidget(renderWidget), settings(settings), fps(fps) {}
void EmuThread::run() const noexcept { void EmuThread::run() const noexcept {
n64::Core& core = n64::Core::GetInstance(); n64::Core& core = n64::Core::GetInstance();
@@ -45,9 +43,7 @@ void EmuThread::TogglePause() const noexcept {
} }
void EmuThread::Reset() const noexcept { void EmuThread::Reset() const noexcept {
n64::Core& core = n64::Core::GetInstance(); n64::Core::GetInstance().Reset();
core.Stop();
core.LoadROM(core.rom);
} }
void EmuThread::Stop() const noexcept { void EmuThread::Stop() const noexcept {

View File

@@ -8,10 +8,9 @@ struct Core;
} }
class EmuThread final { class EmuThread final {
RenderWidget &renderWidget;
bool started = false; bool started = false;
public: public:
explicit EmuThread(double &, RenderWidget &, SettingsWindow &) noexcept; explicit EmuThread(double &, SettingsWindow &) noexcept;
~EmuThread() = default; ~EmuThread() = default;
void run() const noexcept; void run() const noexcept;
void TogglePause() const noexcept; void TogglePause() const noexcept;