core vdp, fix FIFO DMA wait, improve save/load
authorkub <derkub@gmail.com>
Tue, 7 Dec 2021 22:59:53 +0000 (23:59 +0100)
committerkub <derkub@gmail.com>
Tue, 7 Dec 2021 22:59:53 +0000 (23:59 +0100)
pico/videoport.c

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