if (is_from_z80) {\r
// ugh... compute by dividing cycles since frame start by cycles per line\r
// need some fractional resolution here, else there may be an extra line\r
- int cycles_line = cycles_68k_to_z80(488 << 8); // cycles per line, as Q8\r
+ int cycles_line = cycles_68k_to_z80(488 << 8)+1; // cycles per line, as Q8\r
int cycles_z80 = (z80_cyclesLeft<0 ? Pico.t.z80c_aim:z80_cyclesDone())<<8;\r
int cycles = cycles_line * Pico.t.z80_scanline;\r
// approximation by multiplying with inverse\r
return Pico.m.scanline;\r
}\r
\r
+#define ym2612_update_status(xcycles) \\r
+ if (xcycles >= Pico.t.timer_a_next_oflow) \\r
+ ym2612.OPN.ST.status |= (ym2612.OPN.ST.mode >> 2) & 1; \\r
+ if (xcycles >= Pico.t.timer_b_next_oflow) \\r
+ ym2612.OPN.ST.status |= (ym2612.OPN.ST.mode >> 2) & 2\r
+\r
/* probably should not be in this file, but it's near related code here */\r
void ym2612_sync_timers(int z80_cycles, int mode_old, int mode_new)\r
{\r
int xcycles = z80_cycles << 8;\r
\r
- /* check for overflows */\r
- if ((mode_old & 4) && xcycles >= Pico.t.timer_a_next_oflow)\r
- ym2612.OPN.ST.status |= 1;\r
-\r
- if ((mode_old & 8) && xcycles >= Pico.t.timer_b_next_oflow)\r
- ym2612.OPN.ST.status |= 2;\r
+ // update timer status\r
+ ym2612_update_status(xcycles);\r
\r
- /* update timer a */\r
+ // update timer a\r
if (mode_old & 1)\r
- while (xcycles > Pico.t.timer_a_next_oflow)\r
+ while (xcycles >= Pico.t.timer_a_next_oflow)\r
Pico.t.timer_a_next_oflow += Pico.t.timer_a_step;\r
\r
- if ((mode_old ^ mode_new) & 1) // turning on/off\r
+ // turning on/off\r
+ if ((mode_old ^ mode_new) & 1)\r
{\r
if (mode_old & 1)\r
Pico.t.timer_a_next_oflow = TIMER_NO_OFLOW;\r
- else\r
- Pico.t.timer_a_next_oflow = xcycles + Pico.t.timer_a_step;\r
+ else {\r
+ /* The internal tick of the YM2612 takes 144 clock cycles (with clock\r
+ * being OSC/7), or 67.2 z80 cycles. Timers are run once each tick.\r
+ * Starting a timer takes place at the next tick, so xcycles needs to be\r
+ * rounded up to that: t = next tick# = (xcycles / TICK_ZCYCLES) + 1\r
+ */\r
+ unsigned t = ((xcycles * (((1<<20)/TIMER_A_TICK_ZCYCLES)+1))>>20) + 1;\r
+ Pico.t.timer_a_next_oflow = t*TIMER_A_TICK_ZCYCLES + Pico.t.timer_a_step;\r
+ }\r
}\r
+\r
if (mode_new & 1)\r
elprintf(EL_YMTIMER, "timer a upd to %i @ %i", Pico.t.timer_a_next_oflow>>8, z80_cycles);\r
\r
- /* update timer b */\r
+ // update timer b\r
if (mode_old & 2)\r
- while (xcycles > Pico.t.timer_b_next_oflow)\r
+ while (xcycles >= Pico.t.timer_b_next_oflow)\r
Pico.t.timer_b_next_oflow += Pico.t.timer_b_step;\r
\r
+ // turning on/off\r
if ((mode_old ^ mode_new) & 2)\r
{\r
if (mode_old & 2)\r
Pico.t.timer_b_next_oflow = TIMER_NO_OFLOW;\r
- else\r
- Pico.t.timer_b_next_oflow = xcycles + Pico.t.timer_b_step;\r
+ else {\r
+ /* timer b has a divider of 16 which runs in its own counter. It is not\r
+ * reset by loading timer b. The first run of timer b after loading is\r
+ * therefore shorter by up to 15 ticks.\r
+ */\r
+ unsigned t = ((xcycles * (((1<<20)/TIMER_A_TICK_ZCYCLES)+1))>>20) + 1;\r
+ int step = Pico.t.timer_b_step - TIMER_A_TICK_ZCYCLES*(t&15);\r
+ Pico.t.timer_b_next_oflow = t*TIMER_A_TICK_ZCYCLES + step;\r
+ }\r
}\r
+\r
if (mode_new & 2)\r
elprintf(EL_YMTIMER, "timer b upd to %i @ %i", Pico.t.timer_b_next_oflow>>8, z80_cycles);\r
}\r
\r
switch (addr)\r
{\r
+ // NB, OD2 A/V sync HACK: lower timer step by 1/4 z80 cycle (=64 in Q8)\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 = TAnew;\r
//ym2612.OPN.ST.TAC = (1024-TAnew)*18;\r
//ym2612.OPN.ST.TAT = 0;\r
- Pico.t.timer_a_step = TIMER_A_TICK_ZCYCLES * (1024 - TAnew);\r
+ Pico.t.timer_a_step = TIMER_A_TICK_ZCYCLES * (1024 - TAnew) - 64;\r
elprintf(EL_YMTIMER, "timer a set to %i, %i", 1024 - TAnew, Pico.t.timer_a_next_oflow>>8);\r
}\r
return 0;\r
ym2612.OPN.ST.TB = d;\r
//ym2612.OPN.ST.TBC = (256-d) * 288;\r
//ym2612.OPN.ST.TBT = 0;\r
- Pico.t.timer_b_step = TIMER_B_TICK_ZCYCLES * (256 - d); // 262800\r
+ Pico.t.timer_b_step = TIMER_B_TICK_ZCYCLES * (256 - d) - 64;\r
elprintf(EL_YMTIMER, "timer b set to %i, %i", 256 - d, Pico.t.timer_b_next_oflow>>8);\r
}\r
return 0;\r
int old_mode = ym2612.OPN.ST.mode;\r
int cycles = is_from_z80 ? z80_cyclesDone() : z80_cycles_from_68k();\r
\r
- ym2612.OPN.ST.mode = d;\r
-\r
elprintf(EL_YMTIMER, "st mode %02x", d);\r
ym2612_sync_timers(cycles, old_mode, d);\r
\r
+ ym2612.OPN.ST.mode = d;\r
+\r
/* reset Timer a flag */\r
if (d & 0x10)\r
ym2612.OPN.ST.status &= ~1;\r
}\r
\r
\r
-#define ym2612_read_local() \\r
- if (xcycles >= Pico.t.timer_a_next_oflow) \\r
- ym2612.OPN.ST.status |= (ym2612.OPN.ST.mode >> 2) & 1; \\r
- if (xcycles >= Pico.t.timer_b_next_oflow) \\r
- ym2612.OPN.ST.status |= (ym2612.OPN.ST.mode >> 2) & 2\r
-\r
static u32 ym2612_read_local_z80(void)\r
{\r
int xcycles = z80_cyclesDone() << 8;\r
\r
- ym2612_read_local();\r
+ ym2612_update_status(xcycles);\r
\r
elprintf(EL_YMTIMER, "timer z80 read %i, sched %i, %i @ %i|%i",\r
ym2612.OPN.ST.status, Pico.t.timer_a_next_oflow >> 8,\r
{\r
int xcycles = z80_cycles_from_68k() << 8;\r
\r
- ym2612_read_local();\r
+ ym2612_update_status(xcycles);\r
\r
elprintf(EL_YMTIMER, "timer 68k read %i, sched %i, %i @ %i|%i",\r
ym2612.OPN.ST.status, Pico.t.timer_a_next_oflow >> 8,\r