core vdp, fix FIFO DMA wait, improve save/load

This commit is contained in:
kub 2021-12-07 23:59:53 +01:00
parent d650a7a268
commit fda7339b94

View file

@ -179,11 +179,11 @@ int (*PicoDmaHook)(u32 source, int len, unsigned short **base, u32 *mask) = NULL
// NB code assumes fifo_* arrays have size 2^n // NB code assumes fifo_* arrays have size 2^n
static struct VdpFIFO { // XXX this must go into save file! static struct VdpFIFO { // XXX this must go into save file!
// last transferred FIFO data, ...x = index XXX currently only CPU // last transferred FIFO data, ...x = index XXX currently only CPU
unsigned short fifo_data[4], fifo_dx; u16 fifo_data[4], fifo_dx;
// queued FIFO transfers, ...x = index, ...l = queue length // queued FIFO transfers, ...x = index, ...l = queue length
// each entry has 2 values: [n]>>3 = #writes, [n]&7 = flags (FQ_*) // each entry has 2 values: [n]>>3 = #writes, [n]&7 = flags (FQ_*)
unsigned int fifo_queue[8], fifo_qx, fifo_ql; u32 fifo_queue[8], fifo_qx, fifo_ql;
int fifo_total; // total# of pending FIFO entries (w/o BGDMA) int fifo_total; // total# of pending FIFO entries (w/o BGDMA)
unsigned short fifo_slot; // last executed slot in current scanline unsigned short fifo_slot; // last executed slot in current scanline
@ -212,7 +212,6 @@ static __inline int AdvanceFIFOEntry(struct VdpFIFO *vf, struct PicoVideo *pv, i
l = cnt; l = cnt;
if (!(vf->fifo_queue[vf->fifo_qx] & FQ_BGDMA)) if (!(vf->fifo_queue[vf->fifo_qx] & FQ_BGDMA))
vf->fifo_total -= ((cnt & b) + l) >> b; vf->fifo_total -= ((cnt & b) + l) >> b;
if (vf->fifo_total < 0) vf->fifo_total = 0;
cnt -= l; cnt -= l;
// if entry has been processed... // if entry has been processed...
@ -238,7 +237,7 @@ static __inline int AdvanceFIFOEntry(struct VdpFIFO *vf, struct PicoVideo *pv, i
static __inline void SetFIFOState(struct VdpFIFO *vf, struct PicoVideo *pv) static __inline void SetFIFOState(struct VdpFIFO *vf, struct PicoVideo *pv)
{ {
unsigned int st = pv->status, cmd = pv->command; u32 st = pv->status, cmd = pv->command;
// release CPU and terminate DMA if FIFO isn't blocking the 68k anymore // release CPU and terminate DMA if FIFO isn't blocking the 68k anymore
if (vf->fifo_total <= 4) { if (vf->fifo_total <= 4) {
st &= ~PVS_CPUWR; st &= ~PVS_CPUWR;
@ -287,28 +286,29 @@ static int PicoVideoFIFODrain(int level, int cycles, int bgdma)
struct VdpFIFO *vf = &VdpFIFO; struct VdpFIFO *vf = &VdpFIFO;
struct PicoVideo *pv = &Pico.video; struct PicoVideo *pv = &Pico.video;
unsigned ocyc = cycles; unsigned ocyc = cycles;
int bd = vf->fifo_queue[vf->fifo_qx] & bgdma;
int burn = 0; int burn = 0;
// process FIFO entries until low level is reached // process FIFO entries until low level is reached
while (vf->fifo_slot <= vf->fifo_maxslot && cycles < 488 && while (vf->fifo_slot < vf->fifo_maxslot &&
((vf->fifo_total > level) | (vf->fifo_queue[vf->fifo_qx] & bgdma))) { vf->fifo_ql && ((vf->fifo_total > level) | bd)) {
int b = vf->fifo_queue[vf->fifo_qx] & FQ_BYTE; int b = vf->fifo_queue[vf->fifo_qx] & FQ_BYTE;
int cnt = bgdma ? pv->fifo_cnt : ((vf->fifo_total-level)<<b) - (pv->fifo_cnt&b); int cnt = bd ? pv->fifo_cnt : ((vf->fifo_total-level)<<b) - (pv->fifo_cnt&b);
int slot = (pv->fifo_cnt<cnt ? pv->fifo_cnt:cnt) + vf->fifo_slot; int slot = (pv->fifo_cnt<cnt ? pv->fifo_cnt:cnt) + vf->fifo_slot;
if (slot > vf->fifo_maxslot) { if (slot > vf->fifo_maxslot) {
// target slot in later scanline, advance to eol // target slot in later scanline, advance to eol
slot = vf->fifo_maxslot; slot = vf->fifo_maxslot;
cycles = 488;
} else {
// advance FIFO to target slot and CPU to cycles at that slot
cycles = Sl2Cyc(vf, slot);
} }
if (slot > vf->fifo_slot) { if (slot > vf->fifo_slot) {
AdvanceFIFOEntry(vf, pv, slot - vf->fifo_slot); // advance FIFO to target slot and CPU to cycles at that slot
vf->fifo_slot = slot; vf->fifo_slot += AdvanceFIFOEntry(vf, pv, slot - vf->fifo_slot);
cycles = Sl2Cyc(vf, vf->fifo_slot);
bd = vf->fifo_queue[vf->fifo_qx] & bgdma;
} }
} }
if (vf->fifo_ql && ((vf->fifo_total > level) | bd))
cycles = 488; // not completed in this scanline
if (cycles > ocyc) if (cycles > ocyc)
burn = cycles - ocyc; burn = cycles - ocyc;
@ -911,6 +911,7 @@ PICO_INTERNAL_ASM void PicoVideoWrite(u32 a,unsigned short d)
if (num == 12 && ((pvid->reg[12]^d)&0x01)) if (num == 12 && ((pvid->reg[12]^d)&0x01))
PicoVideoFIFOMode(pvid->reg[1]&0x40, d & 1); PicoVideoFIFOMode(pvid->reg[1]&0x40, d & 1);
DrawSync(SekCyclesDone() - Pico.t.m68c_line_start <= 488-390); DrawSync(SekCyclesDone() - Pico.t.m68c_line_start <= 488-390);
d &= 0xff;
pvid->reg[num]=(unsigned char)d; pvid->reg[num]=(unsigned char)d;
switch (num) switch (num)
{ {
@ -1146,14 +1147,24 @@ void PicoVideoLoad(void)
{ {
struct VdpFIFO *vf = &VdpFIFO; struct VdpFIFO *vf = &VdpFIFO;
struct PicoVideo *pv = &Pico.video; struct PicoVideo *pv = &Pico.video;
int b = pv->type == 1;
// convert former dma_xfers (why was this in PicoMisc anyway?) // convert former dma_xfers (why was this in PicoMisc anyway?)
if (Pico.m.dma_xfers) { if (Pico.m.dma_xfers) {
pv->status |= SR_DMA|PVS_FIFORUN; pv->status |= SR_DMA;
pv->fifo_cnt = Pico.m.dma_xfers * (pv->type == 1 ? 2 : 1); pv->fifo_cnt = Pico.m.dma_xfers * (b ? 2 : 1);
vf->fifo_total = Pico.m.dma_xfers;
Pico.m.dma_xfers = 0; Pico.m.dma_xfers = 0;
} }
// make an entry in the FIFO if there are outstanding transfers
vf->fifo_ql = vf->fifo_total = 0;
if (pv->fifo_cnt) {
pv->status |= PVS_FIFORUN|PVS_CPUWR;
vf->fifo_total = (pv->fifo_cnt + (b)) >> b;
if (pv->status & SR_DMA)
b |= (pv->status & (PVS_DMAFILL|PVS_DMABG)) ? FQ_BGDMA : FQ_FGDMA;
vf->fifo_queue[vf->fifo_qx] = (vf->fifo_total << 3) | b;
vf->fifo_ql = 1;
}
PicoVideoCacheSAT(); PicoVideoCacheSAT();
} }
// vim:shiftwidth=2:ts=2:expandtab // vim:shiftwidth=2:ts=2:expandtab