Huge refactor: Make Core a singleton

This commit is contained in:
irisz64
2025-07-29 11:08:05 +02:00
parent e0e887ce90
commit 3061334004
56 changed files with 426 additions and 594 deletions

View File

@@ -1,15 +1,21 @@
#include <Core.hpp>
#include <ParallelRDPWrapper.hpp>
#include <Scheduler.hpp>
#include <Options.hpp>
namespace n64 {
Core::Core(CPUType cpuType) {
switch (cpuType) {
case Interpreted: cpu = std::make_unique<Interpreter>(parallel); break;
Core::Core() {
auto cpuType = Options::GetInstance().GetValue<std::string>("cpu", "type");
if (cpuType == "interpreter") {
cpu = std::make_unique<Interpreter>(parallel);
} else if(cpuType == "jit") {
#ifndef __aarch64__
case DynamicRecompiler: cpu = std::make_unique<JIT>(parallel); break;
cpu = std::make_unique<JIT>(parallel);
#else
panic("JIT currently unsupported on aarch64");
#endif
default: panic("Unimplemented CPU type\n");
} else {
panic("Unimplemented CPU type");
}
}
@@ -31,7 +37,7 @@ void Core::LoadROM(const std::string &rom_) {
const bool isArchive = std::ranges::any_of(archive_types, [&extension](const auto &e) { return e == extension; });
cpu->GetMem().LoadROM(isArchive, rom);
GameDB::match(cpu->GetMem());
GameDB::match();
if (cpu->GetMem().rom.gameNameDB.empty()) {
cpu->GetMem().rom.gameNameDB = fs::path(rom).stem().string();
}
@@ -82,7 +88,7 @@ void Core::Run(float volumeL, float volumeR) {
cycles += taken;
frameCycles += taken;
Scheduler::GetInstance().Tick(taken, mem);
Scheduler::GetInstance().Tick(taken);
}
cycles -= mmio.vi.cyclesPerHalfline;
@@ -93,32 +99,7 @@ void Core::Run(float volumeL, float volumeR) {
}
mmio.ai.Step(frameCycles, volumeL, volumeR);
Scheduler::GetInstance().Tick(frameCycles, mem);
Scheduler::GetInstance().Tick(frameCycles);
}
}
void Core::Serialize() {
auto sMEM = cpu->GetMem().Serialize();
auto sCPU = cpu->Serialize();
auto sVER = std::vector<u8>{KAIZEN_VERSION >> 8, KAIZEN_VERSION >> 4, KAIZEN_VERSION & 0xFF};
memSize = sMEM.size();
cpuSize = sCPU.size();
verSize = sVER.size();
serialized[slot].insert(serialized[slot].begin(), sVER.begin(), sVER.end());
serialized[slot].insert(serialized[slot].end(), sMEM.begin(), sMEM.end());
serialized[slot].insert(serialized[slot].end(), sCPU.begin(), sCPU.end());
}
void Core::Deserialize() {
std::vector dVER(serialized[slot].begin(), serialized[slot].begin() + verSize);
if (dVER[0] != (KAIZEN_VERSION >> 8) || dVER[1] != (KAIZEN_VERSION >> 4) || dVER[2] != (KAIZEN_VERSION & 0xFF)) {
panic("PROBLEMI!");
}
cpu->GetMem().Deserialize(
std::vector(serialized[slot].begin() + verSize, serialized[slot].begin() + verSize + memSize));
cpu->Deserialize(
std::vector(serialized[slot].begin() + verSize + memSize, serialized[slot].begin() + verSize + memSize + cpuSize));
serialized[slot].erase(serialized[slot].begin(), serialized[slot].end());
}
} // namespace n64

View File

@@ -11,13 +11,18 @@ struct Core {
DynamicRecompiler,
CachedInterpreter
};
explicit Core(CPUType);
explicit Core();
static Core& GetInstance() {
static Core instance;
return instance;
}
void Stop();
void LoadROM(const std::string &);
[[nodiscard]] bool LoadTAS(const fs::path &) const;
void Run(float volumeL, float volumeR);
void Serialize();
void Deserialize();
void TogglePause() { pause = !pause; }
[[nodiscard]] VI &GetVI() const { return cpu->GetMem().mmio.vi; }
@@ -28,7 +33,6 @@ struct Core {
bool romLoaded = false;
std::string rom;
std::unique_ptr<BaseCPU> cpu;
std::vector<u8> serialized[10]{};
size_t memSize{}, cpuSize{}, verSize{};
int slot = 0;
ParallelRDP parallel;

View File

@@ -1,8 +1,9 @@
#include <GameDB.hpp>
#include <Mem.hpp>
#include <Core.hpp>
namespace n64 {
void GameDB::match(Mem &mem) {
void GameDB::match() {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
const ROM &rom = mem.rom;
for (const auto &[code, regions, saveType, name] : gamedb) {
const bool matches_code = code == rom.code;

View File

@@ -4,7 +4,6 @@
namespace n64 {
enum SaveType { SAVE_NONE, SAVE_EEPROM_4k, SAVE_EEPROM_16k, SAVE_FLASH_1m, SAVE_SRAM_256k };
struct Mem;
struct GameDBEntry {
std::string code;
std::string regions;
@@ -13,7 +12,7 @@ struct GameDBEntry {
};
namespace GameDB {
void match(Mem &mem);
void match();
}
static const GameDBEntry gamedb[] = {

View File

@@ -1,6 +1,5 @@
#include <Scheduler.hpp>
#include <core/Mem.hpp>
#include <core/registers/Registers.hpp>
#include <Core.hpp>
void Scheduler::EnqueueRelative(const u64 t, const EventType type) { EnqueueAbsolute(t + ticks, type); }
@@ -19,7 +18,9 @@ u64 Scheduler::Remove(const EventType eventType) const {
return 0;
}
void Scheduler::Tick(const u64 t, n64::Mem &mem) {
void Scheduler::Tick(const u64 t) {
n64::Core& core = n64::Core::GetInstance();
n64::Mem& mem = core.cpu->GetMem();
ticks += t;
n64::MI &mi = mem.mmio.mi;
n64::SI &si = mem.mmio.si;

View File

@@ -3,11 +3,6 @@
#include <log.hpp>
#include <queue>
namespace n64 {
struct Mem;
struct Registers;
} // namespace n64
enum EventType { NONE, PI_BUS_WRITE_COMPLETE, PI_DMA_COMPLETE, SI_DMA, IMPOSSIBLE };
struct Event {
@@ -43,7 +38,7 @@ struct Scheduler {
void EnqueueRelative(u64, EventType);
void EnqueueAbsolute(u64, EventType);
[[nodiscard]] u64 Remove(EventType) const;
void Tick(u64 t, n64::Mem &);
void Tick(u64 t);
IterableEvents events{};
u64 ticks = 0;

View File

@@ -8,8 +8,6 @@ struct BaseCPU {
virtual ~BaseCPU() = default;
virtual int Step() = 0;
virtual void Reset() = 0;
virtual std::vector<u8> Serialize() = 0;
virtual void Deserialize(const std::vector<u8> &) = 0;
virtual Mem &GetMem() = 0;
virtual Registers &GetRegs() = 0;
[[nodiscard]] virtual Disassembler::DisassemblyResult Disassemble(u32) = 0;

View File

@@ -1,7 +1,7 @@
#include <Core.hpp>
namespace n64 {
Interpreter::Interpreter(ParallelRDP &parallel) : mem(regs, parallel) {}
Interpreter::Interpreter(ParallelRDP &parallel) {}
bool Interpreter::ShouldServiceInterrupt() const {
const bool interrupts_pending = (regs.cop0.status.im & regs.cop0.cause.interruptPending) != 0;
@@ -26,7 +26,7 @@ Disassembler::DisassemblyResult Interpreter::Disassemble(const u32 address) {
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
return {};
}
return Disassembler::GetInstance().Disassemble(address, mem.Read<u32>(regs, paddr));
return Disassembler::GetInstance().Disassemble(address, mem.Read<u32>(paddr));
}
int Interpreter::Step() {
@@ -48,7 +48,7 @@ int Interpreter::Step() {
return 1;
}
const u32 instruction = mem.Read<u32>(regs, paddr);
const u32 instruction = mem.Read<u32>(paddr);
if (ShouldServiceInterrupt()) {
regs.cop0.FireException(ExceptionCode::Interrupt, 0, regs.pc);
@@ -63,16 +63,4 @@ int Interpreter::Step() {
return 1;
}
std::vector<u8> Interpreter::Serialize() {
std::vector<u8> res{};
res.resize(sizeof(Registers));
memcpy(res.data(), &regs, sizeof(Registers));
return res;
}
void Interpreter::Deserialize(const std::vector<u8> &data) { memcpy(&regs, data.data(), sizeof(Registers)); }
} // namespace n64

View File

@@ -31,8 +31,6 @@ private:
(((!regs.cop0.is64BitAddressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0))
bool ShouldServiceInterrupt() const;
void CheckCompareInterrupt();
std::vector<u8> Serialize() override;
void Deserialize(const std::vector<u8> &) override;
void cop2Decode(u32);
void special(u32);

View File

@@ -3,7 +3,7 @@
namespace n64 {
#ifndef __aarch64__
JIT::JIT(ParallelRDP &parallel) : regs(this), mem(regs, parallel, this) {
JIT::JIT(ParallelRDP &parallel) : regs(this), mem(this) {
blockCache.resize(kUpperSize);
if (cs_open(CS_ARCH_MIPS, static_cast<cs_mode>(CS_MODE_MIPS64 | CS_MODE_BIG_ENDIAN), &disassemblerMips) !=
CS_ERR_OK) {
@@ -58,7 +58,7 @@ u32 JIT::FetchInstruction() {
static_cast<int>(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD)), static_cast<u64>(blockPC));
}
return mem.Read<u32>(regs, paddr);
return mem.Read<u32>(paddr);
}
int JIT::Step() {
@@ -181,17 +181,5 @@ int JIT::Step() {
// panic("");
return block();
}
std::vector<u8> JIT::Serialize() {
std::vector<u8> res{};
res.resize(sizeof(Registers));
memcpy(res.data(), &regs, sizeof(Registers));
return res;
}
void JIT::Deserialize(const std::vector<u8> &data) { memcpy(&regs, data.data(), sizeof(Registers)); }
#endif
} // namespace n64

View File

@@ -145,8 +145,6 @@ private:
[[nodiscard]] bool ShouldServiceInterrupt() const;
void CheckCompareInterrupt();
std::vector<u8> Serialize() override;
void Deserialize(const std::vector<u8> &) override;
u32 FetchInstruction();
void Emit(u32);

View File

@@ -66,101 +66,4 @@ void MMIO::Write(const u32 addr, const u32 val) {
panic("Unhandled mmio write at addr {:08X} with val {:08X}", addr, val);
}
}
std::vector<u8> MMIO::Serialize() {
std::vector<u8> res{};
auto sPIF = si.pif.Serialize();
constexpr u32 rdpSize = sizeof(DPC) + 0xFFFFF + RDRAM_SIZE;
res.resize(rdpSize + sizeof(RSP) + sizeof(MI) + sizeof(VI) + sizeof(SI) + sizeof(PI) + sizeof(RI) + sizeof(AI) +
sizeof(u32) * 2 + sizeof(SIStatus));
u32 index = 0;
memcpy(res.data(), &rsp, sizeof(RSP));
index += sizeof(RSP);
memcpy(res.data() + index, &rdp.dpc, sizeof(DPC));
index += sizeof(DPC);
memcpy(res.data() + index, rdp.cmd_buf.data(), RDP::COMMAND_BUFFER_SIZE);
index += 0xFFFFF;
std::ranges::copy(rdp.rdram, res.begin() + index);
index += RDRAM_SIZE;
memcpy(res.data() + index, &mi, sizeof(MI));
index += sizeof(MI);
memcpy(res.data() + index, &vi, sizeof(VI));
index += sizeof(VI);
memcpy(res.data() + index, &ai.dmaEnable, sizeof(ai.dmaEnable));
index += sizeof(ai.dmaEnable);
memcpy(res.data() + index, &ai.dacRate, sizeof(ai.dacRate));
index += sizeof(ai.dacRate);
memcpy(res.data() + index, &ai.bitrate, sizeof(ai.bitrate));
index += sizeof(ai.bitrate);
memcpy(res.data() + index, &ai.dmaCount, sizeof(ai.dmaCount));
index += sizeof(ai.dmaCount);
memcpy(res.data() + index, &ai.dmaLen, sizeof(ai.dmaLen));
index += sizeof(ai.dmaLen);
memcpy(res.data() + index, &ai.dmaAddr, sizeof(ai.dmaAddr));
index += sizeof(ai.dmaAddr);
memcpy(res.data() + index, &ai.dmaAddrCarry, sizeof(ai.dmaAddrCarry));
index += sizeof(ai.dmaAddrCarry);
memcpy(res.data() + index, &ai.cycles, sizeof(ai.cycles));
index += sizeof(ai.cycles);
memcpy(res.data() + index, &ai.dac, sizeof(ai.dac));
index += sizeof(ai.dac);
memcpy(res.data() + index, &pi, sizeof(PI));
index += sizeof(PI);
memcpy(res.data() + index, &ri, sizeof(RI));
index += sizeof(RI);
memcpy(res.data() + index, &si.dramAddr, sizeof(u32));
index += sizeof(u32);
memcpy(res.data() + index, &si.pifAddr, sizeof(u32));
index += sizeof(u32);
memcpy(res.data() + index, &si.status, sizeof(SIStatus));
res.insert(res.end(), sPIF.begin(), sPIF.end());
return res;
}
void MMIO::Deserialize(const std::vector<u8> &data) {
u32 index = 0;
memcpy(&rsp, data.data(), sizeof(RSP));
index += sizeof(RSP);
memcpy(&rdp.dpc, data.data() + index, sizeof(DPC));
index += sizeof(DPC);
memcpy(rdp.cmd_buf.data(), data.data() + index, RDP::COMMAND_BUFFER_SIZE);
index += 0xFFFFF;
std::copy_n(data.begin() + index, RDRAM_SIZE, rdp.rdram.begin());
index += RDRAM_SIZE;
memcpy(&mi, data.data() + index, sizeof(MI));
index += sizeof(MI);
memcpy(&vi, data.data() + index, sizeof(VI));
index += sizeof(VI);
memcpy(&ai.dmaEnable, data.data() + index, sizeof(ai.dmaEnable));
index += sizeof(ai.dmaEnable);
memcpy(&ai.dacRate, data.data() + index, sizeof(ai.dacRate));
index += sizeof(ai.dacRate);
memcpy(&ai.bitrate, data.data() + index, sizeof(ai.bitrate));
index += sizeof(ai.bitrate);
memcpy(&ai.dmaCount, data.data() + index, sizeof(ai.dmaCount));
index += sizeof(ai.dmaCount);
memcpy(&ai.dmaLen, data.data() + index, sizeof(ai.dmaLen));
index += sizeof(ai.dmaLen);
memcpy(&ai.dmaAddr, data.data() + index, sizeof(ai.dmaAddr));
index += sizeof(ai.dmaAddr);
memcpy(&ai.dmaAddrCarry, data.data() + index, sizeof(ai.dmaAddrCarry));
index += sizeof(ai.dmaAddrCarry);
memcpy(&ai.cycles, data.data() + index, sizeof(ai.cycles));
index += sizeof(ai.cycles);
memcpy(&ai.dac, data.data() + index, sizeof(ai.dac));
index += sizeof(ai.dac);
memcpy(&pi, data.data() + index, sizeof(PI));
index += sizeof(PI);
memcpy(&ri, data.data() + index, sizeof(RI));
index += sizeof(RI);
memcpy(&si.dramAddr, data.data() + index, sizeof(u32));
index += sizeof(u32);
memcpy(&si.pifAddr, data.data() + index, sizeof(u32));
index += sizeof(u32);
memcpy(&si.status, data.data() + index, sizeof(SIStatus));
}
} // namespace n64

View File

@@ -15,10 +15,7 @@ struct Mem;
struct Registers;
struct MMIO {
MMIO(Mem &mem, Registers &regs, ParallelRDP &parallel) :
vi(mem, regs), mi(regs), ai(mem, regs), pi(mem, regs), si(mem, regs), rsp(mem, regs), rdp(mem, parallel) {
Reset();
}
MMIO() { Reset(); }
void Reset();
VI vi;
@@ -32,7 +29,5 @@ struct MMIO {
u32 Read(u32);
void Write(u32, u32);
std::vector<u8> Serialize();
void Deserialize(const std::vector<u8> &);
};
} // namespace n64

View File

@@ -2,12 +2,12 @@
#include <Mem.hpp>
#include <backend/RomHelpers.hpp>
#include <cassert>
#include <core/JIT.hpp>
#include <Core.hpp>
#include <unarr.h>
#include <Options.hpp>
namespace n64 {
Mem::Mem(Registers &regs, ParallelRDP &parallel, JIT *jit) : mmio(*this, regs, parallel), flash(saveData), jit(jit) {
Mem::Mem(JIT *jit) : flash(saveData), jit(jit) {
rom.cart.resize(CART_SIZE);
std::ranges::fill(rom.cart, 0);
}
@@ -187,7 +187,8 @@ void Mem::LoadROM(const bool isArchive, const std::string &filename) {
}
template <>
u8 Mem::Read(Registers &regs, const u32 paddr) {
u8 Mem::Read(const u32 paddr) {
n64::Registers& regs = n64::Core::GetInstance().cpu->GetRegs();
const SI &si = mmio.si;
if(Util::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) return mmio.rdp.ReadRDRAM<u8>(paddr);
@@ -218,7 +219,8 @@ u8 Mem::Read(Registers &regs, const u32 paddr) {
}
template <>
u16 Mem::Read(Registers &regs, const u32 paddr) {
u16 Mem::Read(const u32 paddr) {
n64::Registers& regs = n64::Core::GetInstance().cpu->GetRegs();
const SI &si = mmio.si;
if(Util::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) return mmio.rdp.ReadRDRAM<u16>(paddr);
@@ -242,7 +244,8 @@ u16 Mem::Read(Registers &regs, const u32 paddr) {
}
template <>
u32 Mem::Read(Registers &regs, const u32 paddr) {
u32 Mem::Read(const u32 paddr) {
n64::Registers& regs = n64::Core::GetInstance().cpu->GetRegs();
const SI &si = mmio.si;
if(Util::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) return mmio.rdp.ReadRDRAM<u32>(paddr);
@@ -267,7 +270,8 @@ u32 Mem::Read(Registers &regs, const u32 paddr) {
}
template <>
u64 Mem::Read(Registers &regs, const u32 paddr) {
u64 Mem::Read(const u32 paddr) {
n64::Registers& regs = n64::Core::GetInstance().cpu->GetRegs();
const SI &si = mmio.si;
if(Util::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) return mmio.rdp.ReadRDRAM<u64>(paddr);
@@ -292,7 +296,8 @@ u64 Mem::Read(Registers &regs, const u32 paddr) {
}
template <>
void Mem::WriteInterpreter<u8>(Registers &regs, u32 paddr, u32 val) {
void Mem::WriteInterpreter<u8>(u32 paddr, u32 val) {
n64::Registers& regs = n64::Core::GetInstance().cpu->GetRegs();
SI &si = mmio.si;
if(Util::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) { mmio.rdp.WriteRDRAM<u8>(paddr, val); return; }
@@ -317,7 +322,7 @@ void Mem::WriteInterpreter<u8>(Registers &regs, u32 paddr, u32 val) {
val = val << (8 * (3 - (paddr & 3)));
paddr = (paddr - PIF_RAM_REGION_START) & ~3;
Util::WriteAccess<u32>(si.pif.ram, paddr, std::byteswap(val));
si.pif.ProcessCommands(*this);
si.pif.ProcessCommands();
return;
}
@@ -332,20 +337,21 @@ void Mem::WriteInterpreter<u8>(Registers &regs, u32 paddr, u32 val) {
#ifndef __aarch64__
template <>
void Mem::WriteJIT<u8>(Registers &regs, const u32 paddr, const u32 val) {
WriteInterpreter<u8>(regs, paddr, val);
void Mem::WriteJIT<u8>(const u32 paddr, const u32 val) {
WriteInterpreter<u8>(paddr, val);
if (jit)
jit->InvalidateBlock(paddr);
}
#endif
template <>
void Mem::Write<u8>(Registers &regs, const u32 paddr, const u32 val) {
WriteInterpreter<u8>(regs, paddr, val);
void Mem::Write<u8>(const u32 paddr, const u32 val) {
WriteInterpreter<u8>(paddr, val);
}
template <>
void Mem::WriteInterpreter<u16>(Registers &regs, u32 paddr, u32 val) {
void Mem::WriteInterpreter<u16>(u32 paddr, u32 val) {
n64::Registers& regs = n64::Core::GetInstance().cpu->GetRegs();
SI &si = mmio.si;
if(Util::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) { mmio.rdp.WriteRDRAM<u16>(paddr, val); return; }
@@ -370,7 +376,7 @@ void Mem::WriteInterpreter<u16>(Registers &regs, u32 paddr, u32 val) {
val = val << (16 * !(paddr & 2));
paddr &= ~3;
Util::WriteAccess<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START, std::byteswap(val));
si.pif.ProcessCommands(*this);
si.pif.ProcessCommands();
return;
}
@@ -385,20 +391,21 @@ void Mem::WriteInterpreter<u16>(Registers &regs, u32 paddr, u32 val) {
#ifndef __aarch64__
template <>
void Mem::WriteJIT<u16>(Registers &regs, const u32 paddr, const u32 val) {
WriteInterpreter<u16>(regs, paddr, val);
void Mem::WriteJIT<u16>(const u32 paddr, const u32 val) {
WriteInterpreter<u16>(paddr, val);
if (jit)
jit->InvalidateBlock(paddr);
}
#endif
template <>
void Mem::Write<u16>(Registers &regs, const u32 paddr, const u32 val) {
WriteInterpreter<u16>(regs, paddr, val);
void Mem::Write<u16>(const u32 paddr, const u32 val) {
WriteInterpreter<u16>(paddr, val);
}
template <>
void Mem::WriteInterpreter<u32>(Registers &regs, const u32 paddr, const u32 val) {
void Mem::WriteInterpreter<u32>(const u32 paddr, const u32 val) {
n64::Registers& regs = n64::Core::GetInstance().cpu->GetRegs();
SI &si = mmio.si;
if(Util::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) { mmio.rdp.WriteRDRAM<u32>(paddr, val); return; }
@@ -419,7 +426,7 @@ void Mem::WriteInterpreter<u32>(Registers &regs, const u32 paddr, const u32 val)
if(Util::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) {
Util::WriteAccess<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START, std::byteswap(val));
si.pif.ProcessCommands(*this);
si.pif.ProcessCommands();
return;
}
@@ -434,29 +441,30 @@ void Mem::WriteInterpreter<u32>(Registers &regs, const u32 paddr, const u32 val)
#ifndef __aarch64__
template <>
void Mem::WriteJIT<u32>(Registers &regs, const u32 paddr, const u32 val) {
WriteInterpreter<u32>(regs, paddr, val);
void Mem::WriteJIT<u32>(const u32 paddr, const u32 val) {
WriteInterpreter<u32>(paddr, val);
if (jit)
jit->InvalidateBlock(paddr);
}
#endif
template <>
void Mem::Write<u32>(Registers &regs, const u32 paddr, const u32 val) {
WriteInterpreter<u32>(regs, paddr, val);
void Mem::Write<u32>(const u32 paddr, const u32 val) {
WriteInterpreter<u32>(paddr, val);
}
#ifndef __aarch64__
void Mem::WriteJIT(const Registers &regs, const u32 paddr, const u64 val) {
WriteInterpreter(regs, paddr, val);
void Mem::WriteJIT(const const u32 paddr, const u64 val) {
WriteInterpreter(paddr, val);
if (jit)
jit->InvalidateBlock(paddr);
}
#endif
void Mem::Write(const Registers &regs, const u32 paddr, const u64 val) { WriteInterpreter(regs, paddr, val); }
void Mem::Write(const u32 paddr, const u64 val) { WriteInterpreter(paddr, val); }
void Mem::WriteInterpreter(const Registers &regs, const u32 paddr, u64 val) {
void Mem::WriteInterpreter(const u32 paddr, u64 val) {
n64::Registers& regs = n64::Core::GetInstance().cpu->GetRegs();
SI &si = mmio.si;
if(Util::IsInsideRange(paddr, RDRAM_REGION_START, RDRAM_REGION_END)) { mmio.rdp.WriteRDRAM<u64>(paddr, val); return; }
@@ -478,7 +486,7 @@ void Mem::WriteInterpreter(const Registers &regs, const u32 paddr, u64 val) {
if(Util::IsInsideRange(paddr, PIF_RAM_REGION_START, PIF_RAM_REGION_END)) {
Util::WriteAccess<u64>(si.pif.ram, paddr - PIF_RAM_REGION_START, std::byteswap(val));
si.pif.ProcessCommands(*this);
si.pif.ProcessCommands();
return;
}
@@ -575,25 +583,4 @@ void Mem::BackupWrite<u8>(const u32 addr, const u8 val) {
panic("Backup read word with unknown save type");
}
}
std::vector<u8> Mem::Serialize() {
std::vector<u8> res{};
auto sMMIO = mmio.Serialize();
auto sFLASH = flash.Serialize();
mmioSize = sMMIO.size();
flashSize = sFLASH.size();
res.insert(res.begin(), sMMIO.begin(), sMMIO.end());
res.insert(res.end(), sFLASH.begin(), sFLASH.end());
res.insert(res.end(), saveData.begin(), saveData.end());
return res;
}
void Mem::Deserialize(const std::vector<u8> &data) {
mmio.Deserialize(std::vector(data.begin(), data.begin() + mmioSize));
flash.Deserialize(std::vector(data.begin() + mmioSize, data.begin() + mmioSize + flashSize));
memcpy(saveData.data(), data.data() + mmioSize + flashSize, saveData.size());
}
} // namespace n64

View File

@@ -1,7 +1,6 @@
#pragma once
#include <File.hpp>
#include <GameDB.hpp>
#include <Registers.hpp>
#include <backend/MemoryRegions.hpp>
#include <backend/core/MMIO.hpp>
#include <common.hpp>
@@ -70,17 +69,17 @@ struct Flash {
void CommandSetWriteOffs(u32);
void CommandWrite();
void CommandRead();
std::vector<u8> Serialize();
void Deserialize(const std::vector<u8> &data);
template <typename T>
void Write(u32 index, T val);
template <typename T>
T Read(u32 index) const;
};
struct JIT;
struct Mem {
~Mem() = default;
Mem(Registers &, ParallelRDP &, JIT * = nullptr);
Mem(JIT * = nullptr);
void Reset();
void LoadSRAM(SaveType, fs::path);
static std::vector<u8> OpenROM(const std::string &, size_t &);
@@ -90,14 +89,11 @@ struct Mem {
[[nodiscard]] auto GetRDRAM() -> std::vector<u8> & { return mmio.rdp.rdram; }
std::vector<u8> Serialize();
void Deserialize(const std::vector<u8> &);
template <typename T>
T Read(Registers &, u32);
T Read(u32);
template <typename T>
void Write(Registers &, u32, u32);
void Write(const Registers &, u32, u64);
void Write(u32, u32);
void Write(u32, u64);
template <typename T>
T BackupRead(u32);
@@ -133,11 +129,11 @@ struct Mem {
private:
template <typename T>
void WriteInterpreter(Registers &, u32, u32);
void WriteInterpreter(const Registers &, u32, u64);
void WriteInterpreter(u32, u32);
void WriteInterpreter(u32, u64);
template <typename T>
void WriteJIT(Registers &, u32, u32);
void WriteJIT(const Registers &, u32, u64);
void WriteJIT(u32, u32);
void WriteJIT(u32, u64);
JIT *jit = nullptr;
friend struct SI;

View File

@@ -1,15 +1,11 @@
#include <core/RDP.hpp>
#include <core/RSP.hpp>
#include <log.hpp>
#include <parallel-rdp/ParallelRDPWrapper.hpp>
#include <core/Mem.hpp>
#include <Core.hpp>
namespace n64 {
RDP::RDP(Mem &mem, ParallelRDP &parallel) : mem(mem), parallel(parallel) {
RDP::RDP() {
rdram.resize(RDRAM_SIZE);
std::ranges::fill(rdram, 0);
std::ranges::fill(cmd_buf, 0);
dpc.status.raw = 0x80;
Reset();
}
void RDP::Reset() {
@@ -201,6 +197,8 @@ FORCE_INLINE void logCommand(u8 cmd) {
*/
void RDP::RunCommand() {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
ParallelRDP& parallel = n64::Core::GetInstance().parallel;
if (dpc.status.freeze) {
return;
}
@@ -287,6 +285,9 @@ void RDP::RunCommand() {
}
void RDP::OnFullSync() {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
ParallelRDP& parallel = n64::Core::GetInstance().parallel;
parallel.OnFullSync();
dpc.status.pipeBusy = false;

View File

@@ -3,14 +3,8 @@
#include <vector>
#include <common.hpp>
class ParallelRDP;
namespace n64 {
struct RSP;
struct Mem;
struct Registers;
union DPCStatusWrite {
u32 raw;
struct {
@@ -59,7 +53,7 @@ struct RDP {
DPC dpc{};
std::array<u32, COMMAND_BUFFER_SIZE> cmd_buf{};
RDP(Mem &, ParallelRDP &);
RDP();
void Reset();
[[nodiscard]] auto Read(u32 addr) const -> u32;
@@ -93,8 +87,5 @@ private:
friend struct Mem;
friend struct MMIO;
std::vector<u8> rdram{};
Mem &mem;
ParallelRDP &parallel;
};
} // namespace n64

View File

@@ -1,10 +1,8 @@
#include <core/Mem.hpp>
#include <core/RSP.hpp>
#include <core/registers/Registers.hpp>
#include <Core.hpp>
#include <log.hpp>
namespace n64 {
RSP::RSP(Mem &mem, Registers &regs) : regs(regs), mem(mem) { Reset(); }
RSP::RSP() { Reset(); }
void RSP::Reset() {
lastSuccessfulSPAddr.raw = 0;
@@ -90,6 +88,8 @@ auto RSP::Read(const u32 addr) -> u32 {
}
void RSP::WriteStatus(const u32 value) {
Mem& mem = Core::GetInstance().cpu->GetMem();
Registers& regs = Core::GetInstance().cpu->GetRegs();
MI &mi = mem.mmio.mi;
const auto write = SPStatusWrite{.raw = value};
if (write.clearHalt && !write.setHalt) {
@@ -130,6 +130,7 @@ void RSP::WriteStatus(const u32 value) {
template <>
void RSP::DMA<true>() {
Mem& mem = Core::GetInstance().cpu->GetMem();
u32 length = spDMALen.len + 1;
length = (length + 0x7) & ~0x7;
@@ -162,6 +163,7 @@ void RSP::DMA<true>() {
template <>
void RSP::DMA<false>() {
Mem& mem = Core::GetInstance().cpu->GetMem();
u32 length = spDMALen.len + 1;
length = (length + 0x7) & ~0x7;

View File

@@ -118,7 +118,7 @@ struct Registers;
#define DE(x) (((x) >> 11) & 0x1F)
struct RSP {
RSP(Mem &, Registers &);
RSP();
void Reset();
FORCE_INLINE void Step() {
@@ -369,8 +369,6 @@ struct RSP {
void WriteStatus(u32 value);
private:
Registers &regs;
Mem &mem;
FORCE_INLINE void branch(const u16 address, const bool cond) {
if (cond) {
nextPC = address & 0xFFC;

View File

@@ -1,18 +1,30 @@
#include <registers/Cop0.hpp>
#include <registers/Registers.hpp>
#include <Core.hpp>
#include <log.hpp>
#include <ranges>
namespace n64 {
void Cop0::mtc0(const u32 instr) { SetReg32(RD(instr), regs.Read<u32>(RT(instr))); }
void Cop0::mtc0(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
SetReg32(RD(instr), regs.Read<u32>(RT(instr)));
}
void Cop0::dmtc0(const u32 instr) { SetReg64(RD(instr), regs.Read<u64>(RT(instr))); }
void Cop0::dmtc0(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
SetReg64(RD(instr), regs.Read<u64>(RT(instr)));
}
void Cop0::mfc0(const u32 instr) { regs.Write(RT(instr), s32(GetReg32(RD(instr)))); }
void Cop0::mfc0(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
regs.Write(RT(instr), s32(GetReg32(RD(instr))));
}
void Cop0::dmfc0(const u32 instr) const { regs.Write(RT(instr), s64(GetReg64(RD(instr)))); }
void Cop0::dmfc0(const u32 instr) const {
Registers& regs = Core::GetInstance().cpu->GetRegs();
regs.Write(RT(instr), s64(GetReg64(RD(instr))));
}
void Cop0::eret() {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (status.erl) {
regs.SetPC64(ErrorEPC);
status.erl = false;

View File

@@ -1,8 +1,6 @@
#include <cfenv>
#include <cmath>
#include <Interpreter.hpp>
#include <registers/Cop1.hpp>
#include <registers/Registers.hpp>
#include <Core.hpp>
#include <utils/FloatingPoint.hpp>
namespace n64 {
@@ -134,6 +132,7 @@ bool Cop1::isqnan<double>(const double f) {
template <>
bool Cop1::CheckCVTArg<s32>(const float f) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
switch (std::fpclassify(f)) {
case FP_SUBNORMAL:
case FP_INFINITE:
@@ -154,6 +153,7 @@ bool Cop1::CheckCVTArg<s32>(const float f) {
template <>
bool Cop1::CheckCVTArg<s32>(const double f) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
switch (std::fpclassify(f)) {
case FP_SUBNORMAL:
case FP_INFINITE:
@@ -174,6 +174,7 @@ bool Cop1::CheckCVTArg<s32>(const double f) {
template <>
bool Cop1::CheckCVTArg<s64>(const float f) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
switch (std::fpclassify(f)) {
case FP_SUBNORMAL:
case FP_INFINITE:
@@ -194,6 +195,7 @@ bool Cop1::CheckCVTArg<s64>(const float f) {
template <>
bool Cop1::CheckCVTArg<s64>(const double f) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
switch (std::fpclassify(f)) {
case FP_SUBNORMAL:
case FP_INFINITE:
@@ -214,6 +216,7 @@ bool Cop1::CheckCVTArg<s64>(const double f) {
template <typename T>
bool Cop1::CheckArg(const T f) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
switch (std::fpclassify(f)) {
case FP_SUBNORMAL:
SetCauseUnimplemented();
@@ -231,6 +234,7 @@ bool Cop1::CheckArg(const T f) {
template <typename T>
bool Cop1::CheckArgs(const T f1, const T f2) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
auto class1 = std::fpclassify(f1), class2 = std::fpclassify(f2);
if ((class1 == FP_NAN && !isqnan(f1)) || (class2 == FP_NAN && !isqnan(f2))) {
SetCauseUnimplemented();
@@ -256,6 +260,7 @@ bool Cop1::CheckArgs(const T f1, const T f2) {
template <bool preserveCause>
bool Cop1::CheckFPUUsable() {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if constexpr (preserveCause) {
if (!regs.cop0.status.cu1) {
regs.cop0.FireException(ExceptionCode::CoprocessorUnusable, 1, regs.oldPC);
@@ -290,6 +295,7 @@ FORCE_INLINE T FlushResult(T f, const u32 round) {
template <>
bool Cop1::CheckResult<float>(float &f) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
switch (std::fpclassify(f)) {
case FP_SUBNORMAL:
if (!fcr31.fs || fcr31.enable.underflow || fcr31.enable.inexact_operation) {
@@ -312,6 +318,7 @@ bool Cop1::CheckResult<float>(float &f) {
template <>
bool Cop1::CheckResult<double>(double &f) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
switch (std::fpclassify(f)) {
case FP_SUBNORMAL:
if (!fcr31.fs || fcr31.enable.underflow || fcr31.enable.inexact_operation) {
@@ -334,6 +341,7 @@ bool Cop1::CheckResult<double>(double &f) {
template <bool cvt>
bool Cop1::TestExceptions() {
Registers& regs = Core::GetInstance().cpu->GetRegs();
const u32 exc = std::fetestexcept(FE_ALL_EXCEPT);
if (!exc)
@@ -437,6 +445,7 @@ bool Cop1::SetCauseInvalid() {
#define CHECK_FPE_CONV_CONST(type, res, operation) CHECK_FPE_IMPL_CONST(type, res, operation, true)
void Cop1::absd(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
@@ -449,6 +458,7 @@ void Cop1::absd(const u32 instr) {
}
void Cop1::abss(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
@@ -461,6 +471,7 @@ void Cop1::abss(const u32 instr) {
}
void Cop1::adds(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
@@ -474,6 +485,7 @@ void Cop1::adds(const u32 instr) {
}
void Cop1::addd(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
@@ -487,6 +499,7 @@ void Cop1::addd(const u32 instr) {
}
void Cop1::ceills(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
@@ -497,6 +510,7 @@ void Cop1::ceills(const u32 instr) {
}
void Cop1::ceilld(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
@@ -507,6 +521,7 @@ void Cop1::ceilld(const u32 instr) {
}
void Cop1::ceilws(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
@@ -517,6 +532,7 @@ void Cop1::ceilws(const u32 instr) {
}
void Cop1::ceilwd(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
@@ -527,6 +543,7 @@ void Cop1::ceilwd(const u32 instr) {
}
void Cop1::cfc1(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable<true>())
return;
const u8 fd = RD(instr);
@@ -545,6 +562,7 @@ void Cop1::cfc1(const u32 instr) {
}
void Cop1::ctc1(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable<true>())
return;
const u8 fs = RD(instr);
@@ -592,6 +610,7 @@ void Cop1::ctc1(const u32 instr) {
}
void Cop1::cvtds(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
@@ -604,6 +623,7 @@ void Cop1::cvtds(const u32 instr) {
}
void Cop1::cvtsd(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
@@ -616,6 +636,7 @@ void Cop1::cvtsd(const u32 instr) {
}
void Cop1::cvtsw(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<s32>(regs.cop0.status, FS(instr));
@@ -626,6 +647,7 @@ void Cop1::cvtsw(const u32 instr) {
}
void Cop1::cvtsl(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<s64>(regs.cop0.status, FS(instr));
@@ -641,6 +663,7 @@ void Cop1::cvtsl(const u32 instr) {
}
void Cop1::cvtwd(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
@@ -651,6 +674,7 @@ void Cop1::cvtwd(const u32 instr) {
}
void Cop1::cvtws(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
@@ -661,6 +685,7 @@ void Cop1::cvtws(const u32 instr) {
}
void Cop1::cvtls(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
@@ -671,6 +696,7 @@ void Cop1::cvtls(const u32 instr) {
}
void Cop1::cvtdw(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<s32>(regs.cop0.status, FS(instr));
@@ -681,6 +707,7 @@ void Cop1::cvtdw(const u32 instr) {
}
void Cop1::cvtdl(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
@@ -698,6 +725,7 @@ void Cop1::cvtdl(const u32 instr) {
}
void Cop1::cvtld(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
@@ -709,6 +737,7 @@ void Cop1::cvtld(const u32 instr) {
template <typename T, bool quiet, bool cf>
bool Cop1::XORDERED(const T fs, const T ft) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (std::isnan(fs) || std::isnan(ft)) {
if (std::isnan(fs) && (!quiet || isqnan(fs)) && SetCauseInvalid()) {
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
@@ -730,6 +759,7 @@ bool Cop1::XORDERED(const T fs, const T ft) {
template <typename T>
void Cop1::cf(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
@@ -741,6 +771,7 @@ void Cop1::cf(const u32 instr) {
template <typename T>
void Cop1::cun(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const T fs = FGR_S<T>(regs.cop0.status, FS(instr));
@@ -751,6 +782,7 @@ void Cop1::cun(const u32 instr) {
template <typename T>
void Cop1::ceq(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const T fs = FGR_S<T>(regs.cop0.status, FS(instr));
@@ -762,6 +794,7 @@ void Cop1::ceq(const u32 instr) {
template <typename T>
void Cop1::cueq(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const T fs = FGR_S<T>(regs.cop0.status, FS(instr));
@@ -773,6 +806,7 @@ void Cop1::cueq(const u32 instr) {
template <typename T>
void Cop1::colt(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const T fs = FGR_S<T>(regs.cop0.status, FS(instr));
@@ -784,6 +818,7 @@ void Cop1::colt(const u32 instr) {
template <typename T>
void Cop1::cult(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const T fs = FGR_S<T>(regs.cop0.status, FS(instr));
@@ -795,6 +830,7 @@ void Cop1::cult(const u32 instr) {
template <typename T>
void Cop1::cole(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const T fs = FGR_S<T>(regs.cop0.status, FS(instr));
@@ -806,6 +842,7 @@ void Cop1::cole(const u32 instr) {
template <typename T>
void Cop1::cule(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const T fs = FGR_S<T>(regs.cop0.status, FS(instr));
@@ -817,6 +854,7 @@ void Cop1::cule(const u32 instr) {
template <typename T>
void Cop1::csf(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const T fs = FGR_S<T>(regs.cop0.status, FS(instr));
@@ -827,6 +865,7 @@ void Cop1::csf(const u32 instr) {
template <typename T>
void Cop1::cngle(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const T fs = FGR_S<T>(regs.cop0.status, FS(instr));
@@ -837,6 +876,7 @@ void Cop1::cngle(const u32 instr) {
template <typename T>
void Cop1::cseq(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const T fs = FGR_S<T>(regs.cop0.status, FS(instr));
@@ -848,6 +888,7 @@ void Cop1::cseq(const u32 instr) {
template <typename T>
void Cop1::cngl(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const T fs = FGR_S<T>(regs.cop0.status, FS(instr));
@@ -859,6 +900,7 @@ void Cop1::cngl(const u32 instr) {
template <typename T>
void Cop1::clt(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const T fs = FGR_S<T>(regs.cop0.status, FS(instr));
@@ -870,6 +912,7 @@ void Cop1::clt(const u32 instr) {
template <typename T>
void Cop1::cnge(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const T fs = FGR_S<T>(regs.cop0.status, FS(instr));
@@ -881,6 +924,7 @@ void Cop1::cnge(const u32 instr) {
template <typename T>
void Cop1::cle(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const T fs = FGR_S<T>(regs.cop0.status, FS(instr));
@@ -892,6 +936,7 @@ void Cop1::cle(const u32 instr) {
template <typename T>
void Cop1::cngt(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const T fs = FGR_S<T>(regs.cop0.status, FS(instr));
@@ -935,6 +980,7 @@ template void Cop1::cle<double>(u32 instr);
template void Cop1::cngt<double>(u32 instr);
void Cop1::divs(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
@@ -948,6 +994,7 @@ void Cop1::divs(const u32 instr) {
}
void Cop1::divd(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
@@ -961,6 +1008,7 @@ void Cop1::divd(const u32 instr) {
}
void Cop1::muls(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
@@ -974,6 +1022,7 @@ void Cop1::muls(const u32 instr) {
}
void Cop1::muld(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
@@ -987,6 +1036,7 @@ void Cop1::muld(const u32 instr) {
}
void Cop1::subs(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
@@ -1000,6 +1050,7 @@ void Cop1::subs(const u32 instr) {
}
void Cop1::subd(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
@@ -1015,12 +1066,14 @@ void Cop1::subd(const u32 instr) {
void Cop1::movs(const u32 instr) { movd(instr); }
void Cop1::movd(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable<true>())
return;
FGR_D<double>(regs.cop0.status, FD(instr)) = FGR_S<double>(regs.cop0.status, FS(instr));
}
void Cop1::negs(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
@@ -1033,6 +1086,7 @@ void Cop1::negs(const u32 instr) {
}
void Cop1::negd(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
@@ -1045,6 +1099,7 @@ void Cop1::negd(const u32 instr) {
}
void Cop1::sqrts(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
@@ -1057,6 +1112,7 @@ void Cop1::sqrts(const u32 instr) {
}
void Cop1::sqrtd(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
@@ -1069,6 +1125,7 @@ void Cop1::sqrtd(const u32 instr) {
}
void Cop1::roundls(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
@@ -1083,6 +1140,7 @@ void Cop1::roundls(const u32 instr) {
}
void Cop1::roundld(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
@@ -1097,6 +1155,7 @@ void Cop1::roundld(const u32 instr) {
}
void Cop1::roundws(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
@@ -1111,6 +1170,7 @@ void Cop1::roundws(const u32 instr) {
}
void Cop1::roundwd(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
@@ -1125,6 +1185,7 @@ void Cop1::roundwd(const u32 instr) {
}
void Cop1::floorls(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
@@ -1135,6 +1196,7 @@ void Cop1::floorls(const u32 instr) {
}
void Cop1::floorld(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
@@ -1145,6 +1207,7 @@ void Cop1::floorld(const u32 instr) {
}
void Cop1::floorws(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
@@ -1155,6 +1218,7 @@ void Cop1::floorws(const u32 instr) {
}
void Cop1::floorwd(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
@@ -1165,6 +1229,7 @@ void Cop1::floorwd(const u32 instr) {
}
void Cop1::truncws(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
@@ -1179,6 +1244,7 @@ void Cop1::truncws(const u32 instr) {
}
void Cop1::truncwd(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
@@ -1193,6 +1259,7 @@ void Cop1::truncwd(const u32 instr) {
}
void Cop1::truncls(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
@@ -1207,6 +1274,7 @@ void Cop1::truncls(const u32 instr) {
}
void Cop1::truncld(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
const auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
@@ -1220,53 +1288,62 @@ void Cop1::truncld(const u32 instr) {
FGR_D<s64>(regs.cop0.status, FD(instr)) = fd;
}
void Cop1::lwc1(Mem &mem, u32 instr) {
void Cop1::lwc1(u32 instr) {
Mem& mem = Core::GetInstance().cpu->GetMem();
Registers& regs = Core::GetInstance().cpu->GetRegs();
const u64 addr = static_cast<s64>(static_cast<s16>(instr)) + regs.Read<s64>(BASE(instr));
if (u32 physical; !regs.cop0.MapVAddr(Cop0::LOAD, addr, physical)) {
regs.cop0.HandleTLBException(addr);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else {
const u32 data = mem.Read<u32>(regs, physical);
const u32 data = mem.Read<u32>(physical);
FGR_T<u32>(regs.cop0.status, FT(instr)) = data;
}
}
void Cop1::swc1(Mem &mem, u32 instr) {
void Cop1::swc1(u32 instr) {
Mem& mem = Core::GetInstance().cpu->GetMem();
Registers& regs = Core::GetInstance().cpu->GetRegs();
const u64 addr = static_cast<s64>(static_cast<s16>(instr)) + regs.Read<s64>(BASE(instr));
if (u32 physical; !regs.cop0.MapVAddr(Cop0::STORE, addr, physical)) {
regs.cop0.HandleTLBException(addr);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else {
mem.Write<u32>(regs, physical, FGR_T<u32>(regs.cop0.status, FT(instr)));
mem.Write<u32>(physical, FGR_T<u32>(regs.cop0.status, FT(instr)));
}
}
void Cop1::ldc1(Mem &mem, u32 instr) {
void Cop1::ldc1(u32 instr) {
Mem& mem = Core::GetInstance().cpu->GetMem();
Registers& regs = Core::GetInstance().cpu->GetRegs();
const u64 addr = static_cast<s64>(static_cast<s16>(instr)) + regs.Read<s64>(BASE(instr));
if (u32 physical; !regs.cop0.MapVAddr(Cop0::LOAD, addr, physical)) {
regs.cop0.HandleTLBException(addr);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else {
const u64 data = mem.Read<u64>(regs, physical);
const u64 data = mem.Read<u64>(physical);
FGR_T<u64>(regs.cop0.status, FT(instr)) = data;
}
}
void Cop1::sdc1(Mem &mem, u32 instr) {
void Cop1::sdc1(u32 instr) {
Mem& mem = Core::GetInstance().cpu->GetMem();
Registers& regs = Core::GetInstance().cpu->GetRegs();
const u64 addr = static_cast<s64>(static_cast<s16>(instr)) + regs.Read<s64>(BASE(instr));
if (u32 physical; !regs.cop0.MapVAddr(Cop0::STORE, addr, physical)) {
regs.cop0.HandleTLBException(addr);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else {
mem.Write(regs, physical, FGR_T<u64>(regs.cop0.status, FT(instr)));
mem.Write(physical, FGR_T<u64>(regs.cop0.status, FT(instr)));
}
}
void Cop1::unimplemented() {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable())
return;
SetCauseUnimplemented();
@@ -1274,24 +1351,28 @@ void Cop1::unimplemented() {
}
void Cop1::mfc1(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable<true>())
return;
regs.Write(RT(instr), FGR_T<s32>(regs.cop0.status, FS(instr)));
}
void Cop1::dmfc1(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable<true>())
return;
regs.Write(RT(instr), FGR_S<s64>(regs.cop0.status, FS(instr)));
}
void Cop1::mtc1(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable<true>())
return;
FGR_T<s32>(regs.cop0.status, FS(instr)) = regs.Read<s64>(RT(instr));
}
void Cop1::dmtc1(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
if (!CheckFPUUsable<true>())
return;
FGR_S<u64>(regs.cop0.status, FS(instr)) = regs.Read<s64>(RT(instr));

View File

@@ -418,13 +418,13 @@ void Interpreter::Exec(const u32 instr) {
ll(instr);
break;
case LWC1:
regs.cop1.lwc1(mem, instr);
regs.cop1.lwc1(instr);
break;
case LLD:
lld(instr);
break;
case LDC1:
regs.cop1.ldc1(mem, instr);
regs.cop1.ldc1(instr);
break;
case LD:
ld(instr);
@@ -433,13 +433,13 @@ void Interpreter::Exec(const u32 instr) {
sc(instr);
break;
case SWC1:
regs.cop1.swc1(mem, instr);
regs.cop1.swc1(instr);
break;
case SCD:
scd(instr);
break;
case SDC1:
regs.cop1.sdc1(mem, instr);
regs.cop1.sdc1(instr);
break;
case SD:
sd(instr);

View File

@@ -1,4 +1,4 @@
#include <core/Interpreter.hpp>
#include <Core.hpp>
#define check_signed_overflow(op1, op2, res) (((~((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1)
#define check_signed_underflow(op1, op2, res) (((((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1)
@@ -194,7 +194,7 @@ void Interpreter::lb(const u32 instr) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else {
regs.Write(RT(instr), (s8)mem.Read<u8>(regs, paddr));
regs.Write(RT(instr), (s8)mem.Read<u8>(paddr));
}
}
@@ -211,7 +211,7 @@ void Interpreter::lh(const u32 instr) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else {
regs.Write(RT(instr), (s16)mem.Read<u16>(regs, paddr));
regs.Write(RT(instr), (s16)mem.Read<u16>(paddr));
}
}
@@ -229,7 +229,7 @@ void Interpreter::lw(const u32 instr) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else {
regs.Write(RT(instr), (s32)mem.Read<u32>(regs, physical));
regs.Write(RT(instr), (s32)mem.Read<u32>(physical));
}
}
@@ -240,7 +240,7 @@ void Interpreter::ll(const u32 instr) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else {
const s32 result = mem.Read<u32>(regs, physical);
const s32 result = mem.Read<u32>(physical);
if (check_address_error(0b11, address)) {
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
return;
@@ -262,7 +262,7 @@ void Interpreter::lwl(const u32 instr) {
} else {
const u32 shift = 8 * ((address ^ 0) & 3);
const u32 mask = 0xFFFFFFFF << shift;
const u32 data = mem.Read<u32>(regs, paddr & ~3);
const u32 data = mem.Read<u32>(paddr & ~3);
const s32 result = s32((regs.Read<s64>(RT(instr)) & ~mask) | (data << shift));
regs.Write(RT(instr), result);
}
@@ -277,7 +277,7 @@ void Interpreter::lwr(const u32 instr) {
} else {
const u32 shift = 8 * ((address ^ 3) & 3);
const u32 mask = 0xFFFFFFFF >> shift;
const u32 data = mem.Read<u32>(regs, paddr & ~3);
const u32 data = mem.Read<u32>(paddr & ~3);
const s32 result = s32((regs.Read<s64>(RT(instr)) & ~mask) | (data >> shift));
regs.Write(RT(instr), result);
}
@@ -296,7 +296,7 @@ void Interpreter::ld(const u32 instr) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else {
const s64 value = mem.Read<u64>(regs, paddr);
const s64 value = mem.Read<u64>(paddr);
regs.Write(RT(instr), value);
}
}
@@ -316,7 +316,7 @@ void Interpreter::lld(const u32 instr) {
if (check_address_error(0b111, address)) {
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
} else {
regs.Write(RT(instr), mem.Read<u64>(regs, paddr));
regs.Write(RT(instr), mem.Read<u64>(paddr));
regs.cop0.llbit = true;
regs.cop0.LLAddr = paddr >> 4;
}
@@ -332,7 +332,7 @@ void Interpreter::ldl(const u32 instr) {
} else {
const s32 shift = 8 * ((address ^ 0) & 7);
const u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
const u64 data = mem.Read<u64>(regs, paddr & ~7);
const u64 data = mem.Read<u64>(paddr & ~7);
const s64 result = (s64)((regs.Read<s64>(RT(instr)) & ~mask) | (data << shift));
regs.Write(RT(instr), result);
}
@@ -347,7 +347,7 @@ void Interpreter::ldr(const u32 instr) {
} else {
const s32 shift = 8 * ((address ^ 7) & 7);
const u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
const u64 data = mem.Read<u64>(regs, paddr & ~7);
const u64 data = mem.Read<u64>(paddr & ~7);
const s64 result = (s64)((regs.Read<s64>(RT(instr)) & ~mask) | (data >> shift));
regs.Write(RT(instr), result);
}
@@ -360,7 +360,7 @@ void Interpreter::lbu(const u32 instr) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else {
const u8 value = mem.Read<u8>(regs, paddr);
const u8 value = mem.Read<u8>(paddr);
regs.Write(RT(instr), value);
}
}
@@ -377,7 +377,7 @@ void Interpreter::lhu(const u32 instr) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else {
const u16 value = mem.Read<u16>(regs, paddr);
const u16 value = mem.Read<u16>(paddr);
regs.Write(RT(instr), value);
}
}
@@ -395,7 +395,7 @@ void Interpreter::lwu(const u32 instr) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else {
const u32 value = mem.Read<u32>(regs, paddr);
const u32 value = mem.Read<u32>(paddr);
regs.Write(RT(instr), value);
}
}
@@ -407,7 +407,7 @@ void Interpreter::sb(const u32 instr) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else {
mem.Write<u8>(regs, paddr, regs.Read<s64>(RT(instr)));
mem.Write<u8>(paddr, regs.Read<s64>(RT(instr)));
}
}
@@ -430,7 +430,7 @@ void Interpreter::sc(const u32 instr) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else {
mem.Write<u32>(regs, paddr, regs.Read<s64>(RT(instr)));
mem.Write<u32>(paddr, regs.Read<s64>(RT(instr)));
regs.Write(RT(instr), 1);
}
} else {
@@ -462,7 +462,7 @@ void Interpreter::scd(const u32 instr) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else {
mem.Write<u32>(regs, paddr, regs.Read<s64>(RT(instr)));
mem.Write<u32>(paddr, regs.Read<s64>(RT(instr)));
regs.Write(RT(instr), 1);
}
} else {
@@ -478,7 +478,7 @@ void Interpreter::sh(const u32 instr) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else {
mem.Write<u16>(regs, physical, regs.Read<s64>(RT(instr)));
mem.Write<u16>(physical, regs.Read<s64>(RT(instr)));
}
}
@@ -496,7 +496,7 @@ void Interpreter::sw(const u32 instr) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else {
mem.Write<u32>(regs, physical, regs.Read<s64>(RT(instr)));
mem.Write<u32>(physical, regs.Read<s64>(RT(instr)));
}
}
@@ -513,7 +513,7 @@ void Interpreter::sd(const u32 instr) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else {
mem.Write(regs, physical, regs.Read<s64>(RT(instr)));
mem.Write(physical, regs.Read<s64>(RT(instr)));
}
}
@@ -526,9 +526,9 @@ void Interpreter::sdl(const u32 instr) {
} else {
const s32 shift = 8 * ((address ^ 0) & 7);
const u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
const u64 data = mem.Read<u64>(regs, paddr & ~7);
const u64 data = mem.Read<u64>(paddr & ~7);
const u64 rt = regs.Read<s64>(RT(instr));
mem.Write(regs, paddr & ~7, (data & ~mask) | (rt >> shift));
mem.Write(paddr & ~7, (data & ~mask) | (rt >> shift));
}
}
@@ -541,9 +541,9 @@ void Interpreter::sdr(const u32 instr) {
} else {
const s32 shift = 8 * ((address ^ 7) & 7);
const u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
const u64 data = mem.Read<u64>(regs, paddr & ~7);
const u64 data = mem.Read<u64>(paddr & ~7);
const u64 rt = regs.Read<s64>(RT(instr));
mem.Write(regs, paddr & ~7, (data & ~mask) | (rt << shift));
mem.Write(paddr & ~7, (data & ~mask) | (rt << shift));
}
}
@@ -556,9 +556,9 @@ void Interpreter::swl(const u32 instr) {
} else {
const u32 shift = 8 * ((address ^ 0) & 3);
const u32 mask = 0xFFFFFFFF >> shift;
const u32 data = mem.Read<u32>(regs, paddr & ~3);
const u32 data = mem.Read<u32>(paddr & ~3);
const u32 rt = regs.Read<s64>(RT(instr));
mem.Write<u32>(regs, paddr & ~3, (data & ~mask) | (rt >> shift));
mem.Write<u32>(paddr & ~3, (data & ~mask) | (rt >> shift));
}
}
@@ -571,9 +571,9 @@ void Interpreter::swr(const u32 instr) {
} else {
const u32 shift = 8 * ((address ^ 3) & 3);
const u32 mask = 0xFFFFFFFF << shift;
const u32 data = mem.Read<u32>(regs, paddr & ~3);
const u32 data = mem.Read<u32>(paddr & ~3);
const u32 rt = regs.Read<s64>(RT(instr));
mem.Write<u32>(regs, paddr & ~3, (data & ~mask) | (rt << shift));
mem.Write<u32>(paddr & ~3, (data & ~mask) | (rt << shift));
}
}
@@ -824,8 +824,9 @@ void Interpreter::mtlo(const u32 instr) { regs.lo = regs.Read<s64>(RS(instr)); }
void Interpreter::mthi(const u32 instr) { regs.hi = regs.Read<s64>(RS(instr)); }
void Interpreter::trap(const bool cond) const {
Cop0& cop0 = Core::GetInstance().cpu->GetRegs().cop0;
if (cond) {
regs.cop0.FireException(ExceptionCode::Trap, 0, regs.oldPC);
cop0.FireException(ExceptionCode::Trap, 0, regs.oldPC);
}
}

View File

@@ -958,7 +958,7 @@ void JIT::ldc1(u32 instr) {
// regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
panic("[JIT]: Unhandled TLBL exception in LD1!");
} else {
const u64 data = mem.Read<u64>(regs, physical);
const u64 data = mem.Read<u64>(physical);
regs.cop1.FGR_T<u64>(regs.cop0.status, FT(instr)) = data;
regs.cop1.fgrIsConstant[FT(instr)] = true;
}
@@ -979,7 +979,7 @@ void JIT::ldl(u32 instr) {
panic("[JIT]: Implement constant LDL!");
const s32 shift = 8 * ((address ^ 0) & 7);
const u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
const u64 data = mem.Read<u64>(regs, paddr & ~7);
const u64 data = mem.Read<u64>(paddr & ~7);
const s64 result = (s64)((regs.Read<s64>(RT(instr)) & ~mask) | (data << shift));
regs.Write(RT(instr), result);
}
@@ -999,7 +999,7 @@ void JIT::ldr(u32 instr) {
} else {
const s32 shift = 8 * ((address ^ 7) & 7);
const u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
const u64 data = mem.Read<u64>(regs, paddr & ~7);
const u64 data = mem.Read<u64>(paddr & ~7);
const s64 result = (s64)((regs.Read<s64>(RT(instr)) & ~mask) | (data >> shift));
regs.Write(RT(instr), result);
}

View File

@@ -107,38 +107,6 @@ void Flash::CommandRead() {
status = 0x11118004F0000000;
}
std::vector<u8> Flash::Serialize() {
std::vector<u8> res{};
res.resize(sizeof(state) + sizeof(status) + sizeof(eraseOffs) + sizeof(writeOffs) + 128);
u32 index = 0;
memcpy(res.data() + index, &state, sizeof(state));
index += sizeof(state);
memcpy(res.data() + index, &status, sizeof(status));
index += sizeof(status);
memcpy(res.data() + index, &eraseOffs, sizeof(eraseOffs));
index += sizeof(eraseOffs);
memcpy(res.data() + index, &writeOffs, sizeof(writeOffs));
index += sizeof(writeOffs);
std::ranges::copy(writeBuf, res.begin() + index);
return res;
}
void Flash::Deserialize(const std::vector<u8> &data) {
u32 index = 0;
memcpy(&state, data.data() + index, sizeof(state));
index += sizeof(state);
memcpy(&status, data.data() + index, sizeof(status));
index += sizeof(status);
memcpy(&eraseOffs, data.data() + index, sizeof(eraseOffs));
index += sizeof(eraseOffs);
memcpy(&writeOffs, data.data() + index, sizeof(writeOffs));
index += sizeof(writeOffs);
std::copy(data.begin() + index, data.begin() + index + 128, writeBuf.begin());
}
template <>
void Flash::Write<u32>(u32 index, u32 val) {
if (index > 0) {

View File

@@ -1,10 +1,8 @@
#include <core/Mem.hpp>
#include <core/mmio/AI.hpp>
#include <core/registers/Registers.hpp>
#include <Core.hpp>
#include <log.hpp>
namespace n64 {
AI::AI(Mem &mem, Registers &regs) : mem(mem), regs(regs) {}
AI::AI() { Reset(); }
void AI::Reset() {
dmaEnable = false;
@@ -37,6 +35,7 @@ auto AI::Read(const u32 addr) const -> u32 {
}
void AI::Write(const u32 addr, const u32 val) {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
switch (addr) {
case 0x04500000:
if (dmaCount < 2) {
@@ -81,6 +80,7 @@ void AI::Write(const u32 addr, const u32 val) {
}
void AI::Step(const u32 cpuCycles, const float volumeL, const float volumeR) {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
cycles += cpuCycles;
while (cycles > dac.period) {
if (dmaCount == 0) {

View File

@@ -3,11 +3,8 @@
#include <core/mmio/Audio.hpp>
namespace n64 {
struct Mem;
struct Registers;
struct AI {
AI(Mem &, Registers &regs);
AI();
void Reset();
auto Read(u32) const -> u32;
void Write(u32, u32);
@@ -27,9 +24,5 @@ struct AI {
u32 period{N64_CPU_FREQ / freq};
u32 precision{16};
} dac;
private:
Mem &mem;
Registers &regs;
};
} // namespace n64

View File

@@ -1,5 +1,4 @@
#include <core/mmio/MI.hpp>
#include <core/registers/Registers.hpp>
#include <Core.hpp>
namespace n64 {
void MI::InterruptRaise(const Interrupt intr) {
@@ -53,6 +52,7 @@ void MI::InterruptLower(const Interrupt intr) {
}
void MI::UpdateInterrupt() const {
n64::Registers& regs = n64::Core::GetInstance().cpu->GetRegs();
const bool interrupt = miIntr.raw & miIntrMask.raw;
regs.cop0.cause.ip2 = interrupt;
}

View File

@@ -5,7 +5,7 @@
#define MI_VERSION_REG 0x02020102
namespace n64 {
MI::MI(Registers &regs) : regs(regs) { Reset(); }
MI::MI() { Reset(); }
void MI::Reset() {
miIntrMask.raw = 0;

View File

@@ -16,12 +16,10 @@ union MIIntr {
u32 raw;
};
struct Registers;
struct MI {
enum class Interrupt : u8 { VI, SI, PI, AI, DP, SP };
explicit MI(Registers &);
explicit MI();
void Reset();
[[nodiscard]] auto Read(u32) const -> u32;
void Write(u32, u32);
@@ -31,6 +29,5 @@ struct MI {
u32 miMode{};
MIIntr miIntr{}, miIntrMask{};
Registers &regs;
};
} // namespace n64

View File

@@ -5,7 +5,7 @@
#include <log.hpp>
namespace n64 {
PI::PI(Mem &mem, Registers &regs) : mem(mem), regs(regs) { Reset(); }
PI::PI() { Reset(); }
void PI::Reset() {
dmaBusy = false;
@@ -37,6 +37,7 @@ bool PI::WriteLatch(u32 value) {
}
bool PI::ReadLatch() {
n64::Registers& regs = n64::Core::GetInstance().cpu->GetRegs();
if (ioBusy) [[unlikely]] {
ioBusy = false;
regs.CpuStall(Scheduler::GetInstance().Remove(PI_BUS_WRITE_COMPLETE));
@@ -47,6 +48,7 @@ bool PI::ReadLatch() {
template <>
auto PI::BusRead<u8, true>(u32 addr) -> u8 {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
switch (addr) {
case REGION_PI_UNKNOWN:
panic("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, "
@@ -81,6 +83,7 @@ auto PI::BusRead<u8, true>(u32 addr) -> u8 {
template <>
auto PI::BusRead<u8, false>(u32 addr) -> u8 {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
if (!ReadLatch()) [[unlikely]] {
return latch >> 24;
}
@@ -120,6 +123,7 @@ auto PI::BusRead<u8, false>(u32 addr) -> u8 {
template <>
void PI::BusWrite<u8, true>(u32 addr, u32 val) {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
switch (addr) {
case REGION_PI_UNKNOWN:
panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr);
@@ -157,6 +161,7 @@ void PI::BusWrite<u8, false>(u32 addr, u32 val) {
template <>
auto PI::BusRead<u16, false>(u32 addr) -> u16 {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
if (!ReadLatch()) [[unlikely]] {
return latch >> 16;
}
@@ -226,6 +231,7 @@ void PI::BusWrite<u16, true>(u32 addr, u32 val) {
template <>
auto PI::BusRead<u32, false>(u32 addr) -> u32 {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
if (!ReadLatch()) [[unlikely]] {
return latch;
}
@@ -278,6 +284,7 @@ auto PI::BusRead<u32, true>(u32 addr) -> u32 {
template <>
void PI::BusWrite<u32, false>(u32 addr, u32 val) {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
switch (addr) {
case REGION_PI_UNKNOWN:
if (!WriteLatch(val)) [[unlikely]] {
@@ -341,6 +348,7 @@ void PI::BusWrite<u32, true>(u32 addr, u32 val) {
template <>
auto PI::BusRead<u64, false>(u32 addr) -> u64 {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
if (!ReadLatch()) [[unlikely]] {
return static_cast<u64>(latch) << 32;
}
@@ -401,6 +409,7 @@ void PI::BusWrite<true>(u32 addr, u64 val) {
}
auto PI::Read(u32 addr) const -> u32 {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
switch (addr) {
case 0x04600000:
return dramAddr & 0x00FFFFFE;
@@ -489,6 +498,7 @@ u32 PI::AccessTiming(const u8 domain, const u32 length) const {
// rdram -> cart
template <>
void PI::DMA<false>() {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
const s32 len = rdLen + 1;
trace("PI DMA from RDRAM to CARTRIDGE (size: {} B, {:08X} to {:08X})", len, dramAddr, cartAddr);
@@ -512,6 +522,7 @@ void PI::DMA<false>() {
// cart -> rdram
template <>
void PI::DMA<true>() {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
const s32 len = wrLen + 1;
trace("PI DMA from CARTRIDGE to RDRAM (size: {} B, {:08X} to {:08X})", len, cartAddr, dramAddr);
@@ -533,6 +544,7 @@ void PI::DMA<true>() {
}
void PI::Write(u32 addr, u32 val) {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
MI &mi = mem.mmio.mi;
switch (addr) {
case 0x04600000:

View File

@@ -2,12 +2,8 @@
#include <common.hpp>
namespace n64 {
struct Mem;
struct Registers;
struct PI {
PI(Mem &, Registers &);
PI();
void Reset();
[[nodiscard]] auto Read(u32) const -> u32;
void Write(u32, u32);
@@ -37,8 +33,5 @@ struct PI {
private:
template <bool toDram>
void DMA();
Mem &mem;
Registers &regs;
};
} // namespace n64

View File

@@ -1,9 +1,7 @@
#include <Netplay.hpp>
#include <cassert>
#include <cic_nus_6105/n64_cic_nus_6105.hpp>
#include <core/Mem.hpp>
#include <core/mmio/PIF.hpp>
#include <core/registers/Registers.hpp>
#include <Core.hpp>
#include <log.hpp>
#include <Options.hpp>
@@ -167,7 +165,8 @@ FORCE_INLINE u8 DataCRC(const u8 *data) {
#define BCD_ENCODE(x) (((x) / 10) << 4 | ((x) % 10))
#define BCD_DECODE(x) (((x) >> 4) * 10 + ((x) & 15))
void PIF::ConfigureJoyBusFrame(const Mem& mem) {
void PIF::ConfigureJoyBusFrame() {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
channel = 0;
int i = 0;
while (i < 63) {
@@ -211,10 +210,10 @@ void PIF::ConfigureJoyBusFrame(const Mem& mem) {
MempakWrite(packet, res);
break;
case 4:
EepromRead(packet, res, mem);
EepromRead(packet, res);
break;
case 5:
EepromWrite(packet, res, mem);
EepromWrite(packet, res);
break;
case 6:
res[0] = 0x00;
@@ -259,10 +258,10 @@ void PIF::ConfigureJoyBusFrame(const Mem& mem) {
}
}
void PIF::ProcessCommands(const Mem &mem) {
void PIF::ProcessCommands() {
const u8 control = ram[63];
if (control & 1) {
ConfigureJoyBusFrame(mem);
ConfigureJoyBusFrame();
}
if (control & 0x02) {
@@ -332,7 +331,8 @@ void PIF::MempakWrite(u8 *cmd, u8 *res) {
res[0] = DataCRC(&cmd[5]);
}
void PIF::EepromRead(const u8 *cmd, u8 *res, const Mem &mem) const {
void PIF::EepromRead(const u8 *cmd, u8 *res) const {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
assert(mem.saveType == SAVE_EEPROM_4k || mem.saveType == SAVE_EEPROM_16k);
if (channel == 4) {
const u8 offset = cmd[3];
@@ -346,7 +346,8 @@ void PIF::EepromRead(const u8 *cmd, u8 *res, const Mem &mem) const {
}
}
void PIF::EepromWrite(const u8 *cmd, u8 *res, const Mem &mem) {
void PIF::EepromWrite(const u8 *cmd, u8 *res) {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
assert(mem.saveType == SAVE_EEPROM_4k || mem.saveType == SAVE_EEPROM_16k);
if (channel == 4) {
const u8 offset = cmd[3];
@@ -363,7 +364,9 @@ void PIF::EepromWrite(const u8 *cmd, u8 *res, const Mem &mem) {
}
void PIF::HLE(const bool pal, const CICType cicType) const {
mem.Write<u32>(regs, PIF_RAM_REGION_START + 0x24, cicSeeds[cicType]);
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
n64::Registers& regs = n64::Core::GetInstance().cpu->GetRegs();
mem.Write<u32>(PIF_RAM_REGION_START + 0x24, cicSeeds[cicType]);
switch (cicType) {
case UNKNOWN_CIC_TYPE:
@@ -568,14 +571,14 @@ void PIF::HLE(const bool pal, const CICType cicType) const {
regs.Write<u64>(31, 0xFFFFFFFFA4001554);
}
mem.Write<u32>(regs, IMEM_REGION_START + 0x00, 0x3C0DBFC0);
mem.Write<u32>(regs, IMEM_REGION_START + 0x04, 0x8DA807FC);
mem.Write<u32>(regs, IMEM_REGION_START + 0x08, 0x25AD07C0);
mem.Write<u32>(regs, IMEM_REGION_START + 0x0C, 0x31080080);
mem.Write<u32>(regs, IMEM_REGION_START + 0x10, 0x5500FFFC);
mem.Write<u32>(regs, IMEM_REGION_START + 0x14, 0x3C0DBFC0);
mem.Write<u32>(regs, IMEM_REGION_START + 0x18, 0x8DA80024);
mem.Write<u32>(regs, IMEM_REGION_START + 0x1C, 0x3C0BB000);
mem.Write<u32>(IMEM_REGION_START + 0x00, 0x3C0DBFC0);
mem.Write<u32>(IMEM_REGION_START + 0x04, 0x8DA807FC);
mem.Write<u32>(IMEM_REGION_START + 0x08, 0x25AD07C0);
mem.Write<u32>(IMEM_REGION_START + 0x0C, 0x31080080);
mem.Write<u32>(IMEM_REGION_START + 0x10, 0x5500FFFC);
mem.Write<u32>(IMEM_REGION_START + 0x14, 0x3C0DBFC0);
mem.Write<u32>(IMEM_REGION_START + 0x18, 0x8DA80024);
mem.Write<u32>(IMEM_REGION_START + 0x1C, 0x3C0BB000);
break;
case CIC_NUS_6106_7106:
regs.Write<u64>(0, 0x0000000000000000);
@@ -622,24 +625,25 @@ void PIF::HLE(const bool pal, const CICType cicType) const {
regs.Write<u8>(22, (cicSeeds[cicType] >> 8) & 0xFF);
regs.cop0.Reset();
mem.Write<u32>(regs, 0x04300004, 0x01010101);
mem.Write<u32>(0x04300004, 0x01010101);
std::copy_n(mem.rom.cart.begin(), 0x1000, mem.mmio.rsp.dmem.begin());
regs.SetPC32(static_cast<s32>(0xA4000040));
}
void PIF::Execute() const {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
const CICType cicType = mem.rom.cicType;
const bool pal = mem.rom.pal;
mem.Write<u32>(regs, PIF_RAM_REGION_START + 0x24, cicSeeds[cicType]);
mem.Write<u32>(PIF_RAM_REGION_START + 0x24, cicSeeds[cicType]);
switch (cicType) {
case UNKNOWN_CIC_TYPE:
warn("Unknown CIC type!");
break;
case CIC_NUS_6101 ... CIC_NUS_6103_7103:
mem.Write<u32>(regs, 0x318, RDRAM_SIZE);
mem.Write<u32>(0x318, RDRAM_SIZE);
break;
case CIC_NUS_6105_7105:
mem.Write<u32>(regs, 0x3F0, RDRAM_SIZE);
mem.Write<u32>(0x3F0, RDRAM_SIZE);
break;
case CIC_NUS_6106_7106:
break;
@@ -647,24 +651,4 @@ void PIF::Execute() const {
HLE(pal, cicType);
}
std::vector<u8> PIF::Serialize() {
std::vector<u8> res{};
res.resize(6 * sizeof(JoybusDevice) + PIF_BOOTROM_SIZE + PIF_RAM_SIZE + mempak.size() + eeprom.size() + sizeof(int));
u32 index = 0;
memcpy(res.data() + index, joybusDevices.data(), 6 * sizeof(JoybusDevice));
index += 6 * sizeof(JoybusDevice);
memcpy(res.data() + index, bootrom.data(), PIF_BOOTROM_SIZE);
index += PIF_BOOTROM_SIZE;
memcpy(res.data() + index, ram.data(), PIF_RAM_SIZE);
index += PIF_RAM_SIZE;
memcpy(res.data() + index, mempak.data(), mempak.size());
index += mempak.size();
memcpy(res.data() + index, eeprom.data(), eeprom.size());
index += eeprom.size();
memcpy(res.data() + index, &channel, sizeof(int));
return res;
}
} // namespace n64

View File

@@ -5,7 +5,7 @@
#include <filesystem>
#include <mio/mmap.hpp>
#include <vector>
#include "MupenMovie.hpp"
#include <MupenMovie.hpp>
namespace fs = std::filesystem;
@@ -153,9 +153,6 @@ struct JoybusDevice {
JoybusDevice() = default;
};
struct Mem;
struct Registers;
// https://github.com/ares-emulator/ares/blob/master/ares/n64/cic/cic.cpp
// https://github.com/ares-emulator/ares/blob/master/LICENSE
constexpr u32 cicSeeds[] = {
@@ -179,12 +176,10 @@ enum CICType {
};
struct PIF {
PIF(Mem &mem, Registers &regs) : mem(mem), regs(regs) {}
~PIF() = default;
void Reset();
void MaybeLoadMempak();
void LoadEeprom(SaveType, const std::string &);
void ProcessCommands(const Mem &);
void ProcessCommands();
void InitDevices(SaveType);
void CICChallenge();
void Execute() const;
@@ -193,9 +188,8 @@ struct PIF {
void ControllerID(u8 *) const;
void MempakRead(const u8 *, u8 *);
void MempakWrite(u8 *, u8 *);
void EepromRead(const u8 *, u8 *, const Mem &) const;
void EepromWrite(const u8 *, u8 *, const Mem &);
std::vector<u8> Serialize();
void EepromRead(const u8 *, u8 *) const;
void EepromWrite(const u8 *, u8 *);
void UpdateButton(int index, Controller::Key k, bool state) {
joybusDevices[index].controller.UpdateButton(k, state);
}
@@ -211,8 +205,6 @@ struct PIF {
std::string mempakPath{}, eepromPath{};
size_t eepromSize{};
MupenMovie movie;
Mem &mem;
Registers &regs;
[[nodiscard]] FORCE_INLINE u8 Read(u32 addr) const {
addr &= 0x7FF;
@@ -236,6 +228,6 @@ struct PIF {
return joybusDevices[channel].accessoryType;
}
private:
void ConfigureJoyBusFrame(const Mem &);
void ConfigureJoyBusFrame();
};
} // namespace n64

View File

@@ -1,9 +1,8 @@
#include <Scheduler.hpp>
#include <core/Mem.hpp>
#include <core/mmio/SI.hpp>
#include <Core.hpp>
namespace n64 {
SI::SI(Mem &mem, Registers &regs) : pif(mem, regs), mem(mem), regs(regs) { Reset(); }
SI::SI() { Reset(); }
void SI::Reset() {
status.raw = 0;
@@ -14,6 +13,7 @@ void SI::Reset() {
}
auto SI::Read(u32 addr) const -> u32 {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
switch (addr) {
case 0x04800000:
return dramAddr;
@@ -39,7 +39,8 @@ auto SI::Read(u32 addr) const -> u32 {
// pif -> rdram
template <>
void SI::DMA<true>() {
pif.ProcessCommands(mem);
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
pif.ProcessCommands();
for (int i = 0; i < 64; i++) {
mem.mmio.rdp.WriteRDRAM<u8>(dramAddr + i, pif.Read(pifAddr + i));
}
@@ -49,6 +50,7 @@ void SI::DMA<true>() {
// rdram -> pif
template <>
void SI::DMA<false>() {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
for (int i = 0; i < 64; i++) {
pif.Write(pifAddr + i, mem.mmio.rdp.ReadRDRAM<u8>(dramAddr + i));
}
@@ -56,6 +58,7 @@ void SI::DMA<false>() {
}
void SI::DMA() {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
status.dmaBusy = false;
if (toDram)
DMA<true>();
@@ -65,6 +68,7 @@ void SI::DMA() {
}
void SI::Write(u32 addr, u32 val) {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
switch (addr) {
case 0x04800000:
dramAddr = val & RDRAM_DSIZE;

View File

@@ -17,10 +17,8 @@ union SIStatus {
};
};
struct Mem;
struct SI {
SI(Mem &, Registers &);
SI();
void Reset();
SIStatus status{};
u32 dramAddr{};
@@ -33,10 +31,6 @@ struct SI {
void DMA();
void DMA();
PIF pif;
private:
Mem &mem;
Registers &regs;
};
#define SI_DMA_DELAY (65536 * 2)

View File

@@ -1,10 +1,8 @@
#include <core/Mem.hpp>
#include <core/mmio/VI.hpp>
#include <core/registers/Registers.hpp>
#include <Core.hpp>
#include <log.hpp>
namespace n64 {
VI::VI(Mem &mem, Registers &regs) : mem(mem), regs(regs) { Reset(); }
VI::VI() { Reset(); }
void VI::Reset() {
status.raw = 0xF;
@@ -60,6 +58,7 @@ u32 VI::Read(const u32 paddr) const {
}
void VI::Write(const u32 paddr, const u32 val) {
n64::Mem& mem = n64::Core::GetInstance().cpu->GetMem();
switch (paddr) {
case 0x04400000:
status.raw = val;

View File

@@ -67,11 +67,8 @@ union AxisStart {
};
};
struct Mem;
struct Registers;
struct VI {
VI(Mem &, Registers &);
VI();
void Reset();
[[nodiscard]] u32 Read(u32) const;
void Write(u32, u32);
@@ -88,9 +85,5 @@ struct VI {
int numHalflines{};
int numFields{};
int cyclesPerHalfline{};
private:
Mem &mem;
Registers &regs;
};
} // namespace n64

View File

@@ -1,9 +1,8 @@
#include <core/Interpreter.hpp>
#include <core/registers/Registers.hpp>
#include <Core.hpp>
#include <log.hpp>
namespace n64 {
Cop0::Cop0(Registers &regs) : regs(regs) { Reset(); }
Cop0::Cop0() { Reset(); }
void Cop0::Reset() {
cause.raw = 0xB000007C;
@@ -293,15 +292,15 @@ static FORCE_INLINE u64 getVPN(const u64 addr, const u64 pageMask) {
return vpn & ~mask;
}
TLBEntry *Cop0::TLBTryMatch(const u64 vaddr, int &index) const {
TLBEntry *Cop0::TLBTryMatch(const u64 vaddr, int &index) {
for (int i = 0; i < 32; i++) {
if (TLBEntry *entry = &regs.cop0.tlb[i]; entry->initialized) {
if (TLBEntry *entry = &tlb[i]; entry->initialized) {
const u64 entry_vpn = getVPN(entry->entryHi.raw, entry->pageMask.raw);
const u64 vaddr_vpn = getVPN(vaddr, entry->pageMask.raw);
const bool vpn_match = entry_vpn == vaddr_vpn;
if (const bool asid_match = entry->global || regs.cop0.entryHi.asid == entry->entryHi.asid;
if (const bool asid_match = entry->global || entryHi.asid == entry->entryHi.asid;
vpn_match && asid_match) {
index = i;
return entry;
@@ -312,15 +311,15 @@ TLBEntry *Cop0::TLBTryMatch(const u64 vaddr, int &index) const {
return nullptr;
}
TLBEntry *Cop0::TLBTryMatch(const u64 vaddr) const {
for (auto &i : regs.cop0.tlb) {
TLBEntry *Cop0::TLBTryMatch(const u64 vaddr) {
for (auto &i : tlb) {
if (TLBEntry *entry = &i; entry->initialized) {
const u64 entry_vpn = getVPN(entry->entryHi.raw, entry->pageMask.raw);
const u64 vaddr_vpn = getVPN(vaddr, entry->pageMask.raw);
const bool vpn_match = entry_vpn == vaddr_vpn;
if (const bool asid_match = entry->global || regs.cop0.entryHi.asid == entry->entryHi.asid;
if (const bool asid_match = entry->global || entryHi.asid == entry->entryHi.asid;
vpn_match && asid_match) {
return entry;
}
@@ -330,10 +329,10 @@ TLBEntry *Cop0::TLBTryMatch(const u64 vaddr) const {
return nullptr;
}
bool Cop0::ProbeTLB(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) const {
bool Cop0::ProbeTLB(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
const TLBEntry *entry = TLBTryMatch(vaddr);
if (!entry) {
regs.cop0.tlbError = MISS;
tlbError = MISS;
return false;
}
@@ -343,12 +342,12 @@ bool Cop0::ProbeTLB(const TLBAccessType accessType, const u64 vaddr, u32 &paddr)
const EntryLo entryLo = odd ? entry->entryLo1 : entry->entryLo0;
if (!entryLo.v) {
regs.cop0.tlbError = INVALID;
tlbError = INVALID;
return false;
}
if (accessType == STORE && !entryLo.d) {
regs.cop0.tlbError = MODIFICATION;
tlbError = MODIFICATION;
return false;
}
@@ -370,22 +369,23 @@ FORCE_INLINE bool Is64BitAddressing(const Cop0 &cp0, const u64 addr) {
}
}
void Cop0::FireException(const ExceptionCode code, const int cop, s64 pc) const {
const bool old_exl = regs.cop0.status.exl;
void Cop0::FireException(const ExceptionCode code, const int cop, s64 pc) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
const bool old_exl = status.exl;
if (!regs.cop0.status.exl) {
if ((regs.cop0.cause.branchDelay = regs.prevDelaySlot)) {
if (!status.exl) {
if ((cause.branchDelay = regs.prevDelaySlot)) {
pc -= 4;
}
regs.cop0.status.exl = true;
regs.cop0.EPC = pc;
status.exl = true;
EPC = pc;
}
regs.cop0.cause.copError = cop;
regs.cop0.cause.exceptionCode = static_cast<u8>(code);
cause.copError = cop;
cause.exceptionCode = static_cast<u8>(code);
if (regs.cop0.status.bev) {
if (status.bev) {
panic("BEV bit set!");
} else {
switch (code) {
@@ -423,15 +423,15 @@ void Cop0::FireException(const ExceptionCode code, const int cop, s64 pc) const
regs.cop0.Update();
}
void Cop0::HandleTLBException(const u64 vaddr) const {
void Cop0::HandleTLBException(const u64 vaddr) {
const u64 vpn2 = vaddr >> 13 & 0x7FFFF;
const u64 xvpn2 = vaddr >> 13 & 0x7FFFFFF;
regs.cop0.badVaddr = vaddr;
regs.cop0.context.badvpn2 = vpn2;
regs.cop0.xcontext.badvpn2 = xvpn2;
regs.cop0.xcontext.r = vaddr >> 62 & 3;
regs.cop0.entryHi.vpn2 = xvpn2;
regs.cop0.entryHi.r = vaddr >> 62 & 3;
badVaddr = vaddr;
context.badvpn2 = vpn2;
xcontext.badvpn2 = xvpn2;
xcontext.r = vaddr >> 62 & 3;
entryHi.vpn2 = xvpn2;
entryHi.r = vaddr >> 62 & 3;
}
ExceptionCode Cop0::GetTLBExceptionCode(const TLBError error, const TLBAccessType accessType) {
@@ -452,6 +452,7 @@ ExceptionCode Cop0::GetTLBExceptionCode(const TLBError error, const TLBAccessTyp
}
void Cop0::decode(const u32 instr) {
Registers& regs = Core::GetInstance().cpu->GetRegs();
const u8 mask_cop = instr >> 21 & 0x1F;
const u8 mask_cop2 = instr & 0x3F;
switch (mask_cop) {
@@ -495,30 +496,30 @@ void Cop0::decode(const u32 instr) {
}
bool Cop0::MapVAddr(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
if (regs.cop0.is64BitAddressing) [[unlikely]] {
if (regs.cop0.kernelMode) [[likely]] {
if (is64BitAddressing) [[unlikely]] {
if (kernelMode) [[likely]] {
return MapVAddr64(accessType, vaddr, paddr);
}
if (regs.cop0.userMode) {
if (userMode) {
return UserMapVAddr64(accessType, vaddr, paddr);
}
if (regs.cop0.supervisorMode) {
if (supervisorMode) {
panic("Supervisor mode memory access, 64 bit mode");
} else {
panic("Unknown mode! This should never happen!");
}
} else {
if (regs.cop0.kernelMode) [[likely]] {
if (kernelMode) [[likely]] {
return MapVAddr32(accessType, vaddr, paddr);
}
if (regs.cop0.userMode) {
if (userMode) {
return UserMapVAddr32(accessType, vaddr, paddr);
}
if (regs.cop0.supervisorMode) {
if (supervisorMode) {
panic("Supervisor mode memory access, 32 bit mode");
} else {
panic("Unknown mode! This should never happen!");
@@ -531,7 +532,7 @@ bool Cop0::UserMapVAddr32(const TLBAccessType accessType, const u64 vaddr, u32 &
case VREGION_KUSEG:
return ProbeTLB(accessType, s64(s32(vaddr)), paddr);
default:
regs.cop0.tlbError = DISALLOWED_ADDRESS;
tlbError = DISALLOWED_ADDRESS;
return false;
}
}
@@ -558,7 +559,7 @@ bool Cop0::UserMapVAddr64(const TLBAccessType accessType, const u64 vaddr, u32 &
case VREGION_XKUSEG:
return ProbeTLB(accessType, vaddr, paddr);
default:
regs.cop0.tlbError = DISALLOWED_ADDRESS;
tlbError = DISALLOWED_ADDRESS;
return false;
}
}
@@ -570,7 +571,7 @@ bool Cop0::MapVAddr64(const TLBAccessType accessType, const u64 vaddr, u32 &padd
return ProbeTLB(accessType, vaddr, paddr);
case VREGION_XKPHYS:
{
if (!regs.cop0.kernelMode) {
if (!kernelMode) {
panic("Access to XKPHYS address 0x{:016X} when outside kernel mode!", vaddr);
}
if (const u8 high_two_bits = (vaddr >> 62) & 0b11; high_two_bits != 0b10) {
@@ -580,7 +581,7 @@ bool Cop0::MapVAddr64(const TLBAccessType accessType, const u64 vaddr, u32 &padd
bool cached = subsegment != 2; // do something with this eventually
// If any bits in the range of 58:32 are set, the address is invalid.
if (const bool valid = (vaddr & 0x07FFFFFF00000000) == 0; !valid) {
regs.cop0.tlbError = DISALLOWED_ADDRESS;
tlbError = DISALLOWED_ADDRESS;
return false;
}
paddr = vaddr & 0xFFFFFFFF;
@@ -607,7 +608,7 @@ bool Cop0::MapVAddr64(const TLBAccessType accessType, const u64 vaddr, u32 &padd
case VREGION_XBAD1:
case VREGION_XBAD2:
case VREGION_XBAD3:
regs.cop0.tlbError = DISALLOWED_ADDRESS;
tlbError = DISALLOWED_ADDRESS;
return false;
default:
panic("Resolving virtual address 0x{:016X} in 64 bit mode", vaddr);

View File

@@ -37,11 +37,6 @@ namespace n64 {
#define ENTRY_HI_MASK 0xC00000FFFFFFE0FF
#define PAGEMASK_MASK 0x1FFE000
struct JIT;
struct Interpreter;
struct Registers;
struct Mem;
union Cop0Cause {
u32 raw;
struct {
@@ -194,7 +189,7 @@ union Cop0XContext {
};
struct Cop0 {
Cop0(Registers &);
Cop0();
u32 GetReg32(u8);
[[nodiscard]] u64 GetReg64(u8) const;
@@ -257,22 +252,21 @@ struct Cop0 {
enum TLBAccessType { LOAD, STORE };
bool ProbeTLB(TLBAccessType accessType, u64 vaddr, u32 &paddr) const;
void FireException(ExceptionCode code, int cop, s64 pc) const;
bool ProbeTLB(TLBAccessType accessType, u64 vaddr, u32 &paddr);
void FireException(ExceptionCode code, int cop, s64 pc);
bool MapVAddr(TLBAccessType accessType, u64 vaddr, u32 &paddr);
bool UserMapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr);
bool MapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr);
bool UserMapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr);
bool MapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr);
TLBEntry *TLBTryMatch(u64 vaddr, int &index) const;
TLBEntry *TLBTryMatch(u64 vaddr) const;
void HandleTLBException(u64 vaddr) const;
TLBEntry *TLBTryMatch(u64 vaddr, int &index);
TLBEntry *TLBTryMatch(u64 vaddr);
void HandleTLBException(u64 vaddr);
static ExceptionCode GetTLBExceptionCode(TLBError error, TLBAccessType accessType);
void decode(u32);
private:
Registers &regs;
[[nodiscard]] FORCE_INLINE u32 GetWired() const { return wired & 0x3F; }
[[nodiscard]] FORCE_INLINE u32 GetCount() const { return u32(u64(count >> 1)); }

View File

@@ -1,10 +1,8 @@
#include <core/Interpreter.hpp>
#include <core/registers/Cop1.hpp>
#include <core/registers/Registers.hpp>
#include <Core.hpp>
#include <log.hpp>
namespace n64 {
Cop1::Cop1(Registers &regs) : regs(regs) { Reset(); }
Cop1::Cop1() { Reset(); }
void Cop1::Reset() {
fcr0 = 0xa00;

View File

@@ -109,12 +109,8 @@ union FloatingPointReg {
};
};
struct Interpreter;
struct JIT;
struct Registers;
struct Cop1 {
explicit Cop1(Registers &);
explicit Cop1();
u32 fcr0{};
FCR31 fcr31{};
FloatingPointReg fgr[32]{};
@@ -233,10 +229,10 @@ private:
void negd(u32 instr);
void sqrts(u32 instr);
void sqrtd(u32 instr);
void lwc1(Mem &, u32);
void swc1(Mem &, u32);
void ldc1(Mem &, u32);
void sdc1(Mem &, u32);
void lwc1(u32);
void swc1(u32);
void ldc1(u32);
void sdc1(u32);
void mfc1(u32 instr);
void dmfc1(u32 instr);
@@ -246,7 +242,5 @@ private:
void truncwd(u32 instr);
void truncls(u32 instr);
void truncld(u32 instr);
Registers &regs;
};
} // namespace n64

View File

@@ -1,11 +1,9 @@
#include "jit/helpers.hpp"
#include <jit/helpers.hpp>
#include <core/registers/Registers.hpp>
#include <core/JIT.hpp>
namespace n64 {
Registers::Registers(JIT *jit) : jit(jit), cop0(*this), cop1(*this) { Reset(); }
Registers::Registers(JIT *jit) : jit(jit) { Reset(); }
void Registers::Reset() {
hi = 0;

View File

@@ -1,6 +1,4 @@
#include <Mem.hpp>
#include <core/RSP.hpp>
#include <core/registers/Registers.hpp>
#include <Core.hpp>
#include <log.hpp>
namespace n64 {
@@ -367,6 +365,7 @@ FORCE_INLINE void cop0(Mem &mem, const u32 instr) {
}
void RSP::Exec(const u32 instr) {
Mem& mem = Core::GetInstance().cpu->GetMem();
MMIO &mmio = mem.mmio;
MI &mi = mmio.mi;
switch (const u8 mask = instr >> 26 & 0x3F) {

View File

@@ -1,8 +1,6 @@
#include <Mem.hpp>
#include <Core.hpp>
#include <RCP.hpp>
#include <RSP.hpp>
#include <RSQ.hpp>
#include <core/registers/Registers.hpp>
#include <log.hpp>
namespace n64 {
@@ -1803,7 +1801,10 @@ void RSP::vzero(const u32 instr) {
void RSP::mfc0(const RDP &rdp, const u32 instr) { gpr[RT(instr)] = GetCop0Reg(*this, rdp, RD(instr)); }
void RSP::mtc0(const u32 instr) const { SetCop0Reg(mem, RD(instr), gpr[RT(instr)]); }
void RSP::mtc0(const u32 instr) const {
Mem& mem = Core::GetInstance().cpu->GetMem();
SetCop0Reg(mem, RD(instr), gpr[RT(instr)]);
}
void RSP::mfc2(const u32 instr) {
const u8 hi = vpr[RD(instr)].byte[BYTE_INDEX(E1(instr))];

View File

@@ -5,7 +5,6 @@ class CPUSettings final {
int selectedCpuTypeIndex = 0;
bool modified = false;
public:
int GetCPUType() { return selectedCpuTypeIndex; }
bool render();
explicit CPUSettings();
void setModified(bool v) { modified = v; }

View File

@@ -3,6 +3,7 @@
#include <execution>
bool Debugger::render() {
n64::Core& core = n64::Core::GetInstance();
if(enabled && ImGui::Begin("Debugger", &enabled)) {
static u64 startAddr = 0xFFFF'FFFF'8000'0000;
static constexpr int addrStep = 4;
@@ -13,7 +14,7 @@ bool Debugger::render() {
ImGui::SameLine();
ImGui::Checkbox("Follow program counter:", &followPC);
if(followPC)
startAddr = core->cpu->GetRegs().oldPC - 64; // TODO: arbitrary???
startAddr = core.cpu->GetRegs().oldPC - 64; // TODO: arbitrary???
if(ImGui::BeginTable("Disassembly", 3, ImGuiTableFlags_RowBg)) {
ImGui::TableSetupColumn("Address");
@@ -22,7 +23,7 @@ bool Debugger::render() {
ImGui::TableHeadersRow();
for(u64 addr = startAddr; addr < startAddr + MAX_LINES_OF_DISASM * sizeof(u32); addr += sizeof(u32)) {
auto disasm = core->cpu->Disassemble(addr);
auto disasm = core.cpu->Disassemble(addr);
std::string op_str;
for(int i = 0; i < 3; i++) {
if(i < 2) {
@@ -34,7 +35,7 @@ bool Debugger::render() {
if(!disasm.ops[i].empty()) op_str += disasm.ops[i];
}
}
auto isPc = addr == core->cpu->GetRegs().oldPC;
auto isPc = addr == core.cpu->GetRegs().oldPC;
if(isPc) {
ImGui::PushStyleColor(ImGuiCol_TableRowBg, 0x809a9ade);
ImGui::PushStyleColor(ImGuiCol_TableRowBgAlt, 0x807777bf);

View File

@@ -2,11 +2,9 @@
#include <backend/Core.hpp>
class Debugger final {
std::shared_ptr<n64::Core> core;
bool enabled = false;
static constexpr auto MAX_LINES_OF_DISASM = 150;
public:
Debugger(const std::shared_ptr<n64::Core>& core) : core(core) { }
void Open() { enabled = true; }
void Close() { enabled = false; }
bool render();

View File

@@ -2,12 +2,13 @@
#include <EmuThread.hpp>
#include <KaizenGui.hpp>
EmuThread::EmuThread(const std::shared_ptr<n64::Core> &core, double &fps, RenderWidget &renderWidget,
EmuThread::EmuThread(double &fps, RenderWidget &renderWidget,
SettingsWindow &settings) noexcept :
renderWidget(renderWidget), core(core), settings(settings), fps(fps) {}
renderWidget(renderWidget), settings(settings), fps(fps) {}
void EmuThread::run() const noexcept {
if(!core->romLoaded) return;
n64::Core& core = n64::Core::GetInstance();
if(!core.romLoaded) return;
auto lastSample = std::chrono::high_resolution_clock::now();
auto avgFps = 16.667;
@@ -17,8 +18,8 @@ void EmuThread::run() const noexcept {
fps = 1000.0 / avgFps;
const auto startFrameTime = std::chrono::high_resolution_clock::now();
if (!core->pause) {
core->Run(settings.getVolumeL(), settings.getVolumeR());
if (!core.pause) {
core.Run(settings.getVolumeL(), settings.getVolumeR());
}
const auto endFrameTime = std::chrono::high_resolution_clock::now();
@@ -40,15 +41,17 @@ void EmuThread::run() const noexcept {
}
void EmuThread::TogglePause() const noexcept {
core->TogglePause();
n64::Core::GetInstance().TogglePause();
}
void EmuThread::Reset() const noexcept {
core->Stop();
core->LoadROM(core->rom);
n64::Core& core = n64::Core::GetInstance();
core.Stop();
core.LoadROM(core.rom);
}
void EmuThread::Stop() const noexcept {
core->Stop();
core->rom = {};
n64::Core& core = n64::Core::GetInstance();
core.Stop();
core.rom = {};
}

View File

@@ -11,7 +11,7 @@ class EmuThread final {
RenderWidget &renderWidget;
bool started = false;
public:
explicit EmuThread(const std::shared_ptr<n64::Core> &, double &, RenderWidget &, SettingsWindow &) noexcept;
explicit EmuThread(double &, RenderWidget &, SettingsWindow &) noexcept;
~EmuThread() = default;
void run() const noexcept;
void TogglePause() const noexcept;
@@ -19,7 +19,6 @@ public:
void Stop() const noexcept;
bool interruptionRequested = false, parallelRDPInitialized = false;
std::shared_ptr<n64::Core> core;
SettingsWindow &settings;
double& fps;
};

View File

@@ -4,8 +4,8 @@
#include <ImGuiImpl/StatusBar.hpp>
#include <resources/gamecontrollerdb.h>
KaizenGui::KaizenGui() noexcept : window("Kaizen", 800, 600), settingsWindow(window), core(std::make_shared<n64::Core>(static_cast<n64::Core::CPUType>(settingsWindow.cpuSettings.GetCPUType()))), vulkanWidget(core, window.getHandle()), emuThread(core, fpsCounter, vulkanWidget, settingsWindow), debugger(core) {
gui::Initialize(core->parallel.wsi, window.getHandle());
KaizenGui::KaizenGui() noexcept : window("Kaizen", 800, 600), settingsWindow(window), vulkanWidget(window.getHandle()), emuThread(fpsCounter, vulkanWidget, settingsWindow) {
gui::Initialize(n64::Core::GetInstance().parallel.wsi, window.getHandle());
SDL_InitSubSystem(SDL_INIT_GAMEPAD);
SDL_AddGamepadMapping(gamecontrollerdb_str);
@@ -34,7 +34,8 @@ void KaizenGui::QueryDevices(SDL_Event event) {
}
void KaizenGui::HandleInput(SDL_Event event) {
n64::PIF &pif = core->cpu->GetMem().mmio.si.pif;
n64::Core& core = n64::Core::GetInstance();
n64::PIF &pif = core.cpu->GetMem().mmio.si.pif;
switch(event.type) {
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
if(!gamepad)
@@ -95,9 +96,9 @@ void KaizenGui::HandleInput(SDL_Event event) {
fastForward = keys[SDL_SCANCODE_SPACE];
if(!unlockFramerate)
core->parallel.SetFramerateUnlocked(fastForward);
core.parallel.SetFramerateUnlocked(fastForward);
if(core->romLoaded) {
if(core.romLoaded) {
if(keys[SDL_SCANCODE_P]) {
emuThread.TogglePause();
}
@@ -134,6 +135,7 @@ void KaizenGui::HandleInput(SDL_Event event) {
}
void KaizenGui::RenderUI() {
n64::Core& core = n64::Core::GetInstance();
gui::StartFrame();
if(ImGui::BeginMainMenuBar()) {
@@ -148,9 +150,9 @@ void KaizenGui::RenderUI() {
ImGui::EndMenu();
}
if(ImGui::BeginMenu("Emulation")) {
ImGui::BeginDisabled(!core->romLoaded);
ImGui::BeginDisabled(!core.romLoaded);
if(ImGui::MenuItem(core->pause ? "Resume" : "Pause", "P")) {
if(ImGui::MenuItem(core.pause ? "Resume" : "Pause", "P")) {
emuThread.TogglePause();
}
@@ -160,11 +162,11 @@ void KaizenGui::RenderUI() {
if(ImGui::MenuItem("Stop", "Q")) {
emuThread.Stop();
core->romLoaded = false;
core.romLoaded = false;
}
if(ImGui::Checkbox("Unlock framerate", &unlockFramerate)) {
core->parallel.SetFramerateUnlocked(unlockFramerate);
core.parallel.SetFramerateUnlocked(unlockFramerate);
}
if(ImGui::MenuItem("Open Debugger")) {
@@ -245,17 +247,18 @@ void KaizenGui::RenderUI() {
}, this, window.getHandle(), filters, 3, nullptr, false);
}
if(core->romLoaded) {
core->parallel.UpdateScreen(*core.get());
if(core.romLoaded) {
core.parallel.UpdateScreen();
return;
}
core->parallel.UpdateScreen(*core.get(), false);
core.parallel.UpdateScreen(false);
}
void KaizenGui::LoadROM(const std::string &path) noexcept {
emuThread.core->LoadROM(path);
const auto gameNameDB = emuThread.core->cpu->GetMem().rom.gameNameDB;
n64::Core& core = n64::Core::GetInstance();
core.LoadROM(path);
const auto gameNameDB = core.cpu->GetMem().rom.gameNameDB;
}
void KaizenGui::run() {
@@ -279,8 +282,9 @@ void KaizenGui::run() {
}
void KaizenGui::LoadTAS(const std::string &path) const noexcept {
if (emuThread.core->LoadTAS(fs::path(path))) {
const auto gameNameDB = emuThread.core->cpu->GetMem().rom.gameNameDB;
n64::Core& core = n64::Core::GetInstance();
if (core.LoadTAS(fs::path(path))) {
const auto gameNameDB = core.cpu->GetMem().rom.gameNameDB;
const auto movieName = fs::path(path).stem().string();
return;
}

View File

@@ -16,7 +16,6 @@ public:
bool unlockFramerate = false;
SettingsWindow settingsWindow;
std::shared_ptr<n64::Core> core;
RenderWidget vulkanWidget;
EmuThread emuThread;
Debugger debugger;

View File

@@ -4,8 +4,9 @@
#include <SDL3/SDL.h>
#include <imgui_impl_sdl3.h>
RenderWidget::RenderWidget(const std::shared_ptr<n64::Core> &core, SDL_Window* window) {
wsiPlatform = std::make_shared<SDLWSIPlatform>(core, window);
RenderWidget::RenderWidget(SDL_Window* window) {
wsiPlatform = std::make_shared<SDLWSIPlatform>(window);
windowInfo = std::make_shared<SDLParallelRdpWindowInfo>(window);
core->parallel.Init(wsiPlatform, windowInfo, core->cpu->GetMem().GetRDRAMPtr());
n64::Core& core = n64::Core::GetInstance();
core.parallel.Init(wsiPlatform, windowInfo, core.cpu->GetMem().GetRDRAMPtr());
}

View File

@@ -24,7 +24,7 @@ private:
class SDLWSIPlatform final : public Vulkan::WSIPlatform {
public:
explicit SDLWSIPlatform(const std::shared_ptr<n64::Core> &core, SDL_Window* window) : window(window), core(core) {}
explicit SDLWSIPlatform(SDL_Window* window) : window(window) {}
~SDLWSIPlatform() = default;
std::vector<const char *> get_instance_extensions() override {
@@ -67,13 +67,12 @@ public:
SDL_Window* window{};
VkSurfaceKHR surface;
private:
std::shared_ptr<n64::Core> core;
bool gamepadConnected = false;
};
class RenderWidget final {
public:
explicit RenderWidget(const std::shared_ptr<n64::Core> &, SDL_Window*);
explicit RenderWidget(SDL_Window*);
std::shared_ptr<ParallelRDP::WindowInfo> windowInfo;
std::shared_ptr<SDLWSIPlatform> wsiPlatform;