core vdp, optimisation
authorkub <derkub@gmail.com>
Sat, 5 Feb 2022 21:37:03 +0000 (21:37 +0000)
committerkub <derkub@gmail.com>
Sat, 5 Feb 2022 21:37:03 +0000 (21:37 +0000)
pico/videoport.c

index 1ecb311..7f6ca9a 100644 (file)
@@ -148,7 +148,6 @@ int (*PicoDmaHook)(u32 source, int len, unsigned short **base, u32 *mask) = NULL
 /* 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
@@ -186,7 +185,6 @@ static struct VdpFIFO { // XXX this must go into save file!
   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
@@ -203,38 +201,31 @@ enum { FQ_BYTE = 1, FQ_BGDMA = 2, FQ_FGDMA = 4 }; // queue flags, NB: BYTE = 1!
 #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
@@ -245,10 +236,10 @@ static __inline void SetFIFOState(struct VdpFIFO *vf, struct PicoVideo *pv)
       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
@@ -266,10 +257,11 @@ void PicoVideoFIFOSync(int cycles)
 \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
@@ -288,12 +280,15 @@ static int PicoVideoFIFODrain(int level, int cycles, int bgdma)
   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
@@ -324,14 +319,14 @@ static int PicoVideoFIFORead(void)
   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
@@ -350,31 +345,30 @@ int PicoVideoFIFOWrite(int count, int flags, unsigned sr_mask,unsigned sr_flags)
   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
@@ -383,17 +377,13 @@ int PicoVideoFIFOWrite(int count, int flags, unsigned sr_mask,unsigned sr_flags)
     }\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
@@ -404,15 +394,17 @@ int PicoVideoFIFOHint(void)
 {\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
@@ -654,8 +646,8 @@ static void DmaCopy(int len)
   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
@@ -686,7 +678,7 @@ static NOINLINE void DmaFill(int data)
   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
@@ -769,7 +761,7 @@ static NOINLINE void CommandDma(void)
   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
@@ -1139,17 +1131,13 @@ void PicoVideoSave(void)
 \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
@@ -1165,21 +1153,18 @@ void PicoVideoLoad(void)
   }\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