/* VDP FIFO implementation\r
* \r
* fifo_slot: last slot executed in this scanline\r
- * fifo_cnt: #slots remaining for active FIFO write (#writes<<#bytep)\r
* fifo_total: #total FIFO entries pending\r
* fifo_data: last values transferred through fifo\r
* fifo_queue: fifo transfer queue (#writes, flags)\r
u32 fifo_queue[8], fifo_qx, fifo_ql;\r
int fifo_total; // total# of pending FIFO entries (w/o BGDMA)\r
\r
- int fifo_cnt; // remaining entries in currently active transfer\r
unsigned short fifo_slot; // last executed slot in current scanline\r
unsigned short fifo_maxslot;// #slots in scanline\r
\r
#define Sl2Cyc(vf,sl) (vf->fifo_sl2cyc[sl]*clkdiv)\r
\r
// do the FIFO math\r
-static __inline int AdvanceFIFOEntry(struct VdpFIFO *vf, struct PicoVideo *pv, int slots)\r
+static NOINLINE int AdvanceFIFOEntry(struct VdpFIFO *vf, struct PicoVideo *pv, int slots)\r
{\r
- int l = slots, b = vf->fifo_queue[vf->fifo_qx] & FQ_BYTE;\r
- int cnt = vf->fifo_cnt;\r
+ u32 *qx = &vf->fifo_queue[vf->fifo_qx];\r
+ int l = slots, b = *qx & FQ_BYTE;\r
+ int cnt = *qx >> 3;\r
\r
// advance currently active FIFO entry\r
if (l > cnt)\r
l = cnt;\r
- if (!(vf->fifo_queue[vf->fifo_qx] & FQ_BGDMA))\r
+ if (!(*qx & FQ_BGDMA))\r
vf->fifo_total -= ((cnt & b) + l) >> b;\r
- cnt -= l;\r
- vf->fifo_cnt = cnt;\r
+ *qx -= l << 3;\r
\r
// if entry has been processed...\r
- if (cnt == 0) {\r
+ if (cnt == l) {\r
// remove entry from FIFO\r
- vf->fifo_queue[vf->fifo_qx] = 0;\r
- vf->fifo_qx = (vf->fifo_qx+1) & 7, vf->fifo_ql --;\r
- // start processing for next entry if there is one\r
- if (vf->fifo_ql) {\r
- b = vf->fifo_queue[vf->fifo_qx] & FQ_BYTE;\r
- vf->fifo_cnt = (vf->fifo_queue[vf->fifo_qx] >> 3) << b;\r
- } else { // FIFO empty\r
- pv->status &= ~PVS_FIFORUN;\r
- vf->fifo_total = 0;\r
- }\r
+ *qx = 0;\r
+ vf->fifo_qx = (vf->fifo_qx+1) & 7;\r
+ vf->fifo_ql --;\r
}\r
\r
return l;\r
}\r
\r
-static __inline void SetFIFOState(struct VdpFIFO *vf, struct PicoVideo *pv)\r
+static void SetFIFOState(struct VdpFIFO *vf, struct PicoVideo *pv)\r
{\r
u32 st = pv->status, cmd = pv->command;\r
// release CPU and terminate DMA if FIFO isn't blocking the 68k anymore\r
cmd &= ~0x80;\r
}\r
}\r
- if (vf->fifo_cnt == 0) {\r
- st &= ~PVS_CPURD;\r
+ if (vf->fifo_ql == 0) {\r
+ st &= ~(PVS_CPURD|PVS_FIFORUN);\r
// terminate DMA if applicable\r
- if (!(st & (PVS_FIFORUN|PVS_DMAFILL))) {\r
+ if (!(st & PVS_DMAFILL)) {\r
st &= ~(SR_DMA|PVS_DMABG);\r
cmd &= ~0x80;\r
}\r
\r
// calculate #slots since last executed slot\r
slots = Cyc2Sl(vf, cycles) - vf->fifo_slot;\r
+ if (!slots || !vf->fifo_ql) return;\r
\r
// advance FIFO queue by #done slots\r
done = slots;\r
- while (done > 0 && vf->fifo_cnt) {\r
+ while (done > 0 && vf->fifo_ql) {\r
int l = AdvanceFIFOEntry(vf, pv, done);\r
vf->fifo_slot += l;\r
done -= l;\r
int bd = vf->fifo_queue[vf->fifo_qx] & bgdma;\r
int burn = 0;\r
\r
+ if (!(vf->fifo_ql && ((vf->fifo_total > level) | bd))) return 0;\r
+\r
// process FIFO entries until low level is reached\r
while (vf->fifo_slot < vf->fifo_maxslot &&\r
vf->fifo_ql && ((vf->fifo_total > level) | bd)) {\r
int b = vf->fifo_queue[vf->fifo_qx] & FQ_BYTE;\r
- int cnt = bd ? vf->fifo_cnt : ((vf->fifo_total-level)<<b) - (vf->fifo_cnt&b);\r
- int slot = (vf->fifo_cnt<cnt ? vf->fifo_cnt:cnt) + vf->fifo_slot;\r
+ int c = vf->fifo_queue[vf->fifo_qx] >> 3;\r
+ int cnt = bd ? c : ((vf->fifo_total-level)<<b) - (c&b);\r
+ int slot = (c < cnt ? c : cnt) + vf->fifo_slot;\r
\r
if (slot > vf->fifo_maxslot) {\r
// target slot in later scanline, advance to eol\r
int lc = SekCyclesDone()-Pico.t.m68c_line_start;\r
int burn = 0;\r
\r
- if (vf->fifo_cnt) {\r
+ if (vf->fifo_ql) {\r
PicoVideoFIFOSync(lc);\r
// advance FIFO and CPU until FIFO is empty\r
burn = PicoVideoFIFODrain(0, lc, FQ_BGDMA);\r
lc += burn;\r
}\r
\r
- if (vf->fifo_cnt)\r
+ if (vf->fifo_ql)\r
pv->status |= PVS_CPURD; // target slot is in later scanline\r
else {\r
// use next VDP access slot for reading, block 68k until then\r
int lc = SekCyclesDone()-Pico.t.m68c_line_start;\r
int burn = 0;\r
\r
- if (vf->fifo_cnt)\r
+ if (vf->fifo_total >= 4 || (pv->status & SR_DMA))\r
PicoVideoFIFOSync(lc);\r
pv->status = (pv->status & ~sr_mask) | sr_flags;\r
\r
- if (count && vf->fifo_ql < 8) {\r
+ if (count && vf->fifo_ql < 7) {\r
// determine queue position for entry\r
int x = (vf->fifo_qx + vf->fifo_ql - 1) & 7;\r
if (unlikely(vf->fifo_queue[x] & FQ_BGDMA)) {\r
// CPU FIFO writes have priority over a background DMA Fill/Copy\r
- // XXX if interrupting a DMA fill, fill data changes\r
- if (x == vf->fifo_qx) { // overtaking to queue head?\r
- int f = vf->fifo_queue[x] & 7;\r
- vf->fifo_queue[x] = (vf->fifo_cnt >> (f & FQ_BYTE) << 3) | f;\r
+ vf->fifo_queue[(x+1) & 7] = vf->fifo_queue[x]; // push bg DMA back\r
+ x = (x-1) & 7;\r
+ if (vf->fifo_ql == 1) {\r
+ // XXX if interrupting a DMA fill, fill data changes\r
pv->status &= ~PVS_FIFORUN;\r
}\r
- // push background DMA back\r
- vf->fifo_queue[(x+1) & 7] = vf->fifo_queue[x];\r
- x = (x-1) & 7;\r
}\r
\r
+ if (!(flags & FQ_BGDMA))\r
+ vf->fifo_total += count;\r
+\r
+ count <<= (flags & FQ_BYTE);\r
if ((pv->status & PVS_FIFORUN) && (vf->fifo_queue[x] & 7) == flags) {\r
// amalgamate entries if of same type\r
vf->fifo_queue[x] += (count << 3);\r
- if (x == vf->fifo_qx)\r
- vf->fifo_cnt += count << (flags & FQ_BYTE);\r
} else {\r
// create new xfer queue entry\r
vf->fifo_ql ++;\r
}\r
\r
// update FIFO state if it was empty\r
- if (!(pv->status & PVS_FIFORUN)) {\r
+ if (!(pv->status & PVS_FIFORUN))\r
vf->fifo_slot = Cyc2Sl(vf, lc+7); // FIFO latency ~3 vdp slots\r
- pv->status |= PVS_FIFORUN;\r
- vf->fifo_cnt = count << (flags & FQ_BYTE);\r
- }\r
- if (!(flags & FQ_BGDMA))\r
- vf->fifo_total += count;\r
+ pv->status |= PVS_FIFORUN;\r
}\r
\r
// if CPU is waiting for the bus, advance CPU and FIFO until bus is free\r
- if (pv->status & PVS_CPUWR)\r
+ if (vf->fifo_total > 4 && (pv->status & PVS_CPUWR))\r
burn = PicoVideoFIFODrain(4, lc, 0);\r
\r
return burn;\r
{\r
struct VdpFIFO *vf = &VdpFIFO;\r
struct PicoVideo *pv = &Pico.video;\r
+ int lc = SekCyclesDone()-Pico.t.m68c_line_start;\r
int burn = 0;\r
\r
// reset slot to start of scanline\r
vf->fifo_slot = 0;\r
\r
// if CPU is waiting for the bus, advance CPU and FIFO until bus is free\r
- if (pv->status & PVS_CPUWR)\r
- burn = PicoVideoFIFOWrite(0, 0, 0, 0);\r
- else if (pv->status & PVS_CPURD)\r
+ if (pv->status & PVS_CPUWR) {\r
+ PicoVideoFIFOSync(lc);\r
+ burn = PicoVideoFIFODrain(4, lc, 0);\r
+ } else if (pv->status & PVS_CPURD)\r
burn = PicoVideoFIFORead();\r
\r
return burn;\r
int source;\r
elprintf(EL_VDPDMA, "DmaCopy len %i [%u]", len, SekCyclesDone());\r
\r
- // XXX implement VRAM 128k? Is this even working? xfer/count still FQ_BYTE?\r
- SekCyclesBurnRun(PicoVideoFIFOWrite(len, FQ_BGDMA | FQ_BYTE,\r
+ // XXX implement VRAM 128k? Is this even working? xfer/count still in bytes?\r
+ SekCyclesBurnRun(PicoVideoFIFOWrite(2*len, FQ_BGDMA, // 2 slots each (rd+wr)\r
PVS_CPUWR, SR_DMA | PVS_DMABG));\r
\r
source =Pico.video.reg[0x15];\r
len = GetDmaLength();\r
elprintf(EL_VDPDMA, "DmaFill len %i inc %i [%u]", len, inc, SekCyclesDone());\r
\r
- SekCyclesBurnRun(PicoVideoFIFOWrite(len, FQ_BGDMA | (Pico.video.type == 1),\r
+ SekCyclesBurnRun(PicoVideoFIFOWrite(len, FQ_BGDMA, // 1 slot each (wr)\r
PVS_CPUWR | PVS_DMAFILL, SR_DMA | PVS_DMABG));\r
\r
switch (Pico.video.type)\r
if (pvid->status & SR_DMA) {\r
elprintf(EL_VDPDMA, "Dma overlap, left=%d @ %06x",\r
VdpFIFO.fifo_total, SekPc);\r
- VdpFIFO.fifo_cnt = VdpFIFO.fifo_total = VdpFIFO.fifo_ql = 0;\r
+ VdpFIFO.fifo_total = VdpFIFO.fifo_ql = 0;\r
pvid->status &= ~(PVS_FIFORUN|PVS_DMAFILL);\r
}\r
\r
\r
// account for all outstanding xfers XXX kludge, entry attr's not saved\r
pv->fifo_cnt = pv->fifo_bgcnt = 0;\r
- for (l = vf->fifo_ql, x = vf->fifo_qx + l-1; l > 1; l--, x--) {\r
- int cnt = (vf->fifo_queue[x&7] >> 3) << (vf->fifo_queue[x&7] & FQ_BYTE);\r
+ for (l = vf->fifo_ql, x = vf->fifo_qx + l-1; l > 0; l--, x--) {\r
+ int cnt = (vf->fifo_queue[x&7] >> 3);\r
if (vf->fifo_queue[x&7] & FQ_BGDMA)\r
pv->fifo_bgcnt += cnt;\r
else\r
pv->fifo_cnt += cnt;\r
}\r
- if (vf->fifo_ql && (vf->fifo_queue[vf->fifo_qx] & FQ_BGDMA))\r
- pv->fifo_bgcnt += vf->fifo_cnt;\r
- else\r
- pv->fifo_cnt += vf->fifo_cnt;\r
}\r
\r
void PicoVideoLoad(void)\r
}\r
\r
// fake entries in the FIFO if there are outstanding transfers\r
- vf->fifo_ql = vf->fifo_qx = vf->fifo_cnt = vf->fifo_total = 0;\r
+ vf->fifo_ql = vf->fifo_qx = vf->fifo_total = 0;\r
if (pv->fifo_cnt) {\r
- int wc = (pv->fifo_cnt + b) >> b;\r
+ int wc = pv->fifo_cnt;\r
pv->status |= PVS_FIFORUN|PVS_CPUWR;\r
- vf->fifo_total = wc;\r
+ vf->fifo_total = (wc+b) >> b;\r
vf->fifo_queue[vf->fifo_qx + vf->fifo_ql] = (wc << 3) | b | FQ_FGDMA;\r
vf->fifo_ql ++;\r
- vf->fifo_cnt = pv->fifo_cnt;\r
}\r
if (pv->fifo_bgcnt) {\r
int wc = pv->fifo_bgcnt;\r
- if (!vf->fifo_ql) {\r
- pv->status |= PVS_DMABG;\r
- vf->fifo_cnt = pv->fifo_bgcnt;\r
- }\r
+ if (!vf->fifo_ql)\r
+ pv->status |= PVS_FIFORUN|PVS_DMABG;\r
vf->fifo_queue[vf->fifo_qx + vf->fifo_ql] = (wc << 3) | FQ_BGDMA;\r
vf->fifo_ql ++;\r
}\r