core vdp, some cleanup
authorkub <derkub@gmail.com>
Thu, 27 Apr 2023 19:19:56 +0000 (21:19 +0200)
committerkub <derkub@gmail.com>
Thu, 27 Apr 2023 19:19:56 +0000 (21:19 +0200)
pico/cd/gfx_dma.c
pico/draw.c
pico/draw_arm.S
pico/pico.h
pico/pico_int.h
pico/videoport.c
platform/common/emu.c
platform/libpicofe

index b109610..360afed 100644 (file)
@@ -33,7 +33,6 @@ PICO_INTERNAL void DmaSlowCell(u32 source, u32 a, int len, unsigned char inc)
         // AutoIncrement
         a=(u16)(a+inc);
       }
-      Pico.est.rendstatus |= PDRAW_SPRITES_MOVED;
       break;
 
     case 3: // cram
index b9d23ac..31a6d03 100644 (file)
@@ -1421,7 +1421,7 @@ static NOINLINE void ParseSprites(int max_lines, int limit)
 \r
   // SAT scanning is one line ahead, but don't overshoot. Technically, SAT\r
   // parsing for line 0 is on the last line of the previous frame.\r
-  int first_line = Pico.est.DrawScanline + !!Pico.est.DrawScanline;\r
+  int first_line = est->DrawScanline + !!est->DrawScanline;\r
   if (max_lines > rendlines-1)\r
     max_lines = rendlines-1;\r
 \r
@@ -1584,12 +1584,11 @@ static void DrawAllSprites(unsigned char *sprited, int prio, int sh,
 \r
 // --------------------------------------------\r
 \r
-void BackFill(int reg7, int sh, struct PicoEState *est)\r
+void BackFill(int bgc, int sh, struct PicoEState *est)\r
 {\r
-  unsigned int back;\r
+  u32 back = bgc;\r
 \r
   // Start with a blank scanline (background colour):\r
-  back=reg7&0x3f;\r
   back|=sh<<7; // shadow\r
   back|=back<<8;\r
   back|=back<<16;\r
@@ -1689,11 +1688,11 @@ void FinalizeLine555(int sh, int line, struct PicoEState *est)
   PicoDrawUpdateHighPal();\r
 \r
   len = 256;\r
-  if ((PicoIn.AHW & PAHW_GG) && (Pico.m.hardware & PMS_HW_LCD))\r
-    len = 160;\r
-  else if (!(PicoIn.AHW & PAHW_SMS) && (Pico.video.reg[12]&1))\r
+  if (!(PicoIn.AHW & PAHW_8BIT) && (Pico.video.reg[12]&1))\r
     len = 320;\r
-  if ((PicoIn.AHW & PAHW_SMS) && (Pico.video.reg[0] & 0x20) && len == 256)\r
+  else if ((PicoIn.AHW & PAHW_GG) && (Pico.m.hardware & PMS_HW_LCD))\r
+    len = 160;\r
+  else if ((PicoIn.AHW & PAHW_SMS) && (Pico.video.reg[0] & 0x20))\r
     len -= 8, ps += 8;\r
 \r
   if ((*est->PicoOpt & POPT_EN_SOFTSCALE) && len < 320) {\r
@@ -1741,9 +1740,9 @@ void FinalizeLine8bit(int sh, int line, struct PicoEState *est)
   // a hack for mid-frame palette changes\r
   if (Pico.m.dirtyPal == 1)\r
   {\r
-    // store a maximum of 2 additional palettes in SonicPal\r
-    if (est->SonicPalCount < 2 &&\r
-        (!(est->rendstatus & PDRAW_SONIC_MODE) || (line - dirty_line > 4))) {\r
+    // store a maximum of 3 additional palettes in SonicPal\r
+    if (est->SonicPalCount < 3 &&\r
+        (!(est->rendstatus & PDRAW_SONIC_MODE) || (line - dirty_line >= 4))) {\r
       est->SonicPalCount ++;\r
       dirty_line = line;\r
       est->rendstatus |= PDRAW_SONIC_MODE;\r
@@ -1753,11 +1752,11 @@ void FinalizeLine8bit(int sh, int line, struct PicoEState *est)
   }\r
 \r
   len = 256;\r
-  if ((PicoIn.AHW & PAHW_GG) && (Pico.m.hardware & PMS_HW_LCD))\r
-    len = 160;\r
-  else if (!(PicoIn.AHW & PAHW_SMS) && (Pico.video.reg[12]&1))\r
+  if (!(PicoIn.AHW & PAHW_8BIT) && (Pico.video.reg[12]&1))\r
     len = 320;\r
-  if ((PicoIn.AHW & PAHW_SMS) && (Pico.video.reg[0] & 0x20) && len == 256)\r
+  else if ((PicoIn.AHW & PAHW_GG) && (Pico.m.hardware & PMS_HW_LCD))\r
+    len = 160;\r
+  else if ((PicoIn.AHW & PAHW_SMS) && (Pico.video.reg[0] & 0x20))\r
     len -= 8, ps += 8;\r
 \r
   if (DrawLineDestIncrement == 0)\r
@@ -1897,7 +1896,7 @@ static int DrawDisplay(int sh)
     for (a = 0, c = HighCacheA; *c; c+=2, a++);\r
     for (b = 0, c = HighCacheB; *c; c+=2, b++);\r
     printf("%i:%03i: a=%i, b=%i\n", Pico.m.frame_count,\r
-           Pico.est.DrawScanline, a, b);\r
+           est->DrawScanline, a, b);\r
   }\r
 #endif\r
 \r
@@ -1907,57 +1906,59 @@ static int DrawDisplay(int sh)
 // MUST be called every frame\r
 PICO_INTERNAL void PicoFrameStart(void)\r
 {\r
+  struct PicoEState *est = &Pico.est;\r
   int loffs = 8, lines = 224, coffs = 0, columns = 320;\r
-  int sprep = Pico.est.rendstatus & (PDRAW_SPRITES_MOVED|PDRAW_DIRTY_SPRITES);\r
-  int skipped = Pico.est.rendstatus & PDRAW_SKIP_FRAME;\r
+  int sprep = est->rendstatus & PDRAW_DIRTY_SPRITES;\r
+  int skipped = est->rendstatus & PDRAW_SKIP_FRAME;\r
 \r
   // prepare to do this frame\r
-  Pico.est.rendstatus = 0;\r
+  est->rendstatus = 0;\r
   if ((Pico.video.reg[12] & 6) == 6)\r
-    Pico.est.rendstatus |= PDRAW_INTERLACE; // interlace mode\r
+    est->rendstatus |= PDRAW_INTERLACE; // interlace mode\r
   if (!(Pico.video.reg[12] & 1)) {\r
-    Pico.est.rendstatus |= PDRAW_32_COLS;\r
+    est->rendstatus |= PDRAW_32_COLS;\r
     if (!(PicoIn.opt & POPT_EN_SOFTSCALE)) {\r
       columns = 256;\r
       coffs = 32;\r
     }\r
   }\r
   if (Pico.video.reg[1] & 8) {\r
-    Pico.est.rendstatus |= PDRAW_30_ROWS;\r
+    est->rendstatus |= PDRAW_30_ROWS;\r
     lines = 240;\r
     loffs = 0;\r
   }\r
   if (PicoIn.opt & POPT_DIS_32C_BORDER)\r
     coffs = 0;\r
 \r
-  if (Pico.est.rendstatus != rendstatus_old || lines != rendlines) {\r
+  if (est->rendstatus != rendstatus_old || lines != rendlines) {\r
     rendlines = lines;\r
     // mode_change() might reset rendstatus_old by calling SetColorFormat\r
     emu_video_mode_change(loffs, lines, coffs, columns);\r
-    rendstatus_old = Pico.est.rendstatus;\r
+    rendstatus_old = est->rendstatus & (PDRAW_INTERLACE|PDRAW_32_COLS|PDRAW_30_ROWS);\r
   }\r
   if (PicoIn.skipFrame) // preserve this until something is rendered at last\r
-    Pico.est.rendstatus |= PDRAW_SKIP_FRAME;\r
+    est->rendstatus |= PDRAW_SKIP_FRAME;\r
   if (sprep | skipped)\r
-    Pico.est.rendstatus |= PDRAW_PARSE_SPRITES;\r
+    est->rendstatus |= PDRAW_PARSE_SPRITES;\r
   if (PicoIn.AHW & PAHW_32X)\r
-    Pico.est.rendstatus |= PDRAW_32X_SCALE;\r
+    est->rendstatus |= PDRAW_32X_SCALE;\r
 \r
-  Pico.est.HighCol = HighColBase + loffs * HighColIncrement;\r
-  Pico.est.DrawLineDest = (char *)DrawLineDestBase + loffs * DrawLineDestIncrement;\r
-  Pico.est.DrawScanline = 0;\r
+  est->HighCol = HighColBase + loffs * HighColIncrement;\r
+  est->DrawLineDest = (char *)DrawLineDestBase + loffs * DrawLineDestIncrement;\r
+  est->DrawScanline = 0;\r
   skip_next_line = 0;\r
 \r
   if (FinalizeLine == FinalizeLine8bit) {\r
     // make a backup of the current palette in case Sonic mode is detected later\r
-    Pico.m.dirtyPal = (Pico.m.dirtyPal || Pico.est.SonicPalCount ? 2 : 0);\r
-    blockcpy(Pico.est.SonicPal, PicoMem.cram, 0x40*2);\r
+    Pico.m.dirtyPal = (Pico.m.dirtyPal || est->SonicPalCount ? 2 : 0);\r
+    blockcpy(est->SonicPal, PicoMem.cram, 0x40*2);\r
   }\r
-  Pico.est.SonicPalCount = 0;\r
+  est->SonicPalCount = 0;\r
 }\r
 \r
 static void DrawBlankedLine(int line, int offs, int sh, int bgc)\r
 {\r
+  struct PicoEState *est = &Pico.est;\r
   int skip = skip_next_line;\r
 \r
   if (PicoScanBegin != NULL && skip == 0)\r
@@ -1968,23 +1969,24 @@ static void DrawBlankedLine(int line, int offs, int sh, int bgc)
     return;\r
   }\r
 \r
-  BackFill(bgc, sh, &Pico.est);\r
+  BackFill(bgc, sh, est);\r
 \r
   if (FinalizeLine != NULL)\r
-    FinalizeLine(sh, line, &Pico.est);\r
+    FinalizeLine(sh, line, est);\r
 \r
   if (PicoScanEnd != NULL)\r
     skip_next_line = PicoScanEnd(line + offs);\r
 \r
-  Pico.est.HighCol += HighColIncrement;\r
-  Pico.est.DrawLineDest = (char *)Pico.est.DrawLineDest + DrawLineDestIncrement;\r
+  est->HighCol += HighColIncrement;\r
+  est->DrawLineDest = (char *)est->DrawLineDest + DrawLineDestIncrement;\r
 }\r
 \r
 static void PicoLine(int line, int offs, int sh, int bgc)\r
 {\r
+  struct PicoEState *est = &Pico.est;\r
   int skip = skip_next_line;\r
 \r
-  Pico.est.DrawScanline = line;\r
+  est->DrawScanline = line;\r
   if (PicoScanBegin != NULL && skip == 0)\r
     skip = PicoScanBegin(line + offs);\r
 \r
@@ -1997,18 +1999,18 @@ static void PicoLine(int line, int offs, int sh, int bgc)
     bgc = 0x3f;\r
 \r
   // Draw screen:\r
-  BackFill(bgc, sh, &Pico.est);\r
+  BackFill(bgc, sh, est);\r
   if (Pico.video.reg[1]&0x40)\r
     DrawDisplay(sh);\r
 \r
   if (FinalizeLine != NULL)\r
-    FinalizeLine(sh, line, &Pico.est);\r
+    FinalizeLine(sh, line, est);\r
 \r
   if (PicoScanEnd != NULL)\r
     skip_next_line = PicoScanEnd(line + offs);\r
 \r
-  Pico.est.HighCol += HighColIncrement;\r
-  Pico.est.DrawLineDest = (char *)Pico.est.DrawLineDest + DrawLineDestIncrement;\r
+  est->HighCol += HighColIncrement;\r
+  est->DrawLineDest = (char *)est->DrawLineDest + DrawLineDestIncrement;\r
 }\r
 \r
 void PicoDrawSync(int to, int blank_last_line, int limit_sprites)\r
@@ -2016,7 +2018,7 @@ void PicoDrawSync(int to, int blank_last_line, int limit_sprites)
   struct PicoEState *est = &Pico.est;\r
   int line, offs = 0;\r
   int sh = (Pico.video.reg[0xC] & 8) >> 3; // shadow/hilight?\r
-  int bgc = Pico.video.reg[7];\r
+  int bgc = Pico.video.reg[7] & 0x3f;\r
 \r
   pprof_start(draw);\r
 \r
@@ -2025,8 +2027,8 @@ void PicoDrawSync(int to, int blank_last_line, int limit_sprites)
     if (to > 223)\r
       to = 223;\r
   }\r
-  if (est->DrawScanline <= to && (est->rendstatus &\r
-                (PDRAW_SPRITES_MOVED|PDRAW_DIRTY_SPRITES|PDRAW_PARSE_SPRITES)))\r
+  if (est->DrawScanline <= to &&\r
+                (est->rendstatus & (PDRAW_DIRTY_SPRITES|PDRAW_PARSE_SPRITES)))\r
     ParseSprites(to + 1, limit_sprites);\r
 \r
   for (line = est->DrawScanline; line < to; line++)\r
@@ -2045,12 +2047,13 @@ void PicoDrawSync(int to, int blank_last_line, int limit_sprites)
   pprof_end(draw);\r
 }\r
 \r
-void PicoDrawRefreshSprites()\r
+void PicoDrawRefreshSprites(void)\r
 {\r
-  unsigned char *sprited = &HighLnSpr[Pico.est.DrawScanline][0];\r
+  struct PicoEState *est = &Pico.est;\r
+  unsigned char *sprited = &HighLnSpr[est->DrawScanline][0];\r
   int i;\r
 \r
-  if (Pico.est.DrawScanline == 0 || Pico.est.DrawScanline >= rendlines) return;\r
+  if (est->DrawScanline == 0 || est->DrawScanline >= rendlines) return;\r
 \r
   // compute sprite row. The VDP does this by subtracting the sprite y pos from\r
   // the current line and treating the lower 5 bits as the row number. Y pos\r
@@ -2062,7 +2065,7 @@ void PicoDrawRefreshSprites()
     int sy = (CPU_LE2(VdpSATCache[2*link]) & 0x1ff) - 0x80;\r
     if (sy != (s16)sp[0]) {\r
       // Y info in SAT cache has really changed\r
-      sy = Pico.est.DrawScanline - ((Pico.est.DrawScanline - sy) & 0x1f);\r
+      sy = est->DrawScanline - ((est->DrawScanline - sy) & 0x1f);\r
       sp[0] = (sp[0] & 0xffff0000) | (u16)sy;\r
     }\r
   }\r
@@ -2089,8 +2092,8 @@ void PicoDrawUpdateHighPal(void)
       blockcpy(est->HighPal+0x40, est->HighPal, 0x40*2);\r
       blockcpy(est->HighPal+0x80, est->HighPal, 0x80*2);\r
     }\r
-    Pico.est.HighPal[0xe0] = 0x0000; // black and white, reserved for OSD\r
-    Pico.est.HighPal[0xf0] = 0xffff;\r
+    est->HighPal[0xe0] = 0x0000; // black and white, reserved for OSD\r
+    est->HighPal[0xf0] = 0xffff;\r
   }\r
 }\r
 \r
index 63687b8..a6c524b 100644 (file)
 \r
 .extern DrawStripInterlace\r
 \r
-.equ PDRAW_SPRITES_MOVED, (1<<0)\r
 .equ PDRAW_WND_DIFF_PRIO, (1<<1)\r
-.equ PDRAW_PARSE_SPRITES, (1<<2)\r
-.equ PDRAW_DIRTY_SPRITES, (1<<4)\r
 .equ PDRAW_PLANE_HI_PRIO, (1<<6)\r
 .equ PDRAW_SHHI_DONE,     (1<<7)\r
 .equ PDRAW_32X_SCALE,     (1<<12)\r
@@ -800,11 +797,7 @@ DrawLayer:
 BackFill:\r
     stmfd   sp!, {r4-r9,lr}\r
 \r
-    mov     r0, r0, lsl #26\r
     ldr     lr, [r2, #OFS_EST_HighCol]\r
-    mov     r0, r0, lsr #26\r
-    add     lr, lr, #8\r
-\r
     orr     r0, r0, r1, lsl #7\r
     orr     r0, r0, r0, lsl #8\r
     orr     r0, r0, r0, lsl #16\r
@@ -818,6 +811,7 @@ BackFill:
     mov     r7, r0\r
 \r
     @ go go go!\r
+    add     lr, lr, #8\r
     stmia   lr!, {r0-r7} @ 10*8*4\r
     stmia   lr!, {r0-r7}\r
     stmia   lr!, {r0-r7}\r
index a15a01a..cd525b1 100644 (file)
@@ -82,10 +82,12 @@ extern void *p32x_bios_g, *p32x_bios_m, *p32x_bios_s;
 #define PAHW_32X    (1<<1)\r
 #define PAHW_SVP    (1<<2)\r
 #define PAHW_PICO   (1<<3)\r
+\r
 #define PAHW_SMS    (1<<4)\r
 #define PAHW_GG     (1<<5)\r
 #define PAHW_SG     (1<<6)\r
 #define PAHW_SC     (1<<7)\r
+#define PAHW_8BIT   (PAHW_SMS|PAHW_GG|PAHW_SG|PAHW_SC)\r
 \r
 #define PHWS_AUTO   0\r
 #define PHWS_GG     1\r
@@ -221,7 +223,6 @@ void vidConvCpyRGB565(void *to, void *from, int pixels);
 #endif\r
 void PicoDoHighPal555(int sh, int line, struct PicoEState *est);\r
 // internals, NB must keep in sync with ASM draw functions\r
-#define PDRAW_SPRITES_MOVED (1<<0) // SAT address modified\r
 #define PDRAW_WND_DIFF_PRIO (1<<1) // not all window tiles use same priority\r
 #define PDRAW_PARSE_SPRITES (1<<2) // SAT needs parsing\r
 #define PDRAW_INTERLACE     (1<<3)\r
index 57b6c54..fa6d12d 100644 (file)
@@ -694,6 +694,7 @@ int CM_compareRun(int cyc, int is_sub);
 // draw.c\r
 void PicoDrawInit(void);\r
 PICO_INTERNAL void PicoFrameStart(void);\r
+void PicoDrawRefreshSprites(void);\r
 void PicoDrawSync(int to, int blank_last_line, int limit_sprites);\r
 void BackFill(int reg7, int sh, struct PicoEState *est);\r
 void FinalizeLine555(int sh, int line, struct PicoEState *est);\r
index a444cf3..971a85d 100644 (file)
@@ -191,6 +191,7 @@ static struct VdpFIFO { // XXX this must go into save file!
 \r
   const unsigned short *fifo_cyc2sl;\r
   const unsigned short *fifo_sl2cyc;\r
+  const unsigned char  *fifo_hcounts;\r
 } VdpFIFO;\r
 \r
 enum { FQ_BYTE = 1, FQ_BGDMA = 2, FQ_FGDMA = 4 }; // queue flags, NB: BYTE = 1!\r
@@ -198,8 +199,8 @@ enum { FQ_BYTE = 1, FQ_BGDMA = 2, FQ_FGDMA = 4 }; // queue flags, NB: BYTE = 1!
 \r
 // NB should limit cyc2sl to table size in case 68k overdraws its aim. That can\r
 // happen if the last op is a blocking acess to VDP, or for exceptions (e.g.irq)\r
-#define        Cyc2Sl(vf,lc)   (vf->fifo_cyc2sl[(lc)/clkdiv])\r
-#define Sl2Cyc(vf,sl)   (vf->fifo_sl2cyc[sl]*clkdiv)\r
+#define Cyc2Sl(vf,lc)   ((vf)->fifo_cyc2sl[(lc)/clkdiv])\r
+#define Sl2Cyc(vf,sl)   ((vf)->fifo_sl2cyc[sl]*clkdiv)\r
 \r
 // do the FIFO math\r
 static int AdvanceFIFOEntry(struct VdpFIFO *vf, struct PicoVideo *pv, int slots)\r
@@ -389,6 +390,7 @@ int PicoVideoFIFOHint(void)
 \r
   // reset slot to start of scanline\r
   vf->fifo_slot = 0;\r
+  // only need to refresh sprite position if we are synced\r
   if (Pico.est.DrawScanline == Pico.m.scanline)\r
     PicoDrawRefreshSprites();\r
  \r
@@ -408,6 +410,8 @@ void PicoVideoFIFOMode(int active, int h40)
       { {vdpcyc2sl_32_bl, vdpcyc2sl_40_bl},{vdpcyc2sl_32_ac, vdpcyc2sl_40_ac} };\r
   static const unsigned short *vdpsl2cyc[2][2] =\r
       { {vdpsl2cyc_32_bl, vdpsl2cyc_40_bl},{vdpsl2cyc_32_ac, vdpsl2cyc_40_ac} };\r
+  static const unsigned char *vdphcounts[2] =\r
+      { hcounts_32, hcounts_40 };\r
 \r
   struct VdpFIFO *vf = &VdpFIFO;\r
   struct PicoVideo *pv = &Pico.video;\r
@@ -419,6 +423,7 @@ void PicoVideoFIFOMode(int active, int h40)
 \r
   vf->fifo_cyc2sl = vdpcyc2sl[active][h40];\r
   vf->fifo_sl2cyc = vdpsl2cyc[active][h40];\r
+  vf->fifo_hcounts = vdphcounts[h40];\r
   // recalculate FIFO slot for new mode\r
   vf->fifo_slot = Cyc2Sl(vf, lc);\r
   vf->fifo_maxslot = Cyc2Sl(vf, 488);\r
@@ -508,7 +513,7 @@ static int GetDmaLength(void)
 static void DmaSlow(int len, u32 source)\r
 {\r
   u32 inc = Pico.video.reg[0xf];\r
-  u32 a = Pico.video.addr | (Pico.video.addr_u << 16);\r
+  u32 a = Pico.video.addr | (Pico.video.addr_u << 16), e;\r
   u16 *r, *base = NULL;\r
   u32 mask = 0x1ffff;\r
 \r
@@ -568,10 +573,11 @@ static void DmaSlow(int len, u32 source)
   switch (Pico.video.type)\r
   {\r
     case 1: // vram\r
+      e = a + len*2-1;\r
       r = PicoMem.vram;\r
-      if (inc == 2 && !(a & 1) && (a & ~0xffff) == ((a + len*2-1) & ~0xffff) &&\r
-          ((a >= SATaddr+0x280) | ((a + len*2-1) < SATaddr)) &&\r
-          (source & ~mask) == ((source + len-1) & ~mask))\r
+      if (inc == 2 && !(a & 1) && !((a ^ e) >> 16) &&\r
+          ((a >= SATaddr + 0x280) | (e < SATaddr)) &&\r
+          !((source ^ (source + len-1)) & ~mask))\r
       {\r
         // most used DMA mode\r
         memcpy((char *)r + a, base + (source & mask), len * 2);\r
@@ -659,7 +665,7 @@ static void DmaCopy(int len)
 \r
 static NOINLINE void DmaFill(int data)\r
 {\r
-  u32 a = Pico.video.addr | (Pico.video.addr_u << 16);\r
+  u32 a = Pico.video.addr | (Pico.video.addr_u << 16), e;\r
   u8 *vr = (u8 *)PicoMem.vram;\r
   u8 high = (u8)(data >> 8);\r
   u8 inc = Pico.video.reg[0xf];\r
@@ -675,8 +681,9 @@ static NOINLINE void DmaFill(int data)
   switch (Pico.video.type)\r
   {\r
     case 1: // vram\r
-      if (inc == 1 && (a & ~0xffff) == ((a + len-1) & ~0xffff) &&\r
-          ((a >= SATaddr+0x280) | ((a + len-1) < SATaddr)))\r
+      e = a + len-1;\r
+      if (inc == 1 && !((a ^ e) >> 16) &&\r
+          ((a >= SATaddr + 0x280) | (e < SATaddr)))\r
       {\r
         // most used DMA mode\r
         memset(vr + (u16)a, high, len);\r
@@ -798,7 +805,8 @@ static NOINLINE void CommandChange(struct PicoVideo *pvid)
  \r
 static inline int InHblank(int offs)\r
 {\r
-  return SekCyclesDone() - Pico.t.m68c_line_start <= 488-offs;\r
+  // check if in left border (14 pixels) or HBLANK (86 pixels), 116 68k cycles\r
+  return SekCyclesDone() - Pico.t.m68c_line_start <= offs;\r
 }\r
 \r
 static void DrawSync(int skip)\r
@@ -835,12 +843,13 @@ PICO_INTERNAL_ASM void PicoVideoWrite(u32 a,unsigned short d)
       pvid->pending=0;\r
     }\r
 \r
-    // try avoiding the sync. can't easily do this for VRAM writes since they\r
-    // might update the SAT cache\r
-    if (Pico.m.scanline < (pvid->reg[1]&0x08 ? 240 : 224) && (pvid->reg[1]&0x40) &&\r
+    // try avoiding the sync if the data doesn't change.\r
+    // Writes to the SAT in VRAM are special since they update the SAT cache.\r
+    if ((pvid->reg[1]&0x40) &&\r
+        !(pvid->type == 1 && !(pvid->addr&1) && ((pvid->addr^SATaddr)&SATmask) && PicoMem.vram[pvid->addr>>1] == d) &&\r
         !(pvid->type == 3 && PicoMem.cram[(pvid->addr>>1) & 0x3f] == (d & 0xeee)) &&\r
         !(pvid->type == 5 && PicoMem.vsram[(pvid->addr>>1) & 0x3f] == (d & 0x7ff)))\r
-      DrawSync(InHblank(440)); // experimentally, Overdrive 2\r
+      DrawSync(InHblank(48)); // experimentally, Overdrive 2\r
 \r
     if (!(PicoIn.opt&POPT_DIS_VDP_FIFO))\r
     {\r
@@ -872,7 +881,7 @@ PICO_INTERNAL_ASM void PicoVideoWrite(u32 a,unsigned short d)
       CommandChange(pvid);\r
       // Check for dma:\r
       if (d & 0x80) {\r
-        DrawSync(InHblank(390));\r
+        DrawSync(InHblank(93));\r
         CommandDma();\r
       }\r
     }\r
@@ -889,12 +898,13 @@ PICO_INTERNAL_ASM void PicoVideoWrite(u32 a,unsigned short d)
           return;\r
         }\r
 \r
+        d &= 0xff;\r
         if (num == 0 && !(pvid->reg[0]&2) && (d&2))\r
           pvid->hv_latch = PicoVideoRead(0x08);\r
         if (num == 1 && ((pvid->reg[1]^d)&0x40)) {\r
           PicoVideoFIFOMode(d & 0x40, pvid->reg[12]&1);\r
           // handle line blanking before line rendering\r
-          if (InHblank(390)) {\r
+          if (InHblank(93)) {\r
             // sprite rendering is limited if display is disabled and reenabled\r
             // in HBLANK of the same scanline (Overdrive)\r
             limitsprites = (d&0x40) && blankline == Pico.m.scanline ? Pico.m.scanline : -1;\r
@@ -903,10 +913,10 @@ PICO_INTERNAL_ASM void PicoVideoWrite(u32 a,unsigned short d)
         }\r
         if (num == 12 && ((pvid->reg[12]^d)&0x01))\r
           PicoVideoFIFOMode(pvid->reg[1]&0x40, d & 1);\r
-        if (num <= 18) // no sync needed for DMA setup registers\r
-          DrawSync(InHblank(390));\r
-        d &= 0xff;\r
-        pvid->reg[num]=(unsigned char)d;\r
+        if (num <= 18 && pvid->reg[num] != d) // no sync for DMA setup\r
+          DrawSync(InHblank(93)); // Toy Story\r
+        pvid->reg[num]=d;\r
+\r
         switch (num)\r
         {\r
           case 0x00:\r
@@ -922,7 +932,7 @@ PICO_INTERNAL_ASM void PicoVideoWrite(u32 a,unsigned short d)
             goto update_irq;\r
           case 0x05:\r
           case 0x06:\r
-            if (d^dold) Pico.est.rendstatus |= PDRAW_SPRITES_MOVED;\r
+            if (d^dold) Pico.est.rendstatus |= PDRAW_DIRTY_SPRITES;\r
             break;\r
           case 0x0c:\r
             // renderers should update their palettes if sh/hi mode is changed\r
@@ -1039,9 +1049,7 @@ PICO_INTERNAL_ASM u32 PicoVideoRead(u32 a)
     c = SekCyclesDone() - Pico.t.m68c_line_start;\r
     if (Pico.video.reg[0]&2)\r
          d = Pico.video.hv_latch;\r
-    else if (Pico.video.reg[12]&1)\r
-         d = hcounts_40[c/clkdiv] | (Pico.video.v_counter << 8);\r
-    else d = hcounts_32[c/clkdiv] | (Pico.video.v_counter << 8);\r
+    else d = VdpFIFO.fifo_hcounts[c/clkdiv] | (Pico.video.v_counter << 8);\r
 \r
     elprintf(EL_HVCNT, "hv: %02x %02x [%u] @ %06x", d, Pico.video.v_counter, SekCyclesDone(), SekPc);\r
     return d;\r
@@ -1101,9 +1109,7 @@ unsigned char PicoVideoRead8HV_L(int is_from_z80)
   u32 d = SekCyclesDone() - Pico.t.m68c_line_start;\r
   if (Pico.video.reg[0]&2)\r
        d = Pico.video.hv_latch;\r
-  else if (Pico.video.reg[12]&1)\r
-       d = hcounts_40[d/clkdiv];\r
-  else d = hcounts_32[d/clkdiv];\r
+  else d = VdpFIFO.fifo_hcounts[d/clkdiv];\r
   elprintf(EL_HVCNT, "hcounter: %02x [%u] @ %06x", d, SekCyclesDone(), SekPc);\r
   return d;\r
 }\r
@@ -1125,7 +1131,7 @@ void PicoVideoCacheSAT(int load)
     ((u16 *)VdpSATCache)[l*2 + 1] = PicoMem.vram[(addr>>1) + 1];\r
   }\r
 \r
-  Pico.est.rendstatus |= PDRAW_SPRITES_MOVED;\r
+  Pico.est.rendstatus |= PDRAW_DIRTY_SPRITES;\r
 }\r
 \r
 void PicoVideoSave(void)\r
index 281fb0f..d75d6e4 100644 (file)
@@ -1251,7 +1251,6 @@ void emu_cmn_forced_frame(int no_scale, int do_emu, void *buf)
        PicoDrawSetOutFormat(PDF_RGB555, 1);\r
        PicoDrawSetOutBuf(buf, g_screen_ppitch * 2);\r
        Pico.m.dirtyPal = 1;\r
-       Pico.est.rendstatus |= PDRAW_DIRTY_SPRITES;\r
        if (do_emu)\r
                PicoFrame();\r
        else\r
index 1889fe2..7b58e15 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 1889fe241c1c6059f8955a331dd07f08a47cd0b4
+Subproject commit 7b58e15633b54621f9508cb673da61a6b0844955