don't draw layer where window is (for World Championship Soccer II)
[picodrive.git] / Pico / Pico.c
index 90b06d6..6f9ed4b 100644 (file)
@@ -8,22 +8,22 @@
 \r
 \r
 #include "PicoInt.h"\r
-#include "sound/sound.h"\r
 #include "sound/ym2612.h"\r
 \r
-int PicoVer=0x0080;\r
+int PicoVer=0x0110;\r
 struct Pico Pico;\r
 int PicoOpt=0; // disable everything by default\r
 int PicoSkipFrame=0; // skip rendering frame?\r
 int PicoRegionOverride = 0; // override the region detection 0: Auto, 1: Japan NTSC, 2: Japan PAL, 4: US, 8: Europe\r
+int PicoAutoRgnOrder = 0;\r
 int emustatus = 0;\r
-void (*PicoWriteSound)(void) = 0; // called once per frame at the best time to send sound buffer (PsndOut) to hardware\r
+void (*PicoWriteSound)(int len) = 0; // called once per frame at the best time to send sound buffer (PsndOut) to hardware\r
 \r
 struct PicoSRAM SRam;\r
-int z80startCycle = 0, z80stopCycle = 0; // in 68k cycles\r
+int z80startCycle, z80stopCycle; // in 68k cycles\r
 //int z80ExtraCycles = 0;\r
-int PicoPad[2]; // Joypads, format is SACB RLDU\r
-int PicoMCD = 1; // mega CD status: scd_started\r
+int PicoPad[2];  // Joypads, format is SACB RLDU\r
+int PicoMCD = 0; // mega CD status: scd_started, reset_pending\r
 \r
 // to be called once on emu init\r
 int PicoInit(void)\r
@@ -36,9 +36,6 @@ int PicoInit(void)
   SekInit();\r
   z80_init(); // init even if we aren't going to use it\r
 \r
-  // Setup memory callbacks:\r
-  PicoMemInit();\r
-\r
   PicoInitMCD();\r
 \r
   // notaz: sram\r
@@ -51,7 +48,8 @@ int PicoInit(void)
 // to be called once on emu exit\r
 void PicoExit(void)\r
 {\r
-  PicoExitMCD();\r
+  if (PicoMCD&1)\r
+    PicoExitMCD();\r
   z80_exit();\r
 \r
   // notaz: sram\r
@@ -66,14 +64,21 @@ int PicoReset(int hard)
 \r
   if (Pico.romsize<=0) return 1;\r
 \r
+  // setup correct memory map\r
+  if (PicoMCD & 1)\r
+       PicoMemSetupCD();\r
+  else PicoMemSetup();\r
   PicoMemReset();\r
   SekReset();\r
+  // s68k doesn't have the TAS quirk, so we just globally set normal TAS handler in MCD mode (used by Batman games).\r
+  SekSetRealTAS(PicoMCD & 1);\r
   SekCycleCntT=0;\r
   z80_reset();\r
 \r
   // reset VDP state, VRAM and PicoMisc\r
   //memset(&Pico.video,0,sizeof(Pico.video));\r
   //memset(&Pico.vram,0,sizeof(Pico.vram));\r
+  memset(Pico.ioports,0,sizeof(Pico.ioports)); // needed for MCD to reset properly\r
   memset(&Pico.m,0,sizeof(Pico.m));\r
   Pico.video.pending_ints=0;\r
   emustatus = 0;\r
@@ -105,9 +110,12 @@ int PicoReset(int hard)
       c=region>>(i<<3); c&=0xff;\r
       if (c<=' ') continue;\r
 \r
-           if (c=='J') support|=1;\r
-      else if (c=='U') support|=4;\r
-      else if (c=='E') support|=8;\r
+           if (c=='J')  support|=1;\r
+      else if (c=='U')  support|=4;\r
+      else if (c=='E')  support|=8;\r
+      else if (c=='j') {support|=1; break; }\r
+      else if (c=='u') {support|=4; break; }\r
+      else if (c=='e') {support|=8; break; }\r
       else\r
       {\r
         // New style code:\r
@@ -118,6 +126,13 @@ int PicoReset(int hard)
     }\r
   }\r
 \r
+  // auto detection order override\r
+  if (PicoAutoRgnOrder) {\r
+         if (((PicoAutoRgnOrder>>0)&0xf) & support) support = (PicoAutoRgnOrder>>0)&0xf;\r
+    else if (((PicoAutoRgnOrder>>4)&0xf) & support) support = (PicoAutoRgnOrder>>4)&0xf;\r
+    else if (((PicoAutoRgnOrder>>8)&0xf) & support) support = (PicoAutoRgnOrder>>8)&0xf;\r
+  }\r
+\r
   // Try to pick the best hardware value for English/50hz:\r
        if (support&8) { hw=0xc0; pal=1; } // Europe\r
   else if (support&4)   hw=0x80;          // USA\r
@@ -133,7 +148,6 @@ int PicoReset(int hard)
 \r
   if (PicoMCD & 1) {\r
     PicoResetMCD(hard);\r
-    SRam.data = 0;\r
     return 0;\r
   }\r
 \r
@@ -179,6 +193,8 @@ int PicoReset(int hard)
     // Dino Dini's Soccer malfunctions if SRAM is not filled with 0xff\r
     if (strncmp((char *)Pico.rom+0x150, "IDOND NI'I", 10) == 0)\r
       memset(SRam.data, 0xff, sram_size);\r
+    dprintf("sram: det: %i; eeprom: %i; start: %06x; end: %06x\n",\r
+      (Pico.m.sram_reg>>4)&1, (Pico.m.sram_reg>>2)&1, SRam.start, SRam.end);\r
   }\r
 \r
   Pico.m.sram_reg = SRam.reg_back; // restore sram_reg\r
@@ -201,8 +217,8 @@ static int dma_bsycles[] = {
 (488<<8)/9,   (488<<8)/18,  (488<<8)/17,  (488<<8)/9\r
 };\r
 \r
-//static\r
-int CheckDMA(void)\r
+\r
+PICO_INTERNAL 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
@@ -237,31 +253,6 @@ static __inline void SekRun(int cyc)
 {\r
   int cyc_do;\r
   SekCycleAim+=cyc;\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
@@ -327,20 +318,22 @@ static int CheckIdle(void)
 // to be called on 224 or line_sample scanlines only\r
 static __inline void getSamples(int y)\r
 {\r
+  static int curr_pos = 0;\r
+\r
   if(y == 224) {\r
     //dprintf("sta%i: %i [%i]", (emustatus & 2), emustatus, y);\r
     if(emustatus & 2)\r
-        sound_render(PsndLen/2, PsndLen-PsndLen/2);\r
-    else sound_render(0, PsndLen);\r
+         curr_pos += sound_render(curr_pos, PsndLen-PsndLen/2);\r
+    else curr_pos  = sound_render(0, PsndLen);\r
     if (emustatus&1) emustatus|=2; else emustatus&=~2;\r
-    if (PicoWriteSound) PicoWriteSound();\r
+    if (PicoWriteSound) PicoWriteSound(curr_pos);\r
     // clear sound buffer\r
-    memset(PsndOut, 0, (PicoOpt & 8) ? (PsndLen<<2) : (PsndLen<<1));\r
+    sound_clear();\r
   }\r
   else if(emustatus & 3) {\r
     emustatus|= 2;\r
     emustatus&=~1;\r
-    sound_render(0, PsndLen/2);\r
+    curr_pos = sound_render(0, PsndLen/2);\r
   }\r
 }\r
 \r
@@ -437,11 +430,18 @@ static int PicoFrameHints(void)
       getSamples(y);\r
 \r
     // Run scanline:\r
-    if(Pico.m.dma_bytes) SekCycleCnt+=CheckDMA();\r
+    if (Pico.m.dma_bytes) SekCyclesBurn(CheckDMA());\r
     SekRun(cycles_68k);\r
-    if((PicoOpt&4) && Pico.m.z80Run) {\r
-      Pico.m.z80Run|=2;\r
-      z80CycleAim+=cycles_z80;\r
+    if ((PicoOpt&4) && Pico.m.z80Run) {\r
+      if (Pico.m.z80Run & 2) z80CycleAim+=cycles_z80;\r
+      else {\r
+        int cnt = SekCyclesDone() - z80startCycle;\r
+        cnt = (cnt>>1)-(cnt>>5);\r
+        //if (cnt > cycles_z80) printf("FIXME: z80 cycles: %i\n", cnt);\r
+        if (cnt > cycles_z80) cnt = cycles_z80;\r
+        Pico.m.z80Run |= 2;\r
+        z80CycleAim+=cnt;\r
+      }\r
       total_z80+=z80_run(z80CycleAim-total_z80);\r
     }\r
   }\r
@@ -458,19 +458,9 @@ static void PicoRunZ80Simple(int line_from, int line_to)
 {\r
   int line_from_r=line_from, line_to_r=line_to, line = line_from;\r
   int line_sample = Pico.m.pal ? 68 : 93;\r
-  extern const unsigned short vcounts[];\r
 \r
   if(!(PicoOpt&4) || Pico.m.z80Run == 0) { line_from_r = line_to_r; line_to_r = 0; }\r
 \r
-  if(z80startCycle != 0) {\r
-    line_from_r = vcounts[z80startCycle>>8]+1;\r
-    z80startCycle = 0;\r
-  }\r
-  if(z80stopCycle != 0) {\r
-    line_to_r = vcounts[z80stopCycle>>8]+1;\r
-    z80stopCycle = 0;\r
-  }\r
-\r
   if(PicoOpt&1) {\r
     // we have ym2612 enabled, so we have to run Z80 in lines, so we could update DAC and timers\r
     for(; line < line_to; line++) {\r
@@ -493,7 +483,13 @@ static int PicoFrameSimple(void)
   int y=0,line=0,lines=0,lines_step=0,sects;\r
   int cycles_68k_vblock,cycles_68k_block;\r
 \r
-  if(Pico.m.pal) {\r
+  // we don't emulate DMA timing in this mode\r
+  if (Pico.m.dma_bytes) {\r
+    Pico.m.dma_bytes=0;\r
+    Pico.video.status&=~2;\r
+  }\r
+\r
+  if (Pico.m.pal) {\r
     // M68k cycles/frame: 152009.78\r
     if(pv->reg[1]&8) { // 240 lines\r
       cycles_68k_block  = (int) ((double) OSC_PAL  /  7 / 50 / 312 * 15 + 0.4); // 16 sects, 16*15=240, 7308\r
@@ -549,10 +545,10 @@ static int PicoFrameSimple(void)
 \r
   // here we render sound if ym2612 is disabled\r
   if(!(PicoOpt&1) && PsndOut) {\r
-    sound_render(0, PsndLen);\r
-    if(PicoWriteSound) PicoWriteSound();\r
+    int len = sound_render(0, PsndLen);\r
+    if(PicoWriteSound) PicoWriteSound(len);\r
     // clear sound buffer\r
-    memset(PsndOut, 0, (PicoOpt & 8) ? (PsndLen<<2) : (PsndLen<<1));\r
+    sound_clear();\r
   }\r
 \r
   // render screen\r
@@ -646,47 +642,58 @@ int PicoFrame(void)
   return 0;\r
 }\r
 \r
-static int DefaultCram(int cram)\r
+void PicoFrameDrawOnly(void)\r
 {\r
-  int high=0x0841;\r
-  // Convert 0000bbbb ggggrrrr\r
-  // to      rrrr1ggg g10bbbb1\r
-  high|=(cram&0x00f)<<12; // Red\r
-  high|=(cram&0x0f0)<< 3; // Green\r
-  high|=(cram&0xf00)>> 7; // Blue\r
-  return high;\r
+  int y;\r
+  PicoFrameStart();\r
+  for (y=0;y<224;y++) PicoLine(y);\r
 }\r
 \r
-// Function to convert Megadrive Cram into a native colour:\r
-int (*PicoCram)(int cram)=DefaultCram;\r
+// callback to output message from emu\r
+void (*PicoMessage)(const char *msg)=NULL;\r
 \r
-#if defined(__DEBUG_PRINT) || defined(WIN32)\r
+#if defined(__DEBUG_PRINT) || defined(__GP2X__)\r
 // tmp debug: dump some stuff\r
 #define bit(r, x) ((r>>x)&1)\r
 void z80_debug(char *dstr);\r
-char *debugString()\r
+char *debugString(void)\r
 {\r
 #if 1\r
   static char dstr[1024];\r
-  unsigned char *reg=Pico.video.reg, r;\r
-\r
-  // dump some info\r
-  sprintf(dstr, "mode set 1: %02x\n", (r=reg[0]));\r
-  sprintf(dstr, "%sdisplay_disable: %i, M3: %i, palette: %i, ?, hints: %i\n\n", dstr, bit(r,0), bit(r,1), bit(r,2), bit(r,4));\r
-  sprintf(dstr, "%smode set 2: %02x\n",  dstr,  (r=reg[1]));\r
-  sprintf(dstr, "%sSMS/genesis: %i, pal: %i, dma: %i, vints: %i, disp: %i, TMS9918: %i\n\n",dstr, bit(r,2), bit(r,3), bit(r,4), bit(r,5), bit(r,6), bit(r,7));\r
-  sprintf(dstr, "%smode set 3: %02x\n",  dstr,  (r=reg[0xB]));\r
-  sprintf(dstr, "%sLSCR: %i, HSCR: %i, 2cell vscroll: %i, IE2: %i\n\n", dstr, bit(r,0), bit(r,1), bit(r,2), bit(r,3));\r
-  sprintf(dstr, "%smode set 4: %02x\n",  dstr,  (r=reg[0xC]));\r
-  sprintf(dstr, "%sinterlace: %i%i; cells: %i; shadow: %i\n\n", dstr, bit(r,2), bit(r,1), (r&0x80) ? 40 : 32,  bit(r,3));\r
-  sprintf(dstr, "%sscroll size: w: %i; h: %i\n\n",  dstr, reg[0x10]&3, (reg[0x10]&0x30)>>4);\r
-  sprintf(dstr, "%sSRAM: det: %i; eeprom: %i\n",  dstr, bit(Pico.m.sram_reg, 4), bit(Pico.m.sram_reg, 2));\r
-  sprintf(dstr, "%sCPU state: PC: %06x cycles: %i\n", dstr, SekPc, SekCyclesDoneT());\r
+  struct PicoVideo *pv=&Pico.video;\r
+  unsigned char *reg=pv->reg, r;\r
+  char *dstrp;\r
+\r
+  dstrp = dstr;\r
+  sprintf(dstrp, "mode set 1: %02x\n", (r=reg[0])); dstrp+=strlen(dstrp);\r
+  sprintf(dstrp, "display_disable: %i, M3: %i, palette: %i, ?, hints: %i\n", bit(r,0), bit(r,1), bit(r,2), bit(r,4));\r
+  dstrp+=strlen(dstrp);\r
+  sprintf(dstrp, "mode set 2: %02x\n", (r=reg[1])); dstrp+=strlen(dstrp);\r
+  sprintf(dstrp, "SMS/gen: %i, pal: %i, dma: %i, vints: %i, disp: %i, TMS: %i\n", bit(r,2), bit(r,3), bit(r,4),\r
+       bit(r,5), bit(r,6), bit(r,7)); dstrp+=strlen(dstrp);\r
+  sprintf(dstrp, "mode set 3: %02x\n", (r=reg[0xB])); dstrp+=strlen(dstrp);\r
+  sprintf(dstrp, "LSCR: %i, HSCR: %i, 2cell vscroll: %i, IE2: %i\n", bit(r,0), bit(r,1), bit(r,2), bit(r,3)); dstrp+=strlen(dstrp);\r
+  sprintf(dstrp, "mode set 4: %02x\n", (r=reg[0xC])); dstrp+=strlen(dstrp);\r
+  sprintf(dstrp, "interlace: %i%i, cells: %i, shadow: %i\n", bit(r,2), bit(r,1), (r&0x80) ? 40 : 32,  bit(r,3));\r
+  dstrp+=strlen(dstrp);\r
+  sprintf(dstrp, "scroll size: w: %i, h: %i  SRAM: %i; eeprom: %i\n", reg[0x10]&3, (reg[0x10]&0x30)>>4,\r
+       bit(Pico.m.sram_reg, 4), bit(Pico.m.sram_reg, 2)); dstrp+=strlen(dstrp);\r
+  sprintf(dstrp, "sram range: %06x-%06x, reg: %02x\n", SRam.start, SRam.end, Pico.m.sram_reg); dstrp+=strlen(dstrp);\r
+  sprintf(dstrp, "pend int: v:%i, h:%i, vdp status: %04x\n", bit(pv->pending_ints,5), bit(pv->pending_ints,4), pv->status);\r
+  dstrp+=strlen(dstrp);\r
 #ifdef EMU_C68K\r
-  for(r=0; r < 8; r++)\r
-    sprintf(dstr, "%sd%i=%08x, a%i=%08x\n", dstr, r, PicoCpu.d[r], r, PicoCpu.a[r]);\r
+  sprintf(dstrp, "M68k: PC: %06x, st_flg: %x, cycles: %u\n", SekPc, PicoCpu.state_flags, SekCyclesDoneT());\r
+  dstrp+=strlen(dstrp);\r
+  sprintf(dstrp, "d0=%08x, a0=%08x, osp=%08x, irql=%i\n", PicoCpu.d[0], PicoCpu.a[0], PicoCpu.osp, PicoCpu.irq); dstrp+=strlen(dstrp);\r
+  sprintf(dstrp, "d1=%08x, a1=%08x,  sr=%04x\n", PicoCpu.d[1], PicoCpu.a[1], CycloneGetSr(&PicoCpu)); dstrp+=strlen(dstrp);\r
+  for(r=2; r < 8; r++) {\r
+    sprintf(dstrp, "d%i=%08x, a%i=%08x\n", r, PicoCpu.d[r], r, PicoCpu.a[r]); dstrp+=strlen(dstrp);\r
+  }\r
 #endif\r
-  z80_debug(dstr);\r
+  sprintf(dstrp, "z80Run: %i, pal: %i, frame#: %i\n", Pico.m.z80Run, Pico.m.pal, Pico.m.frame_count); dstrp+=strlen(dstrp);\r
+  z80_debug(dstrp); dstrp+=strlen(dstrp);\r
+  if (strlen(dstr) > sizeof(dstr))\r
+    printf("warning: debug buffer overflow (%i/%i)\n", strlen(dstr), sizeof(dstr));\r
 \r
 #else\r
   struct PicoVideo *pvid=&Pico.video;\r