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