new z80 scheduling method, timers are still wip
authornotaz <notasas@gmail.com>
Sun, 25 May 2008 21:25:46 +0000 (21:25 +0000)
committernotaz <notasas@gmail.com>
Sun, 25 May 2008 21:25:46 +0000 (21:25 +0000)
git-svn-id: file:///home/notaz/opt/svn/PicoDrive@459 be3aeb3a-fb24-0410-a615-afba39da0efa

15 files changed:
Pico/Memory.c
Pico/Memory.s
Pico/MemoryCmn.c
Pico/Pico.c
Pico/PicoFrameHints.c
Pico/PicoInt.h
Pico/sound/sound.c
Pico/sound/ym2612.c
Pico/sound/ym2612.h
platform/gp2x/940ctl.c
platform/gp2x/940ctl.h
platform/gp2x/Makefile
platform/gp2x/version.h
platform/linux/940ctl_ym2612.c
platform/linux/Makefile

index 0304e27..45d9fdf 100644 (file)
@@ -687,6 +687,168 @@ static void m68k_mem_setup(void)
 #endif // EMU_M68K\r
 \r
 \r
+// -----------------------------------------------------------------\r
+\r
+extern const unsigned short vcounts[];\r
+\r
+static int get_scanline(int is_from_z80)\r
+{\r
+  if (is_from_z80) {\r
+    int cycles = z80_cyclesDone();\r
+    while (cycles - z80_scanline_cycles >= 228)\r
+      z80_scanline++, z80_scanline_cycles += 228;\r
+    return z80_scanline;\r
+  }\r
+\r
+  if (Pico.m.scanline != -1)\r
+    return Pico.m.scanline;\r
+\r
+  return vcounts[SekCyclesDone()>>8];\r
+}\r
+\r
+// ym2612 DAC and timer I/O handlers for z80\r
+int ym2612_write_local(u32 a, u32 d, int is_from_z80)\r
+{\r
+  int addr;\r
+\r
+  a &= 3;\r
+  if (a == 1 && ym2612.OPN.ST.address == 0x2a) /* DAC data */\r
+  {\r
+    int scanline = get_scanline(is_from_z80);\r
+    //elprintf(EL_STATUS, "%03i -> %03i dac w %08x z80 %i", PsndDacLine, scanline, d, is_from_z80);\r
+    ym2612.dacout = ((int)d - 0x80) << 6;\r
+    if (PsndOut && ym2612.dacen && scanline >= PsndDacLine)\r
+      PsndDoDAC(scanline);\r
+    return 0;\r
+  }\r
+\r
+  switch (a)\r
+  {\r
+    case 0: /* address port 0 */\r
+      ym2612.OPN.ST.address = d;\r
+      ym2612.addr_A1 = 0;\r
+#ifdef __GP2X__\r
+      if (PicoOpt & POPT_EXT_FM) YM2612Write_940(a, d, -1);\r
+#endif\r
+      return 0;\r
+\r
+    case 1: /* data port 0    */\r
+      if (ym2612.addr_A1 != 0)\r
+        return 0;\r
+\r
+      addr = ym2612.OPN.ST.address;\r
+      ym2612.REGS[addr] = d;\r
+\r
+      switch (addr)\r
+      {\r
+        case 0x24: // timer A High 8\r
+        case 0x25: { // timer A Low 2\r
+          int TAnew = (addr == 0x24) ? ((ym2612.OPN.ST.TA & 0x03)|(((int)d)<<2))\r
+                                     : ((ym2612.OPN.ST.TA & 0x3fc)|(d&3));\r
+          if (ym2612.OPN.ST.TA != TAnew)\r
+          {\r
+            //elprintf(EL_STATUS, "timer a set %i", TAnew);\r
+            ym2612.OPN.ST.TA = TAnew;\r
+            //ym2612.OPN.ST.TAC = (1024-TAnew)*18;\r
+            //ym2612.OPN.ST.TAT = 0;\r
+            //\r
+            timer_a_step = 16495 * (1024 - TAnew);\r
+            if ((ym2612.OPN.ST.mode & 5) == 5) {\r
+              int cycles = is_from_z80 ? z80_cyclesDone() : cycles_68k_to_z80(SekCyclesDone());\r
+              timer_a_next_oflow = (cycles << 8) + timer_a_step;\r
+              //elprintf(EL_STATUS, "set to %i @ %i", timer_a_next_oflow>>8, cycles);\r
+            }\r
+          }\r
+          return 0;\r
+        }\r
+        case 0x26: // timer B\r
+          if (ym2612.OPN.ST.TB != d) {\r
+            //elprintf(EL_STATUS, "timer b set %i", d);\r
+            ym2612.OPN.ST.TB = d;\r
+            //ym2612.OPN.ST.TBC  = (256-d)<<4;\r
+            //ym2612.OPN.ST.TBC *= 18;\r
+            //ym2612.OPN.ST.TBT  = 0;\r
+          }\r
+          return 0;\r
+        case 0x27: { /* mode, timer control */\r
+          int old_mode = ym2612.OPN.ST.mode;\r
+          int xcycles = is_from_z80 ? z80_cyclesDone() : cycles_68k_to_z80(SekCyclesDone());\r
+          xcycles <<= 8;\r
+\r
+          //elprintf(EL_STATUS, "st mode %02x", d);\r
+\r
+          if ((ym2612.OPN.ST.mode & 5) != 5 && (d & 5) == 5) {\r
+            timer_a_next_oflow = xcycles + timer_a_step;\r
+            //elprintf(EL_STATUS, "set to %i @ %i st", timer_a_next_oflow>>8, xcycles >> 8);\r
+          }\r
+\r
+          /* reset Timer b flag */\r
+          if (d & 0x20)\r
+            ym2612.OPN.ST.status &= ~2;\r
+\r
+          /* reset Timer a flag */\r
+          if (d & 0x10) {\r
+            if (ym2612.OPN.ST.status & 1)\r
+              while (xcycles > timer_a_next_oflow)\r
+                timer_a_next_oflow += timer_a_step;\r
+            ym2612.OPN.ST.status &= ~1;\r
+          }\r
+          if (!(d & 5)) timer_a_next_oflow = 0x80000000;\r
+          ym2612.OPN.ST.mode = d;\r
+#ifdef __GP2X__\r
+          if (PicoOpt & POPT_EXT_FM) YM2612Write_940(a, d, get_scanline(is_from_z80));\r
+#endif\r
+          return 0;\r
+        }\r
+        case 0x2b: { /* DAC Sel  (YM2612) */\r
+          int scanline = get_scanline(is_from_z80);\r
+          ym2612.dacen = d & 0x80;\r
+          if (d & 0x80) PsndDacLine = scanline;\r
+#ifdef __GP2X__\r
+          if (PicoOpt & POPT_EXT_FM) YM2612Write_940(a, d, scanline);\r
+#endif\r
+          return 0;\r
+        }\r
+      }\r
+      break;\r
+\r
+    case 2: /* address port 1 */\r
+      ym2612.OPN.ST.address = d;\r
+      ym2612.addr_A1 = 1;\r
+#ifdef __GP2X__\r
+      if (PicoOpt & POPT_EXT_FM) YM2612Write_940(a, d, -1);\r
+#endif\r
+      return 0;\r
+\r
+    case 3: /* data port 1    */\r
+      if (ym2612.addr_A1 != 1)\r
+        return 0;\r
+\r
+      addr = ym2612.OPN.ST.address | 0x100;\r
+      ym2612.REGS[addr] = d;\r
+      break;\r
+  }\r
+\r
+#ifdef __GP2X__\r
+  if (PicoOpt & POPT_EXT_FM)\r
+    return YM2612Write_940(a, d, get_scanline(is_from_z80));\r
+#endif\r
+  return YM2612Write_(a, d);\r
+}\r
+\r
+// TODO: timer b, 68k side + asm, savestates\r
+u32 ym2612_read_local_z80(void)\r
+{\r
+  int xcycles = z80_cyclesDone() << 8;\r
+  if (timer_a_next_oflow != 0x80000000 && xcycles >= timer_a_next_oflow) {\r
+    ym2612.OPN.ST.status |= 1;\r
+  }\r
+\r
+  //elprintf(EL_STATUS, "timer %i, sched %i, @ %i|%i", ym2612.OPN.ST.status, timer_a_next_oflow>>8,\r
+  //     xcycles >> 8, (xcycles >> 8) / 228);\r
+  return ym2612.OPN.ST.status;\r
+}\r
+\r
 // -----------------------------------------------------------------\r
 //                        z80 memhandlers\r
 \r
@@ -696,7 +858,7 @@ PICO_INTERNAL unsigned char z80_read(unsigned short a)
 \r
   if ((a>>13)==2) // 0x4000-0x5fff (Charles MacDonald)\r
   {\r
-    if (PicoOpt&POPT_EN_FM) ret = (u8) YM2612Read();\r
+    if (PicoOpt&POPT_EN_FM) ret = ym2612_read_local_z80();\r
     return ret;\r
   }\r
 \r
@@ -710,7 +872,10 @@ PICO_INTERNAL unsigned char z80_read(unsigned short a)
     if (PicoAHW & PAHW_MCD)\r
          ret = PicoReadM68k8(addr68k);\r
     else ret = PicoRead8(addr68k);\r
-    elprintf(EL_Z80BNK, "z80->68k r8 [%06x] %02x", addr68k, ret);\r
+    if (addr68k >= 0x400000) // not many games do this\r
+      { elprintf(EL_ANOMALY, "z80->68k upper read [%06x] %02x", addr68k, ret); }\r
+    else\r
+      { elprintf(EL_Z80BNK, "z80->68k r8 [%06x] %02x", addr68k, ret); }\r
     return ret;\r
   }\r
 \r
@@ -729,7 +894,7 @@ PICO_INTERNAL_ASM void z80_write(unsigned int a, unsigned char data)
 {\r
   if ((a>>13)==2) // 0x4000-0x5fff (Charles MacDonald)\r
   {\r
-    if(PicoOpt&POPT_EN_FM) emustatus|=YM2612Write(a, data) & 1;\r
+    if(PicoOpt&POPT_EN_FM) emustatus|=ym2612_write_local(a, data, 1) & 1;\r
     return;\r
   }\r
 \r
index 368b640..dbe76ac 100644 (file)
@@ -879,27 +879,21 @@ m_write8_z80_not_ram:
     and     r2, r0, #0x6000\r
     cmp     r2,     #0x4000\r
     bne     m_write8_z80_not_ym2612\r
-    ldr     r2, =PicoOpt\r
+    ldr     r3, =PicoOpt\r
     and     r0, r0, #3\r
-    ldr     r2, [r2]\r
-    tst     r2, #1\r
+    ldr     r3, [r3]\r
+    mov     r2, #0           @ is_from_z80 = 0\r
+    tst     r3, #1\r
     bxeq    lr\r
     stmfd   sp!,{lr}\r
-.if EXTERNAL_YM2612\r
-    tst     r2, #0x200\r
-    ldreq   r2, =YM2612Write_\r
-    ldrne   r2, =YM2612Write_940\r
-    mov     lr, pc\r
-    bx      r2\r
-.else\r
-    bl      YM2612Write_\r
-.endif\r
+    and     r1, r1, #0xff\r
+    bl      ym2612_write_local\r
     ldr     r2, =emustatus\r
     ldmfd   sp!,{lr}\r
     ldr     r1, [r2]\r
     and     r0, r0, #1\r
     orr     r1, r0, r1\r
-    str     r1, [r2]         @ emustatus|=YM2612Write(a&3, d);\r
+    str     r1, [r2]         @ emustatus|=ym2612_write_local(a&3, d);\r
     bx      lr\r
 \r
 m_write8_z80_not_ym2612:     @ not too likely\r
@@ -916,7 +910,7 @@ m_write8_z80_not_ym2612:     @ not too likely
 m_write8_z80_bank_reg:\r
     ldr     r3, =(Pico+0x22208) @ Pico.m\r
     ldrh    r2, [r3, #0x0a]\r
-    mov     r1, r1, lsr #8\r
+    mov     r1, r1, lsl #8\r
     orr     r2, r1, r2, lsr #1\r
     bic     r2, r2, #0xfe00\r
     strh    r2, [r3, #0x0a]\r
@@ -932,7 +926,7 @@ m_write8_not_z80:
     bne     OtherWrite8\r
 m_write8_psg:\r
     ldr     r2, =PicoOpt\r
-    mov     r0, r1\r
+    and     r0, r1, #0xff\r
     ldr     r2, [r2]\r
     tst     r2, #2\r
     bxeq    lr\r
index 62e6867..2cf8e8d 100644 (file)
@@ -69,25 +69,14 @@ void z80WriteBusReq(u32 d)
   {
     if (!d)
     {
-      // this is for a nasty situation where Z80 was enabled and disabled in the same 68k timeslice (Golden Axe III)
       if ((PicoOpt&POPT_EN_Z80) && Pico.m.z80Run)
       {
-        int lineCycles;
         z80stopCycle = SekCyclesDone();
-        if ((Pico.m.z80Run&2) && Pico.m.scanline != -1)
-             lineCycles=(488-SekCyclesLeft)&0x1ff;
-        else lineCycles=z80stopCycle-z80startCycle; // z80 was started at current line
-        if (lineCycles > 0) { // && lineCycles <= 488) {
-          //dprintf("zrun: %i/%i cycles", lineCycles, (lineCycles>>1)-(lineCycles>>5));
-          lineCycles=(lineCycles>>1)-(lineCycles>>5);
-          z80_run_nr(lineCycles);
-        }
+       PicoSyncZ80(z80stopCycle);
       }
     } else {
       if (!Pico.m.z80Run)
-        z80startCycle = SekCyclesDone();
-      else
-        d|=Pico.m.z80Run;
+        z80_cycle_cnt = cycles_68k_to_z80(SekCyclesDone());
     }
   }
   elprintf(EL_BUSREQ, "set_zrun: %i->%i [%i] @%06x", Pico.m.z80Run, d, SekCyclesDone(), SekPc);
@@ -169,12 +158,12 @@ void OtherWrite8(u32 a,u32 d)
   if ((a&0xff4000)==0xa00000) { // z80 RAM
     if (!(Pico.m.z80Run&1)) Pico.zram[a&0x1fff]=(u8)d;
     else {
-      elprintf(EL_ANOMALY, "68k z80 write with no bus! [%06x] %02x @ %06x", a, d, SekPc);
+      elprintf(EL_ANOMALY, "68k z80 write with no bus! [%06x] %02x @ %06x", a, d&0xff, SekPc);
       SekCyclesBurn(4); // hack?
     }
     return;
   }
-  if ((a&0xff6000)==0xa04000)  { if(PicoOpt&1) emustatus|=YM2612Write(a&3, d)&1; return; } // FM Sound
+  if ((a&0xff6000)==0xa04000)  { if(PicoOpt&1) emustatus|=ym2612_write_local(a&3, d&0xff, 0)&1; return; } // FM Sound
   if ((a&0xffffe0)==0xa10000)  { IoWrite8(a, d); return; } // I/O ports
 #endif
   if (a==0xa11100)             { z80WriteBusReq(d); return; }
@@ -185,6 +174,7 @@ void OtherWrite8(u32 a,u32 d)
       Pico.m.z80_reset = 0;
       YM2612ResetChip();
       z80_reset();
+      timers_reset();
     }
     return;
   }
@@ -204,7 +194,7 @@ void OtherWrite8(u32 a,u32 d)
     return;
   }
 
-  PicoWrite8Hook(a, d, 8);
+  PicoWrite8Hook(a, d&0xff, 8);
 }
 
 
@@ -216,10 +206,10 @@ void OtherWrite16(u32 a,u32 d)
   if (a==0xa11100)            { z80WriteBusReq(d>>8); return; }
   if ((a&0xffffe0)==0xa10000) { IoWrite8(a, d); return; } // I/O ports
   if ((a&0xe700f8)==0xc00010||(a&0xff7ff8)==0xa07f10) { if(PicoOpt&2) SN76496Write(d); return; } // PSG Sound
-  if ((a&0xff6000)==0xa04000) { if(PicoOpt&1) emustatus|=YM2612Write(a&3, d)&1; return; } // FM Sound (??)
+  if ((a&0xff6000)==0xa04000) { if(PicoOpt&1) emustatus|=ym2612_write_local(a&3, d&0xff, 0)&1; return; } // FM Sound
   if ((a&0xff4000)==0xa00000) { // Z80 ram (MSB only)
     if (!(Pico.m.z80Run&1)) Pico.zram[a&0x1fff]=(u8)(d>>8);
-    else elprintf(EL_ANOMALY, "68k z80 write with no bus! [%06x] %02x @ %06x", a, d, SekPc);
+    else elprintf(EL_ANOMALY, "68k z80 write with no bus! [%06x] %02x @ %06x", a, d&0xffff, SekPc);
     return;
   }
   if (a==0xa11200) {
@@ -229,6 +219,7 @@ void OtherWrite16(u32 a,u32 d)
       Pico.m.z80_reset = 0;
       YM2612ResetChip();
       z80_reset();
+      timers_reset();
     }
     return;
   }
@@ -256,6 +247,6 @@ void OtherWrite16(u32 a,u32 d)
   }
 #endif
 
-  PicoWrite16Hook(a, d, 16);
+  PicoWrite16Hook(a, d&0xffff, 16);
 }
 
index d206fcb..93d04e7 100644 (file)
@@ -19,7 +19,6 @@ int PicoPad[2];        // Joypads, format is SACB RLDU
 int PicoAHW = 0;       // active addon hardware: scd_active, 32x_active, svp_active, pico_active\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 z80startCycle, z80stopCycle; // in 68k cycles\r
 struct PicoSRAM SRam = {0,};\r
 \r
 void (*PicoWriteSound)(int len) = NULL; // called at the best time to send sound buffer (PsndOut) to hardware\r
@@ -307,62 +306,54 @@ static __inline void getSamples(int y)
 \r
 #include "PicoFrameHints.c"\r
 \r
-// helper z80 runner. Runs only if z80 is enabled at this point\r
-// (z80WriteBusReq will handle the rest)\r
-static void PicoRunZ80Simple(int line_from, int line_to)\r
+\r
+int z80stopCycle;\r
+int z80_cycle_cnt;        /* 'done' z80 cycles before z80_run() */\r
+int z80_cycle_aim;\r
+int z80_scanline;\r
+int z80_scanline_cycles;  /* cycles done until z80_scanline */\r
+\r
+/* sync z80 to 68k */\r
+PICO_INTERNAL void PicoSyncZ80(int m68k_cycles_done)\r
 {\r
-  int line_from_r=line_from, line_to_r=line_to, line=0;\r
-  int line_sample = Pico.m.pal ? 68 : 93;\r
-\r
-  if (!(PicoOpt&POPT_EN_Z80) || Pico.m.z80Run == 0) line_to_r = 0;\r
-  else {\r
-    extern const unsigned short vcounts[];\r
-    if (z80startCycle) {\r
-      line = vcounts[z80startCycle>>8];\r
-      if (line > line_from)\r
-        line_from_r = line;\r
-    }\r
-    z80startCycle = SekCyclesDone();\r
-  }\r
+  int cnt;\r
+  z80_cycle_aim = cycles_68k_to_z80(m68k_cycles_done);\r
+  cnt = z80_cycle_aim - z80_cycle_cnt;\r
 \r
-  if (PicoOpt&POPT_EN_FM) {\r
-    // we have ym2612 enabled, so we have to run Z80 in lines, so we could update DAC and timers\r
-    for (line = line_from; line < line_to; line++) {\r
-      Psnd_timers_and_dac(line);\r
-      if ((line == 224 || line == line_sample) && PsndOut) getSamples(line);\r
-      if (line == 32 && PsndOut) emustatus &= ~1;\r
-      if (line >= line_from_r && line < line_to_r)\r
-        z80_run_nr(228);\r
-    }\r
-  } else if (line_to_r-line_from_r > 0) {\r
-    z80_run_nr(228*(line_to_r-line_from_r));\r
-    // samples will be taken by caller\r
-  }\r
+  elprintf(EL_ANOMALY, "z80 sync %i (%i|%i -> %i|%i)", cnt, z80_cycle_cnt, z80_cycle_cnt / 228,\r
+    z80_cycle_aim, z80_cycle_aim / 228);\r
+\r
+  if (cnt > 0)\r
+    z80_cycle_cnt += z80_run(cnt);\r
 }\r
 \r
+\r
 // Simple frame without H-Ints\r
 static int PicoFrameSimple(void)\r
 {\r
   struct PicoVideo *pv=&Pico.video;\r
-  int y=0,line=0,lines=0,lines_step=0,sects;\r
+  int y=0,lines_step=0,sects,line_last;\r
   int cycles_68k_vblock,cycles_68k_block;\r
 \r
   // split to 16 run calls for active scan, for vblank split to 2 (ntsc), 3 (pal 240), 4 (pal 224)\r
-  if (Pico.m.pal && (pv->reg[1]&8)) {\r
+  if (Pico.m.pal)\r
+  {\r
     if(pv->reg[1]&8) { // 240 lines\r
-      cycles_68k_block  = 7329;  // (488*240+148)/16.0, -4\r
-      cycles_68k_vblock = 11640; // (72*488-148-68)/3.0, 0\r
+      cycles_68k_block  = 7308;\r
+      cycles_68k_vblock = 11694;\r
       lines_step = 15;\r
     } else {\r
-      cycles_68k_block  = 6841;  // (488*224+148)/16.0, -4\r
-      cycles_68k_vblock = 10682; // (88*488-148-68)/4.0, 0\r
+      cycles_68k_block  = 6821;\r
+      cycles_68k_vblock = 10719;\r
       lines_step = 14;\r
     }\r
+    line_last = 312-1;\r
   } else {\r
     // M68k cycles/frame: 127840.71\r
     cycles_68k_block  = 6841; // (488*224+148)/16.0, -4\r
     cycles_68k_vblock = 9164; // (38*488-148-68)/2.0, 0\r
     lines_step = 14;\r
+    line_last = 262-1;\r
   }\r
 \r
   // a hack for VR, to get it running in fast mode\r
@@ -380,9 +371,11 @@ static int PicoFrameSimple(void)
   Pico.video.status|=0x200;\r
 \r
   Pico.m.scanline=-1;\r
-  z80startCycle=0;\r
+  PsndDacLine = 0;\r
 \r
   SekCyclesReset();\r
+  z80_resetCycles();\r
+  timers_cycle();\r
 \r
   // 6 button pad: let's just say it timed out now\r
   Pico.m.padTHPhase[0]=Pico.m.padTHPhase[1]=0;\r
@@ -391,28 +384,19 @@ static int PicoFrameSimple(void)
   pv->status&=~0x88; // clear V-Int, come out of vblank\r
 \r
   // Run in sections:\r
-  for(sects=16; sects; sects--)\r
+  for (sects=16; sects; sects--)\r
   {\r
     if (CheckIdle()) break;\r
 \r
-    lines += lines_step;\r
     SekRunM68k(cycles_68k_block);\r
-\r
-    PicoRunZ80Simple(line, lines);\r
     if (PicoLineHook) PicoLineHook(lines_step);\r
-    line=lines;\r
   }\r
 \r
-  // run Z80 for remaining sections\r
-  if(sects) {\r
-    int c = sects*cycles_68k_block;\r
-\r
-    // this "run" is for approriate line counter, etc\r
-    SekCycleCnt += c;\r
-    SekCycleAim += c;\r
+  // do remaining sections without 68k\r
+  if (sects) {\r
+    SekCycleCnt += sects * cycles_68k_block;\r
+    SekCycleAim += sects * cycles_68k_block;\r
 \r
-    lines += sects*lines_step;\r
-    PicoRunZ80Simple(line, lines);\r
     if (PicoLineHook) PicoLineHook(sects*lines_step);\r
   }\r
 \r
@@ -446,33 +430,37 @@ static int PicoFrameSimple(void)
 #endif\r
   }\r
 \r
-  // here we render sound if ym2612 is disabled\r
-  if (!(PicoOpt&POPT_EN_FM) && PsndOut) {\r
-    int len = PsndRender(0, PsndLen);\r
-    if (PicoWriteSound) PicoWriteSound(len);\r
-    // clear sound buffer\r
-    PsndClear();\r
-  }\r
-\r
   // a gap between flags set and vint\r
   pv->pending_ints|=0x20;\r
   pv->status|=8; // go into vblank\r
   SekRunM68k(68+4);\r
 \r
+  if (Pico.m.z80Run && (PicoOpt&POPT_EN_Z80))\r
+    PicoSyncZ80(SekCycleCnt);\r
+\r
+  // render sound\r
+  if (PsndOut)\r
+  {\r
+    int len;\r
+    if (ym2612.dacen && PsndDacLine <= lines_step*16)\r
+      PsndDoDAC(lines_step*16);\r
+    len = PsndRender(0, PsndLen);\r
+    if (PicoWriteSound) PicoWriteSound(len);\r
+    // clear sound buffer\r
+    PsndClear();\r
+  }\r
+\r
   // ---- V-Blanking period ----\r
   // fix line counts\r
   if(Pico.m.pal) {\r
     if(pv->reg[1]&8) { // 240 lines\r
-      lines = line = 240;\r
       sects = 3;\r
       lines_step = 24;\r
     } else {\r
-      lines = line = 224;\r
       sects = 4;\r
       lines_step = 22;\r
     }\r
   } else {\r
-    lines = line = 224;\r
     sects = 2;\r
     lines_step = 19;\r
   }\r
@@ -481,27 +469,28 @@ static int PicoFrameSimple(void)
   if (Pico.m.z80Run && (PicoOpt&POPT_EN_Z80))\r
     z80_int();\r
 \r
-  while (sects)\r
+  while (1)\r
   {\r
-    lines += lines_step;\r
-\r
     SekRunM68k(cycles_68k_vblock);\r
-\r
-    PicoRunZ80Simple(line, lines);\r
     if (PicoLineHook) PicoLineHook(lines_step);\r
-    line=lines;\r
 \r
     sects--;\r
-    if (sects && CheckIdle()) break;\r
+    if (sects == 0) break;\r
+    if (CheckIdle()) break;\r
   }\r
 \r
-  // run Z80 for remaining sections\r
   if (sects) {\r
-    lines += sects*lines_step;\r
-    PicoRunZ80Simple(line, lines);\r
+    SekCycleCnt += sects * cycles_68k_vblock;\r
+    SekCycleAim += sects * cycles_68k_vblock;\r
     if (PicoLineHook) PicoLineHook(sects*lines_step);\r
   }\r
 \r
+  // must sync z80 before return, and extend last DAC sample\r
+  if (Pico.m.z80Run && (PicoOpt&POPT_EN_Z80))\r
+    PicoSyncZ80(SekCycleCnt);\r
+  if (PsndOut && ym2612.dacen && PsndDacLine <= line_last)\r
+    PsndDoDAC(line_last);\r
+\r
   return 0;\r
 }\r
 \r
@@ -556,7 +545,6 @@ void PicoGetInternal(pint_t which, pint_ret_t *r)
 void (*PicoMessage)(const char *msg)=NULL;\r
 \r
 #if 1 // defined(__DEBUG_PRINT)\r
-// tmp debug: dump some stuff\r
 #define bit(r, x) ((r>>x)&1)\r
 void z80_debug(char *dstr);\r
 char *debugString(void)\r
index d1efa9a..0d414b2 100644 (file)
     if(Pico.m.padDelay[1]++ > 25) Pico.m.padTHPhase[1]=0; \
   }
 
-#define Z80_RUN(z80_cycles) \
-{ \
-  if ((PicoOpt&POPT_EN_Z80) && Pico.m.z80Run) \
-  { \
-    int cnt; \
-    if (Pico.m.z80Run & 2) z80CycleAim += z80_cycles; \
-    else { \
-      cnt = SekCyclesDone() - z80startCycle; \
-      cnt = (cnt>>1)-(cnt>>5); \
-      if (cnt < 0 || cnt > (z80_cycles)) cnt = z80_cycles; \
-      Pico.m.z80Run |= 2; \
-      z80CycleAim+=cnt; \
-    } \
-    cnt=z80CycleAim-total_z80; \
-    if (cnt > 0) total_z80+=z80_run(cnt); \
-  } \
-}
-
 // CPUS_RUN
 #ifndef PICO_CD
 #define CPUS_RUN(m68k_cycles,z80_cycles,s68k_cycles) \
-    SekRunM68k(m68k_cycles); \
-    Z80_RUN(z80_cycles);
+    SekRunM68k(m68k_cycles);
 #else
 #define CPUS_RUN(m68k_cycles,z80_cycles,s68k_cycles) \
 { \
@@ -49,7 +30,6 @@
       if ((Pico_mcd->m.busreq&3) == 1) /* no busreq/no reset */ \
         SekRunS68k(s68k_cycles); \
     } \
-    Z80_RUN(z80_cycles); \
 }
 #endif
 
@@ -57,7 +37,7 @@
 static int PicoFrameHints(void)
 {
   struct PicoVideo *pv=&Pico.video;
-  int lines, y, lines_vis = 224, total_z80 = 0, z80CycleAim = 0, line_sample, skip;
+  int lines, y, lines_vis = 224, line_sample, skip;
   int hint; // Hint counter
 
   if ((PicoOpt&POPT_ALT_RENDERER) && !PicoSkipFrame && (pv->reg[1]&0x40)) { // fast rend., display enabled
@@ -72,20 +52,19 @@ static int PicoFrameHints(void)
   else skip=PicoSkipFrame;
 
   if (Pico.m.pal) {
-    //cycles_68k = (int) ((double) OSC_PAL  /  7 / 50 / 312 + 0.4); // should compile to a constant (488)
-    //cycles_z80 = (int) ((double) OSC_PAL  / 15 / 50 / 312 + 0.4); // 228
     line_sample = 68;
     if(pv->reg[1]&8) lines_vis = 240;
   } else {
-    //cycles_68k = (int) ((double) OSC_NTSC /  7 / 60 / 262 + 0.4); // 488
-    //cycles_z80 = (int) ((double) OSC_NTSC / 15 / 60 / 262 + 0.4); // 228
     line_sample = 93;
   }
 
   SekCyclesReset();
+  z80_resetCycles();
 #ifdef PICO_CD
   SekCyclesResetS68k();
 #endif
+  timers_cycle();
+  PsndDacLine = 0;
 
   pv->status&=~0x88; // clear V-Int, come out of vblank
 
@@ -93,8 +72,6 @@ static int PicoFrameHints(void)
   //dprintf("-hint: %i", hint);
 
   // This is to make active scan longer (needed for Double Dragon 2, mainly)
-  // also trying to adjust for z80 overclock here (due to int line cycle counts)
-  z80CycleAim = Pico.m.pal ? -40 : 7;
   CPUS_RUN(CYCLES_M68K_ASD, 0, CYCLES_S68K_ASD);
 
   for (y=0;y<lines_vis;y++)
@@ -148,15 +125,18 @@ static int PicoFrameHints(void)
       }
     }
 
-    if (PicoOpt&POPT_EN_FM)
-      Psnd_timers_and_dac(y);
-
 #ifndef PICO_CD
     // get samples from sound chips
     if (y == 32 && PsndOut)
       emustatus &= ~1;
     else if ((y == 224 || y == line_sample) && PsndOut)
+    {
+      if (Pico.m.z80Run && (PicoOpt&POPT_EN_Z80))
+        PicoSyncZ80(SekCycleCnt);
+      if (ym2612.dacen && PsndDacLine <= y)
+        PsndDoDAC(y);
       getSamples(y);
+    }
 #endif
 
     // Run scanline:
@@ -205,24 +185,27 @@ static int PicoFrameHints(void)
   // also delay between F bit (bit 7) is set in SR and IRQ happens (Ex-Mutants)
   // also delay between last H-int and V-int (Golden Axe 3)
   SekRunM68k(CYCLES_M68K_VINT_LAG);
+
   if (pv->reg[1]&0x20) {
     elprintf(EL_INTS, "vint: @ %06x [%i]", SekPc, SekCycleCnt);
     SekInterrupt(6);
   }
   if (Pico.m.z80Run && (PicoOpt&POPT_EN_Z80)) {
+    PicoSyncZ80(SekCycleCnt);
     elprintf(EL_INTS, "zint");
     z80_int();
   }
 
-  if (PicoOpt&POPT_EN_FM)
-    Psnd_timers_and_dac(y);
-
   // get samples from sound chips
 #ifndef PICO_CD
   if (y == 224)
 #endif
     if (PsndOut)
+    {
+      if (ym2612.dacen && PsndDacLine <= y)
+        PsndDoDAC(y);
       getSamples(y);
+    }
 
   // Run scanline:
   if (Pico.m.dma_xfers) SekCyclesBurn(CheckDMA());
@@ -247,9 +230,6 @@ static int PicoFrameHints(void)
     check_cd_dma();
 #endif
 
-    if (PicoOpt&POPT_EN_FM)
-      Psnd_timers_and_dac(y);
-
     // Run scanline:
     if (Pico.m.dma_xfers) SekCyclesBurn(CheckDMA());
     CPUS_RUN(CYCLES_M68K_LINE, CYCLES_Z80_LINE, CYCLES_S68K_LINE);
@@ -261,6 +241,12 @@ static int PicoFrameHints(void)
 #endif
   }
 
+  // sync z80
+  if (Pico.m.z80Run && (PicoOpt&POPT_EN_Z80))
+    PicoSyncZ80(SekCycleCnt);
+  if (PsndOut && ym2612.dacen && PsndDacLine <= lines-1)
+    PsndDoDAC(lines-1);
+
   return 0;
 }
 
index d348598..8525198 100644 (file)
@@ -137,7 +137,7 @@ extern unsigned int SekCycleCntT; // total cycle counter, updated once per frame
        SekCycleAim=0; \\r
 }\r
 #define SekCyclesBurn(c)  SekCycleCnt+=c\r
-#define SekCyclesDone()  (SekCycleAim-SekCyclesLeft)    // nuber of cycles done in this frame (can be checked anywhere)\r
+#define SekCyclesDone()  (SekCycleAim-SekCyclesLeft)    // number of cycles done in this frame (can be checked anywhere)\r
 #define SekCyclesDoneT() (SekCycleCntT+SekCyclesDone()) // total nuber of cycles done for this rom\r
 \r
 #define SekEndRun(after) { \\r
@@ -174,10 +174,9 @@ extern int dbg_irq_level;
 #if defined(_USE_MZ80)\r
 #include "../cpu/mz80/mz80.h"\r
 \r
-#define z80_run(cycles)    mz80_run(cycles)\r
+#define z80_run(cycles)    { mz80GetElapsedTicks(1); mz80_run(cycles) }\r
 #define z80_run_nr(cycles) mz80_run(cycles)\r
 #define z80_int()          mz80int(0)\r
-#define z80_resetCycles()  mz80GetElapsedTicks(1)\r
 \r
 #elif defined(_USE_DRZ80)\r
 #include "../cpu/DrZ80/drz80.h"\r
@@ -190,7 +189,8 @@ extern struct DrZ80 drZ80;
   drZ80.z80irqvector = 0xFF; /* default IRQ vector RST opcode */ \\r
   drZ80.Z80_IRQ = 1; \\r
 }\r
-#define z80_resetCycles()\r
+\r
+#define z80_cyclesLeft     drZ80.cycles\r
 \r
 #elif defined(_USE_CZ80)\r
 #include "../cpu/cz80/cz80.h"\r
@@ -198,17 +198,31 @@ extern struct DrZ80 drZ80;
 #define z80_run(cycles)    Cz80_Exec(&CZ80, cycles)\r
 #define z80_run_nr(cycles) Cz80_Exec(&CZ80, cycles)\r
 #define z80_int()          Cz80_Set_IRQ(&CZ80, 0, HOLD_LINE)\r
-#define z80_resetCycles()\r
+\r
+#define z80_cyclesLeft     (CZ80.ICount - CZ80.ExtraCycles)\r
 \r
 #else\r
 \r
 #define z80_run(cycles)    (cycles)\r
 #define z80_run_nr(cycles)\r
 #define z80_int()\r
-#define z80_resetCycles()\r
 \r
 #endif\r
 \r
+extern int z80stopCycle;         /* in 68k cycles */\r
+extern int z80_cycle_cnt;        /* 'done' z80 cycles before z80_run() */\r
+extern int z80_cycle_aim;\r
+extern int z80_scanline;\r
+extern int z80_scanline_cycles;  /* cycles done until z80_scanline */\r
+\r
+#define z80_resetCycles() \\r
+  z80_cycle_cnt = z80_cycle_aim = z80_scanline = z80_scanline_cycles = 0;\r
+\r
+#define z80_cyclesDone() \\r
+  (z80_cycle_aim - z80_cyclesLeft)\r
+\r
+#define cycles_68k_to_z80(x) ((x)*957 >> 11)\r
+\r
 // ---------------------------------------------------------\r
 \r
 // main oscillator clock which controls timing\r
@@ -405,6 +419,7 @@ PICO_INTERNAL unsigned short z80_read16(unsigned short a);
 #else\r
 PICO_INTERNAL_ASM void z80_write(unsigned int a, unsigned char data);\r
 #endif\r
+PICO_INTERNAL int ym2612_write_local(unsigned int a, unsigned int d, int is_from_z80);\r
 extern unsigned int (*PicoRead16Hook)(unsigned int a, int realsize);\r
 extern void (*PicoWrite8Hook) (unsigned int a,unsigned int d,int realsize);\r
 extern void (*PicoWrite16Hook)(unsigned int a,unsigned int d,int realsize);\r
@@ -421,11 +436,11 @@ PICO_INTERNAL void PicoMemSetupPico(void);
 extern struct Pico Pico;\r
 extern struct PicoSRAM SRam;\r
 extern int emustatus;\r
-extern int z80startCycle, z80stopCycle; // in 68k cycles\r
 extern void (*PicoResetHook)(void);\r
 extern void (*PicoLineHook)(int count);\r
 PICO_INTERNAL int  CheckDMA(void);\r
 PICO_INTERNAL void PicoDetectRegion(void);\r
+PICO_INTERNAL void PicoSyncZ80(int m68k_cycles_done);\r
 \r
 // cd/Pico.c\r
 PICO_INTERNAL int  PicoInitMCD(void);\r
@@ -459,6 +474,13 @@ PICO_INTERNAL void cdda_start_play();
 extern short cdda_out_buffer[2*1152];\r
 extern int PsndLen_exc_cnt;\r
 extern int PsndLen_exc_add;\r
+extern int timer_a_next_oflow, timer_a_step; // in z80 cycles\r
+\r
+#define timers_cycle() \\r
+  if (timer_a_next_oflow > 0) timer_a_next_oflow -= Pico.m.pal ? 70938*256 : 59659*256\r
+\r
+#define timers_reset() \\r
+  timer_a_next_oflow = 0x80000000\r
 \r
 // VideoPort.c\r
 PICO_INTERNAL_ASM void PicoVideoWrite(unsigned int a,unsigned short d);\r
@@ -483,7 +505,7 @@ PICO_INTERNAL void PicoCDBufferRead(void *dest, int lba);
 \r
 // sound/sound.c\r
 PICO_INTERNAL void PsndReset(void);\r
-PICO_INTERNAL void Psnd_timers_and_dac(int raster);\r
+PICO_INTERNAL void PsndDoDAC(int line_to);\r
 PICO_INTERNAL int  PsndRender(int offset, int length);\r
 PICO_INTERNAL void PsndClear(void);\r
 // z80 functionality wrappers\r
@@ -492,7 +514,7 @@ PICO_INTERNAL void z80_pack(unsigned char *data);
 PICO_INTERNAL void z80_unpack(unsigned char *data);\r
 PICO_INTERNAL void z80_reset(void);\r
 PICO_INTERNAL void z80_exit(void);\r
-\r
+extern int PsndDacLine;\r
 \r
 #ifdef __cplusplus\r
 } // End of extern "C"\r
index 1d6c168..6c7c6d8 100644 (file)
@@ -21,7 +21,7 @@ void (*PsndMix_32_to_16l)(short *dest, int *src, int count) = mix_32_to_16l_ster
 static int PsndBuffer[2*44100/50];\r
 \r
 // dac\r
-static unsigned short dac_info[312]; // pppppppp ppppllll, p - pos in buff, l - length to write for this sample\r
+static unsigned short dac_info[312+4]; // pppppppp ppppllll, p - pos in buff, l - length to write for this sample\r
 \r
 // cdda output buffer\r
 short cdda_out_buffer[2*1152];\r
@@ -31,8 +31,13 @@ int PsndRate=0;
 int PsndLen=0; // number of mono samples, multiply by 2 for stereo\r
 int PsndLen_exc_add=0; // this is for non-integer sample counts per line, eg. 22050/60\r
 int PsndLen_exc_cnt=0;\r
+int PsndDacLine=0;\r
 short *PsndOut=NULL; // PCM data buffer\r
 \r
+// timers\r
+int timer_a_next_oflow, timer_a_step; // in z80 cycles\r
+//int\r
+\r
 // sn76496\r
 extern int *sn76496_regs;\r
 \r
@@ -83,6 +88,8 @@ static void dac_recalculate(void)
     if (PsndLen_exc_add) len++;\r
     dac_info[224] = (pos<<4)|len;\r
   }\r
+  for (i = lines; i < sizeof(dac_info) / sizeof(dac_info[0]); i++)\r
+    dac_info[i] = 0;\r
   //for(i=len=0; i < lines; i++) {\r
   //  printf("%03i : %03i : %i\n", i, dac_info[i]>>4, dac_info[i]&0xf);\r
   //  len+=dac_info[i]&0xf;\r
@@ -100,7 +107,7 @@ PICO_INTERNAL void PsndReset(void)
   // also clear the internal registers+addr line\r
   ym2612_regs = YM2612GetRegs();\r
   memset(ym2612_regs, 0, 0x200+4);\r
-  z80startCycle = z80stopCycle = 0;\r
+  timers_reset();\r
 \r
   PsndRerate(0);\r
 }\r
@@ -164,44 +171,25 @@ void PsndRerate(int preserve_state)
 }\r
 \r
 \r
-// This is called once per raster (aka line), but not necessarily for every line\r
-PICO_INTERNAL void Psnd_timers_and_dac(int raster)\r
+PICO_INTERNAL void PsndDoDAC(int line_to)\r
 {\r
-  int pos, len;\r
-  int do_dac = PsndOut && (PicoOpt&POPT_EN_FM) && *ym2612_dacen;\r
-//  int do_pcm = PsndOut && (PicoAHW&1) && (PicoOpt&0x400);\r
-\r
-  // Our raster lasts 63.61323/64.102564 microseconds (NTSC/PAL)\r
-  YM2612PicoTick(1);\r
+  int pos, pos1, len;\r
+  int dout = ym2612.dacout;\r
+  int line_from = PsndDacLine;\r
 \r
-  if (!do_dac /*&& !do_pcm*/) return;\r
+  PsndDacLine = line_to + 1;\r
 \r
-  pos=dac_info[raster], len=pos&0xf;\r
+  pos =dac_info[line_from]>>4;\r
+  pos1=dac_info[line_to];\r
+  len = ((pos1>>4)-pos) + (pos1&0xf);\r
   if (!len) return;\r
 \r
-  pos>>=4;\r
-\r
-  if (do_dac)\r
-  {\r
+  if (PicoOpt & POPT_EN_STEREO) {\r
     short *d = PsndOut + pos*2;\r
-    int dout = *ym2612_dacout;\r
-    if(PicoOpt&POPT_EN_STEREO) {\r
-      // some manual loop unrolling here :)\r
-      d[0] = dout;\r
-      if (len > 1) {\r
-        d[2] = dout;\r
-        if (len > 2)\r
-          d[4] = dout;\r
-      }\r
-    } else {\r
-      short *d = PsndOut + pos;\r
-      d[0] = dout;\r
-      if (len > 1) {\r
-        d[1] = dout;\r
-        if (len > 2)\r
-          d[2] = dout;\r
-      }\r
-    }\r
+    for (; len > 0; len--, d+=2) *d = dout;\r
+  } else {\r
+    short *d = PsndOut + pos;\r
+    for (; len > 0; len--, d++)  *d = dout;\r
   }\r
 \r
 #if 0\r
index 144c334..b9749f2 100644 (file)
 #ifndef EXTERNAL_YM2612\r
 #include <stdlib.h>\r
 // let it be 1 global to simplify things\r
-static YM2612 ym2612;\r
+YM2612 ym2612;\r
 \r
 #else\r
 extern YM2612 *ym2612_940;\r
@@ -1584,11 +1584,8 @@ static int OPNWriteReg(int r, int v)
 /*      YM2612 local section                                                   */\r
 /*******************************************************************************/\r
 \r
-int   *ym2612_dacen;\r
-INT32 *ym2612_dacout;\r
 FM_ST *ym2612_st;\r
 \r
-\r
 /* Generate samples for YM2612 */\r
 int YM2612UpdateOne_(int *buffer, int length, int stereo, int is_buf_empty)\r
 {\r
@@ -1654,8 +1651,6 @@ int YM2612UpdateOne_(int *buffer, int length, int stereo, int is_buf_empty)
 void YM2612Init_(int clock, int rate)\r
 {\r
        // notaz\r
-       ym2612_dacen = &ym2612.dacen;\r
-       ym2612_dacout = &ym2612.dacout;\r
        ym2612_st = &ym2612.OPN.ST;\r
 \r
        memset(&ym2612, 0, sizeof(ym2612));\r
@@ -1728,9 +1723,6 @@ int YM2612Write_(unsigned int a, unsigned int v)
                }\r
 \r
                addr = ym2612.OPN.ST.address;\r
-#ifndef EXTERNAL_YM2612\r
-               ym2612.REGS[addr] = v;\r
-#endif\r
 \r
                switch( addr & 0xf0 )\r
                {\r
@@ -1747,6 +1739,7 @@ int YM2612Write_(unsigned int a, unsigned int v)
                                        ym2612.OPN.lfo_inc = 0;\r
                                }\r
                                break;\r
+#if 0 // handled elsewhere\r
                        case 0x24: { // timer A High 8\r
                                        int TAnew = (ym2612.OPN.ST.TA & 0x03)|(((int)v)<<2);\r
                                        if(ym2612.OPN.ST.TA != TAnew) {\r
@@ -1781,6 +1774,7 @@ int YM2612Write_(unsigned int a, unsigned int v)
                                set_timers( v );\r
                                ret=0;\r
                                break;\r
+#endif\r
                        case 0x28:      /* key on / off */\r
                                {\r
                                        UINT8 c;\r
@@ -1794,6 +1788,7 @@ int YM2612Write_(unsigned int a, unsigned int v)
                                        if(v&0x80) FM_KEYON(c,SLOT4); else FM_KEYOFF(c,SLOT4);\r
                                        break;\r
                                }\r
+#if 0\r
                        case 0x2a:      /* DAC data (YM2612) */\r
                                ym2612.dacout = ((int)v - 0x80) << 6;   /* level unknown (notaz: 8 seems to be too much) */\r
                                ret=0;\r
@@ -1803,6 +1798,7 @@ int YM2612Write_(unsigned int a, unsigned int v)
                                ym2612.dacen = v & 0x80;\r
                                ret=0;\r
                                break;\r
+#endif\r
                        default:\r
                                break;\r
                        }\r
@@ -1826,9 +1822,6 @@ int YM2612Write_(unsigned int a, unsigned int v)
                }\r
 \r
                addr = ym2612.OPN.ST.address | 0x100;\r
-#ifndef EXTERNAL_YM2612\r
-               ym2612.REGS[addr] = v;\r
-#endif\r
 \r
                ret = OPNWriteReg(addr, v);\r
                break;\r
index e87cbc1..39c3cf6 100644 (file)
@@ -141,10 +141,10 @@ typedef struct
 } YM2612;\r
 #endif\r
 \r
-extern int   *ym2612_dacen;\r
-extern INT32 *ym2612_dacout;\r
 extern FM_ST *ym2612_st;\r
-\r
+#ifndef EXTERNAL_YM2612\r
+extern YM2612 ym2612;\r
+#endif\r
 \r
 #define YM2612Read() ym2612_st->status\r
 \r
@@ -180,7 +180,6 @@ void *YM2612GetRegs(void);
 #define YM2612Init          YM2612Init_\r
 #define YM2612ResetChip     YM2612ResetChip_\r
 #define YM2612UpdateOne     YM2612UpdateOne_\r
-#define YM2612Write         YM2612Write_\r
 #define YM2612PicoStateLoad YM2612PicoStateLoad_\r
 #else\r
 /* GP2X specific */\r
@@ -197,8 +196,6 @@ extern int PicoOpt;
 #define YM2612UpdateOne(buffer,length,stereo,is_buf_empty) \\r
        (PicoOpt&0x200) ? YM2612UpdateOne_940(buffer, length, stereo, is_buf_empty) : \\r
                                YM2612UpdateOne_(buffer, length, stereo, is_buf_empty);\r
-#define YM2612Write(a,v) \\r
-       (PicoOpt&0x200) ?  YM2612Write_940(a, v) : YM2612Write_(a, v)\r
 #define YM2612PicoStateLoad() { \\r
        if (PicoOpt&0x200) YM2612PicoStateLoad_940(); \\r
        else               YM2612PicoStateLoad_(); \\r
index f217dea..8c8b18b 100644 (file)
@@ -51,160 +51,64 @@ static FILE *loaded_mp3 = 0;
 }\r
 \r
 /* these will be managed locally on our side */\r
-static UINT8 *REGS = 0;                /* we will also keep local copy of regs for savestates and such */\r
-static INT32 *addr_A1;         /* address line A1      */\r
-\r
-static int   dacen;\r
-static INT32 dacout;\r
 static UINT8 ST_address;       /* address register     */\r
+static INT32 addr_A1;          /* address line A1      */\r
 \r
 static int   writebuff_ptr = 0;\r
 \r
 \r
-/* OPN Mode Register Write */\r
-static int set_timers( int v )\r
-{\r
-       int change;\r
-\r
-       /* b7 = CSM MODE */\r
-       /* b6 = 3 slot mode */\r
-       /* b5 = reset b */\r
-       /* b4 = reset a */\r
-       /* b3 = timer enable b */\r
-       /* b2 = timer enable a */\r
-       /* b1 = load b */\r
-       /* b0 = load a */\r
-       change = (ym2612_st->mode ^ v) & 0xc0;\r
-       ym2612_st->mode = v;\r
-\r
-       /* reset Timer b flag */\r
-       if( v & 0x20 )\r
-               ym2612_st->status &= ~2;\r
-\r
-       /* reset Timer a flag */\r
-       if( v & 0x10 )\r
-               ym2612_st->status &= ~1;\r
-\r
-       return change;\r
-}\r
-\r
 /* YM2612 write */\r
 /* a = address */\r
 /* v = value   */\r
 /* returns 1 if sample affecting state changed */\r
-int YM2612Write_940(unsigned int a, unsigned int v)\r
+int YM2612Write_940(unsigned int a, unsigned int v, int scanline)\r
 {\r
-       int addr;\r
        int upd = 1;    /* the write affects sample generation */\r
 \r
-       v &= 0xff;      /* adjust to 8 bit bus */\r
        a &= 3;\r
 \r
        //printf("%05i:%03i: ym w ([%i] %02x)\n", Pico.m.frame_count, Pico.m.scanline, a, v);\r
 \r
-       switch( a ) {\r
-       case 0: /* address port 0 */\r
-               if (!*addr_A1 && ST_address == v)\r
-                       return 0;       /* address already selected, don't send this command to 940 */\r
-               ST_address = v;\r
-               /* don't send DAC or timer related address changes to 940 */\r
-               if (!*addr_A1 && (v & 0xf0) == 0x20 &&\r
-                       (v == 0x24 || v == 0x25 || v == 0x26 || v == 0x2a))\r
+       switch (a) {\r
+               case 0: /* address port 0 */\r
+                       if (addr_A1 == 0 && ST_address == v)\r
+                               return 0; /* address already selected, don't send this command to 940 */\r
+                       ST_address = v;\r
+                       addr_A1 = 0;\r
+                       /* don't send DAC or timer related address changes to 940 */\r
+                       if (v == 0x24 || v == 0x25 || v == 0x26 || v == 0x2a)\r
                                return 0;\r
-               *addr_A1 = 0;\r
-               upd = 0;\r
-               break;\r
-\r
-       case 1: /* data port 0    */\r
-               if (*addr_A1 != 0) {\r
-                       return 0;       /* verified on real YM2608 */\r
-               }\r
+                       upd = 0;\r
+                       break;\r
 \r
-               addr = ST_address;\r
-               REGS[addr] = v;\r
+               case 1: /* data port 0    */\r
+                       if (ST_address == 0x2b) upd = 0; /* DAC sel */\r
+                       break;\r
 \r
-               switch( addr & 0xf0 )\r
-               {\r
-               case 0x20:      /* 0x20-0x2f Mode */\r
-                       switch( addr )\r
-                       {\r
-                       case 0x24: { // timer A High 8\r
-                                       int TAnew = (ym2612_st->TA & 0x03)|(((int)v)<<2);\r
-                                       if (ym2612_st->TA != TAnew) {\r
-                                               // we should reset ticker only if new value is written. Outrun requires this.\r
-                                               ym2612_st->TA = TAnew;\r
-                                               ym2612_st->TAC = (1024-TAnew)*18;\r
-                                               ym2612_st->TAT = 0;\r
-                                       }\r
-                                       return 0;\r
-                               }\r
-                       case 0x25: { // timer A Low 2\r
-                                       int TAnew = (ym2612_st->TA & 0x3fc)|(v&3);\r
-                                       if (ym2612_st->TA != TAnew) {\r
-                                               ym2612_st->TA = TAnew;\r
-                                               ym2612_st->TAC = (1024-TAnew)*18;\r
-                                               ym2612_st->TAT = 0;\r
-                                       }\r
-                                       return 0;\r
-                               }\r
-                       case 0x26: // timer B\r
-                               if (ym2612_st->TB != v) {\r
-                                       ym2612_st->TB = v;\r
-                                       ym2612_st->TBC  = (256-v)<<4;\r
-                                       ym2612_st->TBC *= 18;\r
-                                       ym2612_st->TBT  = 0;\r
-                               }\r
-                               return 0;\r
-                       case 0x27:      /* mode, timer control */\r
-                               if (set_timers( v ))\r
-                                       break; // other side needs ST.mode for 3slot mode\r
-                               return 0;\r
-                       case 0x2a:      /* DAC data (YM2612) */\r
-                               dacout = ((int)v - 0x80) << 6;  /* level unknown (notaz: 8 seems to be too much) */\r
+               case 2: /* address port 1 */\r
+                       if (addr_A1 == 1 && ST_address == v)\r
                                return 0;\r
-                       case 0x2b:      /* DAC Sel  (YM2612) */\r
-                               /* b7 = dac enable */\r
-                               dacen = v & 0x80;\r
-                               upd = 0;\r
-                               break; // other side has to know this\r
-                       default:\r
-                               break;\r
-                       }\r
+                       ST_address = v;\r
+                       addr_A1 = 1;\r
+                       upd = 0;\r
                        break;\r
-               }\r
-               break;\r
-\r
-       case 2: /* address port 1 */\r
-               if (*addr_A1 && ST_address == v)\r
-                       return 0;\r
-               ST_address = v;\r
-               *addr_A1 = 1;\r
-               upd = 0;\r
-               break;\r
-\r
-       case 3: /* data port 1    */\r
-               if (*addr_A1 != 1) {\r
-                       return 0;       /* verified on real YM2608 */\r
-               }\r
-\r
-               addr = ST_address | 0x100;\r
-               REGS[addr] = v;\r
-               break;\r
        }\r
 \r
        //printf("ym pass\n");\r
 \r
-       if(currentConfig.EmuOpt & 4) {\r
+       if (currentConfig.EmuOpt & 4)\r
+       {\r
                UINT16 *writebuff = shared_ctl->writebuffsel ? shared_ctl->writebuff0 : shared_ctl->writebuff1;\r
 \r
                /* detect rapid ym updates */\r
-               if (upd && !(writebuff_ptr & 0x80000000) && Pico.m.scanline < 224) {\r
+               if (upd && !(writebuff_ptr & 0x80000000) && scanline < 224)\r
+               {\r
                        int mid = Pico.m.pal ? 68 : 93;\r
-                       if (Pico.m.scanline > mid) {\r
-                               //printf("%05i:%03i: rapid ym\n", Pico.m.frame_count, Pico.m.scanline);\r
+                       if (scanline > mid) {\r
+                               //printf("%05i:%03i: rapid ym\n", Pico.m.frame_count, scanline);\r
                                writebuff[writebuff_ptr++ & 0xffff] = 0xfffe;\r
                                writebuff_ptr |= 0x80000000;\r
-                               //printf("%05i:%03i: ym w ([%02x] %02x, upd=%i)\n", Pico.m.frame_count, Pico.m.scanline, addr, v, upd);\r
+                               //printf("%05i:%03i: ym w ([%02x] %02x, upd=%i)\n", Pico.m.frame_count, scanline, addr, v, upd);\r
                        }\r
                }\r
 \r
@@ -272,7 +176,9 @@ static void add_job_940(int job)
 \r
 void YM2612PicoStateLoad_940(void)\r
 {\r
-       int i, old_A1 = *addr_A1;\r
+       UINT8 *REGS = YM2612GetRegs();\r
+\r
+       int i;\r
 \r
        /* make sure JOB940_PICOSTATELOAD gets done before next JOB940_YM2612UPDATEONE */\r
        add_job_940(JOB940_PICOSTATELOAD);\r
@@ -282,32 +188,22 @@ void YM2612PicoStateLoad_940(void)
 \r
        // feed all the registers and update internal state\r
        for(i = 0; i < 0x100; i++) {\r
-               YM2612Write_940(0, i);\r
-               YM2612Write_940(1, REGS[i]);\r
+               YM2612Write_940(0, i, -1);\r
+               YM2612Write_940(1, REGS[i], -1);\r
        }\r
        for(i = 0; i < 0x100; i++) {\r
-               YM2612Write_940(2, i);\r
-               YM2612Write_940(3, REGS[i|0x100]);\r
+               YM2612Write_940(2, i, -1);\r
+               YM2612Write_940(3, REGS[i|0x100], -1);\r
        }\r
 \r
-       *addr_A1 = old_A1;\r
+       addr_A1 = *(INT32 *) (REGS + 0x200);\r
 }\r
 \r
 \r
 static void internal_reset(void)\r
 {\r
        writebuff_ptr = 0;\r
-       ym2612_st->mode   = 0;\r
-       ym2612_st->status = 0;  /* normal mode */\r
-       ym2612_st->TA     = 0;\r
-       ym2612_st->TAC    = 0;\r
-       ym2612_st->TAT    = 0;\r
-       ym2612_st->TB     = 0;\r
-       ym2612_st->TBC    = 0;\r
-       ym2612_st->TBT    = 0;\r
-       dacen     = 0;\r
-       dacout    = 0;\r
-       ST_address= 0;\r
+       ST_address = addr_A1 = -1;\r
 }\r
 \r
 \r
@@ -405,12 +301,6 @@ void YM2612Init_940(int baseclock, int rate)
        /* cause local ym2612 to init REGS */\r
        YM2612Init_(baseclock, rate);\r
 \r
-       REGS = YM2612GetRegs();\r
-       addr_A1 = (INT32 *) (REGS + 0x200);\r
-\r
-       ym2612_dacen  = &dacen;\r
-       ym2612_dacout = &dacout;\r
-\r
        internal_reset();\r
 \r
        loaded_mp3 = 0;\r
@@ -440,6 +330,7 @@ void YM2612ResetChip_940(void)
                return;\r
        }\r
 \r
+       YM2612ResetChip_();\r
        internal_reset();\r
 \r
        add_job_940(JOB940_YM2612RESETCHIP);\r
index 95e9a07..0318c1c 100644 (file)
@@ -5,7 +5,7 @@ void YM2612Init_940(int baseclock, int rate);
 void YM2612ResetChip_940(void);\r
 int  YM2612UpdateOne_940(int *buffer, int length, int stereo, int is_buf_empty);\r
 \r
-int  YM2612Write_940(unsigned int a, unsigned int v);\r
+int  YM2612Write_940(unsigned int a, unsigned int v, int scanline);\r
 unsigned char YM2612Read_940(void);\r
 \r
 int  YM2612PicoTick_940(int n);\r
index 59a7c15..4ebecb4 100644 (file)
@@ -74,7 +74,7 @@ OBJS += ../../Pico/cd/Pico.o ../../Pico/cd/Memory.o ../../Pico/cd/Sek.o ../../Pi
                ../../Pico/cd/Area.o ../../Pico/cd/Misc.o ../../Pico/cd/pcm.o ../../Pico/cd/buffering.o\r
 endif\r
 # Pico - Pico\r
-OBJS += ../../Pico/Pico/Pico.o ../../Pico/Pico/Memory.o\r
+OBJS += ../../Pico/Pico/Pico.o ../../Pico/Pico/Memory.o ../../Pico/Pico/xpcm.o\r
 # Pico - carthw\r
 OBJS += ../../Pico/carthw/carthw.o ../../Pico/carthw/svp/svp.o ../../Pico/carthw/svp/Memory.o \\r
                ../../Pico/carthw/svp/ssp16.o ../../Pico/carthw/svp/compiler.o ../../Pico/carthw/svp/stub_arm.o\r
@@ -203,6 +203,8 @@ up: PicoDrive.gpe
 ../../cpu/musashi/m68kops.c :\r
        @make -C ../../cpu/musashi\r
 \r
+../../Pico/Pico.o : ../../Pico/PicoFrameHints.c ../../Pico/PicoInt.h\r
+../../Pico/Memory.o Pico/cd/Memory.o : ../../Pico/MemoryCmn.c ../../Pico/PicoInt.h\r
 \r
 # build helix libs\r
 ../common/helix/helix_mp3.a:\r
index 848b48b..580a8ae 100644 (file)
@@ -1,2 +1,2 @@
-#define VERSION "1.40c"\r
+#define VERSION "1.45"\r
 \r
index 9e07b9f..32e672f 100644 (file)
 #include "../../Pico/PicoInt.h"
 
 
-static YM2612 ym2612;
-
-YM2612 *ym2612_940 = &ym2612;
-
 // static _940_data_t  shared_data_;
 static _940_ctl_t   shared_ctl_;
 // static _940_data_t *shared_data = &shared_data_;
@@ -33,7 +29,7 @@ unsigned char *mp3_mem = 0;
 /***********************************************************/
 
 
-int YM2612Write_940(unsigned int a, unsigned int v)
+int YM2612Write_940(unsigned int a, unsigned int v, int scanline)
 {
        YM2612Write_(a, v);
 
index e3c89fc..cafe81e 100644 (file)
@@ -99,8 +99,8 @@ mkdirs:
        mkdir -p $(DIRS)
 
 Pico/carthw/svp/compiler.o : ../../Pico/carthw/svp/gen_arm.c
-
-Pico/Pico.o : ../../Pico/PicoFrameHints.c
+Pico/Pico.o : ../../Pico/PicoFrameHints.c ../../Pico/PicoInt.h
+Pico/Memory.o Pico/cd/Memory.o : ../../Pico/MemoryCmn.c ../../Pico/PicoInt.h
 
 ../../cpu/musashi/m68kops.c :
        @make -C ../../cpu/musashi