diff --git a/.gitignore b/.gitignore index d4651cd..d16eab8 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ vgcore.* *.data disasm.txt *log*.txt +*.log CMakeSettings.json compile_commands.json *.diagsession diff --git a/src/backend/Core.cpp b/src/backend/Core.cpp index 34bacf3..c48f7f4 100644 --- a/src/backend/Core.cpp +++ b/src/backend/Core.cpp @@ -110,6 +110,15 @@ void Core::Run(const float volumeL, const float volumeR) { } while (cycles < mem->mmio.vi.cyclesPerHalfline) { + if (IsAnythingSkippable()) { + const u32 taken = Scheduler::GetInstance().events.top().time - Scheduler::GetInstance().ticks; + cycles += taken; + frameCycles += taken; + Scheduler::GetInstance().Tick(taken); + isReadingAnyIO = false; + continue; + } + const u32 taken = StepCPU(); cycles += taken; @@ -141,4 +150,9 @@ void Core::Run(const float volumeL, const float volumeR) { if (broken) pause = true; } + +bool Core::IsAnythingSkippable() { + MMIO &mmio = mem->mmio; + return (mmio.si.status.dmaBusy || mmio.pi.dmaBusy || mmio.pi.ioBusy) && isReadingAnyIO; +} } // namespace n64 diff --git a/src/backend/Core.hpp b/src/backend/Core.hpp index 32dccad..83a8ac5 100644 --- a/src/backend/Core.hpp +++ b/src/backend/Core.hpp @@ -19,6 +19,8 @@ struct Core { return instance; } + static void SetIdleSkippingStatus(bool v) { GetInstance().isReadingAnyIO = v; } + static Registers &GetRegs() { return GetInstance().regs; } static Mem &GetMem() { return *GetInstance().mem; } @@ -57,5 +59,8 @@ struct Core { #endif Interpreter interpreter; ParallelRDP parallel; + + bool isReadingAnyIO = false; + bool IsAnythingSkippable(); }; } // namespace n64 diff --git a/src/backend/core/mmio/PI.cpp b/src/backend/core/mmio/PI.cpp index e3877a2..43c0a1e 100644 --- a/src/backend/core/mmio/PI.cpp +++ b/src/backend/core/mmio/PI.cpp @@ -8,593 +8,597 @@ namespace n64 { PI::PI() { Reset(); } void PI::Reset() { - dmaBusy = false; - ioBusy = false; - latch = 0; - dramAddr = 0; - cartAddr = 0; - rdLen = 0; - wrLen = 0; - piBsdDom1Lat = 0; - piBsdDom2Lat = 0; - piBsdDom1Pwd = 0; - piBsdDom2Pwd = 0; - piBsdDom1Pgs = 0; - piBsdDom2Pgs = 0; - piBsdDom1Rls = 0; - piBsdDom2Rls = 0; + dmaBusy = false; + ioBusy = false; + latch = 0; + dramAddr = 0; + cartAddr = 0; + rdLen = 0; + wrLen = 0; + piBsdDom1Lat = 0; + piBsdDom2Lat = 0; + piBsdDom1Pwd = 0; + piBsdDom2Pwd = 0; + piBsdDom1Pgs = 0; + piBsdDom2Pgs = 0; + piBsdDom1Rls = 0; + piBsdDom2Rls = 0; } bool PI::WriteLatch(u32 value) { - if (ioBusy) { - return false; - } else { - ioBusy = true; - latch = value; - Scheduler::GetInstance().EnqueueRelative(100, PI_BUS_WRITE_COMPLETE); - return true; - } + if (ioBusy) { + return false; + } else { + ioBusy = true; + latch = value; + Scheduler::GetInstance().EnqueueRelative(100, PI_BUS_WRITE_COMPLETE); + return true; + } } bool PI::ReadLatch() { - n64::Registers& regs = n64::Core::GetRegs(); - if (ioBusy) [[unlikely]] { - ioBusy = false; - regs.CpuStall(Scheduler::GetInstance().Remove(PI_BUS_WRITE_COMPLETE)); - return false; - } - return true; + n64::Registers ®s = n64::Core::GetRegs(); + if (ioBusy) [[unlikely]] { + ioBusy = false; + regs.CpuStall(Scheduler::GetInstance().Remove(PI_BUS_WRITE_COMPLETE)); + return false; + } + return true; } template <> auto PI::BusRead(u32 addr) -> u8 { - n64::Mem& mem = n64::Core::GetMem(); - switch (addr) { - case REGION_PI_UNKNOWN: - 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); - case REGION_PI_64DD_REG: - panic("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); - case REGION_PI_64DD_ROM: - 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.BackupRead(addr - SREGION_PI_SRAM); - case REGION_PI_ROM: - { - // round to nearest 4 byte boundary, keeping old LSB - const u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM; - if (index >= mem.rom.cart.size()) { - warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr, - index, index, mem.rom.cart.size(), mem.rom.cart.size()); + n64::Mem &mem = n64::Core::GetMem(); + switch (addr) { + case REGION_PI_UNKNOWN: + 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); + case REGION_PI_64DD_REG: + panic("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); + case REGION_PI_64DD_ROM: + 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; - } - return mem.rom.cart[index]; + case REGION_PI_SRAM: + return mem.BackupRead(addr - SREGION_PI_SRAM); + case REGION_PI_ROM: + { + // round to nearest 4 byte boundary, keeping old LSB + const u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM; + if (index >= mem.rom.cart.size()) { + warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr, + index, index, mem.rom.cart.size(), mem.rom.cart.size()); + return 0xFF; + } + return mem.rom.cart[index]; + } + default: + panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); } - default: - panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); - } } template <> auto PI::BusRead(u32 addr) -> u8 { - n64::Mem& mem = n64::Core::GetMem(); - if (!ReadLatch()) [[unlikely]] { - return latch >> 24; - } + n64::Mem &mem = n64::Core::GetMem(); + if (!ReadLatch()) [[unlikely]] { + return latch >> 24; + } - switch (addr) { - case REGION_PI_UNKNOWN: - 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); - case REGION_PI_64DD_REG: - panic("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); - case REGION_PI_64DD_ROM: - 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.BackupRead(addr - SREGION_PI_SRAM); - case REGION_PI_ROM: - { - addr = (addr + 2) & ~2; - // round to nearest 4 byte boundary, keeping old LSB - const u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM; - if (index >= mem.rom.cart.size()) { - warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr, - index, index, mem.rom.cart.size(), mem.rom.cart.size()); + switch (addr) { + case REGION_PI_UNKNOWN: + 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); + case REGION_PI_64DD_REG: + panic("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); + case REGION_PI_64DD_ROM: + 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; - } - return mem.rom.cart[index]; + case REGION_PI_SRAM: + return mem.BackupRead(addr - SREGION_PI_SRAM); + case REGION_PI_ROM: + { + addr = (addr + 2) & ~2; + // round to nearest 4 byte boundary, keeping old LSB + const u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM; + if (index >= mem.rom.cart.size()) { + warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr, + index, index, mem.rom.cart.size(), mem.rom.cart.size()); + return 0xFF; + } + return mem.rom.cart[index]; + } + default: + panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); } - default: - panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); - } } template <> void PI::BusWrite(u32 addr, u32 val) { - n64::Mem& mem = n64::Core::GetMem(); - switch (addr) { - case REGION_PI_UNKNOWN: - panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr); - case REGION_PI_64DD_REG: - if (addr == 0x05000020) { - fprintf(stderr, "%c", val); - } else { - warn("Writing byte 0x{:02X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", + n64::Mem &mem = n64::Core::GetMem(); + switch (addr) { + case REGION_PI_UNKNOWN: + panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr); + case REGION_PI_64DD_REG: + if (addr == 0x05000020) { + fprintf(stderr, "%c", val); + } else { + warn("Writing byte 0x{:02X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", val, addr); + } + break; + case REGION_PI_64DD_ROM: + panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr); + case REGION_PI_SRAM: + mem.BackupWrite(addr - SREGION_PI_SRAM, val); + break; + case REGION_PI_ROM: + warn("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr); + break; + default: + panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); } - break; - case REGION_PI_64DD_ROM: - panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr); - case REGION_PI_SRAM: - mem.BackupWrite(addr - SREGION_PI_SRAM, val); - break; - case REGION_PI_ROM: - warn("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr); - break; - default: - panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); - } } template <> void PI::BusWrite(u32 addr, u32 val) { - u8 latch_shift = 24 - (addr & 1) * 8; + u8 latch_shift = 24 - (addr & 1) * 8; - if (!WriteLatch(val << latch_shift) && addr != 0x05000020) [[unlikely]] { - return; - } + if (!WriteLatch(val << latch_shift) && addr != 0x05000020) [[unlikely]] { + return; + } - BusWrite(addr, val); + BusWrite(addr, val); } template <> auto PI::BusRead(u32 addr) -> u16 { - n64::Mem& mem = n64::Core::GetMem(); - if (!ReadLatch()) [[unlikely]] { - return latch >> 16; - } + n64::Mem &mem = n64::Core::GetMem(); + if (!ReadLatch()) [[unlikely]] { + return latch >> 16; + } - switch (addr) { - case REGION_PI_UNKNOWN: - panic("Reading half from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, " - "returning FF because it is not emulated", - addr); - case REGION_PI_64DD_REG: - panic("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); - case REGION_PI_64DD_ROM: - panic("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); - case REGION_PI_SRAM: - panic("Reading half from address 0x{:08X} in unsupported region: REGION_PI_SRAM", addr); - case REGION_PI_ROM: - { - addr = (addr + 2) & ~3; - const u32 index = HALF_ADDRESS(addr) - SREGION_PI_ROM; - if (index > mem.rom.cart.size() - 1) { - panic("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr, index, index); - } - return ircolib::ReadAccess(mem.rom.cart, index); + switch (addr) { + case REGION_PI_UNKNOWN: + panic("Reading half from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, " + "returning FF because it is not emulated", + addr); + case REGION_PI_64DD_REG: + panic("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); + case REGION_PI_64DD_ROM: + panic("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); + case REGION_PI_SRAM: + panic("Reading half from address 0x{:08X} in unsupported region: REGION_PI_SRAM", addr); + case REGION_PI_ROM: + { + addr = (addr + 2) & ~3; + const u32 index = HALF_ADDRESS(addr) - SREGION_PI_ROM; + if (index > mem.rom.cart.size() - 1) { + panic("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr, index, + index); + } + return ircolib::ReadAccess(mem.rom.cart, index); + } + default: + panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); } - default: - panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); - } } template <> auto PI::BusRead(u32 addr) -> u16 { - return BusRead(addr); + return BusRead(addr); } template <> void PI::BusWrite(u32 addr, u32 val) { - if (!WriteLatch(val << 16)) [[unlikely]] { - return; - } + if (!WriteLatch(val << 16)) [[unlikely]] { + return; + } - switch (addr) { - case REGION_PI_UNKNOWN: - panic("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr); - case REGION_PI_64DD_REG: - panic("Writing half 0x{:04X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", - val, addr); - case REGION_PI_64DD_ROM: - panic("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr); - case REGION_PI_SRAM: - panic("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_SRAM", val, addr); - case REGION_PI_ROM: - warn("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr); - break; - default: - panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); - } + switch (addr) { + case REGION_PI_UNKNOWN: + panic("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr); + case REGION_PI_64DD_REG: + panic("Writing half 0x{:04X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", + val, addr); + case REGION_PI_64DD_ROM: + panic("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr); + case REGION_PI_SRAM: + panic("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_SRAM", val, addr); + case REGION_PI_ROM: + warn("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr); + break; + default: + panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); + } } template <> void PI::BusWrite(u32 addr, u32 val) { - BusWrite(addr, val); + BusWrite(addr, val); } template <> auto PI::BusRead(u32 addr) -> u32 { - n64::Mem& mem = n64::Core::GetMem(); - if (!ReadLatch()) [[unlikely]] { - return latch; - } + n64::Mem &mem = n64::Core::GetMem(); + if (!ReadLatch()) [[unlikely]] { + return latch; + } - switch (addr) { - case REGION_PI_UNKNOWN: - 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: - 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: - 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.BackupRead(addr); - case REGION_PI_ROM: - { - const u32 index = addr - SREGION_PI_ROM; - if (index > mem.rom.cart.size() - 3) { // -3 because we're reading an entire word - switch (addr) { - case REGION_CART_ISVIEWER_BUFFER: - return std::byteswap(ircolib::ReadAccess(mem.isviewer, addr - SREGION_CART_ISVIEWER_BUFFER)); - case CART_ISVIEWER_FLUSH: - panic("Read from ISViewer flush!"); - default: - break; + switch (addr) { + case REGION_PI_UNKNOWN: + 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: + 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: + 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.BackupRead(addr); + case REGION_PI_ROM: + { + const u32 index = addr - SREGION_PI_ROM; + if (index > mem.rom.cart.size() - 3) { // -3 because we're reading an entire word + switch (addr) { + case REGION_CART_ISVIEWER_BUFFER: + return std::byteswap( + ircolib::ReadAccess(mem.isviewer, addr - SREGION_CART_ISVIEWER_BUFFER)); + case CART_ISVIEWER_FLUSH: + panic("Read from ISViewer flush!"); + default: + break; + } + warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr, index, index); + return 0; + } + + return ircolib::ReadAccess(mem.rom.cart, index); } - warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr, index, index); - return 0; - } - - return ircolib::ReadAccess(mem.rom.cart, index); + default: + panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); } - default: - panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); - } } template <> auto PI::BusRead(u32 addr) -> u32 { - return BusRead(addr); + return BusRead(addr); } template <> void PI::BusWrite(u32 addr, u32 val) { - n64::Mem& mem = n64::Core::GetMem(); - switch (addr) { - case REGION_PI_UNKNOWN: - if (!WriteLatch(val)) [[unlikely]] { - return; - } - warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr); - return; - case REGION_PI_64DD_REG: - if (!WriteLatch(val)) [[unlikely]] { - return; - } - 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: - if (!WriteLatch(val)) [[unlikely]] { - return; - } - 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.BackupWrite(addr - SREGION_PI_SRAM, val); - return; - case REGION_PI_ROM: + n64::Mem &mem = n64::Core::GetMem(); switch (addr) { - case REGION_CART_ISVIEWER_BUFFER: - ircolib::WriteAccess(mem.isviewer, addr - SREGION_CART_ISVIEWER_BUFFER, std::byteswap(val)); - break; - case CART_ISVIEWER_FLUSH: - { - if (val < CART_ISVIEWER_SIZE) { - std::string message(val, 0); - std::copy_n(mem.isviewer.begin(), val, message.begin()); - mem.isviewer_sink << message; - mem.isviewer_sink.flush(); - } else { - panic("ISViewer buffer size is emulated at {} bytes, but received a flush command for {} bytes!", - CART_ISVIEWER_SIZE, val); + case REGION_PI_UNKNOWN: + if (!WriteLatch(val)) [[unlikely]] { + return; } - break; - } - default: - if (!WriteLatch(val)) [[unlikely]] { - warn("Couldn't latch PI bus, ignoring write to REGION_PI_ROM"); + warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr); return; - } - warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr); + case REGION_PI_64DD_REG: + if (!WriteLatch(val)) [[unlikely]] { + return; + } + 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: + if (!WriteLatch(val)) [[unlikely]] { + return; + } + 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.BackupWrite(addr - SREGION_PI_SRAM, val); + return; + case REGION_PI_ROM: + switch (addr) { + case REGION_CART_ISVIEWER_BUFFER: + ircolib::WriteAccess(mem.isviewer, addr - SREGION_CART_ISVIEWER_BUFFER, std::byteswap(val)); + break; + case CART_ISVIEWER_FLUSH: + { + if (val < CART_ISVIEWER_SIZE) { + std::string message(val, 0); + std::copy_n(mem.isviewer.begin(), val, message.begin()); + mem.isviewer_sink << message; + mem.isviewer_sink.flush(); + } else { + panic("ISViewer buffer size is emulated at {} bytes, but received a flush command for {} bytes!", + CART_ISVIEWER_SIZE, val); + } + break; + } + default: + if (!WriteLatch(val)) [[unlikely]] { + warn("Couldn't latch PI bus, ignoring write to REGION_PI_ROM"); + return; + } + warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr); + } + return; + default: + panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); } - return; - default: - panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); - } } template <> void PI::BusWrite(u32 addr, u32 val) { - BusWrite(addr, val); + BusWrite(addr, val); } template <> auto PI::BusRead(u32 addr) -> u64 { - n64::Mem& mem = n64::Core::GetMem(); - if (!ReadLatch()) [[unlikely]] { - return static_cast(latch) << 32; - } + n64::Mem &mem = n64::Core::GetMem(); + if (!ReadLatch()) [[unlikely]] { + return static_cast(latch) << 32; + } - switch (addr) { - case REGION_PI_UNKNOWN: - panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", addr); - case REGION_PI_64DD_REG: - panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG", addr); - case REGION_PI_64DD_ROM: - panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", addr); - case REGION_PI_SRAM: - panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_SRAM", addr); - case REGION_PI_ROM: - { - const u32 index = addr - SREGION_PI_ROM; - if (index > mem.rom.cart.size() - 7) { // -7 because we're reading an entire dword - panic("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr, index, index); - } - return ircolib::ReadAccess(mem.rom.cart, index); + switch (addr) { + case REGION_PI_UNKNOWN: + panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", addr); + case REGION_PI_64DD_REG: + panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG", addr); + case REGION_PI_64DD_ROM: + panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", addr); + case REGION_PI_SRAM: + panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_SRAM", addr); + case REGION_PI_ROM: + { + const u32 index = addr - SREGION_PI_ROM; + if (index > mem.rom.cart.size() - 7) { // -7 because we're reading an entire dword + panic("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr, index, + index); + } + return ircolib::ReadAccess(mem.rom.cart, index); + } + default: + panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); } - default: - panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); - } } template <> auto PI::BusRead(u32 addr) -> u64 { - return BusRead(addr); + return BusRead(addr); } template <> void PI::BusWrite(u32 addr, u64 val) { - if (!WriteLatch(val >> 32)) [[unlikely]] { - return; - } + if (!WriteLatch(val >> 32)) [[unlikely]] { + return; + } - switch (addr) { - case REGION_PI_UNKNOWN: - panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr); - case REGION_PI_64DD_REG: - panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_REG", val, addr); - case REGION_PI_64DD_ROM: - panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr); - case REGION_PI_SRAM: - panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_SRAM", val, addr); - case REGION_PI_ROM: - warn("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr); - break; - default: - panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); - } + switch (addr) { + case REGION_PI_UNKNOWN: + panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr); + case REGION_PI_64DD_REG: + panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_REG", val, addr); + case REGION_PI_64DD_ROM: + panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr); + case REGION_PI_SRAM: + panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_SRAM", val, addr); + case REGION_PI_ROM: + warn("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr); + break; + default: + panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); + } } template <> void PI::BusWrite(u32 addr, u64 val) { - BusWrite(addr, val); + BusWrite(addr, val); } auto PI::Read(u32 addr) const -> u32 { - n64::Mem& mem = n64::Core::GetMem(); - switch (addr) { - case 0x04600000: - return dramAddr & 0x00FFFFFE; - case 0x04600004: - return cartAddr & 0xFFFFFFFE; - case 0x04600008: - return rdLen; - case 0x0460000C: - return wrLen; - case 0x04600010: - { - u32 value = 0; - value |= (dmaBusy << 0); // Is PI DMA active? - value |= (ioBusy << 1); // Is PI IO busy? - value |= (0 << 2); // PI DMA error? - value |= (mem.mmio.mi.intr.pi << 3); // PI interrupt? - return value; + n64::Mem &mem = n64::Core::GetMem(); + switch (addr) { + case 0x04600000: + return dramAddr & 0x00FFFFFE; + case 0x04600004: + return cartAddr & 0xFFFFFFFE; + case 0x04600008: + return rdLen; + case 0x0460000C: + return wrLen; + case 0x04600010: + { + Core::SetIdleSkippingStatus(true); + u32 value = 0; + value |= (dmaBusy << 0); // Is PI DMA active? + value |= (ioBusy << 1); // Is PI IO busy? + value |= (0 << 2); // PI DMA error? + value |= (mem.mmio.mi.intr.pi << 3); // PI interrupt? + return value; + } + case 0x04600014: + return piBsdDom1Lat; + case 0x04600018: + return piBsdDom1Pwd; + case 0x0460001C: + return piBsdDom1Pgs; + case 0x04600020: + return piBsdDom1Rls; + case 0x04600024: + return piBsdDom2Lat; + case 0x04600028: + return piBsdDom2Pwd; + case 0x0460002C: + return piBsdDom2Pgs; + case 0x04600030: + return piBsdDom2Rls; + default: + panic("Unhandled PI[{:08X}] read", addr); } - case 0x04600014: - return piBsdDom1Lat; - case 0x04600018: - return piBsdDom1Pwd; - case 0x0460001C: - return piBsdDom1Pgs; - case 0x04600020: - return piBsdDom1Rls; - case 0x04600024: - return piBsdDom2Lat; - case 0x04600028: - return piBsdDom2Pwd; - case 0x0460002C: - return piBsdDom2Pgs; - case 0x04600030: - return piBsdDom2Rls; - default: - panic("Unhandled PI[{:08X}] read", addr); - } } u8 PI::GetDomain(const u32 address) { - switch (address) { - case REGION_PI_UNKNOWN: - case REGION_PI_64DD_ROM: - case REGION_PI_ROM: - return 1; - case REGION_PI_64DD_REG: - case REGION_PI_SRAM: - return 2; - default: - panic("Unknown PI domain for address {:08X}!", address); - } + switch (address) { + case REGION_PI_UNKNOWN: + case REGION_PI_64DD_ROM: + case REGION_PI_ROM: + return 1; + case REGION_PI_64DD_REG: + case REGION_PI_SRAM: + return 2; + default: + panic("Unknown PI domain for address {:08X}!", address); + } } u32 PI::AccessTiming(const u8 domain, const u32 length) const { - uint32_t cycles = 0; - uint32_t latency = 0; - uint32_t pulse_width = 0; - uint32_t release = 0; - uint32_t page_size = 0; + uint32_t cycles = 0; + uint32_t latency = 0; + uint32_t pulse_width = 0; + uint32_t release = 0; + uint32_t page_size = 0; - switch (domain) { - case 1: - latency = piBsdDom1Lat + 1; - pulse_width = piBsdDom1Pwd + 1; - release = piBsdDom1Rls + 1; - page_size = 1 << (piBsdDom1Pgs + 2); - break; - case 2: - latency = piBsdDom2Lat + 1; - pulse_width = piBsdDom2Pwd + 1; - release = piBsdDom2Rls + 1; - page_size = 1 << (piBsdDom2Pgs + 2); - break; - default: - panic("Unknown PI domain: {}\n", domain); - } + switch (domain) { + case 1: + latency = piBsdDom1Lat + 1; + pulse_width = piBsdDom1Pwd + 1; + release = piBsdDom1Rls + 1; + page_size = 1 << (piBsdDom1Pgs + 2); + break; + case 2: + latency = piBsdDom2Lat + 1; + pulse_width = piBsdDom2Pwd + 1; + release = piBsdDom2Rls + 1; + page_size = 1 << (piBsdDom2Pgs + 2); + break; + default: + panic("Unknown PI domain: {}\n", domain); + } - const uint32_t pages = static_cast(ceil(static_cast(length) / static_cast(page_size))); + const uint32_t pages = static_cast(ceil(static_cast(length) / static_cast(page_size))); - cycles += (14 + latency) * pages; - cycles += (pulse_width + release) * (length / 2); - cycles += 5 * pages; - return cycles * 1.5; // Converting RCP clock speed to CPU clock speed + cycles += (14 + latency) * pages; + cycles += (pulse_width + release) * (length / 2); + cycles += 5 * pages; + return cycles * 1.5; // Converting RCP clock speed to CPU clock speed } // rdram -> cart template <> void PI::DMA() { - n64::Mem& mem = n64::Core::GetMem(); - const s32 len = rdLen + 1; - trace("PI DMA from RDRAM to CARTRIDGE (size: {} B, {:08X} to {:08X})", len, dramAddr, cartAddr); + n64::Mem &mem = n64::Core::GetMem(); + const s32 len = rdLen + 1; + trace("PI DMA from RDRAM to CARTRIDGE (size: {} B, {:08X} to {:08X})", len, dramAddr, cartAddr); - for (int i = 0; i < len; i++) { - BusWrite(cartAddr + i, mem.mmio.rdp.ReadRDRAM(dramAddr + i)); - } - - dramAddr += len; - dramAddr = (dramAddr + 7) & ~7; - cartAddr += len; - if (cartAddr & 1) - cartAddr += 1; + for (int i = 0; i < len; i++) { + BusWrite(cartAddr + i, mem.mmio.rdp.ReadRDRAM(dramAddr + i)); + } - dmaBusy = true; - - u64 completo = AccessTiming(GetDomain(cartAddr), len); - trace("Will complete in {} cycles", completo); - Scheduler::GetInstance().EnqueueRelative(completo, PI_DMA_COMPLETE); + dramAddr += len; + dramAddr = (dramAddr + 7) & ~7; + cartAddr += len; + if (cartAddr & 1) + cartAddr += 1; + + dmaBusy = true; + + u64 completo = AccessTiming(GetDomain(cartAddr), len); + trace("Will complete in {} cycles", completo); + Scheduler::GetInstance().EnqueueRelative(completo, PI_DMA_COMPLETE); } // cart -> rdram template <> void PI::DMA() { - n64::Mem& mem = n64::Core::GetMem(); - const s32 len = wrLen + 1; - trace("PI DMA from CARTRIDGE to RDRAM (size: {} B, {:08X} to {:08X})", len, cartAddr, dramAddr); + n64::Mem &mem = n64::Core::GetMem(); + const s32 len = wrLen + 1; + trace("PI DMA from CARTRIDGE to RDRAM (size: {} B, {:08X} to {:08X})", len, cartAddr, dramAddr); - if (mem.saveType == SAVE_FLASH_1m && cartAddr >= SREGION_PI_SRAM && cartAddr < (CART_REGION_START_2_2 + 1_mb)) { - cartAddr = SREGION_PI_SRAM | ((cartAddr & (1_mb-1)) << 1); - } + if (mem.saveType == SAVE_FLASH_1m && cartAddr >= SREGION_PI_SRAM && cartAddr < (CART_REGION_START_2_2 + 1_mb)) { + cartAddr = SREGION_PI_SRAM | ((cartAddr & (1_mb - 1)) << 1); + } - for (u32 i = 0; i < len; i++) { - mem.mmio.rdp.WriteRDRAM(dramAddr + i, BusRead(cartAddr + i)); - } - dramAddr += len; - dramAddr = (dramAddr + 7) & ~7; - cartAddr += len; - if (cartAddr & 1) - cartAddr += 1; + for (u32 i = 0; i < len; i++) { + mem.mmio.rdp.WriteRDRAM(dramAddr + i, BusRead(cartAddr + i)); + } + dramAddr += len; + dramAddr = (dramAddr + 7) & ~7; + cartAddr += len; + if (cartAddr & 1) + cartAddr += 1; - dmaBusy = true; - u64 completo = AccessTiming(GetDomain(cartAddr), len); - trace("Will complete in {} cycles", completo); - Scheduler::GetInstance().EnqueueRelative(completo, PI_DMA_COMPLETE); + dmaBusy = true; + u64 completo = AccessTiming(GetDomain(cartAddr), len); + trace("Will complete in {} cycles", completo); + Scheduler::GetInstance().EnqueueRelative(completo, PI_DMA_COMPLETE); } void PI::Write(u32 addr, u32 val) { - n64::Mem& mem = n64::Core::GetMem(); - MI &mi = mem.mmio.mi; - switch (addr) { - case 0x04600000: - dramAddr = val & 0x00FFFFFE; - break; - case 0x04600004: - cartAddr = val & 0xFFFFFFFE; - break; - case 0x04600008: - rdLen = val & 0x00FFFFFF; - DMA(); - break; - case 0x0460000C: - wrLen = val & 0x00FFFFFF; - DMA(); - break; - case 0x04600010: - if (val & 2) { - mi.InterruptLower(MI::Interrupt::PI); + n64::Mem &mem = n64::Core::GetMem(); + MI &mi = mem.mmio.mi; + switch (addr) { + case 0x04600000: + dramAddr = val & 0x00FFFFFE; + break; + case 0x04600004: + cartAddr = val & 0xFFFFFFFE; + break; + case 0x04600008: + rdLen = val & 0x00FFFFFF; + DMA(); + break; + case 0x0460000C: + wrLen = val & 0x00FFFFFF; + DMA(); + break; + case 0x04600010: + if (val & 2) { + mi.InterruptLower(MI::Interrupt::PI); + } + break; + case 0x04600014: + piBsdDom1Lat = val & 0xff; + break; + case 0x04600018: + piBsdDom1Pwd = val & 0xff; + break; + case 0x0460001C: + piBsdDom1Pgs = val & 0xff; + break; + case 0x04600020: + piBsdDom1Rls = val & 0xff; + break; + case 0x04600024: + piBsdDom2Lat = val & 0xff; + break; + case 0x04600028: + piBsdDom2Pwd = val & 0xff; + break; + case 0x0460002C: + piBsdDom2Pgs = val & 0xff; + break; + case 0x04600030: + piBsdDom2Rls = val & 0xff; + break; + default: + panic("Unhandled PI[{:08X}] write ({:08X})", val, addr); } - break; - case 0x04600014: - piBsdDom1Lat = val & 0xff; - break; - case 0x04600018: - piBsdDom1Pwd = val & 0xff; - break; - case 0x0460001C: - piBsdDom1Pgs = val & 0xff; - break; - case 0x04600020: - piBsdDom1Rls = val & 0xff; - break; - case 0x04600024: - piBsdDom2Lat = val & 0xff; - break; - case 0x04600028: - piBsdDom2Pwd = val & 0xff; - break; - case 0x0460002C: - piBsdDom2Pgs = val & 0xff; - break; - case 0x04600030: - piBsdDom2Rls = val & 0xff; - break; - default: - panic("Unhandled PI[{:08X}] write ({:08X})", val, addr); - } } } // namespace n64 diff --git a/src/backend/core/mmio/PI.hpp b/src/backend/core/mmio/PI.hpp index 66642db..2d6508a 100644 --- a/src/backend/core/mmio/PI.hpp +++ b/src/backend/core/mmio/PI.hpp @@ -3,35 +3,35 @@ namespace n64 { struct PI { - PI(); - void Reset(); - [[nodiscard]] auto Read(u32) const -> u32; - void Write(u32, u32); + PI(); + void Reset(); + [[nodiscard]] auto Read(u32) const -> u32; + void Write(u32, u32); - template - void BusWrite(u32, u32); - template - void BusWrite(u32, u64); + template + void BusWrite(u32, u32); + template + void BusWrite(u32, u64); - template - auto BusRead(u32) -> T; + template + auto BusRead(u32) -> T; - bool ReadLatch(); - bool WriteLatch(u32 val); + bool ReadLatch(); + bool WriteLatch(u32 val); - static u8 GetDomain(u32 address); - [[nodiscard]] u32 AccessTiming(u8 domain, u32 length) const; - bool dmaBusy{}, ioBusy{}; - u32 latch{}; - u32 dramAddr{}, cartAddr{}; - u32 rdLen{}, wrLen{}; - u32 piBsdDom1Lat{}, piBsdDom2Lat{}; - u32 piBsdDom1Pwd{}, piBsdDom2Pwd{}; - u32 piBsdDom1Pgs{}, piBsdDom2Pgs{}; - u32 piBsdDom1Rls{}, piBsdDom2Rls{}; + static u8 GetDomain(u32 address); + [[nodiscard]] u32 AccessTiming(u8 domain, u32 length) const; + bool dmaBusy{}, ioBusy{}; + u32 latch{}; + u32 dramAddr{}, cartAddr{}; + u32 rdLen{}, wrLen{}; + u32 piBsdDom1Lat{}, piBsdDom2Lat{}; + u32 piBsdDom1Pwd{}, piBsdDom2Pwd{}; + u32 piBsdDom1Pgs{}, piBsdDom2Pgs{}; + u32 piBsdDom1Rls{}, piBsdDom2Rls{}; -private: - template - void DMA(); + private: + template + void DMA(); }; } // namespace n64 diff --git a/src/backend/core/mmio/SI.cpp b/src/backend/core/mmio/SI.cpp index 9bedbd8..f4ff64a 100644 --- a/src/backend/core/mmio/SI.cpp +++ b/src/backend/core/mmio/SI.cpp @@ -5,91 +5,92 @@ namespace n64 { SI::SI() { Reset(); } void SI::Reset() { - status.raw = 0; - dramAddr = 0; - pifAddr = 0; - toDram = false; - pif.Reset(); + status.raw = 0; + dramAddr = 0; + pifAddr = 0; + toDram = false; + pif.Reset(); } auto SI::Read(u32 addr) const -> u32 { - n64::Mem& mem = n64::Core::GetMem(); - switch (addr) { - case 0x04800000: - return dramAddr; - case 0x04800004: - case 0x04800010: - return pifAddr; - case 0x0480000C: - return 0; - case 0x04800018: - { - u32 val = 0; - val |= status.dmaBusy; - val |= (0 << 1); - val |= (0 << 3); - val |= (mem.mmio.mi.intr.si << 12); - return val; + n64::Mem &mem = n64::Core::GetMem(); + switch (addr) { + case 0x04800000: + return dramAddr; + case 0x04800004: + case 0x04800010: + return pifAddr; + case 0x0480000C: + return 0; + case 0x04800018: + { + Core::SetIdleSkippingStatus(true); + u32 val = 0; + val |= status.dmaBusy; + val |= (0 << 1); + val |= (0 << 3); + val |= (mem.mmio.mi.intr.si << 12); + return val; + } + default: + panic("Unhandled SI[{:08X}] read", addr); } - default: - panic("Unhandled SI[{:08X}] read", addr); - } } // pif -> rdram template <> void SI::DMA() { - n64::Mem& mem = n64::Core::GetMem(); - pif.ProcessCommands(); - for (int i = 0; i < 64; i++) { - mem.mmio.rdp.WriteRDRAM(dramAddr + i, pif.Read(pifAddr + i)); - } - trace("SI DMA from PIF RAM to RDRAM ({:08X} to {:08X})", pifAddr, dramAddr); + n64::Mem &mem = n64::Core::GetMem(); + pif.ProcessCommands(); + for (int i = 0; i < 64; i++) { + mem.mmio.rdp.WriteRDRAM(dramAddr + i, pif.Read(pifAddr + i)); + } + trace("SI DMA from PIF RAM to RDRAM ({:08X} to {:08X})", pifAddr, dramAddr); } // rdram -> pif template <> void SI::DMA() { - n64::Mem& mem = n64::Core::GetMem(); - for (int i = 0; i < 64; i++) { - pif.Write(pifAddr + i, mem.mmio.rdp.ReadRDRAM(dramAddr + i)); - } - trace("SI DMA from RDRAM to PIF RAM ({:08X} to {:08X})", dramAddr, pifAddr); + n64::Mem &mem = n64::Core::GetMem(); + for (int i = 0; i < 64; i++) { + pif.Write(pifAddr + i, mem.mmio.rdp.ReadRDRAM(dramAddr + i)); + } + trace("SI DMA from RDRAM to PIF RAM ({:08X} to {:08X})", dramAddr, pifAddr); } void SI::DMA() { - n64::Mem& mem = n64::Core::GetMem(); - status.dmaBusy = false; - if (toDram) - DMA(); - else - DMA(); - mem.mmio.mi.InterruptRaise(MI::Interrupt::SI); + n64::Mem &mem = n64::Core::GetMem(); + status.dmaBusy = false; + if (toDram) + DMA(); + else + DMA(); + mem.mmio.mi.InterruptRaise(MI::Interrupt::SI); } void SI::Write(u32 addr, u32 val) { - n64::Mem& mem = n64::Core::GetMem(); - switch (addr) { - case 0x04800000: - dramAddr = val & RDRAM_DSIZE; - break; - case 0x04800004: - pifAddr = val & 0x1FFFFFFF; - status.dmaBusy = true; - toDram = true; - Scheduler::GetInstance().EnqueueRelative(SI_DMA_DELAY, SI_DMA); - break; - case 0x04800010: - pifAddr = val & 0x1FFFFFFF; - status.dmaBusy = true; - toDram = false; - Scheduler::GetInstance().EnqueueRelative(SI_DMA_DELAY, SI_DMA); - break; - case 0x04800018: - mem.mmio.mi.InterruptLower(MI::Interrupt::SI); - break; - default: - panic("Unhandled SI[{:08X}] write ({:08X})", addr, val); - } + n64::Mem &mem = n64::Core::GetMem(); + switch (addr) { + case 0x04800000: + dramAddr = val & RDRAM_DSIZE; + break; + case 0x04800004: + pifAddr = val & 0x1FFFFFFF; + status.dmaBusy = true; + toDram = true; + Scheduler::GetInstance().EnqueueRelative(SI_DMA_DELAY, SI_DMA); + break; + case 0x04800010: + pifAddr = val & 0x1FFFFFFF; + status.dmaBusy = true; + toDram = false; + Scheduler::GetInstance().EnqueueRelative(SI_DMA_DELAY, SI_DMA); + break; + case 0x04800018: + mem.mmio.mi.InterruptLower(MI::Interrupt::SI); + break; + default: + panic("Unhandled SI[{:08X}] write ({:08X})", addr, val); + } } } // namespace n64 diff --git a/src/backend/core/mmio/SI.hpp b/src/backend/core/mmio/SI.hpp index 46d639f..ed57101 100644 --- a/src/backend/core/mmio/SI.hpp +++ b/src/backend/core/mmio/SI.hpp @@ -4,33 +4,32 @@ #include namespace n64 { +struct SI { + SI(); + void Reset(); + [[nodiscard]] auto Read(u32) const -> u32; + void Write(u32, u32); + template + void DMA(); + void DMA(); -union SIStatus { - u32 raw{}; - struct { - unsigned dmaBusy : 1; - unsigned ioBusy : 1; - unsigned reserved : 1; - unsigned dmaErr : 1; - unsigned : 8; - unsigned intr : 1; - }; -}; + union Status { + u32 raw{}; + struct { + unsigned dmaBusy : 1; + unsigned ioBusy : 1; + unsigned reserved : 1; + unsigned dmaErr : 1; + unsigned : 8; + unsigned intr : 1; + }; + }; -struct SI { - SI(); - void Reset(); - [[nodiscard]] auto Read(u32) const -> u32; - void Write(u32, u32); - template - void DMA(); - void DMA(); - - bool toDram = false; - SIStatus status{}; - u32 dramAddr{}; - u32 pifAddr{}; - PIF pif; + bool toDram = false; + Status status{}; + u32 dramAddr{}; + u32 pifAddr{}; + PIF pif; }; #define SI_DMA_DELAY (65536 * 2)