Refactor many other things
This commit is contained in:
@@ -3,18 +3,6 @@
|
||||
#include <ParallelRDPWrapper.hpp>
|
||||
|
||||
namespace n64 {
|
||||
u32 extraCycles = 0;
|
||||
|
||||
void CpuStall(u32 cycles) {
|
||||
extraCycles += cycles;
|
||||
}
|
||||
|
||||
u32 PopStalledCycles() {
|
||||
u32 ret = extraCycles;
|
||||
extraCycles = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Core::Core() : cpu(std::make_unique<Interpreter>()) {}
|
||||
|
||||
void Core::Stop() {
|
||||
@@ -71,7 +59,7 @@ void Core::Run(float volumeL, float volumeR) {
|
||||
|
||||
for(; cycles < mem.mmio.vi.cyclesPerHalfline; cycles++, frameCycles++) {
|
||||
u32 taken = cpu->Step();
|
||||
taken += PopStalledCycles();
|
||||
taken += regs.PopStalledCycles();
|
||||
static u32 cpuSteps = 0;
|
||||
cpuSteps += taken;
|
||||
if(mmio.rsp.spStatus.halt) {
|
||||
@@ -91,7 +79,7 @@ void Core::Run(float volumeL, float volumeR) {
|
||||
|
||||
cycles += taken;
|
||||
frameCycles += taken;
|
||||
scheduler.Tick(taken, mem, regs);
|
||||
scheduler.Tick(taken, mem);
|
||||
}
|
||||
|
||||
cycles -= mmio.vi.cyclesPerHalfline;
|
||||
@@ -101,8 +89,8 @@ void Core::Run(float volumeL, float volumeR) {
|
||||
mmio.mi.InterruptRaise(MI::Interrupt::VI);
|
||||
}
|
||||
|
||||
mmio.ai.Step(cpu->mem, regs, frameCycles, volumeL, volumeR);
|
||||
scheduler.Tick(frameCycles, mem, regs);
|
||||
mmio.ai.Step(frameCycles, volumeL, volumeR);
|
||||
scheduler.Tick(frameCycles, mem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,8 +30,4 @@ struct Core {
|
||||
size_t memSize{}, cpuSize{}, verSize{};
|
||||
int slot = 0;
|
||||
};
|
||||
|
||||
extern u32 extraCycles;
|
||||
void CpuStall(u32 cycles);
|
||||
u32 PopStalledCycles();
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ u64 Scheduler::Remove(EventType type) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Scheduler::Tick(u64 t, n64::Mem& mem, n64::Registers& regs) {
|
||||
void Scheduler::Tick(u64 t, n64::Mem& mem) {
|
||||
ticks += t;
|
||||
n64::MI& mi = mem.mmio.mi;
|
||||
n64::SI& si = mem.mmio.si;
|
||||
@@ -34,7 +34,7 @@ void Scheduler::Tick(u64 t, n64::Mem& mem, n64::Registers& regs) {
|
||||
while(ticks >= events.top().time) {
|
||||
switch(auto type = events.top().type) {
|
||||
case SI_DMA:
|
||||
si.DMA(mem, regs);
|
||||
si.DMA();
|
||||
break;
|
||||
case PI_DMA_COMPLETE:
|
||||
mi.InterruptRaise(n64::MI::Interrupt::PI);
|
||||
|
||||
@@ -53,7 +53,7 @@ struct Scheduler {
|
||||
void EnqueueRelative(u64, EventType);
|
||||
void EnqueueAbsolute(u64, EventType);
|
||||
u64 Remove(EventType);
|
||||
void Tick(u64 t, n64::Mem&, n64::Registers&);
|
||||
void Tick(u64 t, n64::Mem&);
|
||||
|
||||
IterableEvents events;
|
||||
u64 ticks = 0;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#include <core/MMIO.hpp>
|
||||
#include <log.hpp>
|
||||
#include <core/Mem.hpp>
|
||||
#include <core/registers/Registers.hpp>
|
||||
|
||||
namespace n64 {
|
||||
void MMIO::Reset() {
|
||||
@@ -22,24 +20,24 @@ u32 MMIO::Read(u32 addr) {
|
||||
case MI_REGION: return mi.Read(addr);
|
||||
case VI_REGION: return vi.Read(addr);
|
||||
case AI_REGION: return ai.Read(addr);
|
||||
case PI_REGION: return pi.Read(mi, addr);
|
||||
case PI_REGION: return pi.Read(addr);
|
||||
case RI_REGION: return ri.Read(addr);
|
||||
case SI_REGION: return si.Read(mi, addr);
|
||||
case SI_REGION: return si.Read(addr);
|
||||
default:
|
||||
Util::panic("Unhandled mmio read at addr {:08X}", addr);
|
||||
}
|
||||
}
|
||||
|
||||
void MMIO::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
|
||||
void MMIO::Write(u32 addr, u32 val) {
|
||||
switch (addr) {
|
||||
case RSP_REGION: rsp.Write(addr, val); break;
|
||||
case RDP_REGION: rdp.Write(mi, regs, rsp, addr, val); break;
|
||||
case MI_REGION: mi.Write(regs, addr, val); break;
|
||||
case VI_REGION: vi.Write(mi, regs, addr, val); break;
|
||||
case AI_REGION: ai.Write(mem, regs, addr, val); break;
|
||||
case PI_REGION: pi.Write(mem, regs, addr, val); break;
|
||||
case RDP_REGION: rdp.Write(addr, val); break;
|
||||
case MI_REGION: mi.Write(addr, val); break;
|
||||
case VI_REGION: vi.Write(addr, val); break;
|
||||
case AI_REGION: ai.Write(addr, val); break;
|
||||
case PI_REGION: pi.Write(addr, val); break;
|
||||
case RI_REGION: ri.Write(addr, val); break;
|
||||
case SI_REGION: si.Write(mem, regs, addr, val); break;
|
||||
case SI_REGION: si.Write(addr, val); break;
|
||||
default:
|
||||
Util::panic("Unhandled mmio write at addr {:08X} with val {:08X}", addr, val);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ struct Mem;
|
||||
struct Registers;
|
||||
|
||||
struct MMIO {
|
||||
MMIO(Mem& mem, Registers& regs) : mi(regs), si(mem, regs), rsp(mem, regs) {}
|
||||
MMIO(Mem& mem, Registers& regs) : vi(mem, regs), mi(regs), ai(mem, regs), pi(mem, regs), si(mem, regs), rsp(mem, regs), rdp(mem, regs) {}
|
||||
void Reset();
|
||||
|
||||
VI vi;
|
||||
@@ -26,7 +26,7 @@ struct MMIO {
|
||||
RDP rdp;
|
||||
|
||||
u32 Read(u32);
|
||||
void Write(Mem&, Registers&, u32, u32);
|
||||
void Write(u32, u32);
|
||||
std::vector<u8> Serialize();
|
||||
void Deserialize(const std::vector<u8>&);
|
||||
};
|
||||
|
||||
@@ -193,7 +193,7 @@ template<> u8 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
return src[BYTE_ADDRESS(paddr & 0xfff)];
|
||||
}
|
||||
case REGION_CART:
|
||||
return mmio.pi.BusRead<u8, false>(*this, paddr);
|
||||
return mmio.pi.BusRead<u8, false>(paddr);
|
||||
case 0x04040000 ... 0x040FFFFF:
|
||||
case 0x04100000 ... 0x041FFFFF:
|
||||
case 0x04600000 ... 0x048FFFFF:
|
||||
@@ -238,7 +238,7 @@ template<> u16 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
case MMIO_REGION:
|
||||
return mmio.Read(paddr);
|
||||
case REGION_CART:
|
||||
return mmio.pi.BusRead<u16, false>(*this, paddr);
|
||||
return mmio.pi.BusRead<u16, false>(paddr);
|
||||
case PIF_ROM_REGION:
|
||||
return Util::ReadAccess<u16>(si.pif.bootrom, HALF_ADDRESS(paddr) - PIF_ROM_REGION_START);
|
||||
case PIF_RAM_REGION:
|
||||
@@ -273,7 +273,7 @@ template<> u32 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
case MMIO_REGION:
|
||||
return mmio.Read(paddr);
|
||||
case REGION_CART:
|
||||
return mmio.pi.BusRead<u32, false>(*this, paddr);
|
||||
return mmio.pi.BusRead<u32, false>(paddr);
|
||||
case PIF_ROM_REGION:
|
||||
return Util::ReadAccess<u32>(si.pif.bootrom, paddr - PIF_ROM_REGION_START);
|
||||
case PIF_RAM_REGION:
|
||||
@@ -305,7 +305,7 @@ template<> u64 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
case MMIO_REGION:
|
||||
return mmio.Read(paddr);
|
||||
case REGION_CART:
|
||||
return mmio.pi.BusRead<u64, false>(*this, paddr);
|
||||
return mmio.pi.BusRead<u64, false>(paddr);
|
||||
case PIF_ROM_REGION:
|
||||
return Util::ReadAccess<u64>(si.pif.bootrom, paddr - PIF_ROM_REGION_START);
|
||||
case PIF_RAM_REGION:
|
||||
@@ -342,7 +342,7 @@ template<> void Mem::Write<u8>(Registers& regs, u32 paddr, u32 val) {
|
||||
} break;
|
||||
case REGION_CART:
|
||||
Util::trace("BusWrite<u8> @ {:08X} = {:02X}", paddr, val);
|
||||
mmio.pi.BusWrite<u8, false>(*this, paddr, val);
|
||||
mmio.pi.BusWrite<u8, false>(paddr, val);
|
||||
break;
|
||||
case MMIO_REGION:
|
||||
Util::panic("MMIO Write<u8>!");
|
||||
@@ -387,7 +387,7 @@ template<> void Mem::Write<u16>(Registers& regs, u32 paddr, u32 val) {
|
||||
} break;
|
||||
case REGION_CART:
|
||||
Util::trace("BusWrite<u8> @ {:08X} = {:04X}", paddr, val);
|
||||
mmio.pi.BusWrite<u16, false>(*this, paddr, val);
|
||||
mmio.pi.BusWrite<u16, false>(paddr, val);
|
||||
break;
|
||||
case MMIO_REGION:
|
||||
Util::panic("MMIO Write<u16>!");
|
||||
@@ -430,10 +430,10 @@ template<> void Mem::Write<u32>(Registers& regs, u32 paddr, u32 val) {
|
||||
} break;
|
||||
case REGION_CART:
|
||||
Util::trace("BusWrite<u8> @ {:08X} = {:08X}", paddr, val);
|
||||
mmio.pi.BusWrite<u32, false>(*this, paddr, val);
|
||||
mmio.pi.BusWrite<u32, false>(paddr, val);
|
||||
break;
|
||||
case MMIO_REGION:
|
||||
mmio.Write(*this, regs, paddr, val);
|
||||
mmio.Write(paddr, val);
|
||||
break;
|
||||
case PIF_RAM_REGION:
|
||||
Util::WriteAccess<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START, htobe32(val));
|
||||
@@ -470,7 +470,7 @@ void Mem::Write(Registers& regs, u32 paddr, u64 val) {
|
||||
} break;
|
||||
case REGION_CART:
|
||||
Util::trace("BusWrite<u8> @ {:08X} = {:016X}", paddr, val);
|
||||
mmio.pi.BusWrite<false>(*this, paddr, val);
|
||||
mmio.pi.BusWrite<false>(paddr, val);
|
||||
break;
|
||||
case MMIO_REGION:
|
||||
Util::panic("MMIO Write!");
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <core/mmio/Interrupt.hpp>
|
||||
|
||||
namespace n64 {
|
||||
RDP::RDP() {
|
||||
RDP::RDP(Mem& mem, Registers& regs) : mem(mem), regs(regs) {
|
||||
rdram.resize(RDRAM_SIZE);
|
||||
memset(cmd_buf, 0, 0x100000);
|
||||
dpc.status.raw = 0x80;
|
||||
@@ -40,17 +40,17 @@ auto RDP::Read(u32 addr) const -> u32 {
|
||||
}
|
||||
}
|
||||
|
||||
void RDP::Write(MI& mi, Registers& regs, RSP& rsp, u32 addr, u32 val) {
|
||||
void RDP::Write(u32 addr, u32 val) {
|
||||
switch(addr) {
|
||||
case 0x04100000: WriteStart(val); break;
|
||||
case 0x04100004: WriteEnd(mi, regs, rsp, val); break;
|
||||
case 0x0410000C: WriteStatus(mi, regs, rsp, val); break;
|
||||
case 0x04100004: WriteEnd(val); break;
|
||||
case 0x0410000C: WriteStatus(val); break;
|
||||
default:
|
||||
Util::panic("Unhandled DP Command Registers write (addr: {:08X}, val: {:08X})", addr, val);
|
||||
}
|
||||
}
|
||||
|
||||
void RDP::WriteStatus(MI& mi, Registers& regs, RSP& rsp, u32 val) {
|
||||
void RDP::WriteStatus(u32 val) {
|
||||
DPCStatusWrite temp{};
|
||||
temp.raw = val;
|
||||
|
||||
@@ -69,7 +69,7 @@ void RDP::WriteStatus(MI& mi, Registers& regs, RSP& rsp, u32 val) {
|
||||
CLEAR_SET(dpc.status.tmemBusy, temp.clearTmem, false);
|
||||
|
||||
if(!dpc.status.freeze) {
|
||||
RunCommand(mi, regs, rsp);
|
||||
RunCommand();
|
||||
}
|
||||
}
|
||||
/*
|
||||
@@ -114,7 +114,7 @@ FORCE_INLINE void logCommand(u8 cmd) {
|
||||
}
|
||||
*/
|
||||
|
||||
void RDP::RunCommand(MI& mi, Registers& regs, RSP& rsp) {
|
||||
void RDP::RunCommand() {
|
||||
if (dpc.status.freeze) {
|
||||
return;
|
||||
}
|
||||
@@ -138,7 +138,7 @@ void RDP::RunCommand(MI& mi, Registers& regs, RSP& rsp) {
|
||||
|
||||
if (dpc.status.xbusDmemDma) {
|
||||
for (int i = 0; i < len; i += 4) {
|
||||
u32 cmd = Util::ReadAccess<u32>(rsp.dmem, (current + i) & 0xFFF);
|
||||
u32 cmd = Util::ReadAccess<u32>(mem.mmio.rsp.dmem, (current + i) & 0xFFF);
|
||||
cmd_buf[remaining_cmds + (i >> 2)] = cmd;
|
||||
}
|
||||
} else {
|
||||
@@ -181,7 +181,7 @@ void RDP::RunCommand(MI& mi, Registers& regs, RSP& rsp) {
|
||||
}
|
||||
|
||||
if (cmd == 0x29) {
|
||||
OnFullSync(mi, regs);
|
||||
OnFullSync();
|
||||
}
|
||||
|
||||
buf_index += cmd_len;
|
||||
@@ -198,12 +198,12 @@ void RDP::RunCommand(MI& mi, Registers& regs, RSP& rsp) {
|
||||
dpc.status.cbufReady = true;
|
||||
}
|
||||
|
||||
void RDP::OnFullSync(MI& mi, Registers& regs) {
|
||||
void RDP::OnFullSync() {
|
||||
ParallelRdpOnFullSync();
|
||||
|
||||
dpc.status.pipeBusy = false;
|
||||
dpc.status.startGclk = false;
|
||||
dpc.status.cbufReady = false;
|
||||
mi.InterruptRaise(MI::Interrupt::DP);
|
||||
mem.mmio.mi.InterruptRaise(MI::Interrupt::DP);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
namespace n64 {
|
||||
|
||||
struct RSP;
|
||||
struct MI;
|
||||
struct Mem;
|
||||
struct Registers;
|
||||
|
||||
union DPCStatusWrite {
|
||||
@@ -54,15 +54,15 @@ struct RDP {
|
||||
DPC dpc{};
|
||||
u32 cmd_buf[0xFFFFF]{};
|
||||
|
||||
RDP();
|
||||
RDP(Mem&, Registers&);
|
||||
void Reset();
|
||||
|
||||
std::vector<u8> rdram{};
|
||||
[[nodiscard]] auto Read(u32 addr) const -> u32;
|
||||
void Write(MI& mi, Registers& regs, RSP& rsp, u32 addr, u32 val);
|
||||
void WriteStatus(MI& mi, Registers& regs, RSP& rsp, u32 val);
|
||||
void RunCommand(MI& mi, Registers& regs, RSP& rsp);
|
||||
void OnFullSync(MI& mi, Registers& regs);
|
||||
void Write(u32 addr, u32 val);
|
||||
void WriteStatus(u32 val);
|
||||
void RunCommand();
|
||||
void OnFullSync();
|
||||
|
||||
FORCE_INLINE void WriteStart(u32 val) {
|
||||
if(!dpc.status.startValid) {
|
||||
@@ -71,13 +71,16 @@ struct RDP {
|
||||
dpc.status.startValid = true;
|
||||
}
|
||||
|
||||
FORCE_INLINE void WriteEnd(MI& mi, Registers& regs, RSP& rsp, u32 val) {
|
||||
FORCE_INLINE void WriteEnd(u32 val) {
|
||||
dpc.end = val & 0xFFFFF8;
|
||||
if(dpc.status.startValid) {
|
||||
dpc.current = dpc.start;
|
||||
dpc.status.startValid = false;
|
||||
}
|
||||
RunCommand(mi, regs, rsp);
|
||||
RunCommand();
|
||||
}
|
||||
private:
|
||||
Mem& mem;
|
||||
Registers& regs;
|
||||
};
|
||||
} // backend
|
||||
|
||||
@@ -110,26 +110,26 @@ void RSP::WriteStatus(u32 value) {
|
||||
CLEAR_SET(spStatus.signal7, write.clearSignal7, write.setSignal7);
|
||||
}
|
||||
|
||||
void RSP::Write(u32 addr, u32 value) {
|
||||
void RSP::Write(u32 addr, u32 val) {
|
||||
switch (addr) {
|
||||
case 0x04040000: spDMASPAddr.raw = value & 0x1FF8; break;
|
||||
case 0x04040004: spDMADRAMAddr.raw = value & 0xFFFFF8; break;
|
||||
case 0x04040000: spDMASPAddr.raw = val & 0x1FF8; break;
|
||||
case 0x04040004: spDMADRAMAddr.raw = val & 0xFFFFF8; break;
|
||||
case 0x04040008: {
|
||||
spDMALen.raw = value;
|
||||
spDMALen.raw = val;
|
||||
DMAtoRSP(mem.GetRDRAM());
|
||||
} break;
|
||||
case 0x0404000C: {
|
||||
spDMALen.raw = value;
|
||||
spDMALen.raw = val;
|
||||
DMAtoRDRAM(mem.GetRDRAM());
|
||||
} break;
|
||||
case 0x04040010: WriteStatus(value); break;
|
||||
case 0x04040010: WriteStatus(val); break;
|
||||
case 0x0404001C: ReleaseSemaphore(); break;
|
||||
case 0x04080000:
|
||||
if(spStatus.halt) {
|
||||
SetPC(value);
|
||||
SetPC(val);
|
||||
} break;
|
||||
default:
|
||||
Util::panic("Unimplemented SP register write {:08X}, val: {:08X}", addr, value);
|
||||
Util::panic("Unimplemented SP register write {:08X}, val: {:08X}", addr, val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ struct RSP {
|
||||
Exec(instr);
|
||||
}
|
||||
auto Read(u32 addr) -> u32;
|
||||
void Write(u32 addr, u32 value);
|
||||
void Write(u32 addr, u32 val);
|
||||
void Exec(u32 instr);
|
||||
SPStatus spStatus{};
|
||||
u16 oldPC{}, pc{}, nextPC{};
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <core/registers/Registers.hpp>
|
||||
|
||||
namespace n64 {
|
||||
AI::AI(Mem &mem, Registers ®s) : mem(mem), regs(regs) { }
|
||||
|
||||
void AI::Reset() {
|
||||
dmaEnable = false;
|
||||
dacRate = 0;
|
||||
@@ -33,7 +35,7 @@ auto AI::Read(u32 addr) const -> u32 {
|
||||
return dmaLen[0];
|
||||
}
|
||||
|
||||
void AI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
|
||||
void AI::Write(u32 addr, u32 val) {
|
||||
switch(addr) {
|
||||
case 0x04500000:
|
||||
if(dmaCount < 2) {
|
||||
@@ -72,7 +74,7 @@ void AI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
|
||||
}
|
||||
}
|
||||
|
||||
void AI::Step(Mem& mem, Registers& regs, u32 cpuCycles, float volumeL, float volumeR) {
|
||||
void AI::Step(u32 cpuCycles, float volumeL, float volumeR) {
|
||||
cycles += cpuCycles;
|
||||
while(cycles > dac.period) {
|
||||
if (dmaCount == 0) {
|
||||
|
||||
@@ -8,11 +8,11 @@ struct Mem;
|
||||
struct Registers;
|
||||
|
||||
struct AI {
|
||||
AI() = default;
|
||||
AI(Mem&, Registers& regs);
|
||||
void Reset();
|
||||
auto Read(u32) const -> u32;
|
||||
void Write(Mem&, Registers&, u32, u32);
|
||||
void Step(Mem&, Registers&, u32, float, float);
|
||||
void Write(u32, u32);
|
||||
void Step(u32, float, float);
|
||||
bool dmaEnable{};
|
||||
u16 dacRate{};
|
||||
u8 bitrate{};
|
||||
@@ -28,5 +28,8 @@ struct AI {
|
||||
u32 period{N64_CPU_FREQ / freq};
|
||||
u32 precision{16};
|
||||
} dac;
|
||||
private:
|
||||
Mem& mem;
|
||||
Registers& regs;
|
||||
};
|
||||
}
|
||||
@@ -27,7 +27,7 @@ auto MI::Read(u32 paddr) const -> u32 {
|
||||
}
|
||||
}
|
||||
|
||||
void MI::Write(Registers& regs, u32 paddr, u32 val) {
|
||||
void MI::Write(u32 paddr, u32 val) {
|
||||
switch(paddr & 0xF) {
|
||||
case 0x0:
|
||||
miMode &= 0xFFFFFF80;
|
||||
|
||||
@@ -26,7 +26,7 @@ struct MI {
|
||||
MI(Registers&);
|
||||
void Reset();
|
||||
[[nodiscard]] auto Read(u32) const -> u32;
|
||||
void Write(Registers& regs, u32, u32);
|
||||
void Write(u32, u32);
|
||||
void InterruptRaise(Interrupt intr);
|
||||
void InterruptLower(Interrupt intr);
|
||||
void UpdateInterrupt();
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <Scheduler.hpp>
|
||||
|
||||
namespace n64 {
|
||||
PI::PI() {
|
||||
PI::PI(Mem& mem, Registers& regs) : mem(mem), regs(regs) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
@@ -42,13 +42,13 @@ bool PI::WriteLatch(u32 value) {
|
||||
bool PI::ReadLatch() {
|
||||
if (ioBusy) [[unlikely]] {
|
||||
ioBusy = false;
|
||||
CpuStall(scheduler.Remove(PI_BUS_WRITE_COMPLETE));
|
||||
regs.CpuStall(scheduler.Remove(PI_BUS_WRITE_COMPLETE));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<> auto PI::BusRead<u8, true>(Mem& mem, u32 addr) -> u8 {
|
||||
template<> auto PI::BusRead<u8, true>(u32 addr) -> u8 {
|
||||
switch (addr) {
|
||||
case REGION_PI_UNKNOWN:
|
||||
Util::panic("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, returning FF because it is not emulated", addr);
|
||||
@@ -73,7 +73,7 @@ template<> auto PI::BusRead<u8, true>(Mem& mem, u32 addr) -> u8 {
|
||||
}
|
||||
}
|
||||
|
||||
template<> auto PI::BusRead<u8, false>(Mem& mem, u32 addr) -> u8 {
|
||||
template<> auto PI::BusRead<u8, false>(u32 addr) -> u8 {
|
||||
if (!ReadLatch()) [[unlikely]] {
|
||||
return latch >> 24;
|
||||
}
|
||||
@@ -103,7 +103,7 @@ template<> auto PI::BusRead<u8, false>(Mem& mem, u32 addr) -> u8 {
|
||||
}
|
||||
}
|
||||
|
||||
template<> void PI::BusWrite<u8, true>(Mem& mem, u32 addr, u32 val) {
|
||||
template<> void PI::BusWrite<u8, true>(u32 addr, u32 val) {
|
||||
switch (addr) {
|
||||
case REGION_PI_UNKNOWN:
|
||||
Util::panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr);
|
||||
@@ -127,17 +127,17 @@ template<> void PI::BusWrite<u8, true>(Mem& mem, u32 addr, u32 val) {
|
||||
}
|
||||
}
|
||||
|
||||
template<> void PI::BusWrite<u8, false>(Mem& mem, u32 addr, u32 val) {
|
||||
template<> void PI::BusWrite<u8, false>(u32 addr, u32 val) {
|
||||
u8 latch_shift = 24 - (addr & 1) * 8;
|
||||
|
||||
if (!WriteLatch(val << latch_shift) && addr != 0x05000020) [[unlikely]] {
|
||||
return;
|
||||
}
|
||||
|
||||
BusWrite<u8, true>(mem, addr, val);
|
||||
BusWrite<u8, true>(addr, val);
|
||||
}
|
||||
|
||||
template <> auto PI::BusRead<u16, false>(Mem& mem, u32 addr) -> u16 {
|
||||
template <> auto PI::BusRead<u16, false>(u32 addr) -> u16 {
|
||||
if (!ReadLatch()) [[unlikely]] {
|
||||
return latch >> 16;
|
||||
}
|
||||
@@ -164,11 +164,11 @@ template <> auto PI::BusRead<u16, false>(Mem& mem, u32 addr) -> u16 {
|
||||
}
|
||||
}
|
||||
|
||||
template <> auto PI::BusRead<u16, true>(Mem& mem, u32 addr) -> u16 {
|
||||
return BusRead<u16, false>(mem, addr);
|
||||
template <> auto PI::BusRead<u16, true>(u32 addr) -> u16 {
|
||||
return BusRead<u16, false>(addr);
|
||||
}
|
||||
|
||||
template <> void PI::BusWrite<u16, false>(Mem&, u32 addr, u32 val) {
|
||||
template <> void PI::BusWrite<u16, false>(u32 addr, u32 val) {
|
||||
if (!WriteLatch(val << 16)) [[unlikely]] {
|
||||
return;
|
||||
}
|
||||
@@ -190,11 +190,11 @@ template <> void PI::BusWrite<u16, false>(Mem&, u32 addr, u32 val) {
|
||||
}
|
||||
}
|
||||
|
||||
template <> void PI::BusWrite<u16, true>(Mem& mem, u32 addr, u32 val) {
|
||||
BusWrite<u16, false>(mem, addr, val);
|
||||
template <> void PI::BusWrite<u16, true>(u32 addr, u32 val) {
|
||||
BusWrite<u16, false>(addr, val);
|
||||
}
|
||||
|
||||
template <> auto PI::BusRead<u32, false>(Mem& mem, u32 addr) -> u32 {
|
||||
template <> auto PI::BusRead<u32, false>(u32 addr) -> u32 {
|
||||
if (!ReadLatch()) [[unlikely]] {
|
||||
return latch;
|
||||
}
|
||||
@@ -232,11 +232,11 @@ template <> auto PI::BusRead<u32, false>(Mem& mem, u32 addr) -> u32 {
|
||||
}
|
||||
}
|
||||
|
||||
template <> auto PI::BusRead<u32, true>(Mem& mem, u32 addr) -> u32 {
|
||||
return BusRead<u32, false>(mem, addr);
|
||||
template <> auto PI::BusRead<u32, true>(u32 addr) -> u32 {
|
||||
return BusRead<u32, false>(addr);
|
||||
}
|
||||
|
||||
template <> void PI::BusWrite<u32, false>(Mem& mem, u32 addr, u32 val) {
|
||||
template <> void PI::BusWrite<u32, false>(u32 addr, u32 val) {
|
||||
switch (addr) {
|
||||
case REGION_PI_UNKNOWN:
|
||||
if (!WriteLatch(val)) [[unlikely]] {
|
||||
@@ -293,11 +293,11 @@ template <> void PI::BusWrite<u32, false>(Mem& mem, u32 addr, u32 val) {
|
||||
}
|
||||
|
||||
template <>
|
||||
void PI::BusWrite<u32, true>(Mem& mem, u32 addr, u32 val) {
|
||||
BusWrite<u32, false>(mem, addr, val);
|
||||
void PI::BusWrite<u32, true>(u32 addr, u32 val) {
|
||||
BusWrite<u32, false>(addr, val);
|
||||
}
|
||||
|
||||
template <> auto PI::BusRead<u64, false>(Mem& mem, u32 addr) -> u64 {
|
||||
template <> auto PI::BusRead<u64, false>(u32 addr) -> u64 {
|
||||
if (!ReadLatch()) [[unlikely]] {
|
||||
return (u64)latch << 32;
|
||||
}
|
||||
@@ -323,11 +323,11 @@ template <> auto PI::BusRead<u64, false>(Mem& mem, u32 addr) -> u64 {
|
||||
}
|
||||
}
|
||||
|
||||
template <> auto PI::BusRead<u64, true>(Mem& mem, u32 addr) -> u64 {
|
||||
return BusRead<u64, false>(mem, addr);
|
||||
template <> auto PI::BusRead<u64, true>(u32 addr) -> u64 {
|
||||
return BusRead<u64, false>(addr);
|
||||
}
|
||||
|
||||
template <> void PI::BusWrite<false>(Mem&, u32 addr, u64 val) {
|
||||
template <> void PI::BusWrite<false>(u32 addr, u64 val) {
|
||||
if (!WriteLatch(val >> 32)) [[unlikely]] {
|
||||
return;
|
||||
}
|
||||
@@ -349,11 +349,11 @@ template <> void PI::BusWrite<false>(Mem&, u32 addr, u64 val) {
|
||||
}
|
||||
}
|
||||
|
||||
template <> void PI::BusWrite<true>(Mem& mem, u32 addr, u64 val) {
|
||||
BusWrite<false>(mem, addr, val);
|
||||
template <> void PI::BusWrite<true>(u32 addr, u64 val) {
|
||||
BusWrite<false>(addr, val);
|
||||
}
|
||||
|
||||
auto PI::Read(MI& mi, u32 addr) const -> u32 {
|
||||
auto PI::Read(u32 addr) const -> u32 {
|
||||
switch(addr) {
|
||||
case 0x04600000: return dramAddr;
|
||||
case 0x04600004: return cartAddr;
|
||||
@@ -364,7 +364,7 @@ auto PI::Read(MI& mi, u32 addr) const -> u32 {
|
||||
value |= (dmaBusy << 0); // Is PI DMA active? No, because it's instant
|
||||
value |= (ioBusy << 1); // Is PI IO busy? No, because it's instant
|
||||
value |= (0 << 2); // PI IO error?
|
||||
value |= (mi.miIntr.pi << 3); // PI interrupt?
|
||||
value |= (mem.mmio.mi.miIntr.pi << 3); // PI interrupt?
|
||||
return value;
|
||||
}
|
||||
case 0x04600014: return piBsdDom1Lat;
|
||||
@@ -427,7 +427,7 @@ u32 PI::AccessTiming(u8 domain, u32 length) const {
|
||||
return cycles * 1.5; // Converting RCP clock speed to CPU clock speed
|
||||
}
|
||||
|
||||
void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
|
||||
void PI::Write(u32 addr, u32 val) {
|
||||
MI& mi = mem.mmio.mi;
|
||||
switch(addr) {
|
||||
case 0x04600000: dramAddr = val & 0xFFFFFF; break;
|
||||
@@ -444,7 +444,7 @@ void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
|
||||
Util::panic("PI DMA RDRAM->CART ADDRESS TOO HIGH");
|
||||
}
|
||||
for (int i = 0; i < len; i++) {
|
||||
BusWrite<u8, true>(mem, cartAddrInternal + i, mem.mmio.rdp.rdram[BYTE_ADDRESS(dramAddrInternal + i) & RDRAM_DSIZE]);
|
||||
BusWrite<u8, true>(cartAddrInternal + i, mem.mmio.rdp.rdram[BYTE_ADDRESS(dramAddrInternal + i) & RDRAM_DSIZE]);
|
||||
}
|
||||
Util::trace("PI DMA from RDRAM to CARTRIDGE (size: {} B, {:08X} to {:08X})", len, dramAddr, cartAddr);
|
||||
dmaBusy = true;
|
||||
@@ -465,7 +465,7 @@ void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
|
||||
}
|
||||
|
||||
for(u32 i = 0; i < len; i++) {
|
||||
mem.mmio.rdp.rdram[BYTE_ADDRESS(dramAddrInternal + i) & RDRAM_DSIZE] = BusRead<u8, true>(mem, cartAddrInternal + i);
|
||||
mem.mmio.rdp.rdram[BYTE_ADDRESS(dramAddrInternal + i) & RDRAM_DSIZE] = BusRead<u8, true>(cartAddrInternal + i);
|
||||
}
|
||||
dmaBusy = true;
|
||||
Util::trace("PI DMA from CARTRIDGE to RDRAM (size: {} B, {:08X} to {:08X})", len, cartAddr, dramAddr);
|
||||
|
||||
@@ -8,18 +8,18 @@ struct Mem;
|
||||
struct Registers;
|
||||
|
||||
struct PI {
|
||||
PI();
|
||||
PI(Mem&, Registers&);
|
||||
void Reset();
|
||||
auto Read(MI&, u32) const -> u32;
|
||||
void Write(Mem&, Registers&, u32, u32);
|
||||
auto Read(u32) const -> u32;
|
||||
void Write(u32, u32);
|
||||
|
||||
template<typename T, bool isDma>
|
||||
void BusWrite(Mem&, u32, u32);
|
||||
void BusWrite(u32, u32);
|
||||
template<bool isDma>
|
||||
void BusWrite(Mem&, u32, u64);
|
||||
void BusWrite(u32, u64);
|
||||
|
||||
template<typename T, bool isDma>
|
||||
auto BusRead(Mem&, u32) -> T;
|
||||
auto BusRead(u32) -> T;
|
||||
|
||||
bool ReadLatch();
|
||||
bool WriteLatch(u32 val);
|
||||
@@ -34,5 +34,8 @@ struct PI {
|
||||
u32 piBsdDom1Pwd{}, piBsdDom2Pwd{};
|
||||
u32 piBsdDom1Pgs{}, piBsdDom2Pgs{};
|
||||
u32 piBsdDom1Rls{}, piBsdDom2Rls{};
|
||||
private:
|
||||
Mem& mem;
|
||||
Registers& regs;
|
||||
};
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <Scheduler.hpp>
|
||||
|
||||
namespace n64 {
|
||||
SI::SI(Mem& mem, Registers& regs) : pif(mem, regs) {
|
||||
SI::SI(Mem& mem, Registers& regs) : mem(mem), regs(regs), pif(mem, regs) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ void SI::Reset() {
|
||||
pif.Reset();
|
||||
}
|
||||
|
||||
auto SI::Read(MI& mi, u32 addr) const -> u32 {
|
||||
auto SI::Read(u32 addr) const -> u32 {
|
||||
switch(addr) {
|
||||
case 0x04800000: return dramAddr;
|
||||
case 0x04800004: case 0x04800010: return pifAddr;
|
||||
@@ -24,7 +24,7 @@ auto SI::Read(MI& mi, u32 addr) const -> u32 {
|
||||
val |= status.dmaBusy;
|
||||
val |= (0 << 1);
|
||||
val |= (0 << 3);
|
||||
val |= (mi.miIntr.si << 12);
|
||||
val |= (mem.mmio.mi.miIntr.si << 12);
|
||||
return val;
|
||||
}
|
||||
default:
|
||||
@@ -32,26 +32,25 @@ auto SI::Read(MI& mi, u32 addr) const -> u32 {
|
||||
}
|
||||
}
|
||||
|
||||
void SI::DMA(Mem& mem, Registers& regs) const {
|
||||
SI& si = mem.mmio.si;
|
||||
si.status.dmaBusy = false;
|
||||
void SI::DMA() {
|
||||
status.dmaBusy = false;
|
||||
if (toDram) {
|
||||
si.pif.ProcessCommands(mem);
|
||||
pif.ProcessCommands(mem);
|
||||
for(int i = 0; i < 64; i++) {
|
||||
mem.mmio.rdp.rdram[BYTE_ADDRESS(si.dramAddr + i)] = si.pif.Read(si.pifAddr + i);
|
||||
mem.mmio.rdp.rdram[BYTE_ADDRESS(dramAddr + i)] = pif.Read(pifAddr + i);
|
||||
}
|
||||
Util::trace("SI DMA from PIF RAM to RDRAM ({:08X} to {:08X})", si.pifAddr, si.dramAddr);
|
||||
Util::trace("SI DMA from PIF RAM to RDRAM ({:08X} to {:08X})", pifAddr, dramAddr);
|
||||
} else {
|
||||
for(int i = 0; i < 64; i++) {
|
||||
si.pif.Write(si.pifAddr + i, mem.mmio.rdp.rdram[BYTE_ADDRESS(si.dramAddr + i)]);
|
||||
pif.Write(pifAddr + i, mem.mmio.rdp.rdram[BYTE_ADDRESS(dramAddr + i)]);
|
||||
}
|
||||
Util::trace("SI DMA from RDRAM to PIF RAM ({:08X} to {:08X})", si.dramAddr, si.pifAddr);
|
||||
si.pif.ProcessCommands(mem);
|
||||
Util::trace("SI DMA from RDRAM to PIF RAM ({:08X} to {:08X})", dramAddr, pifAddr);
|
||||
pif.ProcessCommands(mem);
|
||||
}
|
||||
mem.mmio.mi.InterruptRaise(MI::Interrupt::SI);
|
||||
}
|
||||
|
||||
void SI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
|
||||
void SI::Write(u32 addr, u32 val) {
|
||||
switch(addr) {
|
||||
case 0x04800000:
|
||||
dramAddr = val & RDRAM_DSIZE;
|
||||
|
||||
@@ -28,10 +28,13 @@ struct SI {
|
||||
u32 pifAddr{};
|
||||
bool toDram = false;
|
||||
|
||||
auto Read(MI&, u32) const -> u32;
|
||||
void Write(Mem&, Registers&, u32, u32);
|
||||
void DMA(Mem&, Registers&) const;
|
||||
auto Read(u32) const -> u32;
|
||||
void Write(u32, u32);
|
||||
void DMA();
|
||||
PIF pif;
|
||||
private:
|
||||
Mem& mem;
|
||||
Registers& regs;
|
||||
};
|
||||
|
||||
#define SI_DMA_DELAY (65536 * 2)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include <core/mmio/VI.hpp>
|
||||
#include <log.hpp>
|
||||
#include <core/registers/Registers.hpp>
|
||||
#include <core/mmio/MI.hpp>
|
||||
#include <core/Mem.hpp>
|
||||
#include <core/mmio/Interrupt.hpp>
|
||||
|
||||
namespace n64 {
|
||||
VI::VI () {
|
||||
VI::VI (Mem& mem, Registers& regs) : mem(mem), regs(regs) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ u32 VI::Read(u32 paddr) const {
|
||||
}
|
||||
}
|
||||
|
||||
void VI::Write(MI& mi, Registers& regs, u32 paddr, u32 val) {
|
||||
void VI::Write(u32 paddr, u32 val) {
|
||||
switch(paddr) {
|
||||
case 0x04400000:
|
||||
status.raw = val;
|
||||
@@ -63,7 +63,7 @@ void VI::Write(MI& mi, Registers& regs, u32 paddr, u32 val) {
|
||||
intr = val & 0x3FF;
|
||||
} break;
|
||||
case 0x04400010:
|
||||
mi.InterruptLower(MI::Interrupt::VI);
|
||||
mem.mmio.mi.InterruptLower(MI::Interrupt::VI);
|
||||
break;
|
||||
case 0x04400014: burst.raw = val; break;
|
||||
case 0x04400018: {
|
||||
|
||||
@@ -72,14 +72,14 @@ union AxisStart {
|
||||
};
|
||||
};
|
||||
|
||||
struct MI;
|
||||
struct Mem;
|
||||
struct Registers;
|
||||
|
||||
struct VI {
|
||||
VI();
|
||||
VI(Mem&, Registers&);
|
||||
void Reset();
|
||||
[[nodiscard]] u32 Read(u32) const;
|
||||
void Write(MI&, Registers&, u32, u32);
|
||||
void Write(u32, u32);
|
||||
AxisScale xscale{}, yscale{};
|
||||
VIHsyncLeap hsyncLeap{};
|
||||
VIStatus status{};
|
||||
@@ -93,5 +93,8 @@ struct VI {
|
||||
int numHalflines{};
|
||||
int numFields{};
|
||||
int cyclesPerHalfline{};
|
||||
private:
|
||||
Mem& mem;
|
||||
Registers& regs;
|
||||
};
|
||||
} // backend
|
||||
|
||||
@@ -14,5 +14,16 @@ struct Registers {
|
||||
s64 hi{}, lo{};
|
||||
bool prevDelaySlot{}, delaySlot{};
|
||||
int steps = 0;
|
||||
u32 extraCycles = 0;
|
||||
|
||||
void CpuStall(u32 cycles) {
|
||||
extraCycles += cycles;
|
||||
}
|
||||
|
||||
u32 PopStalledCycles() {
|
||||
u32 ret = extraCycles;
|
||||
extraCycles = 0;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -75,8 +75,8 @@ FORCE_INLINE void SetCop0Reg(Registers& regs, Mem& mem, u8 index, u32 val) {
|
||||
}
|
||||
break;
|
||||
case 8: rdp.WriteStart(val); break;
|
||||
case 9: rdp.WriteEnd(mi, regs, rsp, val); break;
|
||||
case 11: rdp.WriteStatus(mi, regs, rsp, val); break;
|
||||
case 9: rdp.WriteEnd(val); break;
|
||||
case 11: rdp.WriteStatus(val); break;
|
||||
default: Util::panic("Unhandled RSP COP0 register write at index {}", index);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user