emulator timing fixes, VDP DMA fixes, improved DAC audio
authorkub <derkub@gmail.com>
Tue, 14 Jan 2020 22:00:44 +0000 (23:00 +0100)
committerkub <derkub@gmail.com>
Tue, 14 Jan 2020 22:00:44 +0000 (23:00 +0100)
cpu/cz80/cz80.c
cpu/cz80/cz80_op.c
pico/32x/32x.c
pico/debug.c
pico/memory.c
pico/pico.c
pico/pico_cmn.c
pico/pico_int.h
pico/sound/sound.c
pico/videoport.c

index 0326b0b..6b9afcd 100644 (file)
@@ -288,6 +288,8 @@ Cz80_Exec_End:
 #if CZ80_ENCRYPTED_ROM\r
        CPU->OPBase = OPBase;\r
 #endif\r
+       if (CPU->HaltState)\r
+               CPU->ICount = 0;\r
        cycles -= CPU->ICount;\r
 #if !CZ80_EMULATE_R_EXACTLY\r
        zR = (zR + (cycles >> 2)) & 0x7f;\r
index f84f8e7..5d623ca 100644 (file)
@@ -687,13 +687,14 @@ OP_CCF:
        OP(0x76):   // HALT\r
 OP_HALT:\r
                CPU->HaltState = 1;\r
-               CPU->ICount = 0;\r
+//             CPU->ICount = 0;\r
                goto Cz80_Check_Interrupt;\r
 \r
        OP(0xf3):   // DI\r
 OP_DI:\r
                zIFF = 0;\r
-               RET(4)\r
+               USE_CYCLES(4)\r
+               goto Cz80_Exec_nocheck;\r
 \r
        OP(0xfb):   // EI\r
 OP_EI:\r
@@ -712,8 +713,6 @@ OP_EI:
                        if (CPU->IRQState)\r
                        {\r
                                afterEI = 1;\r
-                               CPU->ExtraCycles += 1 - CPU->ICount;\r
-                               CPU->ICount = 1;\r
                        }\r
                }\r
                else zIFF2 = (1 << 2);\r
index aa45ba7..0f0cc4f 100644 (file)
@@ -269,7 +269,8 @@ void p32x_schedule_hint(SH2 *sh2, unsigned int m68k_cycles)
     return; // nobody cares
   // note: when Pico.m.scanline is 224, SH2s might
   // still be at scanline 93 (or so)
-  if (!(Pico32x.sh2_regs[0] & 0x80) && Pico.m.scanline > 224)
+  if (!(Pico32x.sh2_regs[0] & 0x80) &&
+      Pico.m.scanline > (Pico.video.reg[1] & 0x08 ? 240 : 224))
     return;
 
   after = (Pico32x.sh2_regs[4 / 2] + 1) * 488;
index 50cbaf3..e617d90 100644 (file)
@@ -369,42 +369,32 @@ void PDebugDumpMem(void)
 
 void PDebugZ80Frame(void)
 {
-  int lines, line_sample;
+  int lines;
 
   if (PicoIn.AHW & PAHW_SMS)
     return;
 
-  if (Pico.m.pal) {
+  if (Pico.m.pal)
     lines = 313;
-    line_sample = 68;
-  } else {
+  else
     lines = 262;
-    line_sample = 93;
-  }
 
   z80_resetCycles();
   PsndStartFrame();
 
-  if (/*Pico.m.z80Run &&*/ !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80))
-    PicoSyncZ80(Pico.t.m68c_cnt + line_sample * 488);
-  if (PicoIn.sndOut)
-    PsndGetSamples(line_sample);
-
   if (/*Pico.m.z80Run &&*/ !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80)) {
     PicoSyncZ80(Pico.t.m68c_cnt + 224 * 488);
     z80_int();
   }
-  if (PicoIn.sndOut)
-    PsndGetSamples(224);
 
   // sync z80
   if (/*Pico.m.z80Run &&*/ !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80)) {
     Pico.t.m68c_cnt += Pico.m.pal ? 151809 : 127671; // cycles adjusted for converter
     PicoSyncZ80(Pico.t.m68c_cnt);
   }
-  if (PicoIn.sndOut && ym2612.dacen && Pico.snd.dac_line < lines)
-    PsndDoDAC(lines - 1);
-  PsndDoPSG(lines - 1);
+
+  if (PicoIn.sndOut)
+    PsndGetSamples(lines);
 
   timers_cycle();
   Pico.t.m68c_aim = Pico.t.m68c_cnt;
index 9fe3a08..1d9b913 100644 (file)
@@ -943,11 +943,11 @@ static int ym2612_write_local(u32 a, u32 d, int is_from_z80)
   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", Pico.snd.dac_line, scanline, d, is_from_z80);\r
+    int cycles = is_from_z80 ? z80_cyclesDone() : z80_cycles_from_68k();\r
+    //elprintf(EL_STATUS, "%03i dac w %08x z80 %i", cycles, d, is_from_z80);\r
     ym2612.dacout = ((int)d - 0x80) << 6;\r
     if (ym2612.dacen)\r
-      PsndDoDAC(scanline);\r
+      PsndDoDAC(cycles);\r
     return 0;\r
   }\r
 \r
@@ -1029,13 +1029,9 @@ static int ym2612_write_local(u32 a, u32 d, int is_from_z80)
           return 0;\r
         }\r
         case 0x2b: { /* DAC Sel  (YM2612) */\r
-          int scanline = get_scanline(is_from_z80);\r
-          if (ym2612.dacen != (d & 0x80)) {\r
-            ym2612.dacen = d & 0x80;\r
-            Pico.snd.dac_line = scanline;\r
-          }\r
+          ym2612.dacen = d & 0x80;\r
 #ifdef __GP2X__\r
-          if (PicoIn.opt & POPT_EXT_FM) YM2612Write_940(a, d, scanline);\r
+          if (PicoIn.opt & POPT_EXT_FM) YM2612Write_940(a, d, get_scanline(is_from_z80));\r
 #endif\r
           return 0;\r
         }\r
@@ -1059,8 +1055,7 @@ static int ym2612_write_local(u32 a, u32 d, int is_from_z80)
       break;\r
   }\r
 \r
-  int scanline = get_scanline(is_from_z80);\r
-  PsndDoFM(scanline);\r
+  PsndDoFM(get_scanline(is_from_z80));\r
 #ifdef __GP2X__\r
   if (PicoIn.opt & POPT_EXT_FM)\r
     return YM2612Write_940(a, d, get_scanline(is_from_z80));\r
index f6b43cd..2a16a0e 100644 (file)
@@ -224,40 +224,45 @@ void PicoLoopPrepare(void)
 \r
 // this table is wrong and should be removed\r
 // keeping it for now to compensate wrong timing elswhere, mainly for Outrunners\r
-static const int dma_timings[] = {\r
-   83, 166,  83,  83, // vblank: 32cell: dma2vram dma2[vs|c]ram vram_fill vram_copy\r
-  102, 204, 102, 102, // vblank: 40cell:\r
-    8,  16,   8,   8, // active: 32cell:\r
-   17,  18,   9,   9  // ...\r
+static const int dma_timings[] = { // Q16\r
+  // dma2vram    dma2[vs|c]ram  vram_fill      vram_copy\r
+  // VRAM has half the width of VSRAM/CRAM, thus half the performance\r
+  ( 83<<16)/488, (166<<16)/488, (165<<16)/488, ( 83<<16)/488, // vblank 32cell\r
+  (102<<16)/488, (204<<16)/488, (203<<16)/488, (102<<16)/488, // vblank 40cell\r
+  (  8<<16)/488, ( 16<<16)/488, ( 15<<16)/488, (  8<<16)/488, // active 32cell\r
+  (  9<<16)/488, ( 18<<16)/488, ( 17<<16)/488, (  9<<16)/488  // active 40cell\r
 };\r
 \r
-static const int dma_bsycles[] = {\r
-  (488<<8)/83,  (488<<8)/166, (488<<8)/83,  (488<<8)/83,\r
-  (488<<8)/102, (488<<8)/204, (488<<8)/102, (488<<8)/102,\r
-  (488<<8)/8,   (488<<8)/16,  (488<<8)/8,   (488<<8)/8,\r
-  (488<<8)/9,   (488<<8)/18,  (488<<8)/9,   (488<<8)/9\r
+static const int dma_bsycles[] = { // Q16\r
+  (488<<16)/83,  (488<<16)/166, (488<<16)/165, (488<<16)/83,\r
+  (488<<16)/102, (488<<16)/204, (488<<16)/203, (488<<16)/102,\r
+  (488<<16)/8,   (488<<16)/16,  (488<<16)/15,  (488<<16)/8,\r
+  (488<<16)/9,   (488<<16)/18,  (488<<16)/17,  (488<<16)/9\r
 };\r
 \r
 // grossly inaccurate.. FIXME FIXXXMEE\r
-PICO_INTERNAL int CheckDMA(void)\r
+PICO_INTERNAL int CheckDMA(int cycles)\r
 {\r
   int burn = 0, xfers_can, dma_op = Pico.video.reg[0x17]>>6; // see gens for 00 and 01 modes\r
   int xfers = Pico.m.dma_xfers;\r
   int dma_op1;\r
 \r
+  // safety pin\r
+  if (cycles <= 0) return 0;\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
-  xfers_can = dma_timings[dma_op];\r
+  xfers_can = (dma_timings[dma_op] * cycles + 0xff) >> 16;\r
   if(xfers <= xfers_can)\r
   {\r
     Pico.video.status &= ~SR_DMA;\r
     if (!(dma_op & 2))\r
-      burn = xfers * dma_bsycles[dma_op] >> 8; // have to be approximate because can't afford division..\r
+      burn = xfers * dma_bsycles[dma_op] >> 16;\r
     Pico.m.dma_xfers = 0;\r
   } else {\r
-    if(!(dma_op&2)) burn = 488;\r
+    if(!(dma_op&2)) burn = cycles;\r
     Pico.m.dma_xfers -= xfers_can;\r
   }\r
 \r
index 5fa0b16..8c22c97 100644 (file)
 #endif
 
 // sync m68k to Pico.t.m68c_aim
-static void SekSyncM68k(void)
+static void SekExecM68k(int cyc_do)
 {
-  int cyc_do;
-  pprof_start(m68k);
-  pevt_log_m68k_o(EVT_RUN_START);
-
-  while ((cyc_do = Pico.t.m68c_aim - Pico.t.m68c_cnt) > 0) {
-    Pico.t.m68c_cnt += cyc_do;
+  Pico.t.m68c_cnt += cyc_do;
 
 #if defined(EMU_C68K)
-    PicoCpuCM68k.cycles = cyc_do;
-    CycloneRun(&PicoCpuCM68k);
-    Pico.t.m68c_cnt -= PicoCpuCM68k.cycles;
+  PicoCpuCM68k.cycles = cyc_do;
+  CycloneRun(&PicoCpuCM68k);
+  Pico.t.m68c_cnt -= PicoCpuCM68k.cycles;
 #elif defined(EMU_M68K)
-    Pico.t.m68c_cnt += m68k_execute(cyc_do) - cyc_do;
+  Pico.t.m68c_cnt += m68k_execute(cyc_do) - cyc_do;
 #elif defined(EMU_F68K)
-    Pico.t.m68c_cnt += fm68k_emulate(&PicoCpuFM68k, cyc_do, 0) - cyc_do;
+  Pico.t.m68c_cnt += fm68k_emulate(&PicoCpuFM68k, cyc_do, 0) - cyc_do;
 #endif
-  }
+}
+
+static void SekSyncM68k(void)
+{
+  int cyc_do;
+  pprof_start(m68k);
+  pevt_log_m68k_o(EVT_RUN_START);
+
+  while ((cyc_do = Pico.t.m68c_aim - Pico.t.m68c_cnt) > 0)
+    SekExecM68k(cyc_do);
 
   SekCyclesLeft = 0;
 
@@ -68,7 +72,7 @@ static void do_hint(struct PicoVideo *pv)
   }
 }
 
-static void do_timing_hacks_as(struct PicoVideo *pv, int vdp_slots)
+static void do_timing_hacks_as(struct PicoVideo *pv, int vdp_slots, int cycles)
 {
   pv->lwrite_cnt += vdp_slots - Pico.m.dma_xfers * 2; // wrong *2
   if (pv->lwrite_cnt > vdp_slots)
@@ -76,13 +80,13 @@ static void do_timing_hacks_as(struct PicoVideo *pv, int vdp_slots)
   else if (pv->lwrite_cnt < 0)
     pv->lwrite_cnt = 0;
   if (Pico.m.dma_xfers)
-    SekCyclesBurn(CheckDMA());
+    SekCyclesBurn(CheckDMA(cycles));
 }
 
-static void do_timing_hacks_vb(void)
+static void do_timing_hacks_vb(int cycles)
 {
   if (unlikely(Pico.m.dma_xfers))
-    SekCyclesBurn(CheckDMA());
+    SekCyclesBurn(CheckDMA(cycles));
 }
 
 static int PicoFrameHints(void)
@@ -151,7 +155,7 @@ static int PicoFrameHints(void)
 
     // Run scanline:
     Pico.t.m68c_line_start = Pico.t.m68c_aim;
-    do_timing_hacks_as(pv, vdp_slots);
+    do_timing_hacks_as(pv, vdp_slots, CYCLES_M68K_LINE);
     CPUS_RUN(CYCLES_M68K_LINE);
 
     if (PicoLineHook) PicoLineHook();
@@ -192,19 +196,18 @@ 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)
   Pico.t.m68c_line_start = Pico.t.m68c_aim;
-  do_timing_hacks_vb();
+  do_timing_hacks_vb(CYCLES_M68K_VINT_LAG);
   CPUS_RUN(CYCLES_M68K_VINT_LAG);
 
   pv->status |= SR_F;
   pv->pending_ints |= 0x20;
   if (pv->reg[1] & 0x20) {
-    Pico.t.m68c_aim = Pico.t.m68c_cnt + 11; // HACK
-    SekSyncM68k();
+    SekExecM68k(11); // HACK
     elprintf(EL_INTS, "vint: @ %06x [%u]", SekPc, SekCyclesDone());
     SekInterrupt(6);
   }
 
-  cycles = SekCyclesDone();
+  cycles = Pico.t.m68c_aim;
   if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80)) {
     PicoSyncZ80(cycles);
     elprintf(EL_INTS, "zint");
@@ -221,6 +224,7 @@ static int PicoFrameHints(void)
 #endif
 
   // Run scanline:
+  do_timing_hacks_vb(CYCLES_M68K_LINE - CYCLES_M68K_VINT_LAG);
   CPUS_RUN(CYCLES_M68K_LINE - CYCLES_M68K_VINT_LAG);
 
   if (PicoLineHook) PicoLineHook();
@@ -256,7 +260,7 @@ static int PicoFrameHints(void)
 
     // Run scanline:
     Pico.t.m68c_line_start = Pico.t.m68c_aim;
-    do_timing_hacks_vb();
+    do_timing_hacks_vb(CYCLES_M68K_LINE);
     CPUS_RUN(CYCLES_M68K_LINE);
 
     if (PicoLineHook) PicoLineHook();
@@ -267,7 +271,7 @@ static int PicoFrameHints(void)
     unsigned int l = PicoIn.overclockM68k * lines / 100;
     while (l-- > 0) {
       Pico.t.m68c_cnt -= CYCLES_M68K_LINE;
-      do_timing_hacks_vb();
+      do_timing_hacks_vb(CYCLES_M68K_LINE);
       SekSyncM68k();
     }
   }
@@ -293,20 +297,16 @@ static int PicoFrameHints(void)
 
   // Run scanline:
   Pico.t.m68c_line_start = Pico.t.m68c_aim;
-  do_timing_hacks_as(pv, vdp_slots);
+  do_timing_hacks_as(pv, vdp_slots, CYCLES_M68K_LINE);
   CPUS_RUN(CYCLES_M68K_LINE);
 
   if (PicoLineHook) PicoLineHook();
   pevt_log_m68k_o(EVT_NEXT_LINE);
 
   // sync cpus
-  cycles = SekCyclesDone();
+  cycles = Pico.t.m68c_aim;
   if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80))
     PicoSyncZ80(cycles);
-  if (PicoIn.sndOut && ym2612.dacen && Pico.snd.dac_line < lines)
-    PsndDoDAC(lines - 1);
-  if (PicoIn.sndOut && Pico.snd.psg_line < lines)
-    PsndDoPSG(lines - 1);
 
 #ifdef PICO_CD
   if (PicoIn.AHW & PAHW_MCD)
index d3da72c..58d3da8 100644 (file)
@@ -193,7 +193,7 @@ extern struct DrZ80 drZ80;
 #define z80_int_assert(a)  Cz80_Set_IRQ(&CZ80, 0, (a) ? ASSERT_LINE : CLEAR_LINE)\r
 #define z80_nmi()          Cz80_Set_IRQ(&CZ80, IRQ_LINE_NMI, 0)\r
 \r
-#define z80_cyclesLeft     (CZ80.ICount - CZ80.ExtraCycles)\r
+#define z80_cyclesLeft     CZ80.ICount\r
 #define z80_subCLeft(c)    CZ80.ICount -= c\r
 #define z80_pc()           Cz80_Get_Reg(&CZ80, CZ80_PC)\r
 \r
@@ -431,7 +431,9 @@ struct PicoSound
   short len_use;                        // adjusted\r
   int len_e_add;                        // for non-int samples/frame\r
   int len_e_cnt;\r
-  short dac_line;\r
+  int dac_val, dac_val2;                // last DAC sample\r
+  unsigned int dac_mult;                // z80 clocks per line in Q16\r
+  unsigned int dac_pos;                 // last DAC position in Q16\r
   short psg_line;\r
   unsigned int fm_mult;                 // samples per line in Q16\r
   unsigned int fm_pos;                  // last FM position in Q16\r
@@ -738,7 +740,7 @@ extern struct Pico Pico;
 extern struct PicoMem PicoMem;\r
 extern void (*PicoResetHook)(void);\r
 extern void (*PicoLineHook)(void);\r
-PICO_INTERNAL int  CheckDMA(void);\r
+PICO_INTERNAL int  CheckDMA(int cycles);\r
 PICO_INTERNAL void PicoDetectRegion(void);\r
 PICO_INTERNAL void PicoSyncZ80(unsigned int m68k_cycles_done);\r
 \r
@@ -872,7 +874,7 @@ PICO_INTERNAL_ASM void wram_1M_to_2M(unsigned char *m);
 // sound/sound.c\r
 PICO_INTERNAL void PsndReset(void);\r
 PICO_INTERNAL void PsndStartFrame(void);\r
-PICO_INTERNAL void PsndDoDAC(int line_to);\r
+PICO_INTERNAL void PsndDoDAC(int cycle_to);\r
 PICO_INTERNAL void PsndDoPSG(int line_to);\r
 PICO_INTERNAL void PsndDoFM(int line_to);\r
 PICO_INTERNAL void PsndClear(void);\r
index 74fb6fc..155aa45 100644 (file)
@@ -89,6 +89,8 @@ void PsndRerate(int preserve_state)
 \r
   // samples per line (Q16)\r
   Pico.snd.fm_mult = 65536LL * PicoIn.sndRate / (target_fps*target_lines);\r
+  // samples per z80 clock (Q20)\r
+  Pico.snd.dac_mult = 16 * Pico.snd.fm_mult * 15/7 / 488;\r
 \r
   // recalculate dac info\r
   dac_recalculate();\r
@@ -117,34 +119,46 @@ PICO_INTERNAL void PsndStartFrame(void)
     Pico.snd.len_use++;\r
   }\r
 \r
-  Pico.snd.dac_line = Pico.snd.psg_line = 0;\r
-  Pico.snd.fm_pos = 0;\r
+  Pico.snd.psg_line = 0;\r
 }\r
 \r
-PICO_INTERNAL void PsndDoDAC(int line_to)\r
+PICO_INTERNAL void PsndDoDAC(int cyc_to)\r
 {\r
-  int pos, pos1, len;\r
+  int pos, len;\r
   int dout = ym2612.dacout;\r
-  int line_from = Pico.snd.dac_line;\r
 \r
-  pos  = dac_info[line_from];\r
-  pos1 = dac_info[line_to + 1];\r
-  len = pos1 - pos;\r
+  // number of samples to fill in buffer (Q20)\r
+  len = (cyc_to * Pico.snd.dac_mult) - Pico.snd.dac_pos;\r
+\r
+  // update position and calculate buffer offset and length\r
+  pos = (Pico.snd.dac_pos+0x80000) >> 20;\r
+  Pico.snd.dac_pos += len;\r
+  len = ((Pico.snd.dac_pos+0x80000) >> 20) - pos;\r
+\r
+  // avoid loss of the 1st sample of a new block (Q rounding issues)\r
+  if (pos+len == 0)\r
+    len = 1, Pico.snd.dac_pos += 0x80000;\r
   if (len <= 0)\r
     return;\r
 \r
-  Pico.snd.dac_line = line_to + 1;\r
-\r
   if (!PicoIn.sndOut)\r
     return;\r
 \r
+  // fill buffer, applying a rather weak order 1 bessel IIR on the way\r
+  // y[n] = (x[n] + x[n-1])*(1/2) (3dB cutoff at 11025 Hz, no gain)\r
+  // 1 sample delay for correct IIR filtering over audio frame boundaries\r
   if (PicoIn.opt & POPT_EN_STEREO) {\r
     short *d = PicoIn.sndOut + pos*2;\r
-    for (; len > 0; len--, d+=2) *d += dout;\r
+    // left channel only, mixed ro right channel in mixing phase\r
+    *d++ += Pico.snd.dac_val2; d++;\r
+    while (--len) *d++ += Pico.snd.dac_val, d++;\r
   } else {\r
     short *d = PicoIn.sndOut + pos;\r
-    for (; len > 0; len--, d++)  *d += dout;\r
+    *d++ += Pico.snd.dac_val2;\r
+    while (--len) *d++ += Pico.snd.dac_val;\r
   }\r
+  Pico.snd.dac_val2 = (Pico.snd.dac_val + dout) >> 1;\r
+  Pico.snd.dac_val = dout;\r
 }\r
 \r
 PICO_INTERNAL void PsndDoPSG(int line_to)\r
@@ -258,6 +272,8 @@ PICO_INTERNAL void PsndClear(void)
   }\r
   if (!(PicoIn.opt & POPT_EN_FM))\r
     memset32(PsndBuffer, 0, PicoIn.opt & POPT_EN_STEREO ? len*2 : len);\r
+  // drop pos remainder to avoid rounding errors (not entirely correct though)\r
+  Pico.snd.dac_pos = Pico.snd.fm_pos = 0;\r
 }\r
 \r
 \r
@@ -266,6 +282,7 @@ static int PsndRender(int offset, int length)
   int *buf32;\r
   int stereo = (PicoIn.opt & 8) >> 3;\r
   int fmlen = ((Pico.snd.fm_pos+0x8000) >> 16) - offset;\r
+  int daclen = ((Pico.snd.dac_pos+0x80000) >> 20) - offset;\r
 \r
   offset <<= stereo;\r
   buf32 = PsndBuffer+offset;\r
@@ -277,6 +294,15 @@ static int PsndRender(int offset, int length)
     return length;\r
   }\r
 \r
+  // Fill up DAC output in case of missing samples (Q16 rounding errors)\r
+  if (length-daclen > 0) {\r
+    short *dacbuf = PicoIn.sndOut + (daclen << stereo);\r
+    for (; length-daclen > 0; daclen++) {\r
+      *dacbuf++ += Pico.snd.dac_val;\r
+      if (stereo) dacbuf++;\r
+    }\r
+  }\r
+\r
   // Add in parts of the FM buffer not yet done\r
   if (length-fmlen > 0) {\r
     int *fmbuf = buf32 + (fmlen << stereo);\r
@@ -317,8 +343,8 @@ PICO_INTERNAL void PsndGetSamples(int y)
 {\r
   static int curr_pos = 0;\r
 \r
-  if (ym2612.dacen && Pico.snd.dac_line < y)\r
-    PsndDoDAC(y - 1);\r
+  if (ym2612.dacen)\r
+    PsndDoDAC(cycles_68k_to_z80(Pico.t.m68c_aim - Pico.t.m68c_frame_start));\r
   PsndDoPSG(y - 1);\r
 \r
   curr_pos  = PsndRender(0, Pico.snd.len_use);\r
@@ -327,7 +353,6 @@ PICO_INTERNAL void PsndGetSamples(int y)
     PicoIn.writeSound(curr_pos * ((PicoIn.opt & POPT_EN_STEREO) ? 4 : 2));\r
   // clear sound buffer\r
   PsndClear();\r
-  Pico.snd.dac_line = y;\r
 }\r
 \r
 PICO_INTERNAL void PsndGetSamplesMS(int y)\r
index d18c2cf..d196ee4 100644 (file)
@@ -97,7 +97,7 @@ static void DmaSlow(int len, unsigned int source)
   Pico.m.dma_xfers = len;\r
   if (Pico.m.dma_xfers < len) // lame 16bit var\r
     Pico.m.dma_xfers = ~0;\r
-  SekCyclesBurnRun(CheckDMA());\r
+  SekCyclesBurnRun(CheckDMA(488 - (SekCyclesDone()-Pico.t.m68c_line_start)));\r
 \r
   if ((source & 0xe00000) == 0xe00000) { // Ram\r
     base = (u16 *)PicoMem.ram;\r
@@ -344,7 +344,8 @@ static NOINLINE void CommandChange(void)
 \r
 static void DrawSync(int blank_on)\r
 {\r
-  if (Pico.m.scanline < 224 && !(PicoIn.opt & POPT_ALT_RENDERER) &&\r
+  int lines = Pico.video.reg[1]&0x08 ? 240 : 224;\r
+  if (Pico.m.scanline < lines && !(PicoIn.opt & POPT_ALT_RENDERER) &&\r
       !PicoIn.skipFrame && Pico.est.DrawScanline <= Pico.m.scanline) {\r
     //elprintf(EL_ANOMALY, "sync");\r
     PicoDrawSync(Pico.m.scanline, blank_on);\r
@@ -363,7 +364,7 @@ PICO_INTERNAL_ASM void PicoVideoWrite(unsigned int a,unsigned short d)
   {\r
   case 0x00: // Data port 0 or 2\r
     // try avoiding the sync..\r
-    if (Pico.m.scanline < 224 && (pvid->reg[1]&0x40) &&\r
+    if (Pico.m.scanline < (pvid->reg[1]&0x08 ? 240 : 224) && (pvid->reg[1]&0x40) &&\r
         !(!pvid->pending &&\r
           ((pvid->command & 0xc00000f0) == 0x40000010 && PicoMem.vsram[pvid->addr>>1] == d))\r
        )\r