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