schedule pi dma
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
#include <log.hpp>
|
#include <log.hpp>
|
||||||
#include <core/Mem.hpp>
|
#include <core/Mem.hpp>
|
||||||
#include <core/registers/Registers.hpp>
|
#include <core/registers/Registers.hpp>
|
||||||
|
#include "Scheduler.hpp"
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
PI::PI() {
|
PI::PI() {
|
||||||
@@ -30,14 +31,85 @@ auto PI::Read(MI& mi, u32 addr) const -> u32 {
|
|||||||
value |= (mi.miIntr.pi << 3); // PI interrupt?
|
value |= (mi.miIntr.pi << 3); // PI interrupt?
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
case 0x04600014: case 0x04600018: case 0x0460001C: case 0x04600020:
|
case 0x04600014: return pi_bsd_dom1_lat;
|
||||||
case 0x04600024: case 0x04600028: case 0x0460002C: case 0x04600030:
|
case 0x04600018: return pi_bsd_dom1_pwd;
|
||||||
return stub[(addr & 0xff) - 5];
|
case 0x0460001C: return pi_bsd_dom1_pgs;
|
||||||
|
case 0x04600020: return pi_bsd_dom1_rls;
|
||||||
|
case 0x04600024: return pi_bsd_dom2_lat;
|
||||||
|
case 0x04600028: return pi_bsd_dom2_pwd;
|
||||||
|
case 0x0460002C: return pi_bsd_dom2_pgs;
|
||||||
|
case 0x04600030: return pi_bsd_dom2_rls;
|
||||||
default:
|
default:
|
||||||
Util::panic("Unhandled PI[{:08X}] read", addr);
|
Util::panic("Unhandled PI[{:08X}] read", addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE u8 PIGetDomain(u32 address) {
|
||||||
|
switch (address) {
|
||||||
|
case 0x6000000 ... 0x7FFFFFF:
|
||||||
|
case REGION_CART_1_2:
|
||||||
|
return 1;
|
||||||
|
case REGION_CART_2_1:
|
||||||
|
case REGION_CART_2_2:
|
||||||
|
return 2;
|
||||||
|
default:
|
||||||
|
logfatal("Unknown PI domain for address %08X!\n", address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE u32 PIAccessTiming(PI& pi, u8 domain, u32 length) {
|
||||||
|
uint32_t cycles = 0;
|
||||||
|
uint32_t latency = 0;
|
||||||
|
uint32_t pulse_width = 0;
|
||||||
|
uint32_t release = 0;
|
||||||
|
uint32_t page_size = 0;
|
||||||
|
uint32_t pages = 0;
|
||||||
|
|
||||||
|
switch (domain) {
|
||||||
|
case 1:
|
||||||
|
latency = pi.pi_bsd_dom1_lat + 1;
|
||||||
|
pulse_width = pi.pi_bsd_dom1_pwd + 1;
|
||||||
|
release = pi.pi_bsd_dom1_rls + 1;
|
||||||
|
page_size = pow(2, (pi.pi_bsd_dom1_pgs + 2));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
latency = pi.pi_bsd_dom2_lat + 1;
|
||||||
|
pulse_width = pi.pi_bsd_dom2_pwd + 1;
|
||||||
|
release = pi.pi_bsd_dom2_rls + 1;
|
||||||
|
page_size = pow(2, (pi.pi_bsd_dom2_pgs + 2));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Util::panic("Unknown PI domain: %d\n", domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
pages = ceil((double)length / 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
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool toCart>
|
||||||
|
FORCE_INLINE void DMA(Mem& mem, Registers& regs) {
|
||||||
|
MI& mi = mem.mmio.mi;
|
||||||
|
PI& pi = mem.mmio.pi;
|
||||||
|
u32 len = toCart ? pi.rdLen : pi.wrLen;
|
||||||
|
u32 cart_addr = pi.cartAddr & 0xFFFFFFFE;
|
||||||
|
u32 dram_addr = pi.dramAddr & 0x007FFFFE;
|
||||||
|
for(int i = 0; i < len; i++) {
|
||||||
|
if constexpr (toCart) {
|
||||||
|
mem.rom.cart[BYTE_ADDRESS(cart_addr + i) & mem.rom.mask] = mem.mmio.rdp.rdram[BYTE_ADDRESS(dram_addr + i) & RDRAM_DSIZE];
|
||||||
|
} else {
|
||||||
|
mem.mmio.rdp.rdram[BYTE_ADDRESS(dram_addr + i) & RDRAM_DSIZE] = mem.rom.cart[BYTE_ADDRESS(cart_addr + i) & mem.rom.mask];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pi.dramAddr = dram_addr + len;
|
||||||
|
pi.cartAddr = cart_addr + len;
|
||||||
|
InterruptRaise(mi, regs, Interrupt::PI);
|
||||||
|
Util::debug("PI DMA from RDRAM to CARTRIDGE (size: {} B, {:08X} to {:08X})", len, pi.dramAddr, pi.cartAddr);
|
||||||
|
}
|
||||||
|
|
||||||
void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
|
void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
|
||||||
MI& mi = mem.mmio.mi;
|
MI& mi = mem.mmio.mi;
|
||||||
switch(addr) {
|
switch(addr) {
|
||||||
@@ -51,13 +123,7 @@ void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
|
|||||||
len -= dram_addr & 0x7;
|
len -= dram_addr & 0x7;
|
||||||
}
|
}
|
||||||
rdLen = len;
|
rdLen = len;
|
||||||
for(int i = 0; i < len; i++) {
|
scheduler.enqueueRelative(Event{, DMA<true>});
|
||||||
mem.rom.cart[BYTE_ADDRESS(cart_addr + i) & mem.rom.mask] = mem.mmio.rdp.rdram[BYTE_ADDRESS(dram_addr + i) & RDRAM_DSIZE];
|
|
||||||
}
|
|
||||||
dramAddr = dram_addr + len;
|
|
||||||
cartAddr = cart_addr + len;
|
|
||||||
InterruptRaise(mi, regs, Interrupt::PI);
|
|
||||||
//Util::debug("PI DMA from RDRAM to CARTRIDGE (size: {} B, {:08X} to {:08X})", len, dramAddr, cartAddr);
|
|
||||||
} break;
|
} break;
|
||||||
case 0x0460000C: {
|
case 0x0460000C: {
|
||||||
u32 len = (val & 0x00FFFFFF) + 1;
|
u32 len = (val & 0x00FFFFFF) + 1;
|
||||||
@@ -67,13 +133,7 @@ void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
|
|||||||
len -= (dram_addr & 0x7);
|
len -= (dram_addr & 0x7);
|
||||||
}
|
}
|
||||||
wrLen = len;
|
wrLen = len;
|
||||||
for(int i = 0; i < len; i++) {
|
scheduler.enqueueRelative(Event{, DMA<false>});
|
||||||
mem.mmio.rdp.rdram[BYTE_ADDRESS(dram_addr + i) & RDRAM_DSIZE] = mem.rom.cart[BYTE_ADDRESS(cart_addr + i) & mem.rom.mask];
|
|
||||||
}
|
|
||||||
dramAddr = dram_addr + len;
|
|
||||||
cartAddr = cart_addr + len;
|
|
||||||
InterruptRaise(mi, regs, Interrupt::PI);
|
|
||||||
//Util::debug("PI DMA from CARTRIDGE to RDRAM (size: {} B, {:08X} to {:08X})", len, cart_addr, dram_addr);
|
|
||||||
} break;
|
} break;
|
||||||
case 0x04600010:
|
case 0x04600010:
|
||||||
if(val & 2) {
|
if(val & 2) {
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ struct PI {
|
|||||||
void Write(Mem&, Registers&, u32, u32);
|
void Write(Mem&, Registers&, u32, u32);
|
||||||
u32 dramAddr{}, cartAddr{};
|
u32 dramAddr{}, cartAddr{};
|
||||||
u32 rdLen{}, wrLen{};
|
u32 rdLen{}, wrLen{};
|
||||||
u32 stub[8]{};
|
u32 pi_bsd_dom1_lat{}, pi_bsd_dom2_lat{};
|
||||||
|
u32 pi_bsd_dom1_pwd{}, pi_bsd_dom2_pwd{};
|
||||||
|
u32 pi_bsd_dom1_pgs{}, pi_bsd_dom2_pgs{};
|
||||||
|
u32 pi_bsd_dom1_rls{}, pi_bsd_dom2_rls{};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -34,10 +34,11 @@ auto SI::Read(MI& mi, u32 addr) const -> u32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DMA(Mem& mem, Registers& regs) {
|
template <bool toDram>
|
||||||
|
FORCE_INLINE void DMA(Mem& mem, Registers& regs) {
|
||||||
SI& si = mem.mmio.si;
|
SI& si = mem.mmio.si;
|
||||||
si.status.dmaBusy = false;
|
si.status.dmaBusy = false;
|
||||||
if(si.toDram) {
|
if constexpr(toDram) {
|
||||||
si.pif.ProcessCommands(mem);
|
si.pif.ProcessCommands(mem);
|
||||||
for(int i = 0; i < 64; i++) {
|
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(si.dramAddr + i)] = si.pif.Read(si.pifAddr + i);
|
||||||
@@ -61,14 +62,12 @@ void SI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
|
|||||||
case 0x04800004: {
|
case 0x04800004: {
|
||||||
pifAddr = val & 0x1FFFFFFF;
|
pifAddr = val & 0x1FFFFFFF;
|
||||||
status.dmaBusy = true;
|
status.dmaBusy = true;
|
||||||
toDram = true;
|
scheduler.enqueueRelative({SI_DMA_DELAY, DMA<true>});
|
||||||
scheduler.enqueueRelative({SI_DMA_DELAY, DMA});
|
|
||||||
} break;
|
} break;
|
||||||
case 0x04800010: {
|
case 0x04800010: {
|
||||||
pifAddr = val & 0x1FFFFFFF;
|
pifAddr = val & 0x1FFFFFFF;
|
||||||
status.dmaBusy = true;
|
status.dmaBusy = true;
|
||||||
toDram = false;
|
scheduler.enqueueRelative({SI_DMA_DELAY, DMA<false>});
|
||||||
scheduler.enqueueRelative({SI_DMA_DELAY, DMA});
|
|
||||||
} break;
|
} break;
|
||||||
case 0x04800018:
|
case 0x04800018:
|
||||||
InterruptLower(mem.mmio.mi, regs, Interrupt::SI);
|
InterruptLower(mem.mmio.mi, regs, Interrupt::SI);
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ struct SI {
|
|||||||
u32 dramAddr{};
|
u32 dramAddr{};
|
||||||
u32 pifAddr{};
|
u32 pifAddr{};
|
||||||
|
|
||||||
bool toDram = false;
|
|
||||||
|
|
||||||
auto Read(MI&, u32) const -> u32;
|
auto Read(MI&, u32) const -> u32;
|
||||||
void Write(Mem&, Registers&, u32, u32);
|
void Write(Mem&, Registers&, u32, u32);
|
||||||
PIF pif;
|
PIF pif;
|
||||||
|
|||||||
Reference in New Issue
Block a user