partial gmv implementation
[picodrive.git] / Pico / Pico.c
index 750ffc5..5ab8483 100644 (file)
@@ -187,11 +187,84 @@ int PicoReset(int hard)
   return 0;\r
 }\r
 \r
+static int dma_timings[] = {\r
+83,  167, 166,  83, // vblank: 32cell: dma2vram dma2[vs|c]ram vram_fill vram_copy\r
+102, 205, 204, 102, // vblank: 40cell:\r
+8,    16,  15,   8, // active: 32cell:\r
+9,    18,  17,   9  // ...\r
+};\r
+\r
+static int dma_bsycles[] = {\r
+(488<<8)/83,  (488<<8)/167, (488<<8)/166, (488<<8)/83,\r
+(488<<8)/102, (488<<8)/205, (488<<8)/204, (488<<8)/102,\r
+(488<<8)/8,   (488<<8)/16,  (488<<8)/15,  (488<<8)/8,\r
+(488<<8)/9,   (488<<8)/18,  (488<<8)/17,  (488<<8)/9\r
+};\r
+\r
+//static\r
+int CheckDMA(void)\r
+{\r
+  int burn = 0, bytes_can = 0, dma_op = Pico.video.reg[0x17]>>6; // see gens for 00 and 01 modes\r
+  int bytes = Pico.m.dma_bytes;\r
+  int dma_op1;\r
+\r
+  if(!(dma_op&2)) dma_op = (Pico.video.type==1) ? 0 : 1; // setting dma_timings offset here according to Gens\r
+  dma_op1 = dma_op;\r
+  if(Pico.video.reg[12] & 1) dma_op |= 4; // 40 cell mode?\r
+  if(!(Pico.video.status&8)&&(Pico.video.reg[1]&0x40)) dma_op|=8; // active display?\r
+  bytes_can = dma_timings[dma_op];\r
+\r
+  if(bytes <= bytes_can) {\r
+    if(dma_op&2) Pico.video.status&=~2; // dma no longer busy\r
+    else {\r
+      burn = bytes * dma_bsycles[dma_op] >> 8; // have to be approximate because can't afford division..\r
+      //SekCycleCnt-=Pico.m.dma_endcycles;\r
+      //Pico.m.dma_endcycles = 0;\r
+    }\r
+    Pico.m.dma_bytes = 0;\r
+  } else {\r
+    if(!(dma_op&2)) burn = 488;\r
+    Pico.m.dma_bytes -= bytes_can;\r
+  }\r
+\r
+  //SekCycleCnt+=burn;\r
+  dprintf("~Dma %i op=%i can=%i burn=%i [%i|%i]", Pico.m.dma_bytes, dma_op1, bytes_can, burn, Pico.m.scanline, SekCyclesDone());\r
+  //dprintf("~aim: %i, cnt: %i", SekCycleAim, SekCycleCnt);\r
+  return burn;\r
+}\r
+\r
 static __inline void SekRun(int cyc)\r
 {\r
   int cyc_do;\r
   SekCycleAim+=cyc;\r
-  if((cyc_do=SekCycleAim-SekCycleCnt) < 0) return;\r
+#if 0\r
+  if(Pico.m.dma_bytes) {\r
+    int burn=0;\r
+    if((Pico.video.status&8)||!(Pico.video.reg[1]&0x40)) { // vblank?\r
+      if(Pico.m.dma_bytes < 205) {\r
+       burn = Pico.m.dma_bytes*(((488<<8)/205))>>8;\r
+       Pico.m.dma_bytes = 0;\r
+      } else {\r
+        burn += 488;\r
+       Pico.m.dma_bytes -= 205;\r
+      }\r
+    } else {\r
+      if(Pico.m.dma_bytes < 18) {\r
+       burn = Pico.m.dma_bytes*(((488<<8)/18))>>8;\r
+       Pico.m.dma_bytes = 0;\r
+      } else {\r
+        burn += 488;\r
+       Pico.m.dma_bytes -= 18;\r
+      }\r
+    }\r
+    SekCycleCnt+=burn;\r
+    dprintf("~DmaSlow %i burn=%i do=%i [%i|%i]", Pico.m.dma_bytes, burn, SekCycleAim-SekCycleCnt,\r
+               Pico.m.scanline, SekCyclesDone());\r
+  }\r
+#endif\r
+  //dprintf("aim: %i, cnt: %i", SekCycleAim, SekCycleCnt);\r
+  if((cyc_do=SekCycleAim-SekCycleCnt) <= 0) return;\r
+  //dprintf("cyc_do: %i", cyc_do);\r
 #if   defined(EMU_C68K) && defined(EMU_M68K)\r
   // this means we do run-compare Cyclone vs Musashi\r
   SekCycleCnt+=CM_compareRun(cyc_do);\r
@@ -331,14 +404,14 @@ static int PicoFrameHints(void)
     // V-Interrupt:\r
     if (y == lines_vis)\r
     {\r
-      //dprintf("vint: @ %06x [%i|%i]", SekPc, y, SekCycleCnt);\r
-      pv->status|=0x88; // V-Int happened, go into vblank\r
-      SekRun(128); SekCycleAim-=128; // there must be a gap between H and V ints, also after vblank bit set (Mazin Saga, Bram Stoker's Dracula)\r
-      /*if(Pico.m.z80Run && (PicoOpt&4)) {\r
-        z80CycleAim+=cycles_z80/2;\r
-        total_z80+=z80_run(z80CycleAim-total_z80);\r
-        z80CycleAim-=cycles_z80/2;\r
-      }*/\r
+      dprintf("vint: @ %06x [%i|%i], aim=%i cnt=%i", SekPc, y, SekCycleCnt, SekCycleAim, SekCycleCnt);\r
+      pv->status|=0x08; // go into vblank\r
+      if(!Pico.m.dma_bytes||(Pico.video.reg[0x17]&0x80)) {\r
+        // there must be a gap between H and V ints, also after vblank bit set (Mazin Saga, Bram Stoker's Dracula)\r
+        SekRun(128); SekCycleAim-=128; // 128; ?\r
+      }\r
+      dprintf("[%i|%i], aim=%i cnt=%i @ %x", y, SekCycleCnt, SekCycleAim, SekCycleCnt, SekPc);\r
+      pv->status|=0x80; // V-Int happened\r
       pv->pending_ints|=0x20;\r
       if(pv->reg[1]&0x20) SekInterrupt(6);\r
       if(Pico.m.z80Run && (PicoOpt&4)) // ?\r
@@ -364,6 +437,7 @@ static int PicoFrameHints(void)
       getSamples(y);\r
 \r
     // Run scanline:\r
+    if(Pico.m.dma_bytes) SekCycleCnt+=CheckDMA();\r
     SekRun(cycles_68k);\r
     if((PicoOpt&4) && Pico.m.z80Run) {\r
       Pico.m.z80Run|=2;\r