#include #include namespace n64 { SI::SI() { Reset(); } void SI::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: { 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); } } // 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); } // 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); } void SI::DMA() { 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); } } } // namespace n64