vdp fifo, tentative fix for broken save/load
authorkub <derkub@gmail.com>
Sun, 16 Feb 2020 13:08:48 +0000 (14:08 +0100)
committerkub <derkub@gmail.com>
Sun, 16 Feb 2020 13:08:48 +0000 (14:08 +0100)
pico/pico_int.h
pico/state.c
pico/videoport.c

index b3ce8a7..7032922 100644 (file)
@@ -316,7 +316,10 @@ struct PicoVideo
   unsigned char debug_p;      // ... parsed: PVD_*\r
   unsigned char addr_u;       // bit16 of .addr\r
   unsigned char hint_cnt;\r
-  unsigned char pad[0x0b];\r
+  unsigned char pad2;\r
+  unsigned short hv_latch;    // latched hvcounter value\r
+  signed int fifo_cnt;        // pending xfers for current FIFO queue entry\r
+  unsigned char pad[0x04];\r
 };\r
 \r
 struct PicoMisc\r
@@ -339,7 +342,7 @@ struct PicoMisc
   unsigned char  eeprom_slave; // EEPROM slave word for X24C02 and better SRAMs\r
   unsigned char  eeprom_status;\r
   unsigned char  pad1;         // was ym2612 status\r
-  unsigned short pad2;         // 18 was dma_xfers\r
+  unsigned short dma_xfers;    // 18 unused (was VDP DMA transfer count)\r
   unsigned char  eeprom_wb[2]; // EEPROM latch/write buffer\r
   unsigned int  frame_count;   // 1c for movies and idle det\r
 };\r
@@ -856,6 +859,8 @@ extern int (*PicoDmaHook)(unsigned int source, int len, unsigned short **base, u
 void PicoVideoFIFOSync(int cycles);\r
 int PicoVideoFIFOHint(void);\r
 int PicoVideoFIFOWrite(int count, int byte_p, unsigned sr_mask, unsigned sr_flags);\r
+void PicoVideoSave(void);\r
+void PicoVideoLoad(void);\r
 \r
 // misc.c\r
 PICO_INTERNAL_ASM void memcpy16bswap(unsigned short *dest, void *src, int count);\r
index 5092ddc..6047adb 100644 (file)
@@ -250,6 +250,8 @@ static int state_save(void *file)
   CHECKED_WRITE_BUFF(CHUNK_ZRAM,  PicoMem.zram);\r
   CHECKED_WRITE_BUFF(CHUNK_CRAM,  PicoMem.cram);\r
   CHECKED_WRITE_BUFF(CHUNK_MISC,  Pico.m);\r
+\r
+  PicoVideoSave();\r
   CHECKED_WRITE_BUFF(CHUNK_VIDEO, Pico.video);\r
 \r
   z80_pack(buff_z80);\r
@@ -433,7 +435,11 @@ static int state_load(void *file)
       case CHUNK_CRAM:    CHECKED_READ_BUFF(PicoMem.cram); break;\r
       case CHUNK_VSRAM:   CHECKED_READ_BUFF(PicoMem.vsram); break;\r
       case CHUNK_MISC:    CHECKED_READ_BUFF(Pico.m); break;\r
-      case CHUNK_VIDEO:   CHECKED_READ_BUFF(Pico.video); break;\r
+      case CHUNK_VIDEO:\r
+        CHECKED_READ_BUFF(Pico.video);\r
+        PicoVideoLoad();\r
+        break;\r
+\r
       case CHUNK_IOPORTS: CHECKED_READ_BUFF(PicoMem.ioports); break;\r
       case CHUNK_PSG:     CHECKED_READ2(28*4, sn76496_regs); break;\r
       case CHUNK_FM:\r
index 0a6a103..f64ac69 100644 (file)
@@ -14,7 +14,6 @@
 extern const unsigned char  hcounts_32[];\r
 extern const unsigned char  hcounts_40[];\r
 \r
-static unsigned hvlatch;        // latched hvcounter value\r
 static int blankline;           // display disabled for this line\r
 \r
 int (*PicoDmaHook)(unsigned int source, int len, unsigned short **base, unsigned int *mask) = NULL;\r
@@ -70,7 +69,7 @@ const unsigned char vdpcyc2sl_32[] = { // 68k cycles/4 since HINT to slot #
 14,14,14,14,14,14,14,14,15,16,16,16,16,16,16,16,\r
 };\r
 const unsigned char vdpsl2cyc_32[] = { // slot # to 68k cycles/4 since HINT\r
-  0,  9, 19, 30, 35, 41, 52, 58, 64, 75, 81, 87, 98,104,110,120,121,123,123\r
+  0,  9, 19, 30, 35, 41, 52, 58, 64, 75, 81, 87, 98,104,110,120,121,123\r
 };\r
 \r
 // VDP transfer slots in active display 40col mode. 1 slot is 488/210 = 2.3238\r
@@ -88,33 +87,37 @@ const unsigned char vdpcyc2sl_40[] = { // 68k cycles/4 since HINT to slot #
 16,16,16,16,16,16,16,16,17,18,18,18,18,18,18,18,\r
 };\r
 const unsigned char vdpsl2cyc_40[] = { // slot # to 68k cycles/4 since HINT\r
-  0, 13, 28, 33, 37, 47, 51, 56, 65, 70, 74, 84, 88, 93,102,107,112,120,121,123,123\r
+  0, 13, 28, 33, 37, 47, 51, 56, 65, 70, 74, 84, 88, 93,102,107,112,120,121,123\r
 };\r
 \r
 // NB code assumes fifo_* arrays have size 2^n\r
 // last transferred FIFO data, ...x = index  XXX currently only CPU\r
-static short fifo_data[4], fifo_dx;\r
+static short fifo_data[4], fifo_dx; // XXX must go into save?\r
+\r
 // queued FIFO transfers, ...x = index, ...l = queue length\r
 // each entry has 2 values: [n]>>2=#writes, [n]&3=flags:2=DMA fill 1=byte access\r
-static int fifo_queue[8], fifo_qx, fifo_ql;\r
+static int fifo_queue[8], fifo_qx, fifo_ql; // XXX must go into save?\r
+unsigned int fifo_total;        // total# of pending FIFO entries\r
 \r
-signed int fifo_cnt;            // pending slots for current queue entry\r
 unsigned short fifo_slot;       // last executed slot in current scanline\r
-unsigned int fifo_total;        // total# of pending FIFO entries\r
 \r
 // do the FIFO math\r
-static __inline int AdvanceFIFOEntry(int slots)\r
+static __inline int AdvanceFIFOEntry(struct PicoVideo *pv, int slots)\r
 {\r
   int l = slots, b = fifo_queue[fifo_qx&7] & 1;\r
 \r
-  if (l > fifo_cnt)\r
-    l = fifo_cnt;\r
-  fifo_total -= ((fifo_cnt & b) + l) >> b;\r
-  fifo_cnt -= l;\r
+  if (l > pv->fifo_cnt)\r
+    l = pv->fifo_cnt;\r
+  fifo_total -= ((pv->fifo_cnt & b) + l) >> b;\r
+  pv->fifo_cnt -= l;\r
 \r
-  if (fifo_cnt == 0) {\r
-    fifo_qx ++, fifo_ql --;\r
-    fifo_cnt= (fifo_queue[fifo_qx&7] >> 2) << (fifo_queue[fifo_qx&7] & 1);\r
+  if (pv->fifo_cnt == 0) {\r
+    if (fifo_ql)\r
+      fifo_qx ++, fifo_ql --;\r
+    if (fifo_ql)\r
+      pv->fifo_cnt= (fifo_queue[fifo_qx&7] >> 2) << (fifo_queue[fifo_qx&7] & 1);\r
+    else\r
+      fifo_total = 0;\r
   }\r
   return l;\r
 }\r
@@ -129,7 +132,7 @@ static __inline int GetFIFOSlot(struct PicoVideo *pv, int cycles)
   else         return (cycles * vdpcyc2sl_bl[h40] + cycles) >> 16;\r
 }\r
 \r
-static inline int GetFIFOCycles(struct PicoVideo *pv, int slot)\r
+static __inline int GetFIFOCycles(struct PicoVideo *pv, int slot)\r
 {\r
   int active = !(pv->status & SR_VB) && (pv->reg[1] & 0x40);\r
   int h40 = pv->reg[12] & 1;\r
@@ -146,13 +149,12 @@ void PicoVideoFIFOSync(int cycles)
   int slots, done;\r
 \r
   // calculate #slots since last executed slot\r
-  slots = GetFIFOSlot(pv, cycles);\r
-  slots -= fifo_slot;\r
+  slots = GetFIFOSlot(pv, cycles) - fifo_slot;\r
 \r
   // advance FIFO queue by #done slots\r
   done = slots;\r
-  while (done > 0 && fifo_ql) {\r
-    int l = AdvanceFIFOEntry(done);\r
+  while (done > 0 && pv->fifo_cnt) {\r
+    int l = AdvanceFIFOEntry(pv, done);\r
     fifo_slot += l;\r
     done -= l;\r
   }\r
@@ -181,7 +183,7 @@ int PicoVideoFIFODrain(int level, int cycles)
     int b = fifo_queue[fifo_qx&7] & 1;\r
     int cnt = (fifo_total-level) << b;\r
     int last = fifo_slot;\r
-    int slot = (fifo_cnt<cnt?fifo_cnt:cnt) + last; // target slot\r
+    int slot = (pv->fifo_cnt<cnt?pv->fifo_cnt:cnt) + last; // target slot\r
     unsigned ocyc = cycles;\r
 \r
     if (slot > maxsl) {\r
@@ -196,7 +198,7 @@ int PicoVideoFIFODrain(int level, int cycles)
     }\r
     burn += cycles - ocyc;\r
 \r
-    AdvanceFIFOEntry(slot - last);\r
+    AdvanceFIFOEntry(pv, slot - last);\r
   }\r
 \r
   // release CPU and terminate DMA if FIFO isn't blocking the bus anymore\r
@@ -249,7 +251,7 @@ int PicoVideoFIFOWrite(int count, int flags, unsigned sr_mask,unsigned sr_flags)
     // update FIFO state if it was empty\r
     if (fifo_total == 0 && count) {\r
       fifo_slot = GetFIFOSlot(pv, lc);\r
-      fifo_cnt = count << (flags&1);\r
+      pv->fifo_cnt = count << (flags&1);\r
     }\r
 \r
     // create xfer queue entry\r
@@ -263,8 +265,8 @@ int PicoVideoFIFOWrite(int count, int flags, unsigned sr_mask,unsigned sr_flags)
   if ((pv->status & (PVS_CPUWR|PVS_DMAFILL)) == PVS_CPUWR)\r
     burn = PicoVideoFIFODrain(4, lc);\r
   else if (fifo_queue[fifo_qx&7]&2) {\r
-    // if interrupting a DMA fill terminate it\r
-    AdvanceFIFOEntry(fifo_cnt);\r
+    // if interrupting a DMA fill terminate it XXX wrong, changes fill data\r
+    AdvanceFIFOEntry(pv, pv->fifo_cnt);\r
     pv->status &= ~PVS_DMAFILL;\r
   }\r
 \r
@@ -699,9 +701,9 @@ PICO_INTERNAL_ASM void PicoVideoWrite(unsigned int a,unsigned short d)
     // try avoiding the sync..\r
     if (Pico.m.scanline < (pvid->reg[1]&0x08 ? 240 : 224) && (pvid->reg[1]&0x40) &&\r
         !(!pvid->pending &&\r
-          ((pvid->command & 0xc00000f0) == 0x40000010 && PicoMem.vsram[pvid->addr>>1] == d))\r
+          ((pvid->command & 0xc00000f0) == 0x40000010 && PicoMem.vsram[pvid->addr>>1] == (d & 0x7ff)))\r
        )\r
-      DrawSync(0);\r
+      DrawSync(SekCyclesDone() - Pico.t.m68c_line_start <= 488-440);\r
 \r
     if (pvid->pending) {\r
       CommandChange();\r
@@ -736,7 +738,7 @@ PICO_INTERNAL_ASM void PicoVideoWrite(unsigned int a,unsigned short d)
       CommandChange();\r
       // Check for dma:\r
       if (d & 0x80) {\r
-        DrawSync(0);\r
+        DrawSync(SekCyclesDone() - Pico.t.m68c_line_start <= 488-390);\r
         CommandDma();\r
       }\r
     }\r
@@ -747,7 +749,6 @@ PICO_INTERNAL_ASM void PicoVideoWrite(unsigned int a,unsigned short d)
         // Register write:\r
         int num=(d>>8)&0x1f;\r
         int dold=pvid->reg[num];\r
-        int skip=0;\r
         pvid->type=0; // register writes clear command (else no Sega logo in Golden Axe II)\r
         if (num > 0x0a && !(pvid->reg[1]&4)) {\r
           elprintf(EL_ANOMALY, "%02x written to reg %02x in SMS mode @ %06x", d, num, SekPc);\r
@@ -755,16 +756,14 @@ PICO_INTERNAL_ASM void PicoVideoWrite(unsigned int a,unsigned short d)
         }\r
 \r
         if (num == 0 && !(pvid->reg[0]&2) && (d&2))\r
-          hvlatch = PicoVideoRead(0x08);\r
+          pvid->hv_latch = PicoVideoRead(0x08);\r
         if (num == 1 && ((pvid->reg[1]^d)&0x40)) {\r
           PicoVideoFIFOMode(d & 0x40);\r
           // handle line blanking before line rendering\r
-          if (SekCyclesDone() - Pico.t.m68c_line_start <= 488-390) {\r
-            skip = 1;\r
+          if (SekCyclesDone() - Pico.t.m68c_line_start <= 488-390)\r
             blankline = d&0x40 ? -1 : Pico.m.scanline;\r
-          }\r
         }\r
-        DrawSync(skip);\r
+        DrawSync(SekCyclesDone() - Pico.t.m68c_line_start <= 488-390);\r
         pvid->reg[num]=(unsigned char)d;\r
         switch (num)\r
         {\r
@@ -904,7 +903,7 @@ PICO_INTERNAL_ASM unsigned int PicoVideoRead(unsigned int a)
 \r
     d = (SekCyclesDone() - Pico.t.m68c_line_start) & 0x1ff; // FIXME\r
     if (Pico.video.reg[0]&2)\r
-         d = hvlatch;\r
+         d = Pico.video.hv_latch;\r
     else if (Pico.video.reg[12]&1)\r
          d = hcounts_40[d] | (Pico.video.v_counter << 8);\r
     else d = hcounts_32[d] | (Pico.video.v_counter << 8);\r
@@ -970,4 +969,33 @@ unsigned char PicoVideoRead8HV_L(void)
   return d;\r
 }\r
 \r
+void PicoVideoSave(void)\r
+{\r
+  struct PicoVideo *pv = &Pico.video;\r
+  int l, x;\r
+\r
+  // account for all outstanding xfers XXX kludge, entry attr's not saved\r
+  for (l = fifo_ql, x = fifo_qx + l-1; l > 1; l--, x--)\r
+    pv->fifo_cnt += (fifo_queue[x&7] >> 2) << (fifo_queue[x&7] & 1);\r
+}\r
+\r
+void PicoVideoLoad(void)\r
+{\r
+  struct PicoVideo *pv = &Pico.video;\r
+  int l;\r
+\r
+  // convert former dma_xfers (why was this in PicoMisc anyway?)\r
+  if (Pico.m.dma_xfers) {\r
+    pv->fifo_cnt = Pico.m.dma_xfers * (pv->type == 1 ? 2 : 1);\r
+    fifo_total = Pico.m.dma_xfers;\r
+    Pico.m.dma_xfers = 0;\r
+  }\r
+\r
+  // rebuild SAT cache XXX wrong since cache and memory can differ\r
+  for (l = 0; l < 80; l++) {\r
+    *((u16 *)VdpSATCache + 2*l  ) = PicoMem.vram[(sat>>1) + l*4    ];\r
+    *((u16 *)VdpSATCache + 2*l+1) = PicoMem.vram[(sat>>1) + l*4 + 1];\r
+  }\r
+}\r
+\r
 // vim:shiftwidth=2:ts=2:expandtab\r