Rework logs a little bit to allow choosing the log level from settings
This commit is contained in:
+3
-3
@@ -167,11 +167,11 @@ add_executable(kaizen
|
|||||||
src/frontend/Settings/CPUSettings.cpp
|
src/frontend/Settings/CPUSettings.cpp
|
||||||
src/frontend/Settings/AudioSettings.hpp
|
src/frontend/Settings/AudioSettings.hpp
|
||||||
src/frontend/Settings/AudioSettings.cpp
|
src/frontend/Settings/AudioSettings.cpp
|
||||||
|
src/frontend/Settings/MiscSettings.hpp
|
||||||
|
src/frontend/Settings/MiscSettings.cpp
|
||||||
src/frontend/NativeWindow.hpp
|
src/frontend/NativeWindow.hpp
|
||||||
src/utils/Options.cpp
|
src/utils/Options.cpp
|
||||||
src/utils/File.cpp
|
src/utils/File.cpp)
|
||||||
src/frontend/Debugger.hpp
|
|
||||||
src/frontend/Debugger.cpp)
|
|
||||||
|
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
|
|||||||
+1
-15
@@ -62,9 +62,7 @@ void Core::LoadROM(const std::string &rom_) {
|
|||||||
romLoaded = true;
|
romLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Core::StepCPU() {
|
u32 Core::StepCPU() { return cpu->Step() + regs.PopStalledCycles(); }
|
||||||
return cpu->Step() + regs.PopStalledCycles();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::StepRSP(const u32 cpuCycles) {
|
void Core::StepRSP(const u32 cpuCycles) {
|
||||||
MMIO &mmio = mem->mmio;
|
MMIO &mmio = mem->mmio;
|
||||||
@@ -105,23 +103,14 @@ void Core::Run(const float volumeL, const float volumeR) {
|
|||||||
const u32 taken = StepCPU();
|
const u32 taken = StepCPU();
|
||||||
cycles += taken;
|
cycles += taken;
|
||||||
|
|
||||||
if((broken = breakpoints.contains(regs.nextPC)))
|
|
||||||
break;
|
|
||||||
|
|
||||||
StepRSP(taken);
|
StepRSP(taken);
|
||||||
frameCycles += taken;
|
frameCycles += taken;
|
||||||
Scheduler::GetInstance().Tick(taken);
|
Scheduler::GetInstance().Tick(taken);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(broken)
|
|
||||||
break;
|
|
||||||
|
|
||||||
cycles -= mmio.vi.cyclesPerHalfline;
|
cycles -= mmio.vi.cyclesPerHalfline;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(broken)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) {
|
if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) {
|
||||||
mmio.mi.InterruptRaise(MI::Interrupt::VI);
|
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);
|
mmio.ai.Step(frameCycles, volumeL, volumeR);
|
||||||
Scheduler::GetInstance().Tick(frameCycles);
|
Scheduler::GetInstance().Tick(frameCycles);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(broken)
|
|
||||||
pause = true;
|
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include <Netplay.hpp>
|
#include <Netplay.hpp>
|
||||||
#include <PIF.hpp>
|
#include <PIF.hpp>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
|
|
||||||
namespace Netplay {}
|
namespace Netplay {}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <ircolib/mem_access.hpp>
|
#include <ircolib/mem_access.hpp>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
|
|
||||||
namespace Util {
|
namespace Util {
|
||||||
#define Z64 0x80371200
|
#define Z64 0x80371200
|
||||||
@@ -13,7 +13,7 @@ FORCE_INLINE void SwapN64Rom(std::vector<u8> &rom, u32 endianness) {
|
|||||||
if (endianness >> 24 != 0x80) {
|
if (endianness >> 24 != 0x80) {
|
||||||
if ((endianness & 0xFF) != 0x80) {
|
if ((endianness & 0xFF) != 0x80) {
|
||||||
if ((endianness >> 16 & 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;
|
return;
|
||||||
} else {
|
} else {
|
||||||
altByteShift = 12;
|
altByteShift = 12;
|
||||||
@@ -42,7 +42,7 @@ FORCE_INLINE void SwapN64Rom(std::vector<u8> &rom, u32 endianness) {
|
|||||||
ircolib::SwapBuffer<u32>(rom);
|
ircolib::SwapBuffer<u32>(rom);
|
||||||
break;
|
break;
|
||||||
default:
|
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
|
} // namespace Util
|
||||||
|
|||||||
@@ -40,10 +40,10 @@ void Scheduler::Tick(const u64 t) {
|
|||||||
case NONE:
|
case NONE:
|
||||||
break;
|
break;
|
||||||
case IMPOSSIBLE:
|
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;
|
return;
|
||||||
default:
|
default:
|
||||||
Util::Error::GetInstance().Throw({Util::Error::Severity::UNRECOVERABLE}, {Util::Error::Type::ROM_LOAD_ERROR}, {}, {}, "Unknown scheduler event type {}", static_cast<int>(type));
|
panic("Unknown scheduler event type {}", static_cast<int>(type));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
events.pop();
|
events.pop();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
enum EventType { NONE, PI_BUS_WRITE_COMPLETE, PI_DMA_COMPLETE, SI_DMA, IMPOSSIBLE };
|
enum EventType { NONE, PI_BUS_WRITE_COMPLETE, PI_DMA_COMPLETE, SI_DMA, IMPOSSIBLE };
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <Mem.hpp>
|
#include <Mem.hpp>
|
||||||
#include <Registers.hpp>
|
#include <Registers.hpp>
|
||||||
#include <Disassembler.hpp>
|
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
struct BaseCPU {
|
struct BaseCPU {
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
#include <Disassembler.hpp>
|
|
||||||
#include <Core.hpp>
|
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
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<u32>(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;
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <capstone/capstone.h>
|
|
||||||
#include <utils/log.hpp>
|
|
||||||
#include <ircolib/mem_access.hpp>
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
struct Disassembler {
|
|
||||||
struct DisassemblyResult {
|
|
||||||
bool success = false;
|
|
||||||
std::string full;
|
|
||||||
u64 address;
|
|
||||||
std::string mnemonic;
|
|
||||||
struct Operand {
|
|
||||||
u32 color;
|
|
||||||
std::string str;
|
|
||||||
};
|
|
||||||
std::array<Operand, 3> 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<cs_mode>((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{};
|
|
||||||
};
|
|
||||||
@@ -47,9 +47,7 @@ std::optional<u32> JIT::FetchInstruction(s64 vaddr) {
|
|||||||
/*regs.cop0.HandleTLBException(blockPC);
|
/*regs.cop0.HandleTLBException(blockPC);
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, blockPC);
|
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, blockPC);
|
||||||
return 1;*/
|
return 1;*/
|
||||||
Util::Error::GetInstance().Throw(
|
error("[JIT]: Unhandled exception ADL due to unaligned PC virtual value!");
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_EXCEPTION}, blockPC, {},
|
|
||||||
"[JIT]: Unhandled exception ADL due to unaligned PC virtual value!");
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,17 +55,13 @@ std::optional<u32> JIT::FetchInstruction(s64 vaddr) {
|
|||||||
/*regs.cop0.HandleTLBException(blockPC);
|
/*regs.cop0.HandleTLBException(blockPC);
|
||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, blockPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, blockPC);
|
||||||
return 1;*/
|
return 1;*/
|
||||||
Util::Error::GetInstance().Throw(
|
error("[JIT]: Unhandled exception TLB exception {} when retrieving PC physical address!",
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_EXCEPTION}, blockPC, {},
|
|
||||||
"[JIT]: Unhandled exception TLB exception {} when retrieving PC physical address!",
|
|
||||||
static_cast<int>(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD)));
|
static_cast<int>(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD)));
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 instr = Core::GetMem().Read<u32>(paddr);
|
const u32 instr = Core::GetMem().Read<u32>(paddr);
|
||||||
|
|
||||||
info("{}", Disassembler::GetInstance().DisassembleSimple(paddr, instr).full);
|
|
||||||
|
|
||||||
return instr;
|
return instr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,9 +112,7 @@ u32 JIT::Step() {
|
|||||||
/*regs.cop0.HandleTLBException(blockPC);
|
/*regs.cop0.HandleTLBException(blockPC);
|
||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, blockPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, blockPC);
|
||||||
return 1;*/
|
return 1;*/
|
||||||
Util::Error::GetInstance().Throw({Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_EXCEPTION},
|
error("[JIT]: Unhandled exception TLB exception {} when retrieving PC physical address!",
|
||||||
blockPC, {},
|
|
||||||
"[JIT]: Unhandled exception TLB exception {} when retrieving PC physical address!",
|
|
||||||
static_cast<int>(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD)));
|
static_cast<int>(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD)));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -177,9 +169,7 @@ u32 JIT::Step() {
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if(InstrEndsBlock(delay_instruction.value())) {
|
if(InstrEndsBlock(delay_instruction.value())) {
|
||||||
Util::Error::GetInstance().Throw(
|
error("[JIT]: Unhandled case of branch from delay slot!");
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::JIT_BRANCH_INSIDE_DELAY_SLOT},
|
|
||||||
blockPC, {}, "[JIT]: Unhandled case of branch from delay slot!");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+14
-61
@@ -47,6 +47,7 @@ struct JIT final : BaseCPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void InvalidateBlock(u32);
|
void InvalidateBlock(u32);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend struct Cop1;
|
friend struct Cop1;
|
||||||
friend struct Registers;
|
friend struct Registers;
|
||||||
@@ -73,9 +74,7 @@ private:
|
|||||||
return code.qword[code.rbp + GPR_OFFSET(index)];
|
return code.qword[code.rbp + GPR_OFFSET(index)];
|
||||||
}
|
}
|
||||||
|
|
||||||
Util::Error::GetInstance().Throw(
|
panic("[JIT]: Invalid register addressing mode {}!", sizeof(T));
|
||||||
{Util::Error::Severity::UNRECOVERABLE}, {Util::Error::Type::JIT_INVALID_X86_REG_ADDRESSING},
|
|
||||||
blockPC, {}, "[JIT]: Invalid register addressing mode {}!", sizeof(T));
|
|
||||||
return Xbyak::Address{0};
|
return Xbyak::Address{0};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,57 +203,17 @@ private:
|
|||||||
void mthi(Instruction);
|
void mthi(Instruction);
|
||||||
void mtlo(Instruction);
|
void mtlo(Instruction);
|
||||||
void nor(Instruction);
|
void nor(Instruction);
|
||||||
void sb(const Instruction) {
|
void sb(const Instruction) { panic("[JIT]: Unhandled 'sb' @ blockPC:{:016X}!", blockPC); }
|
||||||
Util::Error::GetInstance().Throw(
|
void sc(const Instruction) { panic("[JIT]: Unhandled 'sc' @ blockPC:{:016X}!", blockPC); }
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
void scd(const Instruction) { panic("[JIT]: Unhandled 'scd' @ blockPC:{:016X}!", blockPC); }
|
||||||
blockPC, {}, "[JIT]: Unhandled 'sb'!");
|
void sd(const Instruction) { panic("[JIT]: Unhandled 'sd' @ blockPC:{:016X}!", blockPC); }
|
||||||
}
|
void sdc1(const Instruction) { panic("[JIT]: Unhandled 'sdc1' @ blockPC:{:016X}!", blockPC); }
|
||||||
void sc(const Instruction) {
|
void sdl(const Instruction) { panic("[JIT]: Unhandled 'sdl' @ blockPC:{:016X}!", blockPC); }
|
||||||
Util::Error::GetInstance().Throw(
|
void sdr(const Instruction) { panic("[JIT]: Unhandled 'sdr' @ blockPC:{:016X}!", blockPC); }
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
void sh(const Instruction) { panic("[JIT]: Unhandled 'sh' @ blockPC:{:016X}!", blockPC); }
|
||||||
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 sw(Instruction);
|
void sw(Instruction);
|
||||||
void swl(const Instruction) {
|
void swl(const Instruction) { panic("[JIT]: Unhandled 'swl' @ blockPC:{:016X}!", blockPC); }
|
||||||
Util::Error::GetInstance().Throw(
|
void swr(const Instruction) { panic("[JIT]: Unhandled 'swr' @ blockPC:{:016X}!", blockPC); }
|
||||||
{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 slti(Instruction);
|
void slti(Instruction);
|
||||||
void sltiu(Instruction);
|
void sltiu(Instruction);
|
||||||
void slt(Instruction);
|
void slt(Instruction);
|
||||||
@@ -264,19 +223,13 @@ private:
|
|||||||
void sub(Instruction);
|
void sub(Instruction);
|
||||||
void subu(Instruction);
|
void subu(Instruction);
|
||||||
void swc1(const Instruction) {
|
void swc1(const Instruction) {
|
||||||
Util::Error::GetInstance().Throw(
|
panic("[JIT]: Unhandled 'swc1' @ blockPC:{:016X}!", blockPC);
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::JIT_BRANCH_INSIDE_DELAY_SLOT},
|
|
||||||
blockPC, {}, "[JIT]: Unhandled case of branch from delay slot!");
|
|
||||||
}
|
}
|
||||||
void sra(Instruction);
|
void sra(Instruction);
|
||||||
void srav(Instruction);
|
void srav(Instruction);
|
||||||
void srl(Instruction);
|
void srl(Instruction);
|
||||||
void srlv(Instruction);
|
void srlv(Instruction);
|
||||||
void trap(bool) {
|
void trap(bool) { panic("[JIT]: Unhandled 'trap' @ blockPC:{:016X}!", blockPC); }
|
||||||
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 or_(Instruction);
|
void or_(Instruction);
|
||||||
void ori(Instruction);
|
void ori(Instruction);
|
||||||
void xor_(Instruction);
|
void xor_(Instruction);
|
||||||
|
|||||||
+95
-64
@@ -19,10 +19,7 @@ void Mem::Reset() {
|
|||||||
std::error_code error;
|
std::error_code error;
|
||||||
saveData.sync(error);
|
saveData.sync(error);
|
||||||
if (error) {
|
if (error) {
|
||||||
Util::Error::GetInstance().Throw(
|
warn("[Mem]: Could not sync save data!");
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::COULD_NOT_SYNC_SAVE_DATA},
|
|
||||||
{}, {}, "[Mem]: Could not sync save data!");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
saveData.unmap();
|
saveData.unmap();
|
||||||
}
|
}
|
||||||
@@ -40,10 +37,7 @@ void Mem::LoadSRAM(SaveType save_type, fs::path path) {
|
|||||||
if (saveData.is_mapped()) {
|
if (saveData.is_mapped()) {
|
||||||
saveData.sync(error);
|
saveData.sync(error);
|
||||||
if (error) {
|
if (error) {
|
||||||
Util::Error::GetInstance().Throw(
|
warn(R"([Mem]: Could not sync save data stored @ "{}")", sramPath);
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::COULD_NOT_SYNC_SAVE_DATA},
|
|
||||||
{}, {}, R"([Mem]: Could not sync save data stored @ "{}")", sramPath);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
saveData.unmap();
|
saveData.unmap();
|
||||||
}
|
}
|
||||||
@@ -55,17 +49,13 @@ void Mem::LoadSRAM(SaveType save_type, fs::path path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sramVec.size() != SRAM_SIZE) {
|
if (sramVec.size() != SRAM_SIZE) {
|
||||||
Util::Error::GetInstance().Throw(
|
panic("[Mem]: Save data is corrupt or has unexpected size! (it's {} KiB)", sramVec.size() / 1024);
|
||||||
{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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveData = mio::make_mmap_sink(sramPath, error);
|
saveData = mio::make_mmap_sink(sramPath, error);
|
||||||
if (error) {
|
if (error) {
|
||||||
Util::Error::GetInstance().Throw(
|
warn(R"([Mem]: Could not create file sink for save data @ "{}")", sramPath);
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::MMAP_MAKE_SINK_ERROR},
|
|
||||||
{}, {}, R"([Mem]: Could not create file sink for save data @ "{}")", sramPath);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,13 +138,15 @@ u8 Mem::Read(const u32 paddr) {
|
|||||||
n64::Registers ®s = n64::Core::GetRegs();
|
n64::Registers ®s = n64::Core::GetRegs();
|
||||||
const SI &si = mmio.si;
|
const SI &si = mmio.si;
|
||||||
|
|
||||||
if(ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) return mmio.rdp.ReadRDRAM<u8>(paddr);
|
if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END))
|
||||||
|
return mmio.rdp.ReadRDRAM<u8>(paddr);
|
||||||
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
||||||
const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||||
return src[BYTE_ADDRESS(paddr & 0xfff)];
|
return src[BYTE_ADDRESS(paddr & 0xfff)];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) return mmio.pi.BusRead<u8, false>(paddr);
|
if (ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2))
|
||||||
|
return mmio.pi.BusRead<u8, false>(paddr);
|
||||||
if (ircolib::IsInsideRange(paddr, AI_REGION_START, AI_REGION_END)) {
|
if (ircolib::IsInsideRange(paddr, AI_REGION_START, AI_REGION_END)) {
|
||||||
const u32 w = mmio.ai.Read(paddr & ~3);
|
const u32 w = mmio.ai.Read(paddr & ~3);
|
||||||
const int offs = 3 - (paddr & 3);
|
const int offs = 3 - (paddr & 3);
|
||||||
@@ -163,22 +155,21 @@ u8 Mem::Read(const u32 paddr) {
|
|||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
||||||
ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2)) {
|
ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2)) {
|
||||||
Util::Error::GetInstance().Throw(
|
warn("8-bit read access from MMIO @ {:08X}", paddr);
|
||||||
{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");
|
|
||||||
return 0;
|
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_ROM_REGION_START, PIF_ROM_REGION_END))
|
||||||
if(ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) return si.pif.ram[paddr - PIF_RAM_REGION_START];
|
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
|
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_2, UNUSED_END_2) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) return 0;
|
ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4))
|
||||||
|
return 0;
|
||||||
|
|
||||||
Util::Error::GetInstance().Throw(
|
warn("8-bit read access in unhandled region @ {:08X}", paddr);
|
||||||
{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");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,25 +178,31 @@ u16 Mem::Read(const u32 paddr) {
|
|||||||
n64::Registers ®s = n64::Core::GetRegs();
|
n64::Registers ®s = n64::Core::GetRegs();
|
||||||
const SI &si = mmio.si;
|
const SI &si = mmio.si;
|
||||||
|
|
||||||
if(ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) return mmio.rdp.ReadRDRAM<u16>(paddr);
|
if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END))
|
||||||
|
return mmio.rdp.ReadRDRAM<u16>(paddr);
|
||||||
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
||||||
const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||||
return ircolib::ReadAccess<u16>(src, HALF_ADDRESS(paddr & 0xfff));
|
return ircolib::ReadAccess<u16>(src, HALF_ADDRESS(paddr & 0xfff));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) return mmio.pi.BusRead<u16, false>(paddr);
|
if (ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2))
|
||||||
|
return mmio.pi.BusRead<u16, false>(paddr);
|
||||||
if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
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);
|
ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2))
|
||||||
if(ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END)) return ircolib::ReadAccess<u16>(si.pif.bootrom, HALF_ADDRESS(paddr) - PIF_ROM_REGION_START);
|
return mmio.Read(paddr);
|
||||||
if(ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) return std::byteswap(ircolib::ReadAccess<u16>(si.pif.ram, paddr - PIF_RAM_REGION_START));
|
if (ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END))
|
||||||
|
return ircolib::ReadAccess<u16>(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<u16>(si.pif.ram, paddr - PIF_RAM_REGION_START));
|
||||||
if (ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused
|
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_2, UNUSED_END_2) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) return 0;
|
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(
|
warn("16-bit read access in unhandled region @ {:08X}", paddr);
|
||||||
{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");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,26 +211,32 @@ u32 Mem::Read(const u32 paddr) {
|
|||||||
n64::Registers ®s = n64::Core::GetRegs();
|
n64::Registers ®s = n64::Core::GetRegs();
|
||||||
const SI &si = mmio.si;
|
const SI &si = mmio.si;
|
||||||
|
|
||||||
if(ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) return mmio.rdp.ReadRDRAM<u32>(paddr);
|
if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END))
|
||||||
|
return mmio.rdp.ReadRDRAM<u32>(paddr);
|
||||||
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
||||||
const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||||
return ircolib::ReadAccess<u32>(src, paddr & 0xfff);
|
return ircolib::ReadAccess<u32>(src, paddr & 0xfff);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) return mmio.pi.BusRead<u32, false>(paddr);
|
if (ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2))
|
||||||
|
return mmio.pi.BusRead<u32, false>(paddr);
|
||||||
if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
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);
|
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<u32>(si.pif.bootrom, paddr - PIF_ROM_REGION_START);
|
if (ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END))
|
||||||
if(ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) return std::byteswap(ircolib::ReadAccess<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START));
|
return ircolib::ReadAccess<u32>(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<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START));
|
||||||
if (ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused
|
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_2, UNUSED_END_2) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) return 0;
|
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(
|
warn("32-bit read access in unhandled region @ {:08X}", paddr);
|
||||||
{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");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,26 +245,32 @@ u64 Mem::Read(const u32 paddr) {
|
|||||||
n64::Registers ®s = n64::Core::GetRegs();
|
n64::Registers ®s = n64::Core::GetRegs();
|
||||||
const SI &si = mmio.si;
|
const SI &si = mmio.si;
|
||||||
|
|
||||||
if(ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) return mmio.rdp.ReadRDRAM<u64>(paddr);
|
if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END))
|
||||||
|
return mmio.rdp.ReadRDRAM<u64>(paddr);
|
||||||
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
||||||
const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||||
return ircolib::ReadAccess<u64>(src, paddr & 0xfff);
|
return ircolib::ReadAccess<u64>(src, paddr & 0xfff);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2)) return mmio.pi.BusRead<u64, false>(paddr);
|
if (ircolib::IsInsideRange(paddr, CART_REGION_START_2_1, CART_REGION_END_1_2))
|
||||||
|
return mmio.pi.BusRead<u64, false>(paddr);
|
||||||
if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
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);
|
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<u64>(si.pif.bootrom, paddr - PIF_ROM_REGION_START);
|
if (ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END))
|
||||||
if(ircolib::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) return std::byteswap(ircolib::ReadAccess<u64>(si.pif.ram, paddr - PIF_RAM_REGION_START));
|
return ircolib::ReadAccess<u64>(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<u64>(si.pif.ram, paddr - PIF_RAM_REGION_START));
|
||||||
if (ircolib::IsInsideRange(paddr, UNUSED_START_1, UNUSED_END_1) || // unused
|
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_2, UNUSED_END_2) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) return 0;
|
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(
|
warn("64-bit read access in unhandled region @ {:08X}", paddr);
|
||||||
{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");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,7 +279,10 @@ void Mem::WriteInterpreter<u8>(u32 paddr, u32 val) {
|
|||||||
n64::Registers ®s = n64::Core::GetRegs();
|
n64::Registers ®s = n64::Core::GetRegs();
|
||||||
SI &si = mmio.si;
|
SI &si = mmio.si;
|
||||||
|
|
||||||
if(ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) { mmio.rdp.WriteRDRAM<u8>(paddr, val); return; }
|
if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) {
|
||||||
|
mmio.rdp.WriteRDRAM<u8>(paddr, val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
||||||
val = val << (8 * (3 - (paddr & 3)));
|
val = val << (8 * (3 - (paddr & 3)));
|
||||||
auto &dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
auto &dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||||
@@ -286,7 +298,8 @@ void Mem::WriteInterpreter<u8>(u32 paddr, u32 val) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
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<u8>!");
|
ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2))
|
||||||
|
panic("MMIO Write<u8>!");
|
||||||
|
|
||||||
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)));
|
val = val << (8 * (3 - (paddr & 3)));
|
||||||
@@ -300,7 +313,8 @@ void Mem::WriteInterpreter<u8>(u32 paddr, u32 val) {
|
|||||||
ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
||||||
ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) ||
|
ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) return;
|
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);
|
panic("Unimplemented 8-bit write at address {:08X} with value {:02X} (PC = {:016X})", paddr, val, (u64)regs.pc);
|
||||||
}
|
}
|
||||||
@@ -324,7 +338,10 @@ void Mem::WriteInterpreter<u16>(u32 paddr, u32 val) {
|
|||||||
n64::Registers ®s = n64::Core::GetRegs();
|
n64::Registers ®s = n64::Core::GetRegs();
|
||||||
SI &si = mmio.si;
|
SI &si = mmio.si;
|
||||||
|
|
||||||
if(ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) { mmio.rdp.WriteRDRAM<u16>(paddr, val); return; }
|
if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) {
|
||||||
|
mmio.rdp.WriteRDRAM<u16>(paddr, val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
||||||
val = val << (16 * !(paddr & 2));
|
val = val << (16 * !(paddr & 2));
|
||||||
auto &dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
auto &dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||||
@@ -340,7 +357,8 @@ void Mem::WriteInterpreter<u16>(u32 paddr, u32 val) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
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<u16>!");
|
ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2))
|
||||||
|
panic("MMIO Write<u16>!");
|
||||||
|
|
||||||
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));
|
val = val << (16 * !(paddr & 2));
|
||||||
@@ -354,7 +372,8 @@ void Mem::WriteInterpreter<u16>(u32 paddr, u32 val) {
|
|||||||
ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
||||||
ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) ||
|
ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) return;
|
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);
|
panic("Unimplemented 16-bit write at address {:08X} with value {:04X} (PC = {:016X})", paddr, val, (u64)regs.pc);
|
||||||
}
|
}
|
||||||
@@ -378,7 +397,10 @@ void Mem::WriteInterpreter<u32>(const u32 paddr, const u32 val) {
|
|||||||
n64::Registers ®s = n64::Core::GetRegs();
|
n64::Registers ®s = n64::Core::GetRegs();
|
||||||
SI &si = mmio.si;
|
SI &si = mmio.si;
|
||||||
|
|
||||||
if(ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) { mmio.rdp.WriteRDRAM<u32>(paddr, val); return; }
|
if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) {
|
||||||
|
mmio.rdp.WriteRDRAM<u32>(paddr, val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
||||||
auto &dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
auto &dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||||
ircolib::WriteAccess<u32>(dest, paddr & 0xfff, val);
|
ircolib::WriteAccess<u32>(dest, paddr & 0xfff, val);
|
||||||
@@ -392,7 +414,10 @@ void Mem::WriteInterpreter<u32>(const u32 paddr, const u32 val) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
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; }
|
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<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START, std::byteswap(val));
|
ircolib::WriteAccess<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START, std::byteswap(val));
|
||||||
@@ -404,7 +429,8 @@ void Mem::WriteInterpreter<u32>(const u32 paddr, const u32 val) {
|
|||||||
ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
||||||
ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) ||
|
ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) return;
|
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);
|
panic("Unimplemented 32-bit write at address {:08X} with value {:08X} (PC = {:016X})", paddr, val, (u64)regs.pc);
|
||||||
}
|
}
|
||||||
@@ -437,7 +463,10 @@ void Mem::WriteInterpreter(const u32 paddr, u64 val) {
|
|||||||
n64::Registers ®s = n64::Core::GetRegs();
|
n64::Registers ®s = n64::Core::GetRegs();
|
||||||
SI &si = mmio.si;
|
SI &si = mmio.si;
|
||||||
|
|
||||||
if(ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) { mmio.rdp.WriteRDRAM<u64>(paddr, val); return; }
|
if (ircolib::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) {
|
||||||
|
mmio.rdp.WriteRDRAM<u64>(paddr, val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
if (ircolib::IsInsideRange(paddr, DMEM_REGION_START, RSP_MEM_REGION_END)) {
|
||||||
auto &dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
auto &dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||||
val >>= 32;
|
val >>= 32;
|
||||||
@@ -452,7 +481,8 @@ void Mem::WriteInterpreter(const u32 paddr, u64 val) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ircolib::IsInsideRange(paddr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
|
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<u64>!");
|
ircolib::IsInsideRange(paddr, MMIO_REGION_START_2, MMIO_REGION_END_2))
|
||||||
|
panic("MMIO Write<u64>!");
|
||||||
|
|
||||||
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<u64>(si.pif.ram, paddr - PIF_RAM_REGION_START, std::byteswap(val));
|
ircolib::WriteAccess<u64>(si.pif.ram, paddr - PIF_RAM_REGION_START, std::byteswap(val));
|
||||||
@@ -464,7 +494,8 @@ void Mem::WriteInterpreter(const u32 paddr, u64 val) {
|
|||||||
ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
ircolib::IsInsideRange(paddr, UNUSED_START_2, UNUSED_END_2) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
ircolib::IsInsideRange(paddr, UNUSED_START_3, UNUSED_END_3) ||
|
||||||
ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) ||
|
ircolib::IsInsideRange(paddr, PIF_ROM_REGION_START, PIF_ROM_REGION_END) ||
|
||||||
ircolib::IsInsideRange(paddr, UNUSED_START_4, UNUSED_END_4)) return;
|
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);
|
panic("Unimplemented 64-bit write at address {:08X} with value {:016X} (PC = {:016X})", paddr, val, (u64)regs.pc);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include <backend/MemoryRegions.hpp>
|
#include <backend/MemoryRegions.hpp>
|
||||||
#include <backend/core/MMIO.hpp>
|
#include <backend/core/MMIO.hpp>
|
||||||
#include <common.hpp>
|
#include <common.hpp>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
@@ -124,6 +124,7 @@ struct Mem {
|
|||||||
ROM rom;
|
ROM rom;
|
||||||
SaveType saveType = SAVE_NONE;
|
SaveType saveType = SAVE_NONE;
|
||||||
Flash flash;
|
Flash flash;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend struct SI;
|
friend struct SI;
|
||||||
friend struct PI;
|
friend struct PI;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
#include <parallel-rdp/ParallelRDPWrapper.hpp>
|
#include <parallel-rdp/ParallelRDPWrapper.hpp>
|
||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
RSP::RSP() { Reset(); }
|
RSP::RSP() { Reset(); }
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
#include <Instruction.hpp>
|
#include <Instruction.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
AI::AI() { Reset(); }
|
AI::AI() { Reset(); }
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <Audio.hpp>
|
#include <Audio.hpp>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include <core/mmio/MI.hpp>
|
#include <core/mmio/MI.hpp>
|
||||||
#include <core/registers/Registers.hpp>
|
#include <core/registers/Registers.hpp>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
|
|
||||||
#define MI_VERSION_REG 0x02020102
|
#define MI_VERSION_REG 0x02020102
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#include <Scheduler.hpp>
|
#include <Scheduler.hpp>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <core/mmio/PI.hpp>
|
#include <core/mmio/PI.hpp>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
PI::PI() { Reset(); }
|
PI::PI() { Reset(); }
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cic_nus_6105/n64_cic_nus_6105.hpp>
|
#include <cic_nus_6105/n64_cic_nus_6105.hpp>
|
||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
#include <Options.hpp>
|
#include <Options.hpp>
|
||||||
|
|
||||||
#define MEMPAK_SIZE 32768
|
#define MEMPAK_SIZE 32768
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include <Netplay.hpp>
|
#include <Netplay.hpp>
|
||||||
#include <PIF.hpp>
|
#include <PIF.hpp>
|
||||||
#include <PIF/MupenMovie.hpp>
|
#include <PIF/MupenMovie.hpp>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
void PIF::InitDevices(SaveType saveType) {
|
void PIF::InitDevices(SaveType saveType) {
|
||||||
|
|||||||
@@ -80,22 +80,24 @@ void MupenMovie::Reset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE void LogController(const n64::Controller &controller) {
|
FORCE_INLINE void LogController(const n64::Controller &controller) {
|
||||||
debug("c_right: {}", controller.cRight);
|
trace("-- TAS CONTROLLER DATA --");
|
||||||
debug("c_left: {}", controller.cLeft);
|
trace("c_right: {}", controller.cRight);
|
||||||
debug("c_down: {}", controller.cDown);
|
trace("c_left: {}", controller.cLeft);
|
||||||
debug("c_up: {}", controller.cUp);
|
trace("c_down: {}", controller.cDown);
|
||||||
debug("r: {}", controller.r);
|
trace("c_up: {}", controller.cUp);
|
||||||
debug("l: {}", controller.l);
|
trace("r: {}", controller.r);
|
||||||
debug("dp_right: {}", controller.dpRight);
|
trace("l: {}", controller.l);
|
||||||
debug("dp_left: {}", controller.dpLeft);
|
trace("dp_right: {}", controller.dpRight);
|
||||||
debug("dp_down: {}", controller.dpDown);
|
trace("dp_left: {}", controller.dpLeft);
|
||||||
debug("dp_up: {}", controller.dpUp);
|
trace("dp_down: {}", controller.dpDown);
|
||||||
debug("z: {}", controller.z);
|
trace("dp_up: {}", controller.dpUp);
|
||||||
debug("b: {}", controller.b);
|
trace("z: {}", controller.z);
|
||||||
debug("a: {}", controller.a);
|
trace("b: {}", controller.b);
|
||||||
debug("start: {}", controller.start);
|
trace("a: {}", controller.a);
|
||||||
debug("joy_x: {}", controller.joyX);
|
trace("start: {}", controller.start);
|
||||||
debug("joy_y: {}", controller.joyY);
|
trace("joy_x: {}", controller.joyX);
|
||||||
|
trace("joy_y: {}", controller.joyY);
|
||||||
|
trace("-- TAS CONTROLLER DATA --");
|
||||||
}
|
}
|
||||||
|
|
||||||
n64::Controller MupenMovie::NextInputs() {
|
n64::Controller MupenMovie::NextInputs() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <core/mmio/RI.hpp>
|
#include <core/mmio/RI.hpp>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
RI::RI() { Reset(); }
|
RI::RI() { Reset(); }
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
VI::VI() { Reset(); }
|
VI::VI() { Reset(); }
|
||||||
@@ -54,9 +54,7 @@ u32 VI::Read(const u32 paddr) const {
|
|||||||
return yscale.raw;
|
return yscale.raw;
|
||||||
default: {
|
default: {
|
||||||
n64::Registers& regs = n64::Core::GetRegs();
|
n64::Registers& regs = n64::Core::GetRegs();
|
||||||
Util::Error::GetInstance().Throw(
|
error("32-bit read access on unhandled VI register @ {:08X}, pc: {:016X}", paddr, (u64)regs.oldPC);
|
||||||
{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");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,8 +118,10 @@ void VI::Write(const u32 paddr, const u32 val) {
|
|||||||
break;
|
break;
|
||||||
case 0x0440003C:
|
case 0x0440003C:
|
||||||
break;
|
break;
|
||||||
default:
|
default: {
|
||||||
panic("Unimplemented VI[{:08X}] write ({:08X})", paddr, val);
|
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
|
} // namespace n64
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
Cop0::Cop0() { Reset(); }
|
Cop0::Cop0() { Reset(); }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <common.hpp>
|
#include <common.hpp>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <Instruction.hpp>
|
#include <Instruction.hpp>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
Cop1::Cop1() { Reset(); }
|
Cop1::Cop1() { Reset(); }
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
void RSP::special(const Instruction instr) {
|
void RSP::special(const Instruction instr) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
#include <RCP.hpp>
|
#include <RCP.hpp>
|
||||||
#include <RSQ.hpp>
|
#include <RSQ.hpp>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
FORCE_INLINE bool AcquireSemaphore(RSP &rsp) {
|
FORCE_INLINE bool AcquireSemaphore(RSP &rsp) {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <types.hpp>
|
#include <types.hpp>
|
||||||
#include <ErrorData.hpp>
|
|
||||||
|
|
||||||
#define FORCE_INLINE inline __attribute__((always_inline))
|
#define FORCE_INLINE inline __attribute__((always_inline))
|
||||||
|
|
||||||
|
|||||||
@@ -1,249 +0,0 @@
|
|||||||
#include <Debugger.hpp>
|
|
||||||
#include <imgui.h>
|
|
||||||
|
|
||||||
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<u32>(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<u64>(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<u64>(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;
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <backend/Core.hpp>
|
|
||||||
|
|
||||||
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<Column, 3> 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();
|
|
||||||
};
|
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <imgui_impl_sdl3.h>
|
#include <imgui_impl_sdl3.h>
|
||||||
#include <imgui_impl_vulkan.h>
|
#include <imgui_impl_vulkan.h>
|
||||||
#include <utils/log.hpp>
|
#include <utils/Log.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace gui {
|
namespace gui {
|
||||||
|
|||||||
+28
-140
@@ -5,7 +5,9 @@
|
|||||||
#include <ImGuiImpl/StatusBar.hpp>
|
#include <ImGuiImpl/StatusBar.hpp>
|
||||||
#include <resources/gamecontrollerdb.h>
|
#include <resources/gamecontrollerdb.h>
|
||||||
|
|
||||||
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());
|
gui::Initialize(n64::Core::GetInstance().parallel.wsi, window.getHandle());
|
||||||
SDL_InitSubSystem(SDL_INIT_GAMEPAD);
|
SDL_InitSubSystem(SDL_INIT_GAMEPAD);
|
||||||
|
|
||||||
@@ -33,7 +35,8 @@ void KaizenGui::QueryDevices(const SDL_Event &event) {
|
|||||||
if (gamepad)
|
if (gamepad)
|
||||||
SDL_CloseGamepad(gamepad);
|
SDL_CloseGamepad(gamepad);
|
||||||
break;
|
break;
|
||||||
default: break;
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +48,8 @@ void KaizenGui::HandleInput(const SDL_Event &event) {
|
|||||||
if (!gamepad)
|
if (!gamepad)
|
||||||
break;
|
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::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::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::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::CLeft, SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHTX) <= -127);
|
||||||
@@ -134,37 +138,24 @@ void KaizenGui::HandleInput(const SDL_Event &event) {
|
|||||||
|
|
||||||
float x = 0, y = 0;
|
float x = 0, y = 0;
|
||||||
|
|
||||||
if (keys[SDL_SCANCODE_UP]) y = 86;
|
if (keys[SDL_SCANCODE_UP])
|
||||||
if (keys[SDL_SCANCODE_DOWN]) y = -86;
|
y = 86;
|
||||||
if (keys[SDL_SCANCODE_LEFT]) x = -86;
|
if (keys[SDL_SCANCODE_DOWN])
|
||||||
if (keys[SDL_SCANCODE_RIGHT]) x = 86;
|
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::X, x);
|
||||||
pif.UpdateAxis(0, n64::Controller::Axis::Y, y);
|
pif.UpdateAxis(0, n64::Controller::Axis::Y, y);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default: break;
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::optional<s64>, std::optional<Util::Error::MemoryAccess>> RenderErrorMessageDetails() {
|
|
||||||
auto lastPC = Util::Error::GetLastPC();
|
|
||||||
if(lastPC.has_value()) {
|
|
||||||
ImGui::Text("%s", std::format("Occurred @ PC = {:016X}", Util::Error::GetLastPC().value()).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
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<u8>(size), address,
|
|
||||||
is_write ? std::format(" (value = 0x{:X})", written_val) : "")
|
|
||||||
.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
return {lastPC, memoryAccess};
|
|
||||||
}
|
|
||||||
|
|
||||||
void KaizenGui::RenderUI() {
|
void KaizenGui::RenderUI() {
|
||||||
n64::Core &core = n64::Core::GetInstance();
|
n64::Core &core = n64::Core::GetInstance();
|
||||||
gui::StartFrame();
|
gui::StartFrame();
|
||||||
@@ -200,10 +191,6 @@ void KaizenGui::RenderUI() {
|
|||||||
core.parallel.SetFramerateUnlocked(unlockFramerate);
|
core.parallel.SetFramerateUnlocked(unlockFramerate);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ImGui::MenuItem("Open Debugger")) {
|
|
||||||
debugger.Open();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
if (ImGui::MenuItem("Options")) {
|
if (ImGui::MenuItem("Options")) {
|
||||||
@@ -221,10 +208,6 @@ void KaizenGui::RenderUI() {
|
|||||||
ImGui::EndMainMenuBar();
|
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);
|
ImGui::OpenPopup("Settings", ImGuiPopupFlags_None);
|
||||||
}
|
}
|
||||||
@@ -234,7 +217,6 @@ void KaizenGui::RenderUI() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
settingsWindow.render();
|
settingsWindow.render();
|
||||||
debugger.render();
|
|
||||||
|
|
||||||
const ImVec2 center = ImGui::GetMainViewport()->GetCenter();
|
const ImVec2 center = ImGui::GetMainViewport()->GetCenter();
|
||||||
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
||||||
@@ -255,111 +237,14 @@ void KaizenGui::RenderUI() {
|
|||||||
ImGui::EndPopup();
|
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::Text("FPS: %.2f", ImGui::GetIO().Framerate);
|
||||||
ImGui::EndMainStatusBar();
|
ImGui::EndMainStatusBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldDisplaySpinner) {
|
if (shouldDisplaySpinner) {
|
||||||
ImGui::SetNextWindowPos({static_cast<float>(width) * 0.5f, static_cast<float>(height) * 0.5f}, 0, ImVec2(0.5f, 0.5f));
|
ImGui::SetNextWindowPos({static_cast<float>(width) * 0.5f, static_cast<float>(height) * 0.5f}, 0,
|
||||||
|
ImVec2(0.5f, 0.5f));
|
||||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, IM_COL32_BLACK_TRANS);
|
ImGui::PushStyleColor(ImGuiCol_WindowBg, IM_COL32_BLACK_TRANS);
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
||||||
|
|
||||||
@@ -386,8 +271,11 @@ void KaizenGui::RenderUI() {
|
|||||||
|
|
||||||
if (fileDialogOpen) {
|
if (fileDialogOpen) {
|
||||||
fileDialogOpen = false;
|
fileDialogOpen = false;
|
||||||
constexpr SDL_DialogFileFilter filters[] = {{"All files", "*"}, {"Nintendo 64 executable", "n64;z64;v64"}, {"Nintendo 64 executable archive", "rar;tar;zip;7z"}};
|
constexpr SDL_DialogFileFilter filters[] = {{"All files", "*"},
|
||||||
SDL_ShowOpenFileDialog([](void *userdata, const char * const *filelist, int) {
|
{"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<KaizenGui *>(userdata);
|
auto kaizen = static_cast<KaizenGui *>(userdata);
|
||||||
|
|
||||||
if (!filelist) {
|
if (!filelist) {
|
||||||
@@ -405,7 +293,8 @@ void KaizenGui::RenderUI() {
|
|||||||
|
|
||||||
std::thread fileWorker(&KaizenGui::FileWorker, kaizen);
|
std::thread fileWorker(&KaizenGui::FileWorker, kaizen);
|
||||||
fileWorker.detach();
|
fileWorker.detach();
|
||||||
}, this, window.getHandle(), filters, 3, nullptr, false);
|
},
|
||||||
|
this, window.getHandle(), filters, 3, nullptr, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (minimized)
|
if (minimized)
|
||||||
@@ -455,6 +344,5 @@ void KaizenGui::run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KaizenGui::LoadTAS(const std::string &path) noexcept {
|
void KaizenGui::LoadTAS(const std::string &path) noexcept { n64::Core::GetInstance().LoadTAS(fs::path(path)); }
|
||||||
n64::Core::GetInstance().LoadTAS(fs::path(path));
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <RenderWidget.hpp>
|
#include <RenderWidget.hpp>
|
||||||
#include <NativeWindow.hpp>
|
#include <NativeWindow.hpp>
|
||||||
#include <Debugger.hpp>
|
|
||||||
#include <EmuThread.hpp>
|
#include <EmuThread.hpp>
|
||||||
#include <SDL3/SDL_gamepad.h>
|
#include <SDL3/SDL_gamepad.h>
|
||||||
|
|
||||||
class KaizenGui final {
|
class KaizenGui final {
|
||||||
gui::NativeWindow window;
|
gui::NativeWindow window;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit KaizenGui() noexcept;
|
explicit KaizenGui() noexcept;
|
||||||
~KaizenGui();
|
~KaizenGui();
|
||||||
@@ -19,13 +19,13 @@ public:
|
|||||||
SettingsWindow settingsWindow;
|
SettingsWindow settingsWindow;
|
||||||
RenderWidget vulkanWidget;
|
RenderWidget vulkanWidget;
|
||||||
EmuThread emuThread;
|
EmuThread emuThread;
|
||||||
Debugger debugger;
|
|
||||||
|
|
||||||
SDL_Gamepad *gamepad = nullptr;
|
SDL_Gamepad *gamepad = nullptr;
|
||||||
|
|
||||||
void run();
|
void run();
|
||||||
static void LoadTAS(const std::string &path) noexcept;
|
static void LoadTAS(const std::string &path) noexcept;
|
||||||
void LoadROM(const std::string &path) noexcept;
|
void LoadROM(const std::string &path) noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int width{}, height{};
|
int width{}, height{};
|
||||||
bool aboutOpen = false;
|
bool aboutOpen = false;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <volk.h>
|
#include <volk.h>
|
||||||
#include <utils/log.hpp>
|
#include <utils/Log.hpp>
|
||||||
|
|
||||||
namespace gui {
|
namespace gui {
|
||||||
struct NativeWindow {
|
struct NativeWindow {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include <CPUSettings.hpp>
|
#include <CPUSettings.hpp>
|
||||||
#include <Options.hpp>
|
#include <Options.hpp>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
|
||||||
CPUSettings::CPUSettings() {
|
CPUSettings::CPUSettings() {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include <GeneralSettings.hpp>
|
#include <GeneralSettings.hpp>
|
||||||
#include <Options.hpp>
|
#include <Options.hpp>
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
|
|
||||||
GeneralSettings::GeneralSettings(gui::NativeWindow& window) : window(window) {
|
GeneralSettings::GeneralSettings(gui::NativeWindow& window) : window(window) {
|
||||||
savesPath = Options::GetInstance().GetValue<std::string>("general", "savePath");
|
savesPath = Options::GetInstance().GetValue<std::string>("general", "savePath");
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#include <MiscSettings.hpp>
|
||||||
|
#include <Options.hpp>
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <Log.hpp>
|
||||||
|
|
||||||
|
MiscSettings::MiscSettings() {
|
||||||
|
currLogLevel = static_cast<Util::LogLevel>(Options::GetInstance().GetValue<int>("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<int>("misc", "logLevel", static_cast<int>(selectedLogLevel));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <SettingsTab.hpp>
|
||||||
|
#include <Log.hpp>
|
||||||
|
|
||||||
|
struct MiscSettings final : SettingsTab {
|
||||||
|
void render() override;
|
||||||
|
explicit MiscSettings();
|
||||||
|
private:
|
||||||
|
Util::LogLevel currLogLevel;
|
||||||
|
int selectedLogLevel = 4;
|
||||||
|
};
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <AudioSettings.hpp>
|
#include <AudioSettings.hpp>
|
||||||
#include <CPUSettings.hpp>
|
#include <CPUSettings.hpp>
|
||||||
#include <GeneralSettings.hpp>
|
#include <GeneralSettings.hpp>
|
||||||
|
#include <MiscSettings.hpp>
|
||||||
#include <NativeWindow.hpp>
|
#include <NativeWindow.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -10,17 +11,19 @@ class SettingsWindow final {
|
|||||||
GeneralSettings generalSettings;
|
GeneralSettings generalSettings;
|
||||||
CPUSettings cpuSettings;
|
CPUSettings cpuSettings;
|
||||||
AudioSettings audioSettings;
|
AudioSettings audioSettings;
|
||||||
|
MiscSettings miscSettings;
|
||||||
bool applyEnabled = false;
|
bool applyEnabled = false;
|
||||||
|
|
||||||
std::vector<std::pair<std::string, SettingsTab*>> tabs = {
|
std::vector<std::pair<std::string, SettingsTab*>> tabs = {
|
||||||
{ "General", &generalSettings },
|
{ "General", &generalSettings },
|
||||||
{ "CPU", &cpuSettings },
|
{ "CPU", &cpuSettings },
|
||||||
{ "Audio", &audioSettings },
|
{ "Audio", &audioSettings },
|
||||||
|
{ "Misc", &miscSettings },
|
||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
bool isOpen = false;
|
bool isOpen = false;
|
||||||
bool render();
|
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 getVolumeL() const { return audioSettings.volumeL / 100.f; }
|
||||||
[[nodiscard]] float getVolumeR() const { return audioSettings.volumeR / 100.f; }
|
[[nodiscard]] float getVolumeR() const { return audioSettings.volumeR / 100.f; }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,149 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <string>
|
|
||||||
#include <types.hpp>
|
|
||||||
#include <format>
|
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
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 <class... Args>
|
|
||||||
void Throw (const Severity severity, const Type type, const std::optional<u64> lastPC,
|
|
||||||
const std::optional<MemoryAccess> memoryAccess,
|
|
||||||
const std::format_string<Args...> fmt, Args... args) {
|
|
||||||
this->severity = severity;
|
|
||||||
this->lastPC = lastPC;
|
|
||||||
this->memoryAccess = memoryAccess;
|
|
||||||
this->type = type;
|
|
||||||
err = std::format(fmt, std::forward<Args>(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<s64>& GetLastPC() { return GetInstance().lastPC; }
|
|
||||||
static std::optional<MemoryAccess>& 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<s64> lastPC = {};
|
|
||||||
std::optional<MemoryAccess> memoryAccess = {};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <log.hpp>
|
#include <Log.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <ircolib/file.hpp>
|
#include <ircolib/file.hpp>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <Options.hpp>
|
#include <Options.hpp>
|
||||||
|
#include <Log.hpp>
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void Options::SetValue<std::string>(const std::string &key, const std::string &field, const std::string &value) {
|
void Options::SetValue<std::string>(const std::string &key, const std::string &field, const std::string &value) {
|
||||||
@@ -10,6 +11,11 @@ void Options::SetValue<float>(const std::string &key, const std::string &field,
|
|||||||
structure[key][field] = std::format("{:.2f}", value);
|
structure[key][field] = std::format("{:.2f}", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void Options::SetValue<int>(const std::string &key, const std::string &field, const int &value) {
|
||||||
|
structure[key][field] = std::format("{}", value);
|
||||||
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void Options::SetValue<bool>(const std::string &key, const std::string &field, const bool &value) {
|
void Options::SetValue<bool>(const std::string &key, const std::string &field, const bool &value) {
|
||||||
structure[key][field] = value ? "true" : "false";
|
structure[key][field] = value ? "true" : "false";
|
||||||
@@ -25,7 +31,36 @@ float Options::GetValue<float>(const std::string &key, const std::string &field)
|
|||||||
return std::stof(structure[key][field]);
|
return std::stof(structure[key][field]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
int Options::GetValue<int>(const std::string &key, const std::string &field) {
|
||||||
|
return std::stoi(structure[key][field]);
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
bool Options::GetValue<bool>(const std::string &key, const std::string &field) {
|
bool Options::GetValue<bool>(const std::string &key, const std::string &field) {
|
||||||
return structure[key][field] == "true" ? true : false;
|
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!");
|
||||||
|
}
|
||||||
+2
-22
@@ -3,28 +3,11 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <common.hpp>
|
#include <common.hpp>
|
||||||
#include <mini/ini.h>
|
#include <mini/ini.h>
|
||||||
#include <log.hpp>
|
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
struct Options {
|
struct Options {
|
||||||
Options() : file{"resources/options.ini"} {
|
Options();
|
||||||
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!");
|
|
||||||
}
|
|
||||||
|
|
||||||
static Options &GetInstance() {
|
static Options &GetInstance() {
|
||||||
static Options instance;
|
static Options instance;
|
||||||
@@ -36,10 +19,7 @@ struct Options {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
T GetValue(const std::string &key, const std::string &field);
|
T GetValue(const std::string &key, const std::string &field);
|
||||||
|
|
||||||
void Apply() {
|
void Apply();
|
||||||
if(!file.write(structure))
|
|
||||||
panic("Could not modify options on disk!");
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
mINI::INIFile file;
|
mINI::INIFile file;
|
||||||
mINI::INIStructure structure;
|
mINI::INIStructure structure;
|
||||||
|
|||||||
+7
-16
@@ -2,29 +2,20 @@
|
|||||||
#include <common.hpp>
|
#include <common.hpp>
|
||||||
#include <print>
|
#include <print>
|
||||||
#include <string>
|
#include <string>
|
||||||
#if !defined(NDEBUG) && !defined(_WIN32)
|
#include <Options.hpp>
|
||||||
#include <dlfcn.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Util {
|
namespace Util {
|
||||||
enum LogLevel : u8 { Trace, Debug, Warn, Info, Error, Always };
|
enum LogLevel : u8 { Trace, Debug, Warn, Info, Error, Always, Panic};
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
static constexpr auto globalLogLevel = Debug;
|
|
||||||
#else
|
|
||||||
static constexpr auto globalLogLevel = Info;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <LogLevel messageType = Info, class... Args>
|
template <LogLevel messageType = Info, class... Args>
|
||||||
void print(const std::format_string<Args...> fmt, Args... args) {
|
void print(const std::format_string<Args...> fmt, Args... args) {
|
||||||
if (messageType >= globalLogLevel) {
|
if (messageType == Panic) {
|
||||||
if (messageType <= Debug) {
|
|
||||||
#ifndef NDEBUG
|
|
||||||
std::println(fmt, std::forward<Args>(args)...);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
std::println(fmt, std::forward<Args>(args)...);
|
std::println(fmt, std::forward<Args>(args)...);
|
||||||
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (messageType >= Options::GetInstance().GetValue<int>("misc", "logLevel")) {
|
||||||
|
std::println(fmt, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user