Lay down initial PI bus latch implementation
This commit is contained in:
@@ -2,6 +2,18 @@
|
||||
#include <Scheduler.hpp>
|
||||
|
||||
namespace n64 {
|
||||
u32 extraCycles = 0;
|
||||
|
||||
void CpuStall(u32 cycles) {
|
||||
extraCycles += cycles;
|
||||
}
|
||||
|
||||
u32 PopStalledCycles() {
|
||||
u32 ret = extraCycles;
|
||||
extraCycles = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Core::Core() {
|
||||
if(SDL_GameControllerAddMappingsFromFile("resources/gamecontrollerdb.txt") < 0) {
|
||||
Util::warn("Failed to load game controller DB");
|
||||
@@ -46,8 +58,9 @@ void Core::Run(float volumeL, float volumeR) {
|
||||
MMIO& mmio = mem.mmio;
|
||||
Registers& regs = cpu->regs;
|
||||
|
||||
Event event;
|
||||
for (int field = 0; field < mmio.vi.numFields; field++) {
|
||||
int frameCycles = 0;
|
||||
u32 frameCycles = 0;
|
||||
for (int i = 0; i < mmio.vi.numHalflines; i++) {
|
||||
mmio.vi.current = (i << 1) + field;
|
||||
|
||||
@@ -56,8 +69,9 @@ void Core::Run(float volumeL, float volumeR) {
|
||||
}
|
||||
|
||||
for(; cycles < mem.mmio.vi.cyclesPerHalfline; cycles++, frameCycles++) {
|
||||
int taken = cpu->Step();
|
||||
static int cpuSteps = 0;
|
||||
u32 taken = cpu->Step();
|
||||
taken += PopStalledCycles();
|
||||
static u32 cpuSteps = 0;
|
||||
cpuSteps += taken;
|
||||
if(mmio.rsp.spStatus.halt) {
|
||||
cpuSteps = 0;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <SDL2/SDL_timer.h>
|
||||
|
||||
struct Window;
|
||||
struct Event;
|
||||
|
||||
namespace n64 {
|
||||
struct Core {
|
||||
@@ -17,13 +18,14 @@ struct Core {
|
||||
void Serialize();
|
||||
void Deserialize();
|
||||
void TogglePause() { pause = !pause; }
|
||||
void HandleEvents(Event*);
|
||||
[[nodiscard]] VI& GetVI() { return cpu->mem.mmio.vi; }
|
||||
|
||||
u32 breakpoint = 0;
|
||||
|
||||
bool pause = true;
|
||||
bool render = true;
|
||||
int cycles = 0;
|
||||
u32 cycles = 0;
|
||||
bool romLoaded = false;
|
||||
std::string rom;
|
||||
std::unique_ptr<BaseCPU> cpu;
|
||||
@@ -31,4 +33,8 @@ struct Core {
|
||||
int memSize, cpuSize, verSize;
|
||||
int slot = 0;
|
||||
};
|
||||
|
||||
extern u32 extraCycles;
|
||||
void CpuStall(u32 cycles);
|
||||
u32 PopStalledCycles();
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
#define PI_REGION 0x04600000 ... 0x046FFFFF
|
||||
#define RI_REGION 0x04700000 ... 0x047FFFFF
|
||||
#define SI_REGION 0x04800000 ... 0x048FFFFF
|
||||
#define REGION_CART CART_REGION_START_2_1 ... CART_REGION_END_1_2
|
||||
#define REGION_CART CART_REGION_START_2_1 ... CART_REGION_END_1_2
|
||||
#define PIF_ROM_REGION PIF_ROM_REGION_START ... PIF_ROM_REGION_END
|
||||
#define PIF_RAM_REGION PIF_RAM_REGION_START ... PIF_RAM_REGION_END
|
||||
|
||||
|
||||
@@ -1,4 +1,60 @@
|
||||
#include <Scheduler.hpp>
|
||||
#include <core/registers/Registers.hpp>
|
||||
#include <core/Mem.hpp>
|
||||
|
||||
Scheduler scheduler;
|
||||
|
||||
void Scheduler::enqueueRelative(u64 t, const EventType type) {
|
||||
enqueueAbsolute(t + ticks, type);
|
||||
}
|
||||
|
||||
void Scheduler::enqueueAbsolute(u64 t, const EventType type) {
|
||||
events.push({t, type});
|
||||
}
|
||||
|
||||
u64 Scheduler::remove(EventType type) {
|
||||
auto copy = events;
|
||||
while(!copy.empty()) {
|
||||
if(copy.top().type == type) {
|
||||
u64 ret = copy.top().time - ticks;
|
||||
copy.pop();
|
||||
events.swap(copy);
|
||||
return ret;
|
||||
}
|
||||
|
||||
copy.pop();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Scheduler::tick(u64 t, n64::Mem& mem, n64::Registers& regs) {
|
||||
ticks += t;
|
||||
n64::MI& mi = mem.mmio.mi;
|
||||
n64::SI& si = mem.mmio.si;
|
||||
n64::PI& pi = mem.mmio.pi;
|
||||
|
||||
while(ticks >= events.top().time) {
|
||||
switch(events.top().type) {
|
||||
case SI_DMA:
|
||||
si.status.dmaBusy = false;
|
||||
si.DMA(mem, regs);
|
||||
InterruptRaise(mi, regs, n64::Interrupt::SI);
|
||||
break;
|
||||
case PI_DMA_COMPLETE:
|
||||
InterruptRaise(mi, regs, n64::Interrupt::PI);
|
||||
pi.dmaBusy = false;
|
||||
break;
|
||||
case PI_BUS_WRITE_COMPLETE:
|
||||
pi.ioBusy = false;
|
||||
break;
|
||||
case NONE:
|
||||
break;
|
||||
case IMPOSSIBLE:
|
||||
Util::panic("Congratulations on keeping the emulator on for about 5 billion years, I guess, nerd.");
|
||||
default:
|
||||
Util::panic("Unknown scheduler event type");
|
||||
}
|
||||
events.pop();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include <queue>
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <log.hpp>
|
||||
|
||||
namespace n64 {
|
||||
@@ -8,9 +9,17 @@ struct Mem;
|
||||
struct Registers;
|
||||
}
|
||||
|
||||
enum EventType {
|
||||
NONE,
|
||||
PI_BUS_WRITE_COMPLETE,
|
||||
PI_DMA_COMPLETE,
|
||||
SI_DMA,
|
||||
IMPOSSIBLE
|
||||
};
|
||||
|
||||
struct Event {
|
||||
u64 time = 0;
|
||||
void(*handler)(n64::Mem&, n64::Registers&) = nullptr;
|
||||
u64 time;
|
||||
EventType type;
|
||||
|
||||
friend bool operator<(const Event& rhs, const Event& lhs) {
|
||||
return rhs.time < lhs.time;
|
||||
@@ -27,26 +36,14 @@ struct Event {
|
||||
|
||||
struct Scheduler {
|
||||
Scheduler() {
|
||||
enqueueAbsolute(Event{std::numeric_limits<u64>::max(), [](n64::Mem&, n64::Registers&) {
|
||||
Util::panic("How the fuck did we get here?!");
|
||||
}});
|
||||
enqueueAbsolute(std::numeric_limits<u64>::max(), IMPOSSIBLE);
|
||||
}
|
||||
|
||||
FORCE_INLINE void enqueueRelative(const Event& event) {
|
||||
enqueueAbsolute({event.time + ticks, event.handler});
|
||||
}
|
||||
|
||||
FORCE_INLINE void enqueueAbsolute(const Event& e) {
|
||||
events.push(e);
|
||||
}
|
||||
|
||||
FORCE_INLINE void tick(u64 t, n64::Mem& mem, n64::Registers& regs) {
|
||||
ticks += t;
|
||||
while(ticks >= events.top().time) {
|
||||
events.top().handler(mem, regs);
|
||||
events.pop();
|
||||
}
|
||||
}
|
||||
void enqueueRelative(u64, const EventType);
|
||||
void enqueueAbsolute(u64, const EventType);
|
||||
u64 remove(const EventType);
|
||||
void tick(u64 t, n64::Mem&, n64::Registers&);
|
||||
|
||||
std::priority_queue<Event, std::vector<Event>, std::greater<>> events;
|
||||
u64 ticks = 0;
|
||||
u8 index = 0;
|
||||
|
||||
@@ -363,11 +363,12 @@ void Mem::Write8(Registers& regs, u32 paddr, u32 val) {
|
||||
Util::WriteAccess<u32>(mmio.rsp.dmem, mirrAddr, val);
|
||||
}
|
||||
} break;
|
||||
case MMIO_REGION:
|
||||
Util::panic("MMIO Write8!");
|
||||
case REGION_CART:
|
||||
Util::debug("BusWrite8 @ {:08X} = {:02X}", paddr, val);
|
||||
mmio.pi.BusWrite8(*this, paddr, val);
|
||||
break;
|
||||
case MMIO_REGION:
|
||||
Util::panic("MMIO Write8!");
|
||||
case PIF_RAM_REGION:
|
||||
val = val << (8 * (3 - (paddr & 3)));
|
||||
paddr = (paddr - PIF_RAM_REGION_START) & ~3;
|
||||
@@ -411,6 +412,10 @@ void Mem::Write16(Registers& regs, u32 paddr, u32 val) {
|
||||
Util::WriteAccess<u32>(mmio.rsp.dmem, mirrAddr, val);
|
||||
}
|
||||
} break;
|
||||
case REGION_CART:
|
||||
Util::debug("BusWrite8 @ {:08X} = {:04X}", paddr, val);
|
||||
mmio.pi.BusWrite16(*this, paddr, val);
|
||||
break;
|
||||
case MMIO_REGION:
|
||||
Util::panic("MMIO Write16!");
|
||||
case PIF_RAM_REGION:
|
||||
@@ -419,9 +424,6 @@ void Mem::Write16(Registers& regs, u32 paddr, u32 val) {
|
||||
Util::WriteAccess<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START, htobe32(val));
|
||||
si.pif.ProcessCommands(*this);
|
||||
break;
|
||||
case REGION_CART:
|
||||
mmio.pi.BusWrite16(*this, paddr, val);
|
||||
break;
|
||||
case 0x00800000 ... 0x03FFFFFF:
|
||||
case 0x04200000 ... 0x042FFFFF:
|
||||
case 0x04900000 ... 0x04FFFFFF:
|
||||
@@ -457,6 +459,10 @@ void Mem::Write32(Registers& regs, u32 paddr, u32 val) {
|
||||
Util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
|
||||
}
|
||||
} break;
|
||||
case REGION_CART:
|
||||
Util::debug("BusWrite8 @ {:08X} = {:08X}", paddr, val);
|
||||
mmio.pi.BusWrite32(*this, paddr, val);
|
||||
break;
|
||||
case MMIO_REGION:
|
||||
mmio.Write(*this, regs, paddr, val);
|
||||
break;
|
||||
@@ -470,9 +476,6 @@ void Mem::Write32(Registers& regs, u32 paddr, u32 val) {
|
||||
case PIF_ROM_REGION:
|
||||
case 0x1FC00800 ... 0x7FFFFFFF:
|
||||
case 0x80000000 ... 0xFFFFFFFF: break;
|
||||
case REGION_CART:
|
||||
mmio.pi.BusWrite32(*this, paddr, val);
|
||||
break;
|
||||
default: Util::panic("Unimplemented 32-bit write at address {:08X} with value {:0X} (PC = {:016X})", paddr, val, (u64)regs.pc);
|
||||
}
|
||||
}
|
||||
@@ -500,15 +503,16 @@ void Mem::Write64(Registers& regs, u32 paddr, u64 val) {
|
||||
Util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
|
||||
}
|
||||
} break;
|
||||
case REGION_CART:
|
||||
Util::debug("BusWrite8 @ {:08X} = {:016X}", paddr, val);
|
||||
mmio.pi.BusWrite64(*this, paddr, val);
|
||||
break;
|
||||
case MMIO_REGION:
|
||||
Util::panic("MMIO Write64!");
|
||||
case PIF_RAM_REGION:
|
||||
Util::WriteAccess<u64>(si.pif.ram, paddr - PIF_RAM_REGION_START, htobe64(val));
|
||||
si.pif.ProcessCommands(*this);
|
||||
break;
|
||||
case REGION_CART:
|
||||
mmio.pi.BusWrite64(*this, paddr, val);
|
||||
break;
|
||||
case 0x00800000 ... 0x03FFFFFF:
|
||||
case 0x04200000 ... 0x042FFFFF:
|
||||
case 0x04900000 ... 0x04FFFFFF:
|
||||
|
||||
@@ -73,7 +73,7 @@ void AI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
|
||||
}
|
||||
}
|
||||
|
||||
void AI::Step(Mem& mem, Registers& regs, int cpuCycles, float volumeL, float volumeR) {
|
||||
void AI::Step(Mem& mem, Registers& regs, u32 cpuCycles, float volumeL, float volumeR) {
|
||||
cycles += cpuCycles;
|
||||
while(cycles > dac.period) {
|
||||
if (dmaCount == 0) {
|
||||
|
||||
@@ -11,7 +11,7 @@ struct AI {
|
||||
void Reset();
|
||||
auto Read(u32) const -> u32;
|
||||
void Write(Mem&, Registers&, u32, u32);
|
||||
void Step(Mem&, Registers&, int, float, float);
|
||||
void Step(Mem&, Registers&, u32, float, float);
|
||||
bool dmaEnable{};
|
||||
u16 dacRate{};
|
||||
u8 bitrate{};
|
||||
@@ -19,7 +19,7 @@ struct AI {
|
||||
u32 dmaLen[2]{};
|
||||
u32 dmaAddr[2]{};
|
||||
bool dmaAddrCarry{};
|
||||
int cycles{};
|
||||
u32 cycles{};
|
||||
|
||||
struct {
|
||||
u32 freq{44100};
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#include <core/mmio/PI.hpp>
|
||||
#include <log.hpp>
|
||||
#include <core/Mem.hpp>
|
||||
#include <core/registers/Registers.hpp>
|
||||
#include "Scheduler.hpp"
|
||||
#include <Core.hpp>
|
||||
#include <Scheduler.hpp>
|
||||
|
||||
namespace n64 {
|
||||
PI::PI() {
|
||||
@@ -10,23 +9,59 @@ PI::PI() {
|
||||
}
|
||||
|
||||
void PI::Reset() {
|
||||
dmaBusy = false;
|
||||
ioBusy = false;
|
||||
latch = 0;
|
||||
dramAddr = 0;
|
||||
cartAddr = 0;
|
||||
dramAddrInternal = 0;
|
||||
cartAddrInternal = 0;
|
||||
rdLen = 0;
|
||||
wrLen = 0;
|
||||
pi_bsd_dom1_lat = 0;
|
||||
pi_bsd_dom2_lat = 0;
|
||||
pi_bsd_dom1_pwd = 0;
|
||||
pi_bsd_dom2_pwd = 0;
|
||||
pi_bsd_dom1_pgs = 0;
|
||||
pi_bsd_dom2_pgs = 0;
|
||||
pi_bsd_dom1_rls = 0;
|
||||
pi_bsd_dom2_rls = 0;
|
||||
}
|
||||
|
||||
auto PI::BusRead8(Mem& mem, u32 addr) const -> u8 {
|
||||
// TODO: Latch with CPU stall
|
||||
bool PI::WriteLatch(u32 value) {
|
||||
if (ioBusy) {
|
||||
return false;
|
||||
} else {
|
||||
ioBusy = true;
|
||||
latch = value;
|
||||
scheduler.enqueueRelative(100, PI_BUS_WRITE_COMPLETE);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool PI::ReadLatch() {
|
||||
if (ioBusy) [[unlikely]] {
|
||||
ioBusy = false;
|
||||
CpuStall(scheduler.remove(PI_BUS_WRITE_COMPLETE));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
auto PI::BusRead8(Mem& mem, u32 addr) -> u8 {
|
||||
if (!ReadLatch()) [[unlikely]] {
|
||||
return latch >> 24;
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case REGION_PI_UNKNOWN:
|
||||
Util::warn("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, returning FF because it is not emulated", addr);
|
||||
//Util::warn("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, returning FF because it is not emulated", addr);
|
||||
return 0xFF;
|
||||
case REGION_PI_64DD_REG:
|
||||
Util::warn("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, returning FF because it is not emulated", addr);
|
||||
//Util::warn("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, returning FF because it is not emulated", addr);
|
||||
return 0xFF;
|
||||
case REGION_PI_64DD_ROM:
|
||||
Util::warn("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM - This is the N64DD, returning FF because it is not emulated", addr);
|
||||
//Util::warn("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM - This is the N64DD, returning FF because it is not emulated", addr);
|
||||
return 0xFF;
|
||||
case REGION_PI_SRAM:
|
||||
return mem.BackupRead8(addr - SREGION_PI_SRAM);
|
||||
@@ -35,7 +70,7 @@ auto PI::BusRead8(Mem& mem, u32 addr) const -> u8 {
|
||||
addr = (addr + 2) & ~2;
|
||||
u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM;
|
||||
if (index > mem.rom.size) {
|
||||
Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr, index, index, mem.rom.size, mem.rom.size);
|
||||
//Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr, index, index, mem.rom.size, mem.rom.size);
|
||||
return 0xFF;
|
||||
}
|
||||
return mem.rom.cart[index];
|
||||
@@ -46,51 +81,59 @@ auto PI::BusRead8(Mem& mem, u32 addr) const -> u8 {
|
||||
}
|
||||
|
||||
void PI::BusWrite8(Mem& mem, u32 addr, u32 val) {
|
||||
int latch_shift = 24 - (addr & 1) * 8;
|
||||
|
||||
if (!WriteLatch(val << latch_shift) && addr != 0x05000020) [[unlikely]] {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case REGION_PI_UNKNOWN:
|
||||
Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr);
|
||||
//Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr);
|
||||
return;
|
||||
case REGION_PI_64DD_REG:
|
||||
if (addr == 0x05000020) {
|
||||
fprintf(stderr, "%c", val);
|
||||
} else {
|
||||
Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", val, addr);
|
||||
//Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", val, addr);
|
||||
}
|
||||
return;
|
||||
case REGION_PI_64DD_ROM:
|
||||
Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr);
|
||||
//Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr);
|
||||
return;
|
||||
case REGION_PI_SRAM:
|
||||
mem.BackupWrite8(addr - SREGION_PI_SRAM, val);
|
||||
return;
|
||||
case REGION_PI_ROM:
|
||||
Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr);
|
||||
//Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr);
|
||||
return;
|
||||
default:
|
||||
Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr);
|
||||
}
|
||||
}
|
||||
|
||||
auto PI::BusRead16(Mem& mem, u32 addr) const -> u16 {
|
||||
// TODO: Latch with CPU stall
|
||||
auto PI::BusRead16(Mem& mem, u32 addr) -> u16 {
|
||||
if (!ReadLatch()) [[unlikely]] {
|
||||
return latch >> 16;
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case REGION_PI_UNKNOWN:
|
||||
Util::warn("Reading half from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, returning FF because it is not emulated", addr);
|
||||
//Util::warn("Reading half from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, returning FF because it is not emulated", addr);
|
||||
return 0xFF;
|
||||
case REGION_PI_64DD_REG:
|
||||
Util::warn("Reading half from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, returning FF because it is not emulated", addr);
|
||||
//Util::warn("Reading half from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, returning FF because it is not emulated", addr);
|
||||
return 0xFF;
|
||||
case REGION_PI_64DD_ROM:
|
||||
Util::warn("Reading half from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM - This is the N64DD, returning FF because it is not emulated", addr);
|
||||
//Util::warn("Reading half from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM - This is the N64DD, returning FF because it is not emulated", addr);
|
||||
return 0xFF;
|
||||
case REGION_PI_SRAM:
|
||||
Util::panic("Reading half from address 0x{:08X} in unsupported region: REGION_PI_SRAM", addr);
|
||||
case REGION_PI_ROM: {
|
||||
// round to nearest 4 byte boundary, keeping old LSB
|
||||
addr = (addr + 2) & ~3;
|
||||
u32 index = HALF_ADDRESS(addr) - SREGION_PI_ROM;
|
||||
if (index > mem.rom.size - 1) {
|
||||
Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr, index, index, mem.rom.size, mem.rom.size);
|
||||
//Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr, index, index, mem.rom.size, mem.rom.size);
|
||||
return 0xFFFF;
|
||||
}
|
||||
return Util::ReadAccess<u16>(mem.rom.cart, index);
|
||||
@@ -101,38 +144,45 @@ auto PI::BusRead16(Mem& mem, u32 addr) const -> u16 {
|
||||
}
|
||||
|
||||
void PI::BusWrite16(Mem& mem, u32 addr, u16 val) {
|
||||
if (!WriteLatch(val << 16)) [[unlikely]] {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case REGION_PI_UNKNOWN:
|
||||
Util::warn("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr);
|
||||
//Util::warn("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr);
|
||||
return;
|
||||
case REGION_PI_64DD_REG:
|
||||
Util::warn("Writing half 0x{:04X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", val, addr);
|
||||
//Util::warn("Writing half 0x{:04X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", val, addr);
|
||||
return;
|
||||
case REGION_PI_64DD_ROM:
|
||||
Util::warn("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr);
|
||||
//Util::warn("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr);
|
||||
return;
|
||||
case REGION_PI_SRAM:
|
||||
Util::warn("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_SRAM", val, addr);
|
||||
//Util::warn("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_SRAM", val, addr);
|
||||
return;
|
||||
case REGION_PI_ROM:
|
||||
Util::warn("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr);
|
||||
//Util::warn("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr);
|
||||
return;
|
||||
default:
|
||||
Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr);
|
||||
}
|
||||
}
|
||||
|
||||
auto PI::BusRead32(Mem& mem, u32 addr) const -> u32 {
|
||||
// TODO: Latch with CPU stall
|
||||
auto PI::BusRead32(Mem& mem, u32 addr) -> u32 {
|
||||
if (!ReadLatch()) [[unlikely]] {
|
||||
return latch;
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case REGION_PI_UNKNOWN:
|
||||
Util::warn("Reading word from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, returning FF because it is not emulated", addr);
|
||||
//Util::warn("Reading word from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, returning FF because it is not emulated", addr);
|
||||
return 0xFF;
|
||||
case REGION_PI_64DD_REG:
|
||||
Util::warn("Reading word from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, returning FF because it is not emulated", addr);
|
||||
//Util::warn("Reading word from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, returning FF because it is not emulated", addr);
|
||||
return 0xFF;
|
||||
case REGION_PI_64DD_ROM:
|
||||
Util::warn("Reading word from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM - This is the N64DD, returning FF because it is not emulated", addr);
|
||||
//Util::warn("Reading word from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM - This is the N64DD, returning FF because it is not emulated", addr);
|
||||
return 0xFF;
|
||||
case REGION_PI_SRAM:
|
||||
return mem.BackupRead32(addr - SREGION_PI_SRAM);
|
||||
@@ -145,7 +195,7 @@ auto PI::BusRead32(Mem& mem, u32 addr) const -> u32 {
|
||||
case CART_ISVIEWER_FLUSH:
|
||||
Util::panic("Read from ISViewer flush!");
|
||||
}
|
||||
Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr, index, index);
|
||||
//Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr, index, index);
|
||||
return 0;
|
||||
} else {
|
||||
return Util::ReadAccess<u32>(mem.rom.cart, index);
|
||||
@@ -159,15 +209,27 @@ auto PI::BusRead32(Mem& mem, u32 addr) const -> u32 {
|
||||
void PI::BusWrite32(Mem& mem, u32 addr, u32 val) {
|
||||
switch (addr) {
|
||||
case REGION_PI_UNKNOWN:
|
||||
Util::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr);
|
||||
if (!WriteLatch(val)) [[unlikely]] {
|
||||
return;
|
||||
}
|
||||
//Util::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr);
|
||||
return;
|
||||
case REGION_PI_64DD_REG:
|
||||
Util::warn("Writing word 0x{:08X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", val, addr);
|
||||
if (!WriteLatch(val)) [[unlikely]] {
|
||||
return;
|
||||
}
|
||||
//Util::warn("Writing word 0x{:08X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", val, addr);
|
||||
return;
|
||||
case REGION_PI_64DD_ROM:
|
||||
Util::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr);
|
||||
if (!WriteLatch(val)) [[unlikely]] {
|
||||
return;
|
||||
}
|
||||
//Util::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr);
|
||||
return;
|
||||
case REGION_PI_SRAM:
|
||||
if (!WriteLatch(val)) [[unlikely]] {
|
||||
return;
|
||||
}
|
||||
mem.BackupWrite32(addr - SREGION_PI_SRAM, val);
|
||||
return;
|
||||
case REGION_PI_ROM:
|
||||
@@ -188,7 +250,10 @@ void PI::BusWrite32(Mem& mem, u32 addr, u32 val) {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Util::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr);
|
||||
if (!WriteLatch(val)) [[unlikely]] {
|
||||
return;
|
||||
}
|
||||
//Util::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
@@ -196,19 +261,23 @@ void PI::BusWrite32(Mem& mem, u32 addr, u32 val) {
|
||||
}
|
||||
}
|
||||
|
||||
auto PI::BusRead64(Mem& mem, u32 addr) const -> u64 {
|
||||
auto PI::BusRead64(Mem& mem, u32 addr) -> u64 {
|
||||
if (!ReadLatch()) [[unlikely]] {
|
||||
return (u64)latch << 32;
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case REGION_PI_UNKNOWN:
|
||||
Util::warn("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", addr);
|
||||
//Util::warn("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", addr);
|
||||
return 0xFFFFFFFFFFFFFFFF;
|
||||
case REGION_PI_64DD_REG:
|
||||
Util::warn("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG", addr);
|
||||
//Util::warn("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG", addr);
|
||||
return 0xFFFFFFFFFFFFFFFF;
|
||||
case REGION_PI_64DD_ROM:
|
||||
Util::warn("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", addr);
|
||||
//Util::warn("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", addr);
|
||||
return 0xFFFFFFFFFFFFFFFF;
|
||||
case REGION_PI_SRAM:
|
||||
Util::warn("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_SRAM", addr);
|
||||
//Util::warn("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_SRAM", addr);
|
||||
return 0xFFFFFFFFFFFFFFFF;
|
||||
case REGION_PI_ROM: {
|
||||
u32 index = addr - SREGION_PI_ROM;
|
||||
@@ -223,6 +292,10 @@ auto PI::BusRead64(Mem& mem, u32 addr) const -> u64 {
|
||||
}
|
||||
|
||||
void PI::BusWrite64(Mem& mem, u32 addr, u64 val) {
|
||||
if (!WriteLatch(val >> 32)) [[unlikely]] {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case REGION_PI_UNKNOWN:
|
||||
Util::panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr);
|
||||
@@ -233,7 +306,7 @@ void PI::BusWrite64(Mem& mem, u32 addr, u64 val) {
|
||||
case REGION_PI_SRAM:
|
||||
Util::panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_SRAM", val, addr);
|
||||
case REGION_PI_ROM:
|
||||
Util::warn("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr);
|
||||
//Util::warn("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr);
|
||||
break;
|
||||
default:
|
||||
Util::panic("Should never end up here! Access to address %08X which did not match any PI bus regions!", addr);
|
||||
@@ -248,8 +321,8 @@ auto PI::Read(MI& mi, u32 addr) const -> u32 {
|
||||
case 0x0460000C: return wrLen;
|
||||
case 0x04600010: {
|
||||
u32 value = 0;
|
||||
value |= (0 << dmaBusy); // Is PI DMA active? No, because it's instant
|
||||
value |= (0 << ioBusy); // Is PI IO busy? No, because it's instant
|
||||
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?
|
||||
return value;
|
||||
@@ -314,23 +387,6 @@ FORCE_INLINE u32 PIAccessTiming(PI& pi, u8 domain, u32 length) {
|
||||
return cycles * 1.5; // Converting RCP clock speed to CPU clock speed
|
||||
}
|
||||
|
||||
template <bool toCart>
|
||||
FORCE_INLINE void OnDMAComplete(Mem& mem, Registers& regs) {
|
||||
PI& pi = mem.mmio.pi;
|
||||
u32 len;
|
||||
if constexpr (toCart) {
|
||||
len = pi.rdLen;
|
||||
} else {
|
||||
len = pi.wrLen;
|
||||
}
|
||||
|
||||
pi.dramAddr = pi.dramAddrInternal + len;
|
||||
pi.cartAddr = pi.cartAddrInternal + len;
|
||||
pi.dmaBusy = false;
|
||||
pi.ioBusy = false;
|
||||
InterruptRaise(mem.mmio.mi, regs, Interrupt::PI);
|
||||
}
|
||||
|
||||
void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
|
||||
MI& mi = mem.mmio.mi;
|
||||
switch(addr) {
|
||||
@@ -349,8 +405,8 @@ void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
|
||||
}
|
||||
Util::trace("PI DMA from RDRAM to CARTRIDGE (size: {} B, {:08X} to {:08X})", len, dramAddr, cartAddr);
|
||||
dmaBusy = true;
|
||||
ioBusy = true;
|
||||
scheduler.enqueueRelative(Event{PIAccessTiming(*this, PIGetDomain(cartAddr), len), OnDMAComplete<true>});
|
||||
toCart = true;
|
||||
scheduler.enqueueRelative(PIAccessTiming(*this, PIGetDomain(cartAddr), len), PI_DMA_COMPLETE);
|
||||
} break;
|
||||
case 0x0460000C: {
|
||||
u32 len = (val & 0x00FFFFFF) + 1;
|
||||
@@ -364,9 +420,9 @@ void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
|
||||
mem.mmio.rdp.rdram[BYTE_ADDRESS(dramAddrInternal + i) & RDRAM_DSIZE] = mem.rom.cart[BYTE_ADDRESS(cartAddrInternal + i) & mem.rom.mask];
|
||||
}
|
||||
dmaBusy = true;
|
||||
ioBusy = true;
|
||||
Util::trace("PI DMA from CARTRIDGE to RDRAM (size: {} B, {:08X} to {:08X})", len, cartAddr, dramAddr);
|
||||
scheduler.enqueueRelative(Event{PIAccessTiming(*this, PIGetDomain(cartAddr), len), OnDMAComplete<false>});
|
||||
toCart = false;
|
||||
scheduler.enqueueRelative(PIAccessTiming(*this, PIGetDomain(cartAddr), len), PI_DMA_COMPLETE);
|
||||
} break;
|
||||
case 0x04600010:
|
||||
if(val & 2) {
|
||||
|
||||
@@ -12,15 +12,18 @@ struct PI {
|
||||
void Reset();
|
||||
auto Read(MI&, u32) const -> u32;
|
||||
void Write(Mem&, Registers&, u32, u32);
|
||||
auto BusRead8(Mem&, u32) const -> u8;
|
||||
auto BusRead8(Mem&, u32) -> u8;
|
||||
void BusWrite8(Mem&, u32, u32);
|
||||
auto BusRead16(Mem&, u32) const -> u16;
|
||||
auto BusRead16(Mem&, u32) -> u16;
|
||||
void BusWrite16(Mem&, u32, u16);
|
||||
auto BusRead32(Mem&, u32) const -> u32;
|
||||
auto BusRead32(Mem&, u32) -> u32;
|
||||
void BusWrite32(Mem&, u32, u32);
|
||||
auto BusRead64(Mem&, u32) const -> u64;
|
||||
auto BusRead64(Mem&, u32) -> u64;
|
||||
void BusWrite64(Mem&, u32, u64);
|
||||
bool dmaBusy{}, ioBusy{};
|
||||
bool ReadLatch();
|
||||
bool WriteLatch(u32 val);
|
||||
bool dmaBusy{}, ioBusy{}, toCart{};
|
||||
u32 latch;
|
||||
u32 dramAddr{}, cartAddr{}, dramAddrInternal{}, cartAddrInternal{};
|
||||
u32 rdLen{}, wrLen{};
|
||||
u32 pi_bsd_dom1_lat{}, pi_bsd_dom2_lat{};
|
||||
|
||||
@@ -32,11 +32,10 @@ auto SI::Read(MI& mi, u32 addr) const -> u32 {
|
||||
}
|
||||
}
|
||||
|
||||
template <bool toDram>
|
||||
FORCE_INLINE void DMA(Mem& mem, Registers& regs) {
|
||||
void SI::DMA(Mem& mem, Registers& regs) {
|
||||
SI& si = mem.mmio.si;
|
||||
si.status.dmaBusy = false;
|
||||
if constexpr(toDram) {
|
||||
if (toDram) {
|
||||
si.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);
|
||||
@@ -60,12 +59,14 @@ void SI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
|
||||
case 0x04800004: {
|
||||
pifAddr = val & 0x1FFFFFFF;
|
||||
status.dmaBusy = true;
|
||||
scheduler.enqueueRelative({SI_DMA_DELAY, DMA<true>});
|
||||
toDram = true;
|
||||
scheduler.enqueueRelative(SI_DMA_DELAY, SI_DMA);
|
||||
} break;
|
||||
case 0x04800010: {
|
||||
pifAddr = val & 0x1FFFFFFF;
|
||||
status.dmaBusy = true;
|
||||
scheduler.enqueueRelative({SI_DMA_DELAY, DMA<false>});
|
||||
toDram = false;
|
||||
scheduler.enqueueRelative(SI_DMA_DELAY, SI_DMA);
|
||||
} break;
|
||||
case 0x04800018:
|
||||
InterruptLower(mem.mmio.mi, regs, Interrupt::SI);
|
||||
|
||||
@@ -26,9 +26,11 @@ struct SI {
|
||||
SIStatus status{};
|
||||
u32 dramAddr{};
|
||||
u32 pifAddr{};
|
||||
bool toDram = false;
|
||||
|
||||
auto Read(MI&, u32) const -> u32;
|
||||
void Write(Mem&, Registers&, u32, u32);
|
||||
void DMA(Mem&, Registers&);
|
||||
PIF pif;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user