Huge refactor: Make Core a singleton
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <Core.hpp>
|
||||
|
||||
namespace n64 {
|
||||
Interpreter::Interpreter(ParallelRDP ¶llel) : mem(regs, parallel) {}
|
||||
Interpreter::Interpreter(ParallelRDP ¶llel) {}
|
||||
|
||||
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(), ®s, sizeof(Registers));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void Interpreter::Deserialize(const std::vector<u8> &data) { memcpy(®s, data.data(), sizeof(Registers)); }
|
||||
} // namespace n64
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
namespace n64 {
|
||||
#ifndef __aarch64__
|
||||
JIT::JIT(ParallelRDP ¶llel) : regs(this), mem(regs, parallel, this) {
|
||||
JIT::JIT(ParallelRDP ¶llel) : 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(), ®s, sizeof(Registers));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void JIT::Deserialize(const std::vector<u8> &data) { memcpy(®s, data.data(), sizeof(Registers)); }
|
||||
#endif
|
||||
} // namespace n64
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -15,10 +15,7 @@ struct Mem;
|
||||
struct Registers;
|
||||
|
||||
struct MMIO {
|
||||
MMIO(Mem &mem, Registers ®s, ParallelRDP ¶llel) :
|
||||
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
|
||||
|
||||
@@ -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 ®s, ParallelRDP ¶llel, 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 ®s, 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 ®s, const u32 paddr) {
|
||||
}
|
||||
|
||||
template <>
|
||||
u16 Mem::Read(Registers ®s, 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 ®s, const u32 paddr) {
|
||||
}
|
||||
|
||||
template <>
|
||||
u32 Mem::Read(Registers ®s, 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 ®s, const u32 paddr) {
|
||||
}
|
||||
|
||||
template <>
|
||||
u64 Mem::Read(Registers ®s, 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 ®s, const u32 paddr) {
|
||||
}
|
||||
|
||||
template <>
|
||||
void Mem::WriteInterpreter<u8>(Registers ®s, 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 ®s, 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 ®s, u32 paddr, u32 val) {
|
||||
|
||||
#ifndef __aarch64__
|
||||
template <>
|
||||
void Mem::WriteJIT<u8>(Registers ®s, 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 ®s, 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 ®s, 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 ®s, 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 ®s, u32 paddr, u32 val) {
|
||||
|
||||
#ifndef __aarch64__
|
||||
template <>
|
||||
void Mem::WriteJIT<u16>(Registers ®s, 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 ®s, 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 ®s, 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 ®s, 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 ®s, const u32 paddr, const u32 val)
|
||||
|
||||
#ifndef __aarch64__
|
||||
template <>
|
||||
void Mem::WriteJIT<u32>(Registers ®s, 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 ®s, 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 ®s, 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 ®s, 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 ®s, 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 ®s, 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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 ¶llel) : 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;
|
||||
|
||||
@@ -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 ∥
|
||||
};
|
||||
} // namespace n64
|
||||
|
||||
@@ -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 ®s) : 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;
|
||||
|
||||
@@ -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 ®s;
|
||||
Mem &mem;
|
||||
FORCE_INLINE void branch(const u16 address, const bool cond) {
|
||||
if (cond) {
|
||||
nextPC = address & 0xFFC;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 ®s) : 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) {
|
||||
|
||||
@@ -3,11 +3,8 @@
|
||||
#include <core/mmio/Audio.hpp>
|
||||
|
||||
namespace n64 {
|
||||
struct Mem;
|
||||
struct Registers;
|
||||
|
||||
struct AI {
|
||||
AI(Mem &, Registers ®s);
|
||||
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 ®s;
|
||||
};
|
||||
} // namespace n64
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#define MI_VERSION_REG 0x02020102
|
||||
|
||||
namespace n64 {
|
||||
MI::MI(Registers ®s) : regs(regs) { Reset(); }
|
||||
MI::MI() { Reset(); }
|
||||
|
||||
void MI::Reset() {
|
||||
miIntrMask.raw = 0;
|
||||
|
||||
@@ -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 ®s;
|
||||
};
|
||||
} // namespace n64
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <log.hpp>
|
||||
|
||||
namespace n64 {
|
||||
PI::PI(Mem &mem, Registers ®s) : 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:
|
||||
|
||||
@@ -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 ®s;
|
||||
};
|
||||
} // namespace n64
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ®s) : 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 ®s;
|
||||
|
||||
[[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
|
||||
|
||||
@@ -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 ®s) : 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;
|
||||
|
||||
@@ -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 ®s;
|
||||
};
|
||||
|
||||
#define SI_DMA_DELAY (65536 * 2)
|
||||
|
||||
@@ -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 ®s) : 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;
|
||||
|
||||
@@ -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 ®s;
|
||||
};
|
||||
} // namespace n64
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#include <core/Interpreter.hpp>
|
||||
#include <core/registers/Registers.hpp>
|
||||
#include <Core.hpp>
|
||||
#include <log.hpp>
|
||||
|
||||
namespace n64 {
|
||||
Cop0::Cop0(Registers ®s) : 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 = ®s.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);
|
||||
|
||||
@@ -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 ®s;
|
||||
[[nodiscard]] FORCE_INLINE u32 GetWired() const { return wired & 0x3F; }
|
||||
[[nodiscard]] FORCE_INLINE u32 GetCount() const { return u32(u64(count >> 1)); }
|
||||
|
||||
|
||||
@@ -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 ®s) : regs(regs) { Reset(); }
|
||||
Cop1::Cop1() { Reset(); }
|
||||
|
||||
void Cop1::Reset() {
|
||||
fcr0 = 0xa00;
|
||||
|
||||
@@ -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 ®s;
|
||||
};
|
||||
} // namespace n64
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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))];
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 = {};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ public:
|
||||
bool unlockFramerate = false;
|
||||
|
||||
SettingsWindow settingsWindow;
|
||||
std::shared_ptr<n64::Core> core;
|
||||
RenderWidget vulkanWidget;
|
||||
EmuThread emuThread;
|
||||
Debugger debugger;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user