From 2db12b808312bb2ff61ab0d764467bc795ffc51a Mon Sep 17 00:00:00 2001 From: iris Date: Tue, 7 Apr 2026 15:45:30 +0200 Subject: [PATCH] Rework logs a little bit to allow choosing the log level from settings --- CMakeLists.txt | 32 +- src/backend/Core.cpp | 36 +- src/backend/Netplay.cpp | 2 +- src/backend/RomHelpers.hpp | 6 +- src/backend/Scheduler.cpp | 4 +- src/backend/Scheduler.hpp | 2 +- src/backend/core/BaseCPU.hpp | 1 - src/backend/core/Disassembler.cpp | 77 --- src/backend/core/Disassembler.hpp | 46 -- src/backend/core/JIT.cpp | 18 +- src/backend/core/JIT.hpp | 85 +--- src/backend/core/Mem.cpp | 285 ++++++----- src/backend/core/Mem.hpp | 5 +- src/backend/core/RDP.cpp | 2 +- src/backend/core/RSP.cpp | 2 +- .../core/interpreter/cop0instructions.cpp | 2 +- src/backend/core/interpreter/decode.cpp | 2 +- src/backend/core/mmio/AI.cpp | 2 +- src/backend/core/mmio/Audio.cpp | 2 +- src/backend/core/mmio/MI.cpp | 2 +- src/backend/core/mmio/PI.cpp | 2 +- src/backend/core/mmio/PIF.cpp | 2 +- src/backend/core/mmio/PIF/Device.cpp | 2 +- src/backend/core/mmio/PIF/MupenMovie.cpp | 34 +- src/backend/core/mmio/RI.cpp | 2 +- src/backend/core/mmio/VI.cpp | 12 +- src/backend/core/registers/Cop0.cpp | 2 +- src/backend/core/registers/Cop0.hpp | 2 +- src/backend/core/registers/Cop1.cpp | 2 +- src/backend/core/rsp/decode.cpp | 2 +- src/backend/core/rsp/instructions.cpp | 2 +- src/common.hpp | 1 - src/frontend/Debugger.cpp | 249 ---------- src/frontend/Debugger.hpp | 28 -- src/frontend/ImGuiImpl/GUI.hpp | 2 +- src/frontend/KaizenGui.cpp | 458 +++++++----------- src/frontend/KaizenGui.hpp | 10 +- src/frontend/NativeWindow.hpp | 2 +- src/frontend/Settings/CPUSettings.cpp | 2 +- src/frontend/Settings/GeneralSettings.cpp | 2 +- src/frontend/Settings/MiscSettings.cpp | 34 ++ src/frontend/Settings/MiscSettings.hpp | 11 + src/frontend/SettingsWindow.hpp | 5 +- src/utils/ErrorData.hpp | 149 ------ src/utils/File.hpp | 2 +- src/utils/Options.cpp | 35 ++ src/utils/Options.hpp | 24 +- src/utils/log.hpp | 27 +- 48 files changed, 536 insertions(+), 1182 deletions(-) delete mode 100644 src/backend/core/Disassembler.cpp delete mode 100644 src/backend/core/Disassembler.hpp delete mode 100644 src/frontend/Debugger.cpp delete mode 100644 src/frontend/Debugger.hpp create mode 100644 src/frontend/Settings/MiscSettings.cpp create mode 100644 src/frontend/Settings/MiscSettings.hpp delete mode 100644 src/utils/ErrorData.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f659f5b..6c94ceb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,26 +27,26 @@ endif() find_program(GIT_EXECUTABLE git) if (GIT_EXECUTABLE) - execute_process( + execute_process( COMMAND ${GIT_EXECUTABLE} rev-parse HEAD WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE _git_hash OUTPUT_STRIP_TRAILING_WHITESPACE ) - if (NOT "${KAIZEN_GIT_COMMIT_HASH}" STREQUAL "${_git_hash}") - file(REMOVE ${CMAKE_CURRENT_LIST_DIR}/resources/version.hpp) - set(KAIZEN_GIT_COMMIT_HASH "${_git_hash}" CACHE STRING "" FORCE) - endif() + if (NOT "${KAIZEN_GIT_COMMIT_HASH}" STREQUAL "${_git_hash}") + file(REMOVE ${CMAKE_CURRENT_LIST_DIR}/resources/version.hpp) + set(KAIZEN_GIT_COMMIT_HASH "${_git_hash}" CACHE STRING "" FORCE) + endif() else() - # Otherwise, ensure KAIZEN_GIT_COMMIT_HASH is defined - if (DEFINED KAIZEN_GIT_COMMIT_HASH) - set(_git_hash "${KAIZEN_GIT_COMMIT_HASH}" CACHE STRING "" FORCE) - file(REMOVE ${CMAKE_CURRENT_LIST_DIR}/resources/version.hpp) - message("Git not found, but git commit hash was defined as ${KAIZEN_GIT_COMMIT_HASH}") - else() - message(FATAL_ERROR "Git not found, please define KAIZEN_GIT_COMMIT_HASH manually.") - endif() + # Otherwise, ensure KAIZEN_GIT_COMMIT_HASH is defined + if (DEFINED KAIZEN_GIT_COMMIT_HASH) + set(_git_hash "${KAIZEN_GIT_COMMIT_HASH}" CACHE STRING "" FORCE) + file(REMOVE ${CMAKE_CURRENT_LIST_DIR}/resources/version.hpp) + message("Git not found, but git commit hash was defined as ${KAIZEN_GIT_COMMIT_HASH}") + else() + message(FATAL_ERROR "Git not found, please define KAIZEN_GIT_COMMIT_HASH manually.") + endif() endif() configure_file(${CMAKE_CURRENT_LIST_DIR}/cmake/version.hpp.in ${CMAKE_CURRENT_LIST_DIR}/resources/version.hpp) @@ -167,11 +167,11 @@ add_executable(kaizen src/frontend/Settings/CPUSettings.cpp src/frontend/Settings/AudioSettings.hpp src/frontend/Settings/AudioSettings.cpp + src/frontend/Settings/MiscSettings.hpp + src/frontend/Settings/MiscSettings.cpp src/frontend/NativeWindow.hpp src/utils/Options.cpp - src/utils/File.cpp - src/frontend/Debugger.hpp - src/frontend/Debugger.cpp) + src/utils/File.cpp) if (WIN32) diff --git a/src/backend/Core.cpp b/src/backend/Core.cpp index e3edd5e..793c3f4 100644 --- a/src/backend/Core.cpp +++ b/src/backend/Core.cpp @@ -9,13 +9,13 @@ Core::Core() { if (selectedCpu == "interpreter") { cpuType = Interpreted; cpu = std::make_unique(*mem, regs); - } else if(selectedCpu == "jit") { - #ifndef __aarch64__ + } else if (selectedCpu == "jit") { +#ifndef __aarch64__ cpuType = DynamicRecompiler; cpu = std::make_unique(*mem, regs); - #else +#else panic("JIT currently unsupported on aarch64"); - #endif +#endif } else { panic("Unimplemented CPU type"); } @@ -31,7 +31,7 @@ void Core::Reset() { regs.Reset(); mem->Reset(); cpu->Reset(); - if(romLoaded) + if (romLoaded) mem->mmio.si.pif.Execute(); } @@ -40,12 +40,12 @@ void Core::LoadTAS(const fs::path &path) const { mem->mmio.si.pif.movie.Load(pat void Core::LoadROM(const std::string &rom_) { Stop(); rom = rom_; - + std::string archive_types[] = {".zip", ".7z", ".rar", ".tar"}; - + auto extension = fs::path(rom).extension().string(); const bool isArchive = std::ranges::any_of(archive_types, [&extension](const auto &e) { return e == extension; }); - + mem->LoadROM(isArchive, rom); GameDB::match(); if (mem->rom.gameNameDB.empty()) { @@ -62,9 +62,7 @@ void Core::LoadROM(const std::string &rom_) { romLoaded = true; } -u32 Core::StepCPU() { - return cpu->Step() + regs.PopStalledCycles(); -} +u32 Core::StepCPU() { return cpu->Step() + regs.PopStalledCycles(); } void Core::StepRSP(const u32 cpuCycles) { MMIO &mmio = mem->mmio; @@ -76,7 +74,7 @@ void Core::StepRSP(const u32 cpuCycles) { } static constexpr u32 cpuRatio = 3, rspRatio = 2; - + regs.steps += cpuCycles; const auto sets = regs.steps / cpuRatio; mmio.rsp.steps += sets * rspRatio; @@ -101,27 +99,18 @@ void Core::Run(const float volumeL, const float volumeR) { mmio.mi.InterruptRaise(MI::Interrupt::VI); } - while(cycles < mem->mmio.vi.cyclesPerHalfline) { + while (cycles < mem->mmio.vi.cyclesPerHalfline) { const u32 taken = StepCPU(); cycles += taken; - if((broken = breakpoints.contains(regs.nextPC))) - break; - StepRSP(taken); frameCycles += taken; Scheduler::GetInstance().Tick(taken); } - if(broken) - break; - cycles -= mmio.vi.cyclesPerHalfline; } - if(broken) - break; - if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) { mmio.mi.InterruptRaise(MI::Interrupt::VI); } @@ -129,8 +118,5 @@ void Core::Run(const float volumeL, const float volumeR) { mmio.ai.Step(frameCycles, volumeL, volumeR); Scheduler::GetInstance().Tick(frameCycles); } - - if(broken) - pause = true; } } // namespace n64 diff --git a/src/backend/Netplay.cpp b/src/backend/Netplay.cpp index 9ef2f8d..358b476 100644 --- a/src/backend/Netplay.cpp +++ b/src/backend/Netplay.cpp @@ -1,6 +1,6 @@ #include #include #include -#include +#include namespace Netplay {} diff --git a/src/backend/RomHelpers.hpp b/src/backend/RomHelpers.hpp index b69b9ae..14f3fba 100644 --- a/src/backend/RomHelpers.hpp +++ b/src/backend/RomHelpers.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include +#include namespace Util { #define Z64 0x80371200 @@ -13,7 +13,7 @@ FORCE_INLINE void SwapN64Rom(std::vector &rom, u32 endianness) { if (endianness >> 24 != 0x80) { if ((endianness & 0xFF) != 0x80) { if ((endianness >> 16 & 0xff) != 0x80) { - Error::GetInstance().Throw({Error::Severity::UNRECOVERABLE}, {Error::Type::ROM_LOAD_ERROR}, {}, {}, "Unrecognized rom endianness"); + panic("Unrecognized rom endianness"); return; } else { altByteShift = 12; @@ -42,7 +42,7 @@ FORCE_INLINE void SwapN64Rom(std::vector &rom, u32 endianness) { ircolib::SwapBuffer(rom); break; default: - Error::GetInstance().Throw({Error::Severity::UNRECOVERABLE}, {Error::Type::ROM_LOAD_ERROR}, {}, {}, "Unrecognized rom format! Make sure this is a valid Nintendo 64 ROM dump!"); + panic("Unrecognized rom format! Make sure this is a valid Nintendo 64 ROM dump!"); } } } // namespace Util diff --git a/src/backend/Scheduler.cpp b/src/backend/Scheduler.cpp index d031a0d..42eb0f2 100644 --- a/src/backend/Scheduler.cpp +++ b/src/backend/Scheduler.cpp @@ -40,10 +40,10 @@ void Scheduler::Tick(const u64 t) { case NONE: break; case IMPOSSIBLE: - Util::Error::GetInstance().Throw({Util::Error::Severity::UNRECOVERABLE}, {Util::Error::Type::ROM_LOAD_ERROR}, {}, {}, "Unrecognized rom endianness"); + panic("Scheduler reached end-of-life. How?!"); return; default: - Util::Error::GetInstance().Throw({Util::Error::Severity::UNRECOVERABLE}, {Util::Error::Type::ROM_LOAD_ERROR}, {}, {}, "Unknown scheduler event type {}", static_cast(type)); + panic("Unknown scheduler event type {}", static_cast(type)); return; } events.pop(); diff --git a/src/backend/Scheduler.hpp b/src/backend/Scheduler.hpp index 5a37a52..7121fde 100644 --- a/src/backend/Scheduler.hpp +++ b/src/backend/Scheduler.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include +#include #include enum EventType { NONE, PI_BUS_WRITE_COMPLETE, PI_DMA_COMPLETE, SI_DMA, IMPOSSIBLE }; diff --git a/src/backend/core/BaseCPU.hpp b/src/backend/core/BaseCPU.hpp index 0b4d01c..aa5c370 100644 --- a/src/backend/core/BaseCPU.hpp +++ b/src/backend/core/BaseCPU.hpp @@ -1,7 +1,6 @@ #pragma once #include #include -#include namespace n64 { struct BaseCPU { diff --git a/src/backend/core/Disassembler.cpp b/src/backend/core/Disassembler.cpp deleted file mode 100644 index 5ff5fe8..0000000 --- a/src/backend/core/Disassembler.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include -#include - -Disassembler::DisassemblyResult Disassembler::DisassembleSimple(const u32 address, const u32 instruction) const { - cs_insn *insn; - const auto bytes = ircolib::IntegralToBuffer(std::byteswap(instruction)); - const auto count = cs_disasm(handle, bytes.data(), bytes.size(), address, 0, &insn); - - if (count <= 0) - return {}; - - DisassemblyResult result{true, std::format("0x{:016X}:\t{}\t{}", insn[0].address, insn[0].mnemonic, insn[0].op_str)}; - - cs_free(insn, count); - - return result; -} - -[[nodiscard]] Disassembler::DisassemblyResult Disassembler::Disassemble(const u32 address) const { - u32 paddr; - if(!n64::Core::GetRegs().cop0.MapVAddr(n64::Cop0::TLBAccessType::LOAD, address, paddr)) - return DisassemblyResult{false, ""}; - - u32 instruction = n64::Core::GetMem().Read(paddr); - - return details ? DisassembleDetailed(address, instruction) : DisassembleSimple(address, instruction); -} - -Disassembler::DisassemblyResult Disassembler::DisassembleDetailed(const u32 address, const u32 instruction) const { - n64::Core& core = n64::Core::GetInstance(); - cs_insn *insn; - const auto bytes = ircolib::IntegralToBuffer(std::byteswap(instruction)); - const auto count = cs_disasm(handle, bytes.data(), bytes.size(), address, 0, &insn); - - if (count <= 0) - return {}; - - DisassemblyResult result{true}; - result.address = insn[0].address; - result.mnemonic = insn[0].mnemonic; - - result.full += std::format("0x{:016X}", result.address) + ":\t"; - result.full += result.mnemonic + "\t"; - - const cs_detail *details = insn[0].detail; - auto formatOperand = [&](const cs_mips_op &operand) { - switch (operand.type) { - case MIPS_OP_IMM: - return DisassemblyResult::Operand{ - 0xffcbf1ae, - std::format("#{:X}", operand.is_unsigned ? operand.uimm : operand.imm) - }; - case MIPS_OP_MEM: - return DisassemblyResult::Operand{ - 0xffaef1c3, - std::format("{}(0x{:X})", cs_reg_name(handle, operand.mem.base), operand.mem.disp) - }; - case MIPS_OP_REG: - return DisassemblyResult::Operand{ - 0xffaef1eb, - std::format("{}", cs_reg_name(handle, operand.reg)) - }; - default: - return DisassemblyResult::Operand { 0xff808080, "" }; - } - }; - - 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].str + "\t"; - } - - cs_free(insn, count); - - return result; -} \ No newline at end of file diff --git a/src/backend/core/Disassembler.hpp b/src/backend/core/Disassembler.hpp deleted file mode 100644 index 6f634aa..0000000 --- a/src/backend/core/Disassembler.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once -#include -#include -#include -#include - -struct Disassembler { - struct DisassemblyResult { - bool success = false; - std::string full; - u64 address; - std::string mnemonic; - struct Operand { - u32 color; - std::string str; - }; - std::array ops{}; - }; - - ~Disassembler() { cs_close(&handle); } - - static Disassembler &GetInstance(bool rsp = false) { - static Disassembler ret(rsp); - return ret; - } - - [[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) { - panic("Could not initialize {} disassembler!", rsp ? "RSP" : "CPU"); - } - - if (cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON) != CS_ERR_OK) { - Util::Error::GetInstance().Throw({Util::Error::Severity::WARN}, {Util::Error::Type::CAPSTONE_ERROR}, {}, {}, "Could not enable disassembler's details!"); - details = false; - } - } - - bool rsp = false; - bool details = true; - csh handle{}; -}; diff --git a/src/backend/core/JIT.cpp b/src/backend/core/JIT.cpp index e2b6dff..743e082 100644 --- a/src/backend/core/JIT.cpp +++ b/src/backend/core/JIT.cpp @@ -47,9 +47,7 @@ std::optional JIT::FetchInstruction(s64 vaddr) { /*regs.cop0.HandleTLBException(blockPC); regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, blockPC); return 1;*/ - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_EXCEPTION}, blockPC, {}, - "[JIT]: Unhandled exception ADL due to unaligned PC virtual value!"); + error("[JIT]: Unhandled exception ADL due to unaligned PC virtual value!"); return std::nullopt; } @@ -57,17 +55,13 @@ std::optional JIT::FetchInstruction(s64 vaddr) { /*regs.cop0.HandleTLBException(blockPC); regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, blockPC); return 1;*/ - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_EXCEPTION}, blockPC, {}, - "[JIT]: Unhandled exception TLB exception {} when retrieving PC physical address!", + error("[JIT]: Unhandled exception TLB exception {} when retrieving PC physical address!", static_cast(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD))); return std::nullopt; } const u32 instr = Core::GetMem().Read(paddr); - info("{}", Disassembler::GetInstance().DisassembleSimple(paddr, instr).full); - return instr; } @@ -118,9 +112,7 @@ u32 JIT::Step() { /*regs.cop0.HandleTLBException(blockPC); regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, blockPC); return 1;*/ - Util::Error::GetInstance().Throw({Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_EXCEPTION}, - blockPC, {}, - "[JIT]: Unhandled exception TLB exception {} when retrieving PC physical address!", + error("[JIT]: Unhandled exception TLB exception {} when retrieving PC physical address!", static_cast(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD))); return 0; } @@ -177,9 +169,7 @@ u32 JIT::Step() { return 0; if(InstrEndsBlock(delay_instruction.value())) { - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::JIT_BRANCH_INSIDE_DELAY_SLOT}, - blockPC, {}, "[JIT]: Unhandled case of branch from delay slot!"); + error("[JIT]: Unhandled case of branch from delay slot!"); return 0; } diff --git a/src/backend/core/JIT.hpp b/src/backend/core/JIT.hpp index 2948d01..f04f83d 100644 --- a/src/backend/core/JIT.hpp +++ b/src/backend/core/JIT.hpp @@ -29,7 +29,7 @@ static constexpr u32 kCodeCacheAllocSize = kCodeCacheSize + 4_kb; struct JIT : BaseCPU {}; #else struct JIT final : BaseCPU { - explicit JIT(Mem&, Registers&); + explicit JIT(Mem &, Registers &); ~JIT() override = default; u32 Step() override; @@ -47,14 +47,15 @@ struct JIT final : BaseCPU { } void InvalidateBlock(u32); + private: friend struct Cop1; friend struct Registers; using BlockFn = int (*)(); bool branch_taken; - Registers& regs; - Mem& mem; + Registers ®s; + Mem &mem; u64 cop2Latch{}; s64 blockOldPC = 0, blockPC = 0, blockNextPC = 0; Xbyak::CodeGenerator code{kCodeCacheAllocSize}; @@ -73,9 +74,7 @@ private: return code.qword[code.rbp + GPR_OFFSET(index)]; } - Util::Error::GetInstance().Throw( - {Util::Error::Severity::UNRECOVERABLE}, {Util::Error::Type::JIT_INVALID_X86_REG_ADDRESSING}, - blockPC, {}, "[JIT]: Invalid register addressing mode {}!", sizeof(T)); + panic("[JIT]: Invalid register addressing mode {}!", sizeof(T)); return Xbyak::Address{0}; } @@ -109,8 +108,8 @@ private: void SetPC32(s32 val); void SetPC64(s64 val); - void SetPC32(const Xbyak::Reg32& val); - void SetPC64(const Xbyak::Reg64& val); + void SetPC32(const Xbyak::Reg32 &val); + void SetPC64(const Xbyak::Reg64 &val); void BranchNotTaken(); void BranchTaken(s64 offs); void BranchTaken(const Xbyak::Reg64 &offs); @@ -204,57 +203,17 @@ private: void mthi(Instruction); void mtlo(Instruction); void nor(Instruction); - void sb(const Instruction) { - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION}, - blockPC, {}, "[JIT]: Unhandled 'sb'!"); - } - void sc(const Instruction) { - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION}, - blockPC, {}, "[JIT]: Unhandled 'sc'!"); - } - void scd(const Instruction) { - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION}, - blockPC, {}, "[JIT]: Unhandled 'scd'!"); - } - void sd(const Instruction) { - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION}, - blockPC, {}, "[JIT]: Unhandled 'sd'!"); - } - void sdc1(const Instruction) { - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION}, - blockPC, {}, "[JIT]: Unhandled 'sdc1'!"); - } - void sdl(const Instruction) { - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION}, - blockPC, {}, "[JIT]: Unhandled 'sdl'!"); - } - void sdr(const Instruction) { - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION}, - blockPC, {}, "[JIT]: Unhandled 'sdr'!"); - } - void sh(const Instruction) { - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION}, - blockPC, {}, "[JIT]: Unhandled 'sh'!"); - } + void sb(const Instruction) { panic("[JIT]: Unhandled 'sb' @ blockPC:{:016X}!", blockPC); } + void sc(const Instruction) { panic("[JIT]: Unhandled 'sc' @ blockPC:{:016X}!", blockPC); } + void scd(const Instruction) { panic("[JIT]: Unhandled 'scd' @ blockPC:{:016X}!", blockPC); } + void sd(const Instruction) { panic("[JIT]: Unhandled 'sd' @ blockPC:{:016X}!", blockPC); } + void sdc1(const Instruction) { panic("[JIT]: Unhandled 'sdc1' @ blockPC:{:016X}!", blockPC); } + void sdl(const Instruction) { panic("[JIT]: Unhandled 'sdl' @ blockPC:{:016X}!", blockPC); } + void sdr(const Instruction) { panic("[JIT]: Unhandled 'sdr' @ blockPC:{:016X}!", blockPC); } + void sh(const Instruction) { panic("[JIT]: Unhandled 'sh' @ blockPC:{:016X}!", blockPC); } void sw(Instruction); - void swl(const Instruction) { - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION}, - blockPC, {}, "[JIT]: Unhandled 'swl'!"); - } - void swr(const Instruction) { - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION}, - blockPC, {}, "[JIT]: Unhandled 'swr'!"); - } + void swl(const Instruction) { panic("[JIT]: Unhandled 'swl' @ blockPC:{:016X}!", blockPC); } + void swr(const Instruction) { panic("[JIT]: Unhandled 'swr' @ blockPC:{:016X}!", blockPC); } void slti(Instruction); void sltiu(Instruction); void slt(Instruction); @@ -264,19 +223,13 @@ private: void sub(Instruction); void subu(Instruction); void swc1(const Instruction) { - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::JIT_BRANCH_INSIDE_DELAY_SLOT}, - blockPC, {}, "[JIT]: Unhandled case of branch from delay slot!"); + panic("[JIT]: Unhandled 'swc1' @ blockPC:{:016X}!", blockPC); } void sra(Instruction); void srav(Instruction); void srl(Instruction); void srlv(Instruction); - void trap(bool) { - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::JIT_BRANCH_INSIDE_DELAY_SLOT}, - blockPC, {}, "[JIT]: Unhandled case of branch from delay slot!"); - } + void trap(bool) { panic("[JIT]: Unhandled 'trap' @ blockPC:{:016X}!", blockPC); } void or_(Instruction); void ori(Instruction); void xor_(Instruction); diff --git a/src/backend/core/Mem.cpp b/src/backend/core/Mem.cpp index eadd4a8..b588ab8 100644 --- a/src/backend/core/Mem.cpp +++ b/src/backend/core/Mem.cpp @@ -19,10 +19,7 @@ void Mem::Reset() { std::error_code error; saveData.sync(error); if (error) { - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::COULD_NOT_SYNC_SAVE_DATA}, - {}, {}, "[Mem]: Could not sync save data!"); - return; + warn("[Mem]: Could not sync save data!"); } saveData.unmap(); } @@ -40,10 +37,7 @@ void Mem::LoadSRAM(SaveType save_type, fs::path path) { if (saveData.is_mapped()) { saveData.sync(error); if (error) { - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::COULD_NOT_SYNC_SAVE_DATA}, - {}, {}, R"([Mem]: Could not sync save data stored @ "{}")", sramPath); - return; + warn(R"([Mem]: Could not sync save data stored @ "{}")", sramPath); } saveData.unmap(); } @@ -55,17 +49,13 @@ void Mem::LoadSRAM(SaveType save_type, fs::path path) { } if (sramVec.size() != SRAM_SIZE) { - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::SAVE_DATA_IS_CORRUPT_OR_INVALID_SIZE}, - {}, {}, "[Mem]: Save data is corrupt or has unexpected size! (it's {} KiB)", sramVec.size() / 1024); - return; + panic("[Mem]: Save data is corrupt or has unexpected size! (it's {} KiB)", sramVec.size() / 1024); + return; } saveData = mio::make_mmap_sink(sramPath, error); if (error) { - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::MMAP_MAKE_SINK_ERROR}, - {}, {}, R"([Mem]: Could not create file sink for save data @ "{}")", sramPath); + warn(R"([Mem]: Could not create file sink for save data @ "{}")", sramPath); } } } @@ -145,133 +135,155 @@ void Mem::LoadROM(const bool isArchive, const std::string &filename) { template <> u8 Mem::Read(const u32 paddr) { - n64::Registers& regs = n64::Core::GetRegs(); + n64::Registers ®s = n64::Core::GetRegs(); const SI &si = mmio.si; - if(ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) return mmio.rdp.ReadRDRAM(paddr); - if(ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) { + if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) + return mmio.rdp.ReadRDRAM(paddr); + if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) { const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem; return src[BYTE_ADDRESS(paddr & 0xfff)]; } - if(ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) return mmio.pi.BusRead(paddr); - if(ircolib::IsInsideRange(paddr, AI_REGION_START, AI_REGION_END)) { + if (ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) + return mmio.pi.BusRead(paddr); + if (ircolib::IsInsideRange(paddr, AI_REGION_START, AI_REGION_END)) { const u32 w = mmio.ai.Read(paddr & ~3); const int offs = 3 - (paddr & 3); return w >> offs * 8 & 0xff; } - if(ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) || - ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2)) { - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::MEM_INVALID_ACCESS}, regs.pc, - Util::Error::MemoryAccess{false, Util::Error::MemoryAccess::BYTE, paddr, 0}, "8-bit read access from MMIO"); + if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) || + ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2)) { + warn("8-bit read access from MMIO @ {:08X}", paddr); return 0; } - if(ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END)) return si.pif.bootrom[BYTE_ADDRESS(paddr) - PIF_ROM_REGION_START]; - if(ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) return si.pif.ram[paddr - PIF_RAM_REGION_START]; - if(ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused - ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) || - ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) || - ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) return 0; + if (ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END)) + return si.pif.bootrom[BYTE_ADDRESS(paddr) - PIF_ROM_REGION_START]; + if (ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) + return si.pif.ram[paddr - PIF_RAM_REGION_START]; + if (ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused + ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) || + ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) || + ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) + return 0; - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::MEM_UNHANDLED_ACCESS}, regs.pc, - Util::Error::MemoryAccess{false, Util::Error::MemoryAccess::BYTE, paddr, 0}, "8-bit read access in unhandled region"); + warn("8-bit read access in unhandled region @ {:08X}", paddr); return 0; } template <> u16 Mem::Read(const u32 paddr) { - n64::Registers& regs = n64::Core::GetRegs(); + n64::Registers ®s = n64::Core::GetRegs(); const SI &si = mmio.si; - if(ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) return mmio.rdp.ReadRDRAM(paddr); - if(ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) { + if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) + return mmio.rdp.ReadRDRAM(paddr); + if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) { const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem; return ircolib::ReadAccess(src, HALF_ADDRESS(paddr & 0xfff)); } - if(ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) return mmio.pi.BusRead(paddr); - if(ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) || - ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2)) return mmio.Read(paddr); - if(ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END)) return ircolib::ReadAccess(si.pif.bootrom, HALF_ADDRESS(paddr) - PIF_ROM_REGION_START); - if(ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) return std::byteswap(ircolib::ReadAccess(si.pif.ram, paddr - PIF_RAM_REGION_START)); - if(ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused - ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) || - ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) || - ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) return 0; + if (ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) + return mmio.pi.BusRead(paddr); + if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) || + ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2)) + return mmio.Read(paddr); + if (ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END)) + return ircolib::ReadAccess(si.pif.bootrom, HALF_ADDRESS(paddr) - PIF_ROM_REGION_START); + if (ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) + return std::byteswap(ircolib::ReadAccess(si.pif.ram, paddr - PIF_RAM_REGION_START)); + if (ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused + ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) || + ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) || + ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) { + warn("16-bit read access in unused region @ {:08X}", paddr); + return 0; + } - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::MEM_UNHANDLED_ACCESS}, regs.pc, - Util::Error::MemoryAccess{false, Util::Error::MemoryAccess::SHORT, paddr, 0}, "16-bit read access in unhandled region"); + warn("16-bit read access in unhandled region @ {:08X}", paddr); return 0; } template <> u32 Mem::Read(const u32 paddr) { - n64::Registers& regs = n64::Core::GetRegs(); + n64::Registers ®s = n64::Core::GetRegs(); const SI &si = mmio.si; - if(ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) return mmio.rdp.ReadRDRAM(paddr); - if(ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) { + if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) + return mmio.rdp.ReadRDRAM(paddr); + if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) { const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem; return ircolib::ReadAccess(src, paddr & 0xfff); } - if(ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) return mmio.pi.BusRead(paddr); - if(ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) || - ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2)) return mmio.Read(paddr); + if (ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) + return mmio.pi.BusRead(paddr); + if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) || + ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2)) + return mmio.Read(paddr); - if(ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END)) return ircolib::ReadAccess(si.pif.bootrom, paddr - PIF_ROM_REGION_START); - if(ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) return std::byteswap(ircolib::ReadAccess(si.pif.ram, paddr - PIF_RAM_REGION_START)); - if(ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused - ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) || - ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) || - ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) return 0; + if (ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END)) + return ircolib::ReadAccess(si.pif.bootrom, paddr - PIF_ROM_REGION_START); + if (ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) + return std::byteswap(ircolib::ReadAccess(si.pif.ram, paddr - PIF_RAM_REGION_START)); + if (ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused + ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) || + ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) || + ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) { + warn("32-bit read access in unused region @ {:08X}", paddr); + return 0; + } - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::MEM_UNHANDLED_ACCESS}, regs.pc, - Util::Error::MemoryAccess{false, Util::Error::MemoryAccess::WORD, paddr, 0}, "32-bit read access in unhandled region"); + warn("32-bit read access in unhandled region @ {:08X}", paddr); return 0; } template <> u64 Mem::Read(const u32 paddr) { - n64::Registers& regs = n64::Core::GetRegs(); + n64::Registers ®s = n64::Core::GetRegs(); const SI &si = mmio.si; - if(ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) return mmio.rdp.ReadRDRAM(paddr); - if(ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) { + if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) + return mmio.rdp.ReadRDRAM(paddr); + if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) { const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem; return ircolib::ReadAccess(src, paddr & 0xfff); } - if(ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) return mmio.pi.BusRead(paddr); - if(ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) || - ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2)) return mmio.Read(paddr); + if (ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) + return mmio.pi.BusRead(paddr); + if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) || + ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2)) + return mmio.Read(paddr); - if(ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END)) return ircolib::ReadAccess(si.pif.bootrom, paddr - PIF_ROM_REGION_START); - if(ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) return std::byteswap(ircolib::ReadAccess(si.pif.ram, paddr - PIF_RAM_REGION_START)); - if(ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused - ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) || - ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) || - ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) return 0; + if (ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END)) + return ircolib::ReadAccess(si.pif.bootrom, paddr - PIF_ROM_REGION_START); + if (ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) + return std::byteswap(ircolib::ReadAccess(si.pif.ram, paddr - PIF_RAM_REGION_START)); + if (ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused + ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) || + ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) || + ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) { + warn("64-bit read access in unused region @ {:08X}", paddr); + return 0; + } - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::MEM_UNHANDLED_ACCESS}, regs.pc, - Util::Error::MemoryAccess{false, Util::Error::MemoryAccess::DWORD, paddr, 0}, "64-bit read access in unhandled region"); + warn("64-bit read access in unhandled region @ {:08X}", paddr); return 0; } template <> void Mem::WriteInterpreter(u32 paddr, u32 val) { - n64::Registers& regs = n64::Core::GetRegs(); + n64::Registers ®s = n64::Core::GetRegs(); SI &si = mmio.si; - if(ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) { mmio.rdp.WriteRDRAM(paddr, val); return; } - if(ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) { + if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) { + mmio.rdp.WriteRDRAM(paddr, val); + return; + } + if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) { val = val << (8 * (3 - (paddr & 3))); auto &dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem; paddr = (paddr & 0xFFF) & ~3; @@ -279,16 +291,17 @@ void Mem::WriteInterpreter(u32 paddr, u32 val) { return; } - if(ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) { + if (ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) { trace("BusWrite @ {:08X} = {:02X}", paddr, val); mmio.pi.BusWrite(paddr, val); return; } - if(ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) || - ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2)) panic("MMIO Write!"); + if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) || + ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2)) + panic("MMIO Write!"); - if(ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) { + if (ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) { val = val << (8 * (3 - (paddr & 3))); paddr = (paddr - PIF_RAM_REGION_START) & ~3; ircolib::WriteAccess(si.pif.ram, paddr, std::byteswap(val)); @@ -296,11 +309,12 @@ void Mem::WriteInterpreter(u32 paddr, u32 val) { return; } - if(ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused - ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) || - ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) || - ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) || - ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) return; + if (ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused + ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) || + ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) || + ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) || + ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) + return; panic("Unimplemented 8-bit write at address {:08X} with value {:02X} (PC = {:016X})", paddr, val, (u64)regs.pc); } @@ -321,11 +335,14 @@ void Mem::Write(const u32 paddr, const u32 val) { template <> void Mem::WriteInterpreter(u32 paddr, u32 val) { - n64::Registers& regs = n64::Core::GetRegs(); + n64::Registers ®s = n64::Core::GetRegs(); SI &si = mmio.si; - if(ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) { mmio.rdp.WriteRDRAM(paddr, val); return; } - if(ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) { + if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) { + mmio.rdp.WriteRDRAM(paddr, val); + return; + } + if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) { val = val << (16 * !(paddr & 2)); auto &dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem; paddr = (paddr & 0xFFF) & ~3; @@ -333,16 +350,17 @@ void Mem::WriteInterpreter(u32 paddr, u32 val) { return; } - if(ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) { + if (ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) { trace("BusWrite @ {:08X} = {:04X}", paddr, val); mmio.pi.BusWrite(paddr, val); return; } - if(ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) || - ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2)) panic("MMIO Write!"); + if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) || + ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2)) + panic("MMIO Write!"); - if(ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) { + if (ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) { val = val << (16 * !(paddr & 2)); paddr &= ~3; ircolib::WriteAccess(si.pif.ram, paddr - PIF_RAM_REGION_START, std::byteswap(val)); @@ -350,11 +368,12 @@ void Mem::WriteInterpreter(u32 paddr, u32 val) { return; } - if(ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused - ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) || - ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) || - ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) || - ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) return; + if (ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused + ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) || + ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) || + ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) || + ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) + return; panic("Unimplemented 16-bit write at address {:08X} with value {:04X} (PC = {:016X})", paddr, val, (u64)regs.pc); } @@ -375,36 +394,43 @@ void Mem::Write(const u32 paddr, const u32 val) { template <> void Mem::WriteInterpreter(const u32 paddr, const u32 val) { - n64::Registers& regs = n64::Core::GetRegs(); + n64::Registers ®s = n64::Core::GetRegs(); SI &si = mmio.si; - if(ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) { mmio.rdp.WriteRDRAM(paddr, val); return; } - if(ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) { + if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) { + mmio.rdp.WriteRDRAM(paddr, val); + return; + } + if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) { auto &dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem; ircolib::WriteAccess(dest, paddr & 0xfff, val); return; } - if(ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) { + if (ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) { trace("BusWrite @ {:08X} = {:08X}", paddr, val); mmio.pi.BusWrite(paddr, val); return; } - if(ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) || - ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2)) { mmio.Write(paddr, val); return; } + if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) || + ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2)) { + mmio.Write(paddr, val); + return; + } - if(ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) { + if (ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) { ircolib::WriteAccess(si.pif.ram, paddr - PIF_RAM_REGION_START, std::byteswap(val)); si.pif.ProcessCommands(); return; } - if(ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused - ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) || - ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) || - ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) || - ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) return; + if (ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused + ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) || + ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) || + ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) || + ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) + return; panic("Unimplemented 32-bit write at address {:08X} with value {:08X} (PC = {:016X})", paddr, val, (u64)regs.pc); } @@ -434,37 +460,42 @@ void Mem::WriteJIT(const u32 paddr, const u64 val) { void Mem::Write(const u32 paddr, const u64 val) { WriteInterpreter(paddr, val); } void Mem::WriteInterpreter(const u32 paddr, u64 val) { - n64::Registers& regs = n64::Core::GetRegs(); + n64::Registers ®s = n64::Core::GetRegs(); SI &si = mmio.si; - if(ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) { mmio.rdp.WriteRDRAM(paddr, val); return; } - if(ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) { + if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) { + mmio.rdp.WriteRDRAM(paddr, val); + return; + } + if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) { auto &dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem; val >>= 32; ircolib::WriteAccess(dest, paddr & 0xfff, val); return; } - if(ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) { + if (ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) { trace("BusWrite @ {:08X} = {:016X}", paddr, val); mmio.pi.BusWrite(paddr, val); return; } - if(ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) || - ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2)) panic("MMIO Write!"); + if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) || + ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2)) + panic("MMIO Write!"); - if(ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) { + if (ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) { ircolib::WriteAccess(si.pif.ram, paddr - PIF_RAM_REGION_START, std::byteswap(val)); si.pif.ProcessCommands(); return; } - if(ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused - ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) || - ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) || - ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) || - ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) return; + if (ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused + ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) || + ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) || + ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) || + ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) + return; panic("Unimplemented 64-bit write at address {:08X} with value {:016X} (PC = {:016X})", paddr, val, (u64)regs.pc); } diff --git a/src/backend/core/Mem.hpp b/src/backend/core/Mem.hpp index 8c5d5e1..45e3a5c 100644 --- a/src/backend/core/Mem.hpp +++ b/src/backend/core/Mem.hpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include @@ -82,7 +82,7 @@ struct Mem { void Reset(); void LoadSRAM(SaveType, fs::path); void LoadROM(bool, const std::string &); - void SetJIT(JIT* jit) { this->jit = jit; } + void SetJIT(JIT *jit) { this->jit = jit; } [[nodiscard]] auto GetRDRAMPtr() -> u8 * { return mmio.rdp.rdram.data(); } [[nodiscard]] auto GetRDRAM() -> std::vector & { return mmio.rdp.rdram; } @@ -124,6 +124,7 @@ struct Mem { ROM rom; SaveType saveType = SAVE_NONE; Flash flash; + private: friend struct SI; friend struct PI; diff --git a/src/backend/core/RDP.cpp b/src/backend/core/RDP.cpp index d503eb4..fac6ad2 100644 --- a/src/backend/core/RDP.cpp +++ b/src/backend/core/RDP.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/src/backend/core/RSP.cpp b/src/backend/core/RSP.cpp index b63bf50..657244d 100644 --- a/src/backend/core/RSP.cpp +++ b/src/backend/core/RSP.cpp @@ -1,5 +1,5 @@ #include -#include +#include namespace n64 { RSP::RSP() { Reset(); } diff --git a/src/backend/core/interpreter/cop0instructions.cpp b/src/backend/core/interpreter/cop0instructions.cpp index 484316f..c09208b 100644 --- a/src/backend/core/interpreter/cop0instructions.cpp +++ b/src/backend/core/interpreter/cop0instructions.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include namespace n64 { diff --git a/src/backend/core/interpreter/decode.cpp b/src/backend/core/interpreter/decode.cpp index 1bfe6c0..fadf5b8 100644 --- a/src/backend/core/interpreter/decode.cpp +++ b/src/backend/core/interpreter/decode.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include namespace n64 { diff --git a/src/backend/core/mmio/AI.cpp b/src/backend/core/mmio/AI.cpp index 1abdd8b..fa56db2 100644 --- a/src/backend/core/mmio/AI.cpp +++ b/src/backend/core/mmio/AI.cpp @@ -1,5 +1,5 @@ #include -#include +#include namespace n64 { AI::AI() { Reset(); } diff --git a/src/backend/core/mmio/Audio.cpp b/src/backend/core/mmio/Audio.cpp index 61e13d3..252400f 100644 --- a/src/backend/core/mmio/Audio.cpp +++ b/src/backend/core/mmio/Audio.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include namespace n64 { diff --git a/src/backend/core/mmio/MI.cpp b/src/backend/core/mmio/MI.cpp index c55b6fd..2247c7f 100644 --- a/src/backend/core/mmio/MI.cpp +++ b/src/backend/core/mmio/MI.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #define MI_VERSION_REG 0x02020102 diff --git a/src/backend/core/mmio/PI.cpp b/src/backend/core/mmio/PI.cpp index e3877a2..02fcafe 100644 --- a/src/backend/core/mmio/PI.cpp +++ b/src/backend/core/mmio/PI.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include namespace n64 { PI::PI() { Reset(); } diff --git a/src/backend/core/mmio/PIF.cpp b/src/backend/core/mmio/PIF.cpp index 925ef01..0bc553f 100644 --- a/src/backend/core/mmio/PIF.cpp +++ b/src/backend/core/mmio/PIF.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #define MEMPAK_SIZE 32768 diff --git a/src/backend/core/mmio/PIF/Device.cpp b/src/backend/core/mmio/PIF/Device.cpp index db1e783..cabbebb 100644 --- a/src/backend/core/mmio/PIF/Device.cpp +++ b/src/backend/core/mmio/PIF/Device.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include namespace n64 { void PIF::InitDevices(SaveType saveType) { diff --git a/src/backend/core/mmio/PIF/MupenMovie.cpp b/src/backend/core/mmio/PIF/MupenMovie.cpp index 46d60a6..c750797 100644 --- a/src/backend/core/mmio/PIF/MupenMovie.cpp +++ b/src/backend/core/mmio/PIF/MupenMovie.cpp @@ -80,22 +80,24 @@ void MupenMovie::Reset() { } FORCE_INLINE void LogController(const n64::Controller &controller) { - debug("c_right: {}", controller.cRight); - debug("c_left: {}", controller.cLeft); - debug("c_down: {}", controller.cDown); - debug("c_up: {}", controller.cUp); - debug("r: {}", controller.r); - debug("l: {}", controller.l); - debug("dp_right: {}", controller.dpRight); - debug("dp_left: {}", controller.dpLeft); - debug("dp_down: {}", controller.dpDown); - debug("dp_up: {}", controller.dpUp); - debug("z: {}", controller.z); - debug("b: {}", controller.b); - debug("a: {}", controller.a); - debug("start: {}", controller.start); - debug("joy_x: {}", controller.joyX); - debug("joy_y: {}", controller.joyY); + trace("-- TAS CONTROLLER DATA --"); + trace("c_right: {}", controller.cRight); + trace("c_left: {}", controller.cLeft); + trace("c_down: {}", controller.cDown); + trace("c_up: {}", controller.cUp); + trace("r: {}", controller.r); + trace("l: {}", controller.l); + trace("dp_right: {}", controller.dpRight); + trace("dp_left: {}", controller.dpLeft); + trace("dp_down: {}", controller.dpDown); + trace("dp_up: {}", controller.dpUp); + trace("z: {}", controller.z); + trace("b: {}", controller.b); + trace("a: {}", controller.a); + trace("start: {}", controller.start); + trace("joy_x: {}", controller.joyX); + trace("joy_y: {}", controller.joyY); + trace("-- TAS CONTROLLER DATA --"); } n64::Controller MupenMovie::NextInputs() { diff --git a/src/backend/core/mmio/RI.cpp b/src/backend/core/mmio/RI.cpp index 2f41dc3..3e76d6c 100644 --- a/src/backend/core/mmio/RI.cpp +++ b/src/backend/core/mmio/RI.cpp @@ -1,5 +1,5 @@ #include -#include +#include namespace n64 { RI::RI() { Reset(); } diff --git a/src/backend/core/mmio/VI.cpp b/src/backend/core/mmio/VI.cpp index f4d790f..472087b 100644 --- a/src/backend/core/mmio/VI.cpp +++ b/src/backend/core/mmio/VI.cpp @@ -1,5 +1,5 @@ #include -#include +#include namespace n64 { VI::VI() { Reset(); } @@ -54,9 +54,7 @@ u32 VI::Read(const u32 paddr) const { return yscale.raw; default: { n64::Registers& regs = n64::Core::GetRegs(); - Util::Error::GetInstance().Throw( - {Util::Error::Severity::NON_FATAL}, {Util::Error::Type::MEM_UNHANDLED_ACCESS}, regs.pc, - Util::Error::MemoryAccess{false, Util::Error::MemoryAccess::WORD, paddr, 0}, "32-bit read access on unhandled VI register"); + error("32-bit read access on unhandled VI register @ {:08X}, pc: {:016X}", paddr, (u64)regs.oldPC); return 0; } } @@ -120,8 +118,10 @@ void VI::Write(const u32 paddr, const u32 val) { break; case 0x0440003C: break; - default: - panic("Unimplemented VI[{:08X}] write ({:08X})", paddr, val); + default: { + n64::Registers& regs = n64::Core::GetRegs(); + error("32-bit write access on unhandled VI register @ {:08X}, pc: {:016X}, val: {:08X}", paddr, (u64)regs.oldPC, val); + } } } } // namespace n64 diff --git a/src/backend/core/registers/Cop0.cpp b/src/backend/core/registers/Cop0.cpp index e1dba7e..85f6771 100644 --- a/src/backend/core/registers/Cop0.cpp +++ b/src/backend/core/registers/Cop0.cpp @@ -1,5 +1,5 @@ #include -#include +#include namespace n64 { Cop0::Cop0() { Reset(); } diff --git a/src/backend/core/registers/Cop0.hpp b/src/backend/core/registers/Cop0.hpp index 915c0c5..7e500e3 100644 --- a/src/backend/core/registers/Cop0.hpp +++ b/src/backend/core/registers/Cop0.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include +#include #include #include diff --git a/src/backend/core/registers/Cop1.cpp b/src/backend/core/registers/Cop1.cpp index 98626c1..ff32512 100644 --- a/src/backend/core/registers/Cop1.cpp +++ b/src/backend/core/registers/Cop1.cpp @@ -1,5 +1,5 @@ #include -#include +#include namespace n64 { Cop1::Cop1() { Reset(); } diff --git a/src/backend/core/rsp/decode.cpp b/src/backend/core/rsp/decode.cpp index b559f39..2b9d5ae 100644 --- a/src/backend/core/rsp/decode.cpp +++ b/src/backend/core/rsp/decode.cpp @@ -1,5 +1,5 @@ #include -#include +#include namespace n64 { void RSP::special(const Instruction instr) { diff --git a/src/backend/core/rsp/instructions.cpp b/src/backend/core/rsp/instructions.cpp index da5af5e..a97e709 100644 --- a/src/backend/core/rsp/instructions.cpp +++ b/src/backend/core/rsp/instructions.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include namespace n64 { FORCE_INLINE bool AcquireSemaphore(RSP &rsp) { diff --git a/src/common.hpp b/src/common.hpp index b1813c5..2f9bf69 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -1,6 +1,5 @@ #pragma once #include -#include #define FORCE_INLINE inline __attribute__((always_inline)) diff --git a/src/frontend/Debugger.cpp b/src/frontend/Debugger.cpp deleted file mode 100644 index 8fd9888..0000000 --- a/src/frontend/Debugger.cpp +++ /dev/null @@ -1,249 +0,0 @@ -#include -#include - -char const* regNames[] = { - "zero", "at", "v0", "v1", - "a0", "a1", "a2", "a3", - "t0", "t1", "t2", "t3", - "t4", "t5", "t6", "t7", - "s0", "s1", "s2", "s3", - "s4", "s5", "s6", "s7", - "t8", "t9", "k0", "k1", - "gp", "sp", "s8", "ra", -}; - -void BreakpointFunc(s64 addr, Disassembler::DisassemblyResult&) { - n64::Core& core = n64::Core::GetInstance(); - bool isBroken = core.breakpoints.contains(addr); - ImGui::PushStyleColor(ImGuiCol_CheckMark, 0xff0000ff); - ImGui::PushStyleColor(ImGuiCol_FrameBg, 0); - ImGui::PushStyleColor(ImGuiCol_FrameBgActive, 0); - ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, 0x800000ff); - ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 0.5f); - if(ImGui::Checkbox(std::format("##toggleBreakpoint{}", addr).c_str(), &isBroken)) { - core.ToggleBreakpoint(addr); - } - ImGui::PopStyleVar(); - ImGui::PopStyleColor(); - ImGui::PopStyleColor(); - ImGui::PopStyleColor(); - ImGui::PopStyleColor(); -} - -void AddressFunc(s64, Disassembler::DisassemblyResult& disasm) { - if(!disasm.success) { - ImGui::TextColored(ImColor(0xffeaefb6), "????????????????"); - return; - } - - ImGui::TextColored(ImColor(0xffeaefb6), "%s", std::format("{:016X}:", disasm.address).c_str()); -} - -void InstructionFunc(s64, Disassembler::DisassemblyResult& disasm) { - if(!disasm.success) { - ImGui::TextColored(ImColor(0xffcbf1ae), "Disassembly unsuccessful..."); - return; - } - - ImGui::TextColored(ImColor(0xffcbf1ae), "%s", std::format("{} ", disasm.mnemonic).c_str()); - ImGui::SameLine(0, 0); - for(int i = 0; i < 3; i++) { - if(disasm.ops[i].str.empty()) - continue; - - if(i >= 2) { - ImGui::TextColored(ImColor(disasm.ops[i].color), "%s", disasm.ops[i].str.c_str()); - ImGui::SameLine(0, 0); - continue; - } - - 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); - } -} - -void Debugger::RegisterView() { - if(!ImGui::BeginTabItem("Registers")) - return; - - if(!ImGui::BeginTable("##regs", 4, ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody)) - return; - - ImGui::TableSetupColumn("Name"); - ImGui::TableSetupColumn("Value"); - ImGui::TableSetupColumn("Name"); - ImGui::TableSetupColumn("Value"); - - ImGui::TableHeadersRow(); - - auto renderMemoryTable = [&](u64 vaddr) { - if(!ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_ForTooltip)) - return; - - if(!ImGui::BeginTooltip()) - return; - - ImGui::Text("%s", std::format("Memory contents @ 0x{:016X}", vaddr).c_str()); - if(!ImGui::BeginTable("##memoryContents", 16)) - return; - - for(u32 col = 0; col < 16; col++) - ImGui::TableSetupColumn(std::format("##hexCol{}", col).c_str()); - - ImGui::TableHeadersRow(); - - for(u32 row = 0; row < 16; row++) { - ImGui::TableNextRow(); - for(u32 col = 0; col < 16; col+=4) { - u32 paddr; - if (!n64::Core::GetRegs().cop0.MapVAddr(n64::Cop0::LOAD, vaddr + row * 0x10 + col, paddr)) - continue; - - const u32 val = n64::Core::GetMem().Read(paddr); - - ImGui::TableSetColumnIndex(col+0); - ImGui::Text("%02X", (val >> 24) & 0xff); - ImGui::TableSetColumnIndex(col+1); - ImGui::Text("%02X", (val >> 16) & 0xff); - ImGui::TableSetColumnIndex(col+2); - ImGui::Text("%02X", (val >> 8) & 0xff); - ImGui::TableSetColumnIndex(col+3); - ImGui::Text("%02X", (val >> 0) & 0xff); - } - } - - ImGui::EndTable(); - ImGui::EndTooltip(); - }; - - n64::Registers& regs = n64::Core::GetRegs(); - - for(int i = 0; i < 32; i+=2) { - ImGui::TableNextRow(); - - ImGui::TableSetColumnIndex(0); - ImGui::Text("%s", regNames[i]); - - ImGui::TableSetColumnIndex(1); - auto value = regs.Read(i); - ImGui::Text("%s", std::format("{:016X}", value).c_str()); - renderMemoryTable(value); - - ImGui::TableSetColumnIndex(2); - ImGui::Text("%s", regNames[i+1]); - - ImGui::TableSetColumnIndex(3); - value = regs.Read(i+1); - ImGui::Text("%s", std::format("{:016X}", value).c_str()); - renderMemoryTable(value); - } - - ImGui::EndTable(); - ImGui::EndTabItem(); -} - -bool Debugger::render() { - n64::Core &core = n64::Core::GetInstance(); - const n64::Registers& regs = n64::Core::GetRegs(); - - if(!enabled) - return false; - - static s64 startAddr = 0xFFFF'FFFF'8000'0000; - constexpr int step = 4; - constexpr int stepFast = 256; - - if(!ImGui::Begin("Debugger", &enabled)) { - ImGui::End(); - return false; - } - - ImGui::BeginDisabled(followPC); - ImGui::InputScalar("Address", ImGuiDataType_S64, &startAddr, &step, &stepFast, "%016lX", ImGuiInputTextFlags_CharsHexadecimal); - ImGui::EndDisabled(); - - ImGui::Text("Follow program counter:"); - ImGui::SameLine(0,0); - - ImGui::Checkbox("##followPC", &followPC); - ImGui::SameLine(0,0); - - ImGui::Text("Add a breakpoint"); - ImGui::SameLine(0,0); - - if(followPC) - startAddr = regs.pc - 256; // TODO: arbitrary??? - - if (ImGui::Button(core.breakpoints.contains(startAddr) ? "-" : "+")) { - core.ToggleBreakpoint(startAddr); - } - - if(!ImGui::BeginTabBar("##debuggerTabs")) { - ImGui::EndTabBar(); - ImGui::End(); - return false; - } - - RegisterView(); - - if(!ImGui::BeginTabItem("MIPS R4300i code view")) { - ImGui::EndTabBar(); - ImGui::End(); - return false; - } - - constexpr auto disasmTableFlags = ImGuiTableFlags_SizingFixedSame | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | - ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody; - - if(!ImGui::BeginTable("Disassembly", columns.size(), disasmTableFlags)) { - ImGui::EndTabBar(); - ImGui::End(); - return false; - } - - for(auto &[name, _] : columns) - ImGui::TableSetupColumn(name); - - ImGui::TableHeadersRow(); - - for(auto addr = startAddr; addr < startAddr + MAX_LINES_OF_DISASM * sizeof(u32); addr += sizeof(u32)) { - auto disasm = Disassembler::GetInstance().Disassemble(addr); - const auto addrIsCurrent = addr == regs.nextPC; - const auto addrIsBreakpoint = core.breakpoints.contains(addr); - ImColor colorChoice = ImGui::GetStyle().Colors[ImGuiCol_TableRowBg]; - ImColor colorChoiceAlt = ImGui::GetStyle().Colors[ImGuiCol_TableRowBgAlt]; - if(addrIsCurrent) { - colorChoice = 0x80e27fbc; - colorChoiceAlt = 0x80e27fbc; - } - - if(addrIsBreakpoint) { - colorChoice = 0x800000ff; - colorChoiceAlt = 0x800000ff; - } - - ImGui::PushStyleColor(ImGuiCol_TableRowBg, colorChoice.Value); - ImGui::PushStyleColor(ImGuiCol_TableRowBgAlt, colorChoiceAlt.Value); - - ImGui::TableNextRow(); - for(int i = 0; auto &[_, func] : columns) { - ImGui::TableSetColumnIndex(i++); - func(addr, disasm); - } - - ImGui::PopStyleColor(); - ImGui::PopStyleColor(); - } - - ImGui::EndTable(); - - ImGui::EndTabItem(); - ImGui::EndTabBar(); - - ImGui::End(); - return true; -} diff --git a/src/frontend/Debugger.hpp b/src/frontend/Debugger.hpp deleted file mode 100644 index 659e2b7..0000000 --- a/src/frontend/Debugger.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include - -void BreakpointFunc(s64, Disassembler::DisassemblyResult&); -void AddressFunc(s64, Disassembler::DisassemblyResult&); -void InstructionFunc(s64, Disassembler::DisassemblyResult&); - -class Debugger final { - bool enabled = false; - static constexpr auto MAX_LINES_OF_DISASM = 150; - - struct Column { - const char* name = nullptr; - void (*func)(s64, Disassembler::DisassemblyResult&) = nullptr; - }; - - std::array columns = { - Column{"##BreakpointColumn", &BreakpointFunc}, - Column{"Address", &AddressFunc}, - Column{"Instruction", &InstructionFunc}, - }; -public: - static void RegisterView(); - bool followPC = true; - void Open(bool wantFollowPC = true) { enabled = true; followPC = wantFollowPC; } - void Close() { enabled = false; } - bool render(); -}; \ No newline at end of file diff --git a/src/frontend/ImGuiImpl/GUI.hpp b/src/frontend/ImGuiImpl/GUI.hpp index 293a36b..01d3e9c 100644 --- a/src/frontend/ImGuiImpl/GUI.hpp +++ b/src/frontend/ImGuiImpl/GUI.hpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include namespace gui { diff --git a/src/frontend/KaizenGui.cpp b/src/frontend/KaizenGui.cpp index dd4f4d8..78bf381 100644 --- a/src/frontend/KaizenGui.cpp +++ b/src/frontend/KaizenGui.cpp @@ -5,7 +5,9 @@ #include #include -KaizenGui::KaizenGui() noexcept : window("Kaizen " KAIZEN_VERSION_STR, 1280, 720), settingsWindow(window), vulkanWidget(window.getHandle()), emuThread(fpsCounter, settingsWindow) { +KaizenGui::KaizenGui() noexcept : + window("Kaizen " KAIZEN_VERSION_STR, 1280, 720), settingsWindow(window), vulkanWidget(window.getHandle()), + emuThread(fpsCounter, settingsWindow) { gui::Initialize(n64::Core::GetInstance().parallel.wsi, window.getHandle()); SDL_InitSubSystem(SDL_INIT_GAMEPAD); @@ -33,208 +35,188 @@ void KaizenGui::QueryDevices(const SDL_Event &event) { if (gamepad) SDL_CloseGamepad(gamepad); break; - default: break; + default: + break; } } void KaizenGui::HandleInput(const SDL_Event &event) { - const n64::Core& core = n64::Core::GetInstance(); + const n64::Core &core = n64::Core::GetInstance(); n64::PIF &pif = n64::Core::GetMem().mmio.si.pif; - switch(event.type) { - case SDL_EVENT_GAMEPAD_AXIS_MOTION: - if(!gamepad) - break; - { - pif.UpdateButton(0, n64::Controller::Key::Z, SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFT_TRIGGER) == SDL_JOYSTICK_AXIS_MAX); - pif.UpdateButton(0, n64::Controller::Key::CUp, SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTY) <= -127); - pif.UpdateButton(0, n64::Controller::Key::CDown, SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTY) >= 127); - pif.UpdateButton(0, n64::Controller::Key::CLeft, SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTX) <= -127); - pif.UpdateButton(0, n64::Controller::Key::CRight, SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTX) >= 127); + switch (event.type) { + case SDL_EVENT_GAMEPAD_AXIS_MOTION: + if (!gamepad) + break; + { + pif.UpdateButton(0, n64::Controller::Key::Z, + SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFT_TRIGGER) == SDL_JOYSTICK_AXIS_MAX); + pif.UpdateButton(0, n64::Controller::Key::CUp, SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTY) <= -127); + pif.UpdateButton(0, n64::Controller::Key::CDown, SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTY) >= 127); + pif.UpdateButton(0, n64::Controller::Key::CLeft, SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTX) <= -127); + pif.UpdateButton(0, n64::Controller::Key::CRight, SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTX) >= 127); - float xclamped = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTX); - if (xclamped < 0) { - xclamped /= static_cast(std::abs(SDL_JOYSTICK_AXIS_MAX)); - } else { - xclamped /= SDL_JOYSTICK_AXIS_MAX; - } - - xclamped *= 86; - - float yclamped = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTY); - if (yclamped < 0) { - yclamped /= static_cast(std::abs(SDL_JOYSTICK_AXIS_MIN)); - } else { - yclamped /= SDL_JOYSTICK_AXIS_MAX; - } - - yclamped *= 86; - - pif.UpdateAxis(0, n64::Controller::Axis::Y, static_cast(-yclamped)); - pif.UpdateAxis(0, n64::Controller::Axis::X, static_cast( xclamped)); + float xclamped = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTX); + if (xclamped < 0) { + xclamped /= static_cast(std::abs(SDL_JOYSTICK_AXIS_MAX)); + } else { + xclamped /= SDL_JOYSTICK_AXIS_MAX; } - break; - case SDL_EVENT_GAMEPAD_BUTTON_DOWN: - case SDL_EVENT_GAMEPAD_BUTTON_UP: - if(!gamepad) - break; - - pif.UpdateButton(0, n64::Controller::Key::A, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_SOUTH)); - pif.UpdateButton(0, n64::Controller::Key::B, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_WEST)); - pif.UpdateButton(0, n64::Controller::Key::Start, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_START)); - pif.UpdateButton(0, n64::Controller::Key::DUp, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_UP)); - pif.UpdateButton(0, n64::Controller::Key::DDown, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_DOWN)); - pif.UpdateButton(0, n64::Controller::Key::DLeft, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_LEFT)); - pif.UpdateButton(0, n64::Controller::Key::DRight, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_RIGHT)); - pif.UpdateButton(0, n64::Controller::Key::LT, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER)); - pif.UpdateButton(0, n64::Controller::Key::RT, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER)); - break; - case SDL_EVENT_KEY_DOWN: - case SDL_EVENT_KEY_UP: - { - const auto keys = SDL_GetKeyboardState(nullptr); - if((keys[SDL_SCANCODE_LCTRL] || keys[SDL_SCANCODE_RCTRL]) && keys[SDL_SCANCODE_O]) { - fileDialogOpen = true; - } - fastForward = keys[SDL_SCANCODE_SPACE]; - if(!unlockFramerate) - core.parallel.SetFramerateUnlocked(fastForward); + xclamped *= 86; - if(core.romLoaded) { - if(keys[SDL_SCANCODE_P]) { - emuThread.TogglePause(); - } - - if(keys[SDL_SCANCODE_R]) { - emuThread.Reset(); - } - - if(keys[SDL_SCANCODE_Q]) { - emuThread.Stop(); - } - } - - if(gamepad) - break; - - pif.UpdateButton(0, n64::Controller::Key::Z, keys[SDL_SCANCODE_Z]); - pif.UpdateButton(0, n64::Controller::Key::CUp, keys[SDL_SCANCODE_HOME]); - pif.UpdateButton(0, n64::Controller::Key::CDown, keys[SDL_SCANCODE_END]); - pif.UpdateButton(0, n64::Controller::Key::CLeft, keys[SDL_SCANCODE_DELETE]); - pif.UpdateButton(0, n64::Controller::Key::CRight, keys[SDL_SCANCODE_PAGEDOWN]); - pif.UpdateButton(0, n64::Controller::Key::A, keys[SDL_SCANCODE_X]); - pif.UpdateButton(0, n64::Controller::Key::B, keys[SDL_SCANCODE_C]); - pif.UpdateButton(0, n64::Controller::Key::Start, keys[SDL_SCANCODE_RETURN]); - pif.UpdateButton(0, n64::Controller::Key::DUp, keys[SDL_SCANCODE_I]); - pif.UpdateButton(0, n64::Controller::Key::DDown, keys[SDL_SCANCODE_K]); - pif.UpdateButton(0, n64::Controller::Key::DLeft, keys[SDL_SCANCODE_J]); - pif.UpdateButton(0, n64::Controller::Key::DRight, keys[SDL_SCANCODE_L]); - pif.UpdateButton(0, n64::Controller::Key::LT, keys[SDL_SCANCODE_A]); - pif.UpdateButton(0, n64::Controller::Key::RT, keys[SDL_SCANCODE_S]); - - float x = 0, y = 0; - - if (keys[SDL_SCANCODE_UP]) y = 86; - if (keys[SDL_SCANCODE_DOWN]) y = -86; - if (keys[SDL_SCANCODE_LEFT]) x = -86; - if (keys[SDL_SCANCODE_RIGHT]) x = 86; - - pif.UpdateAxis(0, n64::Controller::Axis::X, x); - pif.UpdateAxis(0, n64::Controller::Axis::Y, y); + float yclamped = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTY); + if (yclamped < 0) { + yclamped /= static_cast(std::abs(SDL_JOYSTICK_AXIS_MIN)); + } else { + yclamped /= SDL_JOYSTICK_AXIS_MAX; } + + yclamped *= 86; + + pif.UpdateAxis(0, n64::Controller::Axis::Y, static_cast(-yclamped)); + pif.UpdateAxis(0, n64::Controller::Axis::X, static_cast(xclamped)); + } + break; + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: + case SDL_EVENT_GAMEPAD_BUTTON_UP: + if (!gamepad) break; - default: break; - } -} -std::pair, std::optional> RenderErrorMessageDetails() { - auto lastPC = Util::Error::GetLastPC(); - if(lastPC.has_value()) { - ImGui::Text("%s", std::format("Occurred @ PC = {:016X}", Util::Error::GetLastPC().value()).c_str()); - } + pif.UpdateButton(0, n64::Controller::Key::A, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_SOUTH)); + pif.UpdateButton(0, n64::Controller::Key::B, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_WEST)); + pif.UpdateButton(0, n64::Controller::Key::Start, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_START)); + pif.UpdateButton(0, n64::Controller::Key::DUp, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_UP)); + pif.UpdateButton(0, n64::Controller::Key::DDown, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_DOWN)); + pif.UpdateButton(0, n64::Controller::Key::DLeft, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_LEFT)); + pif.UpdateButton(0, n64::Controller::Key::DRight, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_DPAD_RIGHT)); + pif.UpdateButton(0, n64::Controller::Key::LT, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER)); + pif.UpdateButton(0, n64::Controller::Key::RT, SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER)); + break; + case SDL_EVENT_KEY_DOWN: + case SDL_EVENT_KEY_UP: + { + const auto keys = SDL_GetKeyboardState(nullptr); + if ((keys[SDL_SCANCODE_LCTRL] || keys[SDL_SCANCODE_RCTRL]) && keys[SDL_SCANCODE_O]) { + fileDialogOpen = true; + } - auto memoryAccess = Util::Error::GetMemoryAccess(); - if(memoryAccess.has_value()) { - const auto [is_write, size, address, written_val] = memoryAccess.value(); - ImGui::Text("%s", std::format("{} {}-bit value @ {:08X}{}", is_write ? "Writing" : "Reading", - static_cast(size), address, - is_write ? std::format(" (value = 0x{:X})", written_val) : "") - .c_str()); - } + fastForward = keys[SDL_SCANCODE_SPACE]; + if (!unlockFramerate) + core.parallel.SetFramerateUnlocked(fastForward); - return {lastPC, memoryAccess}; + if (core.romLoaded) { + if (keys[SDL_SCANCODE_P]) { + emuThread.TogglePause(); + } + + if (keys[SDL_SCANCODE_R]) { + emuThread.Reset(); + } + + if (keys[SDL_SCANCODE_Q]) { + emuThread.Stop(); + } + } + + if (gamepad) + break; + + pif.UpdateButton(0, n64::Controller::Key::Z, keys[SDL_SCANCODE_Z]); + pif.UpdateButton(0, n64::Controller::Key::CUp, keys[SDL_SCANCODE_HOME]); + pif.UpdateButton(0, n64::Controller::Key::CDown, keys[SDL_SCANCODE_END]); + pif.UpdateButton(0, n64::Controller::Key::CLeft, keys[SDL_SCANCODE_DELETE]); + pif.UpdateButton(0, n64::Controller::Key::CRight, keys[SDL_SCANCODE_PAGEDOWN]); + pif.UpdateButton(0, n64::Controller::Key::A, keys[SDL_SCANCODE_X]); + pif.UpdateButton(0, n64::Controller::Key::B, keys[SDL_SCANCODE_C]); + pif.UpdateButton(0, n64::Controller::Key::Start, keys[SDL_SCANCODE_RETURN]); + pif.UpdateButton(0, n64::Controller::Key::DUp, keys[SDL_SCANCODE_I]); + pif.UpdateButton(0, n64::Controller::Key::DDown, keys[SDL_SCANCODE_K]); + pif.UpdateButton(0, n64::Controller::Key::DLeft, keys[SDL_SCANCODE_J]); + pif.UpdateButton(0, n64::Controller::Key::DRight, keys[SDL_SCANCODE_L]); + pif.UpdateButton(0, n64::Controller::Key::LT, keys[SDL_SCANCODE_A]); + pif.UpdateButton(0, n64::Controller::Key::RT, keys[SDL_SCANCODE_S]); + + float x = 0, y = 0; + + if (keys[SDL_SCANCODE_UP]) + y = 86; + if (keys[SDL_SCANCODE_DOWN]) + y = -86; + if (keys[SDL_SCANCODE_LEFT]) + x = -86; + if (keys[SDL_SCANCODE_RIGHT]) + x = 86; + + pif.UpdateAxis(0, n64::Controller::Axis::X, x); + pif.UpdateAxis(0, n64::Controller::Axis::Y, y); + } + break; + default: + break; + } } void KaizenGui::RenderUI() { - n64::Core& core = n64::Core::GetInstance(); + n64::Core &core = n64::Core::GetInstance(); gui::StartFrame(); - if(ImGui::BeginMainMenuBar()) { - if(ImGui::BeginMenu("File")) { - if(ImGui::MenuItem("Open", "Ctrl-O")) { + if (ImGui::BeginMainMenuBar()) { + if (ImGui::BeginMenu("File")) { + if (ImGui::MenuItem("Open", "Ctrl-O")) { fileDialogOpen = true; } - if(ImGui::MenuItem("Exit")) { + if (ImGui::MenuItem("Exit")) { quit = true; emuThread.Stop(); } ImGui::EndMenu(); } - if(ImGui::BeginMenu("Emulation")) { + if (ImGui::BeginMenu("Emulation")) { ImGui::BeginDisabled(!core.romLoaded); - - if(ImGui::MenuItem(core.pause ? "Resume" : "Pause", "P")) { + + if (ImGui::MenuItem(core.pause ? "Resume" : "Pause", "P")) { emuThread.TogglePause(); } - - if(ImGui::MenuItem("Reset", "R")) { + + if (ImGui::MenuItem("Reset", "R")) { emuThread.Reset(); } - - if(ImGui::MenuItem("Stop", "Q")) { + + if (ImGui::MenuItem("Stop", "Q")) { emuThread.Stop(); core.romLoaded = false; } - - if(ImGui::Checkbox("Unlock framerate", &unlockFramerate)) { - core.parallel.SetFramerateUnlocked(unlockFramerate); - } - if(ImGui::MenuItem("Open Debugger")) { - debugger.Open(); + if (ImGui::Checkbox("Unlock framerate", &unlockFramerate)) { + core.parallel.SetFramerateUnlocked(unlockFramerate); } ImGui::EndDisabled(); - if(ImGui::MenuItem("Options")) { + if (ImGui::MenuItem("Options")) { settingsWindow.isOpen = true; } ImGui::EndMenu(); } - if(ImGui::BeginMenu("Help")) { - if(ImGui::MenuItem("About")) { + if (ImGui::BeginMenu("Help")) { + if (ImGui::MenuItem("About")) { aboutOpen = true; } - + ImGui::EndMenu(); } ImGui::EndMainMenuBar(); } - if(!Util::Error::IsHandled()) { - ImGui::OpenPopup(Util::Error::GetSeverity().as_c_str()); - } - - if(settingsWindow.isOpen) { + if (settingsWindow.isOpen) { ImGui::OpenPopup("Settings", ImGuiPopupFlags_None); } - if(aboutOpen) { + if (aboutOpen) { ImGui::OpenPopup("About Kaizen"); } settingsWindow.render(); - debugger.render(); const ImVec2 center = ImGui::GetMainViewport()->GetCenter(); ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); @@ -247,119 +229,22 @@ void KaizenGui::RenderUI() { ImGui::Separator(); ImGui::Text("Kaizen %s%s", KAIZEN_USE_HASH ? "dev build " : "", KAIZEN_VERSION_STR); ImGui::Separator(); - if(ImGui::Button("OK")) { + if (ImGui::Button("OK")) { aboutOpen = false; ImGui::CloseCurrentPopup(); } - + ImGui::EndPopup(); } - ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); - - if (ImGui::BeginPopupModal(Util::Error::GetSeverity().as_c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { - emuThread.TogglePause(); - switch(Util::Error::GetSeverity().as_enum) { - case Util::Error::Severity::WARN: { - ImGui::PushStyleColor(ImGuiCol_TitleBg, 0x8054eae5); - ImGui::PushStyleColor(ImGuiCol_Text, 0xff7be4e1); - ImGui::Text("Warning of type: %s", Util::Error::GetType().as_c_str()); - ImGui::PopStyleColor(); - ImGui::PopStyleColor(); - ImGui::Text(R"(Warning message: "%s")", Util::Error::GetError().c_str()); - RenderErrorMessageDetails(); - - if(n64::Core::GetInstance().romLoaded && !n64::Core::GetInstance().pause) { - const bool ignore = ImGui::Button("Try continuing"); ImGui::SameLine(); - const bool stop = ImGui::Button("Stop emulation"); ImGui::SameLine(); - const bool chooseAnother = ImGui::Button("Choose another ROM"); - if(ignore || stop || chooseAnother) { - Util::Error::SetHandled(); - ImGui::CloseCurrentPopup(); - } - - if(ignore) { - emuThread.TogglePause(); - } - - if(stop || chooseAnother) { - emuThread.Stop(); - } - - if(chooseAnother) { - fileDialogOpen = true; - } - break; - } - - if(ImGui::Button("OK")) - ImGui::CloseCurrentPopup(); - } break; - case Util::Error::Severity::UNRECOVERABLE: { - emuThread.Stop(); - ImGui::PushStyleColor(ImGuiCol_TitleBg, 0x800000ff); - ImGui::PushStyleColor(ImGuiCol_Text, 0xff3b3bbf); - ImGui::Text("An unrecoverable error has occurred! Emulation has been stopped..."); - ImGui::Text("Error of type: %s", Util::Error::GetType().as_c_str()); - ImGui::PopStyleColor(); - ImGui::PopStyleColor(); - ImGui::Text(R"(Error message: "%s")", Util::Error::GetError().c_str()); - RenderErrorMessageDetails(); - if(ImGui::Button("OK")) - ImGui::CloseCurrentPopup(); - } break; - case Util::Error::Severity::NON_FATAL: { - ImGui::PushStyleColor(ImGuiCol_TitleBg, 0x800000ff); - ImGui::PushStyleColor(ImGuiCol_Text, 0xff3b3bbf); - ImGui::Text("An error has occurred!"); - ImGui::Text("Error of type: %s", Util::Error::GetType().as_c_str()); - ImGui::PopStyleColor(); - ImGui::PopStyleColor(); - ImGui::Text(R"(Error message: "%s")", Util::Error::GetError().c_str()); - auto [lastPC, memoryAccess] = RenderErrorMessageDetails(); - - const bool ignore = ImGui::Button("Try continuing"); ImGui::SameLine(); - const bool stop = ImGui::Button("Stop emulation"); ImGui::SameLine(); - const bool chooseAnother = ImGui::Button("Choose another ROM"); - const bool openInDebugger = lastPC.has_value() ? ImGui::Button("Add breakpoint at this PC and open the debugger") : false; - if(ignore || stop || chooseAnother || openInDebugger) { - Util::Error::SetHandled(); - ImGui::CloseCurrentPopup(); - } - - if(ignore) { - emuThread.TogglePause(); - } - - if(stop || chooseAnother) { - emuThread.Stop(); - } - - if(chooseAnother) { - fileDialogOpen = true; - } - - if(openInDebugger) { - if(!n64::Core::GetInstance().breakpoints.contains(lastPC.value())) - n64::Core::GetInstance().ToggleBreakpoint(lastPC.value()); - - debugger.Open(); - emuThread.Reset(); - } - } break; - default: break; - } - - ImGui::EndPopup(); - } - - if(ImGui::BeginMainStatusBar()) { + if (ImGui::BeginMainStatusBar()) { ImGui::Text("FPS: %.2f", ImGui::GetIO().Framerate); ImGui::EndMainStatusBar(); } if (shouldDisplaySpinner) { - ImGui::SetNextWindowPos({static_cast(width) * 0.5f, static_cast(height) * 0.5f}, 0, ImVec2(0.5f, 0.5f)); + ImGui::SetNextWindowPos({static_cast(width) * 0.5f, static_cast(height) * 0.5f}, 0, + ImVec2(0.5f, 0.5f)); ImGui::PushStyleColor(ImGuiCol_WindowBg, IM_COL32_BLACK_TRANS); ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); @@ -384,34 +269,38 @@ void KaizenGui::RenderUI() { ImGui::RenderPlatformWindowsDefault(); } - if(fileDialogOpen) { + if (fileDialogOpen) { fileDialogOpen = false; - constexpr SDL_DialogFileFilter filters[] = {{"All files", "*"}, {"Nintendo 64 executable", "n64;z64;v64"}, {"Nintendo 64 executable archive", "rar;tar;zip;7z"}}; - SDL_ShowOpenFileDialog([](void *userdata, const char * const *filelist, int) { - auto kaizen = static_cast(userdata); - - if (!filelist) { - panic("An error occured: {}", SDL_GetError()); - } + constexpr SDL_DialogFileFilter filters[] = {{"All files", "*"}, + {"Nintendo 64 executable", "n64;z64;v64"}, + {"Nintendo 64 executable archive", "rar;tar;zip;7z"}}; + SDL_ShowOpenFileDialog( + [](void *userdata, const char *const *filelist, int) { + auto kaizen = static_cast(userdata); - if (!*filelist) { - warn("The user did not select any file."); - warn("Most likely, the dialog was canceled."); - return; - } + if (!filelist) { + panic("An error occured: {}", SDL_GetError()); + } - kaizen->fileToLoad = *filelist; - kaizen->shouldDisplaySpinner = true; + if (!*filelist) { + warn("The user did not select any file."); + warn("Most likely, the dialog was canceled."); + return; + } - std::thread fileWorker(&KaizenGui::FileWorker, kaizen); - fileWorker.detach(); - }, this, window.getHandle(), filters, 3, nullptr, false); + kaizen->fileToLoad = *filelist; + kaizen->shouldDisplaySpinner = true; + + std::thread fileWorker(&KaizenGui::FileWorker, kaizen); + fileWorker.detach(); + }, + this, window.getHandle(), filters, 3, nullptr, false); } - if(minimized) + if (minimized) return; - if(core.romLoaded) { + if (core.romLoaded) { core.parallel.UpdateScreen(); return; } @@ -420,29 +309,29 @@ void KaizenGui::RenderUI() { } void KaizenGui::LoadROM(const std::string &path) noexcept { - n64::Core& core = n64::Core::GetInstance(); + n64::Core &core = n64::Core::GetInstance(); core.LoadROM(path); const auto gameNameDB = n64::Core::GetMem().rom.gameNameDB; SDL_SetWindowTitle(window.getHandle(), ("Kaizen " KAIZEN_VERSION_STR " - " + gameNameDB).c_str()); } void KaizenGui::run() { - while(!quit) { + while (!quit) { SDL_Event e; while (SDL_PollEvent(&e)) { ImGui_ImplSDL3_ProcessEvent(&e); - switch(e.type) { - case SDL_EVENT_QUIT: - quit = true; - emuThread.Stop(); - break; - case SDL_EVENT_WINDOW_MINIMIZED: - minimized = true; - break; - case SDL_EVENT_WINDOW_RESTORED: - minimized = false; - break; - default: + switch (e.type) { + case SDL_EVENT_QUIT: + quit = true; + emuThread.Stop(); + break; + case SDL_EVENT_WINDOW_MINIMIZED: + minimized = true; + break; + case SDL_EVENT_WINDOW_RESTORED: + minimized = false; + break; + default: } QueryDevices(e); HandleInput(e); @@ -455,6 +344,5 @@ void KaizenGui::run() { } } -void KaizenGui::LoadTAS(const std::string &path) noexcept { - n64::Core::GetInstance().LoadTAS(fs::path(path)); -} \ No newline at end of file +void KaizenGui::LoadTAS(const std::string &path) noexcept { n64::Core::GetInstance().LoadTAS(fs::path(path)); } + diff --git a/src/frontend/KaizenGui.hpp b/src/frontend/KaizenGui.hpp index d55a78d..fef762a 100644 --- a/src/frontend/KaizenGui.hpp +++ b/src/frontend/KaizenGui.hpp @@ -1,16 +1,16 @@ #pragma once #include #include -#include #include #include class KaizenGui final { gui::NativeWindow window; + public: explicit KaizenGui() noexcept; ~KaizenGui(); - + double fpsCounter = -1.0; bool fastForward = false; bool unlockFramerate = false; @@ -19,13 +19,13 @@ public: SettingsWindow settingsWindow; RenderWidget vulkanWidget; EmuThread emuThread; - Debugger debugger; - SDL_Gamepad* gamepad = nullptr; - + SDL_Gamepad *gamepad = nullptr; + void run(); static void LoadTAS(const std::string &path) noexcept; void LoadROM(const std::string &path) noexcept; + private: int width{}, height{}; bool aboutOpen = false; diff --git a/src/frontend/NativeWindow.hpp b/src/frontend/NativeWindow.hpp index 279afcf..50b5261 100644 --- a/src/frontend/NativeWindow.hpp +++ b/src/frontend/NativeWindow.hpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include namespace gui { struct NativeWindow { diff --git a/src/frontend/Settings/CPUSettings.cpp b/src/frontend/Settings/CPUSettings.cpp index 0b7ee07..6b24466 100644 --- a/src/frontend/Settings/CPUSettings.cpp +++ b/src/frontend/Settings/CPUSettings.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include CPUSettings::CPUSettings() { diff --git a/src/frontend/Settings/GeneralSettings.cpp b/src/frontend/Settings/GeneralSettings.cpp index 9fc83af..8df9f8e 100644 --- a/src/frontend/Settings/GeneralSettings.cpp +++ b/src/frontend/Settings/GeneralSettings.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include GeneralSettings::GeneralSettings(gui::NativeWindow& window) : window(window) { savesPath = Options::GetInstance().GetValue("general", "savePath"); diff --git a/src/frontend/Settings/MiscSettings.cpp b/src/frontend/Settings/MiscSettings.cpp new file mode 100644 index 0000000..e1be4c3 --- /dev/null +++ b/src/frontend/Settings/MiscSettings.cpp @@ -0,0 +1,34 @@ +#include +#include +#include +#include + +MiscSettings::MiscSettings() { + currLogLevel = static_cast(Options::GetInstance().GetValue("misc", "logLevel")); +} + +void MiscSettings::render() { + const char* items[] = { + "Trace", "Debug", "Warn", "Info", "Error", "Always", "Panic" + }; + + const char* combo_preview_value = items[selectedLogLevel]; + if (ImGui::BeginCombo("CPU Type", combo_preview_value)) { + for (int n = 0; n < IM_ARRAYSIZE(items); n++) { + const bool is_selected = (selectedLogLevel == n); + if (ImGui::Selectable(items[n], is_selected)) { + selectedLogLevel = n; + modified = true; + } + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + + if(modified) { + Options::GetInstance().SetValue("misc", "logLevel", static_cast(selectedLogLevel)); + } +} \ No newline at end of file diff --git a/src/frontend/Settings/MiscSettings.hpp b/src/frontend/Settings/MiscSettings.hpp new file mode 100644 index 0000000..80e0410 --- /dev/null +++ b/src/frontend/Settings/MiscSettings.hpp @@ -0,0 +1,11 @@ +#pragma once +#include +#include + +struct MiscSettings final : SettingsTab { + void render() override; + explicit MiscSettings(); +private: + Util::LogLevel currLogLevel; + int selectedLogLevel = 4; +}; \ No newline at end of file diff --git a/src/frontend/SettingsWindow.hpp b/src/frontend/SettingsWindow.hpp index dfa7b41..09e4df0 100644 --- a/src/frontend/SettingsWindow.hpp +++ b/src/frontend/SettingsWindow.hpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -10,17 +11,19 @@ class SettingsWindow final { GeneralSettings generalSettings; CPUSettings cpuSettings; AudioSettings audioSettings; + MiscSettings miscSettings; bool applyEnabled = false; std::vector> tabs = { { "General", &generalSettings }, { "CPU", &cpuSettings }, { "Audio", &audioSettings }, + { "Misc", &miscSettings }, }; public: bool isOpen = false; bool render(); - explicit SettingsWindow(gui::NativeWindow& window) : window(window), generalSettings(window) {} + explicit SettingsWindow(gui::NativeWindow& window) : window(window), generalSettings(window), miscSettings() {} [[nodiscard]] float getVolumeL() const { return audioSettings.volumeL / 100.f; } [[nodiscard]] float getVolumeR() const { return audioSettings.volumeR / 100.f; } }; diff --git a/src/utils/ErrorData.hpp b/src/utils/ErrorData.hpp deleted file mode 100644 index 43de503..0000000 --- a/src/utils/ErrorData.hpp +++ /dev/null @@ -1,149 +0,0 @@ -#pragma once -#include -#include -#include -#include - -namespace Util { -struct Error { - struct Severity { - enum { - NONE, - WARN, - NON_FATAL, - UNRECOVERABLE, - } as_enum; - - [[nodiscard]] const char* as_c_str() const { - switch(as_enum) { - case NONE: return ""; - case WARN: return "Warning"; - case NON_FATAL: return "Error"; - case UNRECOVERABLE: return "Unrecoverable Error"; - } - - return "Unknown"; - } - }; - - struct MemoryAccess { - bool is_write; - enum Size { - BYTE = 8, SHORT = 16, WORD = 32, DWORD = 64 - } size; - u32 address; - u64 written_val; - }; - - struct Type { - enum { - SCHEDULER_EOL, - SCHEDULER_UNKNOWN, - UNHANDLED_EXCEPTION, - UNHANDLED_INSTRUCTION, - INVALID_INSTRUCTION_FORMAT, - TLB_LIMIT_EXCEEDED, - TLB_INVALID_ERROR, - TLB_UNHANDLED_ERROR, - TLB_UNHANDLED_MAPPING, - JIT_BRANCH_INSIDE_DELAY_SLOT, - JIT_INVALID_X86_REG_ADDRESSING, - COULD_NOT_SYNC_SAVE_DATA, - SAVE_DATA_IS_CORRUPT_OR_INVALID_SIZE, - MMAP_MAKE_SINK_ERROR, - MEM_INVALID_ACCESS, - MEM_UNHANDLED_ACCESS, - RDP_LIMIT_EXCEEDED, - FLASH_EXECUTE_COMMAND, - PIF_UNHANDLED_CHANNEL, - UNHANDLED_COP0_STATUS_BIT, - COP0_INVALID_ACCESS, - COP0_UNHANDLED_ACCESS, - SYSTEM_DIALOG_ERROR, - TAS_LOAD_ERROR, - ROM_LOAD_ERROR, - SAVE_OPTIONS_ERROR, - DIALOG_CANCELED, - UNKNOWN_CIC_TYPE, - GAME_DB_NOT_MATCHED, - CAPSTONE_ERROR, - } as_enum; - - - [[nodiscard]] const char* as_c_str() const { - switch(as_enum) { - case SCHEDULER_EOL: return "SCHEDULER_EOL"; - case SCHEDULER_UNKNOWN: return "SCHEDULER_UNKNOWN"; - case UNHANDLED_EXCEPTION: return "UNHANDLED_EXCEPTION"; - case UNHANDLED_INSTRUCTION: return "UNHANDLED_INSTRUCTION"; - case INVALID_INSTRUCTION_FORMAT: return "INVALID_INSTRUCTION_FORMAT"; - case TLB_LIMIT_EXCEEDED: return "TLB_LIMIT_EXCEEDED"; - case TLB_INVALID_ERROR: return "TLB_INVALID_ERROR"; - case TLB_UNHANDLED_ERROR: return "TLB_UNHANDLED_ERROR"; - case TLB_UNHANDLED_MAPPING: return "TLB_UNHANDLED_MAPPING"; - case JIT_BRANCH_INSIDE_DELAY_SLOT: return "JIT_BRANCH_INSIDE_DELAY_SLOT"; - case JIT_INVALID_X86_REG_ADDRESSING: return "JIT_INVALID_X86_REG_ADDRESSING"; - case COULD_NOT_SYNC_SAVE_DATA: return "COULD_NOT_SYNC_SAVE_DATA"; - case SAVE_DATA_IS_CORRUPT_OR_INVALID_SIZE: return "SAVE_DATA_IS_CORRUPT_OR_INVALID_SIZE"; - case MMAP_MAKE_SINK_ERROR: return "MMAP_MAKE_SINK_ERROR"; - case MEM_INVALID_ACCESS: return "MEM_INVALID_ACCESS"; - case MEM_UNHANDLED_ACCESS: return "MEM_UNHANDLED_ACCESS"; - case RDP_LIMIT_EXCEEDED: return "RDP_LIMIT_EXCEEDED"; - case FLASH_EXECUTE_COMMAND: return "FLASH_EXECUTE_COMMAND"; - case PIF_UNHANDLED_CHANNEL: return "PIF_UNHANDLED_CHANNEL"; - case UNHANDLED_COP0_STATUS_BIT: return "UNHANDLED_COP0_STATUS_BIT"; - case COP0_INVALID_ACCESS: return "COP0_INVALID_ACCESS"; - case COP0_UNHANDLED_ACCESS: return "COP0_UNHANDLED_ACCESS"; - case SYSTEM_DIALOG_ERROR: return "SYSTEM_DIALOG_ERROR"; - case TAS_LOAD_ERROR: return "TAS_LOAD_ERROR"; - case ROM_LOAD_ERROR: return "ROM_LOAD_ERROR"; - case SAVE_OPTIONS_ERROR: return "SAVE_OPTIONS_ERROR"; - case DIALOG_CANCELED: return "DIALOG_CANCELED"; - case UNKNOWN_CIC_TYPE: return "UNKNOWN_CIC_TYPE"; - case GAME_DB_NOT_MATCHED: return "GAME_DB_NOT_MATCHED"; - case CAPSTONE_ERROR: return "CAPSTONE_ERROR"; - default: return "Unknown"; - } - } - }; - - template - void Throw (const Severity severity, const Type type, const std::optional lastPC, - const std::optional memoryAccess, - const std::format_string fmt, Args... args) { - this->severity = severity; - this->lastPC = lastPC; - this->memoryAccess = memoryAccess; - this->type = type; - err = std::format(fmt, std::forward(args)...); - } - - static Error& GetInstance() { - static Error instance; - return instance; - } - - static std::string& GetError() { return GetInstance().err; } - static Severity& GetSeverity() { return GetInstance().severity; } - static Type& GetType() { return GetInstance().type; } - static std::optional& GetLastPC() { return GetInstance().lastPC; } - static std::optional& GetMemoryAccess() { return GetInstance().memoryAccess; } - static bool IsHandled() { - return GetSeverity().as_enum == Severity::NONE; - } - - static void SetHandled() { - GetSeverity() = {}; - GetError() = ""; - GetType() = {}; - GetLastPC() = {}; - GetMemoryAccess() = {}; - } -private: - std::string err; - Severity severity = {}; - Type type = {}; - std::optional lastPC = {}; - std::optional memoryAccess = {}; -}; -} \ No newline at end of file diff --git a/src/utils/File.hpp b/src/utils/File.hpp index 2e3f114..0ed5df2 100644 --- a/src/utils/File.hpp +++ b/src/utils/File.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include +#include #include #include #include diff --git a/src/utils/Options.cpp b/src/utils/Options.cpp index 8c02bc1..0fb89a0 100644 --- a/src/utils/Options.cpp +++ b/src/utils/Options.cpp @@ -1,4 +1,5 @@ #include +#include template <> void Options::SetValue(const std::string &key, const std::string &field, const std::string &value) { @@ -10,6 +11,11 @@ void Options::SetValue(const std::string &key, const std::string &field, structure[key][field] = std::format("{:.2f}", value); } +template <> +void Options::SetValue(const std::string &key, const std::string &field, const int &value) { + structure[key][field] = std::format("{}", value); +} + template <> void Options::SetValue(const std::string &key, const std::string &field, const bool &value) { structure[key][field] = value ? "true" : "false"; @@ -25,7 +31,36 @@ float Options::GetValue(const std::string &key, const std::string &field) return std::stof(structure[key][field]); } +template<> +int Options::GetValue(const std::string &key, const std::string &field) { + return std::stoi(structure[key][field]); +} + template<> bool Options::GetValue(const std::string &key, const std::string &field) { return structure[key][field] == "true" ? true : false; +} + +Options::Options() : file{"resources/options.ini"} { + auto fileExists = fs::exists("resources/options.ini"); + if(fileExists) { + file.read(structure); + return; + } + + structure["misc"]["logLevel"] = Util::LogLevel::Error; + structure["general"]["savePath"] = "saves"; + fs::create_directory("saves"); + structure["audio"]["volumeL"] = "0.5"; + structure["audio"]["volumeR"] = "0.5"; + structure["audio"]["lock"] = "true"; + structure["cpu"]["type"] = "interpreter"; + + if(!file.generate(structure)) + panic("Couldn't generate settings' INI!"); +} + +void Options::Apply() { + if(!file.write(structure)) + panic("Could not modify options on disk!"); } \ No newline at end of file diff --git a/src/utils/Options.hpp b/src/utils/Options.hpp index 8450a2b..68a4f1e 100644 --- a/src/utils/Options.hpp +++ b/src/utils/Options.hpp @@ -3,28 +3,11 @@ #include #include #include -#include namespace fs = std::filesystem; struct Options { - Options() : file{"resources/options.ini"} { - auto fileExists = fs::exists("resources/options.ini"); - if(fileExists) { - file.read(structure); - return; - } - - structure["general"]["savePath"] = "saves"; - fs::create_directory("saves"); - structure["audio"]["volumeL"] = "0.5"; - structure["audio"]["volumeR"] = "0.5"; - structure["audio"]["lock"] = "true"; - structure["cpu"]["type"] = "interpreter"; - - if(!file.generate(structure)) - panic("Couldn't generate settings' INI!"); - } + Options(); static Options &GetInstance() { static Options instance; @@ -36,10 +19,7 @@ struct Options { template T GetValue(const std::string &key, const std::string &field); - void Apply() { - if(!file.write(structure)) - panic("Could not modify options on disk!"); - } + void Apply(); private: mINI::INIFile file; mINI::INIStructure structure; diff --git a/src/utils/log.hpp b/src/utils/log.hpp index 966fd6f..dd96415 100644 --- a/src/utils/log.hpp +++ b/src/utils/log.hpp @@ -2,30 +2,21 @@ #include #include #include -#if !defined(NDEBUG) && !defined(_WIN32) -#include -#endif +#include namespace Util { -enum LogLevel : u8 { Trace, Debug, Warn, Info, Error, Always }; - -#ifndef NDEBUG -static constexpr auto globalLogLevel = Debug; -#else -static constexpr auto globalLogLevel = Info; -#endif +enum LogLevel : u8 { Trace, Debug, Warn, Info, Error, Always, Panic}; template void print(const std::format_string fmt, Args... args) { - if (messageType >= globalLogLevel) { - if (messageType <= Debug) { -#ifndef NDEBUG - std::println(fmt, std::forward(args)...); -#endif - } else { - std::println(fmt, std::forward(args)...); + if (messageType == Panic) { + std::println(fmt, std::forward(args)...); + exit(-1); + } + + if (messageType >= Options::GetInstance().GetValue("misc", "logLevel")) { + std::println(fmt, std::forward(args)...); } - } } #define panic(fmt, ...) do { Util::print("[FATAL] " fmt __VA_OPT__(,) __VA_ARGS__); exit(-1); } while(0)