cd: fix yet more desyncs
[picodrive.git] / pico / cd / mcd.c
1 /*
2  * PicoDrive
3  * (C) notaz, 2007,2013
4  *
5  * This work is licensed under the terms of MAME license.
6  * See COPYING file in the top-level directory.
7  */
8
9 #include "../pico_int.h"
10 #include "../sound/ym2612.h"
11
12 extern unsigned char formatted_bram[4*0x10];
13
14 static unsigned int m68k_cycle_mult;
15
16 void (*PicoMCDopenTray)(void) = NULL;
17 void (*PicoMCDcloseTray)(void) = NULL;
18
19
20 PICO_INTERNAL void PicoInitMCD(void)
21 {
22   SekInitS68k();
23   Init_CD_Driver();
24 }
25
26 PICO_INTERNAL void PicoExitMCD(void)
27 {
28   End_CD_Driver();
29 }
30
31 PICO_INTERNAL void PicoPowerMCD(void)
32 {
33   SekCycleCntS68k = SekCycleAimS68k = 0;
34
35   int fmt_size = sizeof(formatted_bram);
36   memset(Pico_mcd->prg_ram,    0, sizeof(Pico_mcd->prg_ram));
37   memset(Pico_mcd->word_ram2M, 0, sizeof(Pico_mcd->word_ram2M));
38   memset(Pico_mcd->pcm_ram,    0, sizeof(Pico_mcd->pcm_ram));
39   memset(Pico_mcd->bram, 0, sizeof(Pico_mcd->bram));
40   memcpy(Pico_mcd->bram + sizeof(Pico_mcd->bram) - fmt_size,
41     formatted_bram, fmt_size);
42   memset(Pico_mcd->s68k_regs, 0, sizeof(Pico_mcd->s68k_regs));
43   memset(&Pico_mcd->pcm, 0, sizeof(Pico_mcd->pcm));
44   memset(&Pico_mcd->m, 0, sizeof(Pico_mcd->m));
45
46   Reset_CD();
47
48   // cold reset state (tested)
49   Pico_mcd->m.state_flags = PCD_ST_S68K_RST;
50   Pico_mcd->m.busreq = 2;     // busreq on, s68k in reset
51   Pico_mcd->s68k_regs[3] = 1; // 2M word RAM mode, m68k access
52   memset(Pico_mcd->bios + 0x70, 0xff, 4);
53 }
54
55 void pcd_soft_reset(void)
56 {
57   // Reset_CD(); // breaks Fahrenheit CD swap
58
59   LC89510_Reset();
60   gfx_cd_reset();
61 #ifdef _ASM_CD_MEMORY_C
62   //PicoMemResetCDdecode(1); // don't have to call this in 2M mode
63 #endif
64
65   pcd_event_schedule_s68k(PCD_EVENT_CDC, 12500000/75);
66
67   // TODO: test if register state/timers change
68 }
69
70 PICO_INTERNAL int PicoResetMCD(void)
71 {
72   // reset button doesn't affect MCD hardware
73
74   // use SRam.data for RAM cart
75   if (PicoOpt & POPT_EN_MCD_RAMCART) {
76     if (SRam.data == NULL)
77       SRam.data = calloc(1, 0x12000);
78   }
79   else if (SRam.data != NULL) {
80     free(SRam.data);
81     SRam.data = NULL;
82   }
83   SRam.start = SRam.end = 0; // unused
84
85   return 0;
86 }
87
88 static __inline void SekRunS68k(unsigned int to)
89 {
90   int cyc_do;
91
92   SekCycleAimS68k = to;
93   if ((cyc_do = SekCycleAimS68k - SekCycleCntS68k) <= 0)
94     return;
95
96   if (SekShouldInterrupt())
97     Pico_mcd->m.s68k_poll_a = 0;
98
99   SekCycleCntS68k += cyc_do;
100 #if defined(EMU_C68K)
101   PicoCpuCS68k.cycles = cyc_do;
102   CycloneRun(&PicoCpuCS68k);
103   SekCycleCntS68k -= PicoCpuCS68k.cycles;
104 #elif defined(EMU_M68K)
105   m68k_set_context(&PicoCpuMS68k);
106   SekCycleCntS68k += m68k_execute(cyc_do) - cyc_do;
107   m68k_set_context(&PicoCpuMM68k);
108 #elif defined(EMU_F68K)
109   g_m68kcontext = &PicoCpuFS68k;
110   SekCycleCntS68k += fm68k_emulate(cyc_do, 0, 0) - cyc_do;
111   g_m68kcontext = &PicoCpuFM68k;
112 #endif
113 }
114
115 static void pcd_set_cycle_mult(void)
116 {
117   // ~1.63 for NTSC, ~1.645 for PAL
118   if (Pico.m.pal)
119     m68k_cycle_mult = ((12500000ull << 16) / (50*312*488));
120   else
121     m68k_cycle_mult = ((12500000ull << 16) / (60*262*488)) + 1;
122 }
123
124 unsigned int pcd_cycles_m68k_to_s68k(unsigned int c)
125 {
126   return (long long)c * m68k_cycle_mult >> 16;
127 }
128
129 /* events */
130 static void pcd_cdc_event(unsigned int now)
131 {
132   // 75Hz CDC update
133   Check_CD_Command();
134   pcd_event_schedule(now, PCD_EVENT_CDC, 12500000/75);
135 }
136
137 static void pcd_int3_timer_event(unsigned int now)
138 {
139   if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN3) {
140     elprintf(EL_INTS|EL_CD, "s68k: timer irq 3");
141     SekInterruptS68k(3);
142   }
143
144   if (Pico_mcd->s68k_regs[0x31] != 0)
145     pcd_event_schedule(now, PCD_EVENT_TIMER3,
146       Pico_mcd->s68k_regs[0x31] * 384);
147 }
148
149 static void pcd_dma_event(unsigned int now)
150 {
151   int ddx = Pico_mcd->s68k_regs[4] & 7;
152         Update_CDC_TRansfer(ddx);
153 }
154
155 typedef void (event_cb)(unsigned int now);
156
157 /* times are in s68k (12.5MHz) cycles */
158 unsigned int pcd_event_times[PCD_EVENT_COUNT];
159 static unsigned int event_time_next;
160 static event_cb *pcd_event_cbs[PCD_EVENT_COUNT] = {
161   [PCD_EVENT_CDC]      = pcd_cdc_event,
162   [PCD_EVENT_TIMER3]   = pcd_int3_timer_event,
163   [PCD_EVENT_GFX]      = gfx_cd_update,
164   [PCD_EVENT_DMA]      = pcd_dma_event,
165 };
166
167 void pcd_event_schedule(unsigned int now, enum pcd_event event, int after)
168 {
169   unsigned int when;
170
171   when = now + after;
172   if (when == 0) {
173     // event cancelled
174     pcd_event_times[event] = 0;
175     return;
176   }
177
178   when |= 1;
179
180   elprintf(EL_CD, "cd: new event #%u %u->%u", event, now, when);
181   pcd_event_times[event] = when;
182
183   if (event_time_next == 0 || CYCLES_GT(event_time_next, when))
184     event_time_next = when;
185 }
186
187 void pcd_event_schedule_s68k(enum pcd_event event, int after)
188 {
189   if (SekCyclesLeftS68k > after)
190     SekEndRunS68k(after);
191
192   pcd_event_schedule(SekCyclesDoneS68k(), event, after);
193 }
194
195 static void pcd_run_events(unsigned int until)
196 {
197   int oldest, oldest_diff, time;
198   int i, diff;
199
200   while (1) {
201     oldest = -1, oldest_diff = 0x7fffffff;
202
203     for (i = 0; i < PCD_EVENT_COUNT; i++) {
204       if (pcd_event_times[i]) {
205         diff = pcd_event_times[i] - until;
206         if (diff < oldest_diff) {
207           oldest_diff = diff;
208           oldest = i;
209         }
210       }
211     }
212
213     if (oldest_diff <= 0) {
214       time = pcd_event_times[oldest];
215       pcd_event_times[oldest] = 0;
216       elprintf(EL_CD, "cd: run event #%d %u", oldest, time);
217       pcd_event_cbs[oldest](time);
218     }
219     else if (oldest_diff < 0x7fffffff) {
220       event_time_next = pcd_event_times[oldest];
221       break;
222     }
223     else {
224       event_time_next = 0;
225       break;
226     }
227   }
228
229   if (oldest != -1)
230     elprintf(EL_CD, "cd: next event #%d at %u",
231       oldest, event_time_next);
232 }
233
234 int pcd_sync_s68k(unsigned int m68k_target, int m68k_poll_sync)
235 {
236   #define now SekCycleCntS68k
237   unsigned int s68k_target =
238     (unsigned long long)m68k_target * m68k_cycle_mult >> 16;
239   unsigned int target;
240
241   elprintf(EL_CD, "s68k sync to %u, %u->%u",
242     m68k_target, now, s68k_target);
243
244   if (Pico_mcd->m.busreq != 1) { /* busreq/reset */
245     SekCycleCntS68k = SekCycleAimS68k = s68k_target;
246     pcd_run_events(m68k_target);
247     return 0;
248   }
249
250   while (CYCLES_GT(s68k_target, now)) {
251     if (event_time_next && CYCLES_GE(now, event_time_next))
252       pcd_run_events(now);
253
254     target = s68k_target;
255     if (event_time_next && CYCLES_GT(target, event_time_next))
256       target = event_time_next;
257
258     SekRunS68k(target);
259     if (m68k_poll_sync && Pico_mcd->m.m68k_poll_cnt == 0)
260       break;
261   }
262
263   return s68k_target - now;
264   #undef now
265 }
266
267 #define pcd_run_cpus_normal pcd_run_cpus
268 //#define pcd_run_cpus_lockstep pcd_run_cpus
269
270 static void SekSyncM68k(void);
271
272 void pcd_run_cpus_normal(int m68k_cycles)
273 {
274   SekCycleAim += m68k_cycles;
275   if (SekShouldInterrupt() || Pico_mcd->m.m68k_poll_cnt < 12)
276     Pico_mcd->m.m68k_poll_cnt = 0;
277   else if (Pico_mcd->m.m68k_poll_cnt >= 16) {
278     int s68k_left = pcd_sync_s68k(SekCycleAim, 1);
279     if (s68k_left <= 0) {
280       elprintf(EL_CDPOLL, "m68k poll [%02x] x%d @%06x",
281         Pico_mcd->m.m68k_poll_a, Pico_mcd->m.m68k_poll_cnt, SekPc);
282       SekCycleCnt = SekCycleAim;
283       return;
284     }
285     SekCycleCnt = SekCycleAim - (s68k_left * 40220 >> 16);
286   }
287
288   SekSyncM68k();
289 }
290
291 void pcd_run_cpus_lockstep(int m68k_cycles)
292 {
293   unsigned int target = SekCycleAim + m68k_cycles;
294   do {
295     SekCycleAim += 8;
296     SekSyncM68k();
297     pcd_sync_s68k(SekCycleAim, 0);
298   } while (CYCLES_GT(target, SekCycleAim));
299
300   SekCycleAim = target;
301 }
302
303 #define PICO_CD
304 #define CPUS_RUN(m68k_cycles) \
305   pcd_run_cpus(m68k_cycles)
306
307 #include "../pico_cmn.c"
308
309
310 PICO_INTERNAL void PicoFrameMCD(void)
311 {
312   if (!(PicoOpt&POPT_ALT_RENDERER))
313     PicoFrameStart();
314
315   pcd_set_cycle_mult();
316   PicoFrameHints();
317 }
318
319 void pcd_state_loaded(void)
320 {
321   unsigned int cycles;
322   int diff;
323
324   pcd_set_cycle_mult();
325   pcd_state_loaded_mem();
326
327   memset(Pico_mcd->pcm_mixbuf, 0, sizeof(Pico_mcd->pcm_mixbuf));
328   Pico_mcd->pcm_mixbuf_dirty = 0;
329   Pico_mcd->pcm_mixpos = 0;
330
331   // old savestates..
332   cycles = pcd_cycles_m68k_to_s68k(SekCycleAim);
333   diff = cycles - SekCycleAimS68k;
334   if (diff < -1000 || diff > 1000) {
335     SekCycleCntS68k = SekCycleAimS68k = cycles;
336   }
337   if (pcd_event_times[PCD_EVENT_CDC] == 0) {
338     pcd_event_schedule(SekCycleAimS68k, PCD_EVENT_CDC, 12500000/75);
339
340     if (Pico_mcd->s68k_regs[0x31])
341       pcd_event_schedule(SekCycleAimS68k, PCD_EVENT_TIMER3,
342         Pico_mcd->s68k_regs[0x31] * 384);
343
344     if (Pico_mcd->rot_comp.Reg_58 & 0x8000) {
345       Pico_mcd->rot_comp.Reg_58 &= 0x7fff;
346       Pico_mcd->rot_comp.Reg_64  = 0;
347       if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN1)
348         SekInterruptS68k(1);
349     }
350     if (Pico_mcd->scd.Status_CDC & 0x08)
351             Update_CDC_TRansfer(Pico_mcd->s68k_regs[4] & 7);
352   }
353   if (Pico_mcd->pcm.update_cycles == 0)
354     Pico_mcd->pcm.update_cycles = cycles;
355
356   // reschedule
357   event_time_next = 0;
358   pcd_run_events(SekCycleCntS68k);
359 }
360
361 // vim:shiftwidth=2:ts=2:expandtab