core, improve bg color DMA handling (and some vdp cleanup)
authorkub <derkub@gmail.com>
Sun, 28 Jan 2024 21:34:17 +0000 (22:34 +0100)
committerkub <derkub@gmail.com>
Sun, 28 Jan 2024 21:34:17 +0000 (22:34 +0100)
pico/draw.c
pico/draw_arm.S
pico/videoport.c

index 3584b6a..d47240c 100644 (file)
@@ -1636,7 +1636,7 @@ void BgcDMA(struct PicoEState *est)
   BgcDMAsrc += xl; // HSYNC DMA\r
   BgcDMAoffs = 0;\r
 \r
-  t = est->HighPal[Pico.video.reg[7] & 0x3f];\r
+  t = PXCONV(PicoMem.cram[Pico.video.reg[7] & 0x3f]);\r
   while (i < len) q[i++] = t; // fill partial line with BG\r
 \r
   if (upscale) {\r
@@ -1737,6 +1737,9 @@ void FinalizeLine555(int sh, int line, struct PicoEState *est)
   if (DrawLineDestIncrement == 0)\r
     return;\r
 \r
+  if (est->rendstatus & PDRAW_BGC_DMA)\r
+    return BgcDMA(est);\r
+\r
   PicoDrawUpdateHighPal();\r
 \r
   len = 256;\r
@@ -1747,9 +1750,6 @@ void FinalizeLine555(int sh, int line, struct PicoEState *est)
   else if ((PicoIn.AHW & PAHW_SMS) && (est->Pico->video.reg[0] & 0x20))\r
     len -= 8, ps += 8;\r
 \r
-  if (est->rendstatus & PDRAW_BGC_DMA)\r
-    return BgcDMA(est);\r
-\r
   if ((est->rendstatus & PDRAW_SOFTSCALE) && len < 320) {\r
     if (len >= 240 && len <= 256) {\r
       pd += (256-len)>>1;\r
index 05f8ba3..2b1b2e4 100644 (file)
@@ -1631,17 +1631,17 @@ PicoDoHighPal555_end:
 .global FinalizeLine555\r
 \r
 FinalizeLine555:\r
+    ldr     r3, [r11, #OFS_EST_rendstatus]\r
+    mov     r0, r2\r
+    tst     r3, #PDRAW_BGC_DMA\r
+    bne     BgcDMA\r
+\r
     stmfd   sp!, {r4-r11,lr}\r
     mov     r11,r2               @ est\r
-    ldr     r4, [r11, #OFS_EST_rendstatus]\r
+    mov     r4, r3\r
 \r
     bl      PicoDrawUpdateHighPal\r
 \r
-    tst     r4, #PDRAW_BGC_DMA\r
-    movne   r0, r11\r
-    ldmnefd sp!, {r4-r11,lr}\r
-    bne     BgcDMA\r
-\r
     ldr     r8, [r11, #OFS_EST_Pico]\r
     add     r3, r11, #OFS_EST_HighPal\r
 \r
index dcfc58c..503e0eb 100644 (file)
@@ -439,8 +439,9 @@ void PicoVideoFIFOMode(int active, int h40)
 \r
 static __inline void AutoIncrement(void)\r
 {\r
-  Pico.video.addr=(unsigned short)(Pico.video.addr+Pico.video.reg[0xf]);\r
-  if (Pico.video.addr < Pico.video.reg[0xf]) Pico.video.addr_u ^= 1;\r
+  struct PicoVideo *pvid = &Pico.video;\r
+  pvid->addr=(unsigned short)(pvid->addr+pvid->reg[0xf]);\r
+  if (pvid->addr < pvid->reg[0xf]) pvid->addr_u ^= 1;\r
 }\r
 \r
 static NOINLINE void VideoWriteVRAM128(u32 a, u16 d)\r
@@ -458,23 +459,24 @@ static NOINLINE void VideoWriteVRAM128(u32 a, u16 d)
 \r
 static void VideoWrite(u16 d)\r
 {\r
-  unsigned int a = Pico.video.addr;\r
+  struct PicoVideo *pvid = &Pico.video;\r
+  unsigned int a = pvid->addr;\r
 \r
-  switch (Pico.video.type)\r
+  switch (pvid->type)\r
   {\r
     case 1: if (a & 1)\r
               d = (u16)((d << 8) | (d >> 8));\r
-            a |= Pico.video.addr_u << 16;\r
+            a |= pvid->addr_u << 16;\r
             VideoWriteVRAM(a, d);\r
             break;\r
-    case 3: if (PicoMem.cram [(a >> 1) & 0x3f] != d) Pico.m.dirtyPal = 1;\r
+    case 3: if (PicoMem.cram [(a >> 1) & 0x3f] != (d & 0xeee)) Pico.m.dirtyPal = 1;\r
             PicoMem.cram [(a >> 1) & 0x3f] = d & 0xeee; break;\r
     case 5: PicoMem.vsram[(a >> 1) & 0x3f] = d & 0x7ff; break;\r
     case 0x81:\r
-            a |= Pico.video.addr_u << 16;\r
+            a |= pvid->addr_u << 16;\r
             VideoWriteVRAM128(a, d);\r
             break;\r
-    //default:elprintf(EL_ANOMALY, "VDP write %04x with bad type %i", d, Pico.video.type); break;\r
+    //default:elprintf(EL_ANOMALY, "VDP write %04x with bad type %i", d, pvid->type); break;\r
   }\r
 \r
   AutoIncrement();\r
@@ -482,21 +484,22 @@ static void VideoWrite(u16 d)
 \r
 static unsigned int VideoRead(int is_from_z80)\r
 {\r
+  struct PicoVideo *pvid = &Pico.video;\r
   unsigned int a, d = VdpFIFO.fifo_data[(VdpFIFO.fifo_dx+1)&3];\r
 \r
-  a=Pico.video.addr; a>>=1;\r
+  a=pvid->addr; a>>=1;\r
 \r
   if (!is_from_z80)\r
     SekCyclesBurnRun(PicoVideoFIFORead());\r
-  switch (Pico.video.type)\r
+  switch (pvid->type)\r
   {\r
     case 0: d=PicoMem.vram [a & 0x7fff]; break;\r
     case 8: d=PicoMem.cram [a & 0x003f] | (d & ~0x0eee); break;\r
     case 4: if ((a & 0x3f) >= 0x28) a = 0;\r
             d=PicoMem.vsram [a & 0x003f] | (d & ~0x07ff); break;\r
-    case 12:a=PicoMem.vram [a & 0x7fff]; if (Pico.video.addr&1) a >>= 8;\r
+    case 12:a=PicoMem.vram [a & 0x7fff]; if (pvid->addr&1) a >>= 8;\r
             d=(a & 0x00ff) | (d & ~0x00ff); break;\r
-    default:elprintf(EL_ANOMALY, "VDP read with bad type %i", Pico.video.type); break;\r
+    default:elprintf(EL_ANOMALY, "VDP read with bad type %i", pvid->type); break;\r
   }\r
 \r
   AutoIncrement();\r
@@ -518,17 +521,18 @@ static int GetDmaLength(void)
 \r
 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), e;\r
+  struct PicoVideo *pvid=&Pico.video;\r
+  u32 inc = pvid->reg[0xf];\r
+  u32 a = pvid->addr | (pvid->addr_u << 16), e;\r
   u16 *r, *base = NULL;\r
   u32 mask = 0x1ffff;\r
   int lc = SekCyclesDone()-Pico.t.m68c_line_start;\r
 \r
   elprintf(EL_VDPDMA, "DmaSlow[%i] %06x->%04x len %i inc=%i blank %i [%u] @ %06x",\r
-    Pico.video.type, source, a, len, inc, (Pico.video.status&SR_VB)||!(Pico.video.reg[1]&0x40),\r
+    pvid->type, source, a, len, inc, (pvid->status&SR_VB)||!(pvid->reg[1]&0x40),\r
     SekCyclesDone(), SekPc);\r
 \r
-  SekCyclesBurnRun(PicoVideoFIFOWrite(len, FQ_FGDMA | (Pico.video.type == 1),\r
+  SekCyclesBurnRun(PicoVideoFIFOWrite(len, FQ_FGDMA | (pvid->type == 1),\r
                               PVS_DMABG, SR_DMA | PVS_CPUWR));\r
 \r
   if ((source & 0xe00000) == 0xe00000) { // Ram\r
@@ -569,7 +573,7 @@ static void DmaSlow(int len, u32 source)
       base = m68k_dma_source(source);\r
   }\r
   if (!base) {\r
-    elprintf(EL_VDPDMA|EL_ANOMALY, "DmaSlow[%i] %06x->%04x: invalid src", Pico.video.type, source, a);\r
+    elprintf(EL_VDPDMA|EL_ANOMALY, "DmaSlow[%i] %06x->%04x: invalid src", pvid->type, source, a);\r
     return;\r
   }\r
 \r
@@ -577,7 +581,7 @@ static void DmaSlow(int len, u32 source)
   source >>= 1;\r
   mask >>= 1;\r
 \r
-  switch (Pico.video.type)\r
+  switch (pvid->type)\r
   {\r
     case 1: // vram\r
       e = a + len*2-1;\r
@@ -604,7 +608,8 @@ static void DmaSlow(int len, u32 source)
     case 3: // cram\r
       Pico.m.dirtyPal = 1;\r
       r = PicoMem.cram;\r
-      if (inc == 0 && (Pico.video.reg[7] & 0x3f) == ((a/2) & 0x3f)) { // bg color DMA\r
+      if (inc == 0 && !(pvid->reg[1] & 0x40) &&\r
+            (pvid->reg[7] & 0x3f) == ((a/2) & 0x3f)) { // bg color DMA\r
         PicoVideoSync(1);\r
         int sl = VdpFIFO.fifo_hcounts[lc/clkdiv];\r
         if (sl > VdpFIFO.fifo_hcounts[0]-5) // hint delay is 5 slots\r
@@ -612,6 +617,9 @@ static void DmaSlow(int len, u32 source)
         // TODO this is needed to cover timing inaccuracies\r
         if (sl <= 12)  sl = -2;\r
         PicoDrawBgcDMA(base, source, mask, len, sl);\r
+        // do last DMA cycle since it's all going to the same cram location\r
+        source = source+len-1;\r
+        len = 1;\r
       }\r
       for (; len; len--)\r
       {\r
@@ -642,20 +650,21 @@ static void DmaSlow(int len, u32 source)
       break;\r
 \r
     default:\r
-      if (Pico.video.type != 0 || (EL_LOGMASK & EL_VDPDMA))\r
-        elprintf(EL_VDPDMA|EL_ANOMALY, "DMA with bad type %i", Pico.video.type);\r
+      if (pvid->type != 0 || (EL_LOGMASK & EL_VDPDMA))\r
+        elprintf(EL_VDPDMA|EL_ANOMALY, "DMA with bad type %i", pvid->type);\r
       break;\r
   }\r
   // remember addr\r
-  Pico.video.addr = a;\r
-  Pico.video.addr_u = a >> 16;\r
+  pvid->addr = a;\r
+  pvid->addr_u = a >> 16;\r
 }\r
 \r
 static void DmaCopy(int len)\r
 {\r
-  u32 a = Pico.video.addr | (Pico.video.addr_u << 16);\r
+  struct PicoVideo *pvid=&Pico.video;\r
+  u32 a = pvid->addr | (pvid->addr_u << 16);\r
   u8 *vr = (u8 *)PicoMem.vram;\r
-  u8 inc = Pico.video.reg[0xf];\r
+  u8 inc = pvid->reg[0xf];\r
   int source;\r
   elprintf(EL_VDPDMA, "DmaCopy len %i [%u]", len, SekCyclesDone());\r
 \r
@@ -663,8 +672,8 @@ static void DmaCopy(int len)
   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
-  source|=Pico.video.reg[0x16]<<8;\r
+  source =pvid->reg[0x15];\r
+  source|=pvid->reg[0x16]<<8;\r
 \r
   for (; len; len--)\r
   {\r
@@ -675,16 +684,17 @@ static void DmaCopy(int len)
     a = (a+inc) & ~0x20000;\r
   }\r
   // remember addr\r
-  Pico.video.addr = a;\r
-  Pico.video.addr_u = a >> 16;\r
+  pvid->addr = a;\r
+  pvid->addr_u = a >> 16;\r
 }\r
 \r
 static NOINLINE void DmaFill(int data)\r
 {\r
-  u32 a = Pico.video.addr | (Pico.video.addr_u << 16), e;\r
+  struct PicoVideo *pvid=&Pico.video;\r
+  u32 a = pvid->addr | (pvid->addr_u << 16), e;\r
   u8 *vr = (u8 *)PicoMem.vram;\r
   u8 high = (u8)(data >> 8);\r
-  u8 inc = Pico.video.reg[0xf];\r
+  u8 inc = pvid->reg[0xf];\r
   int source;\r
   int len, l;\r
 \r
@@ -694,7 +704,7 @@ static NOINLINE void DmaFill(int data)
   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
+  switch (pvid->type)\r
   {\r
     case 1: // vram\r
       e = a + len-1;\r
@@ -751,16 +761,15 @@ static NOINLINE void DmaFill(int data)
   }\r
 \r
   // remember addr\r
-  Pico.video.addr = a;\r
-  Pico.video.addr_u = a >> 16;\r
+  pvid->addr = a;\r
+  pvid->addr_u = a >> 16;\r
   // register update\r
-  Pico.video.reg[0x13] = Pico.video.reg[0x14] = 0;\r
-  source  = Pico.video.reg[0x15];\r
-  source |= Pico.video.reg[0x16] << 8;\r
+  pvid->reg[0x13] = pvid->reg[0x14] = 0;\r
+  source  = pvid->reg[0x15];\r
+  source |= pvid->reg[0x16] << 8;\r
   source += len;\r
-  Pico.video.reg[0x15] = source;\r
-  Pico.video.reg[0x16] = source >> 8;\r
-\r
+  pvid->reg[0x15] = source;\r
+  pvid->reg[0x16] = source >> 8;\r
 }\r
 \r
 // VDP command handling\r
@@ -780,9 +789,9 @@ static NOINLINE void CommandDma(void)
   }\r
 \r
   len = GetDmaLength();\r
-  source =Pico.video.reg[0x15];\r
-  source|=Pico.video.reg[0x16] << 8;\r
-  source|=Pico.video.reg[0x17] << 16;\r
+  source  = pvid->reg[0x15];\r
+  source |= pvid->reg[0x16] << 8;\r
+  source |= pvid->reg[0x17] << 16;\r
 \r
   method=pvid->reg[0x17]>>6;\r
   if (method < 2)\r
@@ -794,9 +803,9 @@ static NOINLINE void CommandDma(void)
     return;\r
   }\r
   source += len;\r
-  Pico.video.reg[0x13] = Pico.video.reg[0x14] = 0;\r
-  Pico.video.reg[0x15] = source;\r
-  Pico.video.reg[0x16] = source >> 8;\r
+  pvid->reg[0x13] = pvid->reg[0x14] = 0;\r
+  pvid->reg[0x15] = source;\r
+  pvid->reg[0x16] = source >> 8;\r
 }\r
 \r
 static NOINLINE void CommandChange(struct PicoVideo *pvid)\r
@@ -893,7 +902,7 @@ PICO_INTERNAL_ASM void PicoVideoWrite(u32 a,unsigned short d)
       SekCyclesBurnRun(PicoVideoFIFOWrite(1, pvid->type == 1, 0, PVS_CPUWR));\r
 \r
       elprintf(EL_ASVDP, "VDP data write: [%04x] %04x [%u] {%i} @ %06x",\r
-        Pico.video.addr, d, SekCyclesDone(), Pico.video.type, SekPc);\r
+        pvid->addr, d, SekCyclesDone(), pvid->type, SekPc);\r
     }\r
     VideoWrite(d);\r
 \r
@@ -948,7 +957,7 @@ PICO_INTERNAL_ASM void PicoVideoWrite(u32 a,unsigned short d)
           lineenabled = (d&0x40) ? Pico.m.scanline : -1;\r
           linedisabled = (d&0x40) ? -1 : Pico.m.scanline;\r
           lineoffset = SekCyclesDone() - Pico.t.m68c_line_start;\r
-       } else if (((1<<num) & 0x738ff) && pvid->reg[num] != d)\r
+        } else if (((1<<num) & 0x738ff) && pvid->reg[num] != d)\r
           // VDP regs 0-7,11-13,16-18 influence rendering, ignore all others\r
           PicoVideoSync(InHblank(93)); // Toy Story\r
         pvid->reg[num] = d;\r
@@ -1064,11 +1073,11 @@ static u32 VideoSr(const struct PicoVideo *pv)
 \r
 PICO_INTERNAL_ASM u32 PicoVideoRead(u32 a)\r
 {\r
+  struct PicoVideo *pv = &Pico.video;\r
   a &= 0x1c;\r
 \r
   if (a == 0x04) // control port\r
   {\r
-    struct PicoVideo *pv = &Pico.video;\r
     u32 d = VideoSr(pv);\r
     if (pv->pending) {\r
       CommandChange(pv);\r
@@ -1084,11 +1093,11 @@ PICO_INTERNAL_ASM u32 PicoVideoRead(u32 a)
     u32 d;\r
 \r
     c = SekCyclesDone() - Pico.t.m68c_line_start;\r
-    if (Pico.video.reg[0]&2)\r
-         d = Pico.video.hv_latch;\r
-    else d = VdpFIFO.fifo_hcounts[c/clkdiv] | (Pico.video.v_counter << 8);\r
+    if (pv->reg[0]&2)\r
+         d = pv->hv_latch;\r
+    else d = VdpFIFO.fifo_hcounts[c/clkdiv] | (pv->v_counter << 8);\r
 \r
-    elprintf(EL_HVCNT, "hv: %02x %02x [%u] @ %06x", d, Pico.video.v_counter, SekCyclesDone(), SekPc);\r
+    elprintf(EL_HVCNT, "hv: %02x %02x [%u] @ %06x", d, pv->v_counter, SekCyclesDone(), SekPc);\r
     return d;\r
   }\r
 \r