32x: some accuracy improvements
[picodrive.git] / pico / 32x / 32x.c
1 /*
2  * PicoDrive
3  * (C) notaz, 2009,2010,2013
4  *
5  * This work is licensed under the terms of MAME license.
6  * See COPYING file in the top-level directory.
7  */
8 #include "../pico_int.h"
9 #include "../sound/ym2612.h"
10 #include "../../cpu/sh2/compiler.h"
11
12 struct Pico32x Pico32x;
13 SH2 sh2s[2];
14
15 #define SH2_IDLE_STATES (SH2_STATE_CPOLL|SH2_STATE_VPOLL|SH2_STATE_SLEEP)
16
17 static int REGPARM(2) sh2_irq_cb(SH2 *sh2, int level)
18 {
19   if (sh2->pending_irl > sh2->pending_int_irq) {
20     elprintf(EL_32X, "%csh2 ack/irl %d @ %08x",
21       sh2->is_slave ? 's' : 'm', level, sh2->pc);
22     return 64 + sh2->pending_irl / 2;
23   } else {
24     elprintf(EL_32X, "%csh2 ack/int %d/%d @ %08x",
25       sh2->is_slave ? 's' : 'm', level, sh2->pending_int_vector, sh2->pc);
26     sh2->pending_int_irq = 0; // auto-clear
27     sh2->pending_level = sh2->pending_irl;
28     return sh2->pending_int_vector;
29   }
30 }
31
32 void p32x_update_irls(SH2 *active_sh2, int m68k_cycles)
33 {
34   int irqs, mlvl = 0, slvl = 0;
35   int mrun, srun;
36
37   if (active_sh2 != NULL)
38     m68k_cycles = sh2_cycles_done_m68k(active_sh2);
39
40   // msh2
41   irqs = (Pico32x.sh2irqs | Pico32x.sh2irqi[0]) & ((Pico32x.sh2irq_mask[0] << 3) | P32XI_VRES);
42   while ((irqs >>= 1))
43     mlvl++;
44   mlvl *= 2;
45
46   // ssh2
47   irqs = (Pico32x.sh2irqs | Pico32x.sh2irqi[1]) & ((Pico32x.sh2irq_mask[1] << 3) | P32XI_VRES);
48   while ((irqs >>= 1))
49     slvl++;
50   slvl *= 2;
51
52   mrun = sh2_irl_irq(&msh2, mlvl, active_sh2 != NULL);
53   if (mrun)
54     p32x_sh2_poll_event(&msh2, SH2_IDLE_STATES, m68k_cycles);
55
56   srun = sh2_irl_irq(&ssh2, slvl, active_sh2 != NULL);
57   if (srun)
58     p32x_sh2_poll_event(&ssh2, SH2_IDLE_STATES, m68k_cycles);
59
60   elprintf(EL_32X, "update_irls: m %d/%d, s %d/%d", mlvl, mrun, slvl, srun);
61 }
62
63 void Pico32xStartup(void)
64 {
65   elprintf(EL_STATUS|EL_32X, "32X startup");
66
67   // TODO: OOM handling
68   PicoAHW |= PAHW_32X;
69   sh2_init(&msh2, 0);
70   msh2.irq_callback = sh2_irq_cb;
71   sh2_init(&ssh2, 1);
72   ssh2.irq_callback = sh2_irq_cb;
73
74   PicoMemSetup32x();
75   p32x_pwm_ctl_changed();
76   p32x_timers_recalc();
77
78   if (!Pico.m.pal)
79     Pico32x.vdp_regs[0] |= P32XV_nPAL;
80
81   PREG8(Pico32xMem->sh2_peri_regs[0], 4) =
82   PREG8(Pico32xMem->sh2_peri_regs[1], 4) = 0x84; // SCI SSR
83
84   rendstatus_old = -1;
85
86   emu_32x_startup();
87 }
88
89 #define HWSWAP(x) (((x) << 16) | ((x) >> 16))
90 void p32x_reset_sh2s(void)
91 {
92   elprintf(EL_32X, "sh2 reset");
93
94   sh2_reset(&msh2);
95   sh2_reset(&ssh2);
96
97   // if we don't have BIOS set, perform it's work here.
98   // MSH2
99   if (p32x_bios_m == NULL) {
100     unsigned int idl_src, idl_dst, idl_size; // initial data load
101     unsigned int vbr;
102
103     // initial data
104     idl_src = HWSWAP(*(unsigned int *)(Pico.rom + 0x3d4)) & ~0xf0000000;
105     idl_dst = HWSWAP(*(unsigned int *)(Pico.rom + 0x3d8)) & ~0xf0000000;
106     idl_size= HWSWAP(*(unsigned int *)(Pico.rom + 0x3dc));
107     if (idl_size > Pico.romsize || idl_src + idl_size > Pico.romsize ||
108         idl_size > 0x40000 || idl_dst + idl_size > 0x40000 || (idl_src & 3) || (idl_dst & 3)) {
109       elprintf(EL_STATUS|EL_ANOMALY, "32x: invalid initial data ptrs: %06x -> %06x, %06x",
110         idl_src, idl_dst, idl_size);
111     }
112     else
113       memcpy(Pico32xMem->sdram + idl_dst, Pico.rom + idl_src, idl_size);
114
115     // GBR/VBR
116     vbr = HWSWAP(*(unsigned int *)(Pico.rom + 0x3e8));
117     sh2_set_gbr(0, 0x20004000);
118     sh2_set_vbr(0, vbr);
119
120     // checksum and M_OK
121     Pico32x.regs[0x28 / 2] = *(unsigned short *)(Pico.rom + 0x18e);
122     // program will set M_OK
123   }
124
125   // SSH2
126   if (p32x_bios_s == NULL) {
127     unsigned int vbr;
128
129     // GBR/VBR
130     vbr = HWSWAP(*(unsigned int *)(Pico.rom + 0x3ec));
131     sh2_set_gbr(1, 0x20004000);
132     sh2_set_vbr(1, vbr);
133     // program will set S_OK
134   }
135
136   msh2.m68krcycles_done = ssh2.m68krcycles_done = SekCyclesDoneT();
137 }
138
139 void Pico32xInit(void)
140 {
141   if (msh2.mult_m68k_to_sh2 == 0 || msh2.mult_sh2_to_m68k == 0)
142     Pico32xSetClocks(PICO_MSH2_HZ, 0);
143   if (ssh2.mult_m68k_to_sh2 == 0 || ssh2.mult_sh2_to_m68k == 0)
144     Pico32xSetClocks(0, PICO_MSH2_HZ);
145 }
146
147 void PicoPower32x(void)
148 {
149   memset(&Pico32x, 0, sizeof(Pico32x));
150
151   Pico32x.regs[0] = P32XS_REN|P32XS_nRES; // verified
152   Pico32x.vdp_regs[0x0a/2] = P32XV_VBLK|P32XV_HBLK|P32XV_PEN;
153   Pico32x.sh2_regs[0] = P32XS2_ADEN;
154 }
155
156 void PicoUnload32x(void)
157 {
158   if (Pico32xMem != NULL)
159     plat_munmap(Pico32xMem, sizeof(*Pico32xMem));
160   Pico32xMem = NULL;
161   sh2_finish(&msh2);
162   sh2_finish(&ssh2);
163
164   PicoAHW &= ~PAHW_32X;
165 }
166
167 void PicoReset32x(void)
168 {
169   if (PicoAHW & PAHW_32X) {
170     Pico32x.sh2irqs |= P32XI_VRES;
171     p32x_update_irls(NULL, SekCyclesDoneT2());
172     p32x_sh2_poll_event(&msh2, SH2_IDLE_STATES, 0);
173     p32x_sh2_poll_event(&ssh2, SH2_IDLE_STATES, 0);
174     p32x_pwm_ctl_changed();
175     p32x_timers_recalc();
176   }
177 }
178
179 static void p32x_start_blank(void)
180 {
181   if (Pico32xDrawMode != PDM32X_OFF && !PicoSkipFrame) {
182     int offs, lines;
183
184     pprof_start(draw);
185
186     offs = 8; lines = 224;
187     if ((Pico.video.reg[1] & 8) && !(PicoOpt & POPT_ALT_RENDERER)) {
188       offs = 0;
189       lines = 240;
190     }
191
192     // XXX: no proper handling of 32col mode..
193     if ((Pico32x.vdp_regs[0] & P32XV_Mx) != 0 && // 32x not blanking
194         (Pico.video.reg[12] & 1) && // 40col mode
195         (PicoDrawMask & PDRAW_32X_ON))
196     {
197       int md_bg = Pico.video.reg[7] & 0x3f;
198
199       // we draw full layer (not line-by-line)
200       PicoDraw32xLayer(offs, lines, md_bg);
201     }
202     else if (Pico32xDrawMode != PDM32X_32X_ONLY)
203       PicoDraw32xLayerMdOnly(offs, lines);
204
205     pprof_end(draw);
206   }
207
208   // enter vblank
209   Pico32x.vdp_regs[0x0a/2] |= P32XV_VBLK|P32XV_PEN;
210
211   // FB swap waits until vblank
212   if ((Pico32x.vdp_regs[0x0a/2] ^ Pico32x.pending_fb) & P32XV_FS) {
213     Pico32x.vdp_regs[0x0a/2] &= ~P32XV_FS;
214     Pico32x.vdp_regs[0x0a/2] |= Pico32x.pending_fb;
215     Pico32xSwapDRAM(Pico32x.pending_fb ^ 1);
216   }
217
218   Pico32x.sh2irqs |= P32XI_VINT;
219   p32x_update_irls(NULL, SekCyclesDoneT2());
220   p32x_sh2_poll_event(&msh2, SH2_STATE_VPOLL, 0);
221   p32x_sh2_poll_event(&ssh2, SH2_STATE_VPOLL, 0);
222 }
223
224 // compare cycles, handling overflows
225 // check if a > b
226 #define CYCLES_GT(a, b) \
227   ((int)((a) - (b)) > 0)
228 // check if a >= b
229 #define CYCLES_GE(a, b) \
230   ((int)((a) - (b)) >= 0)
231
232 /* events */
233 static void fillend_event(unsigned int now)
234 {
235   Pico32x.vdp_regs[0x0a/2] &= ~P32XV_nFEN;
236   p32x_sh2_poll_event(&msh2, SH2_STATE_VPOLL, now);
237   p32x_sh2_poll_event(&ssh2, SH2_STATE_VPOLL, now);
238 }
239
240 typedef void (event_cb)(unsigned int now);
241
242 unsigned int event_times[P32X_EVENT_COUNT];
243 static unsigned int event_time_next;
244 static event_cb *event_cbs[] = {
245   [P32X_EVENT_PWM]      = p32x_pwm_irq_event,
246   [P32X_EVENT_FILLEND]  = fillend_event,
247 };
248
249 // schedule event at some time 'after', in m68k clocks
250 void p32x_event_schedule(unsigned int now, enum p32x_event event, int after)
251 {
252   unsigned int when;
253
254   when = (now + after) | 1;
255
256   elprintf(EL_32X, "new event #%u %u->%u", event, now, when);
257   event_times[event] = when;
258
259   if (event_time_next == 0 || CYCLES_GT(event_time_next, when))
260     event_time_next = when;
261 }
262
263 void p32x_event_schedule_sh2(SH2 *sh2, enum p32x_event event, int after)
264 {
265   unsigned int now = sh2_cycles_done_m68k(sh2);
266   int left_to_next;
267
268   p32x_event_schedule(now, event, after);
269
270   left_to_next = (event_time_next - now) * 3;
271   if (sh2_cycles_left(sh2) > left_to_next)
272     sh2_end_run(sh2, left_to_next);
273 }
274
275 static void run_events(unsigned int until)
276 {
277   int oldest, oldest_diff, time;
278   int i, diff;
279
280   while (1) {
281     oldest = -1, oldest_diff = 0x7fffffff;
282
283     for (i = 0; i < P32X_EVENT_COUNT; i++) {
284       if (event_times[i]) {
285         diff = event_times[i] - until;
286         if (diff < oldest_diff) {
287           oldest_diff = diff;
288           oldest = i;
289         }
290       }
291     }
292
293     if (oldest_diff <= 0) {
294       time = event_times[oldest];
295       event_times[oldest] = 0;
296       elprintf(EL_32X, "run event #%d %u", oldest, time);
297       event_cbs[oldest](time);
298     }
299     else if (oldest_diff < 0x7fffffff) {
300       event_time_next = event_times[oldest];
301       break;
302     }
303     else {
304       event_time_next = 0;
305       break;
306     }
307   }
308
309   if (oldest != -1)
310     elprintf(EL_32X, "next event #%d at %u", oldest, event_time_next);
311 }
312
313 static inline void run_sh2(SH2 *sh2, int m68k_cycles)
314 {
315   int cycles, done;
316
317   pevt_log_sh2_o(sh2, EVT_RUN_START);
318   sh2->state |= SH2_STATE_RUN;
319   cycles = C_M68K_TO_SH2(*sh2, m68k_cycles);
320   elprintf(EL_32X, "%csh2 +run %u %d",
321     sh2->is_slave?'s':'m', sh2->m68krcycles_done, cycles);
322
323   done = sh2_execute(sh2, cycles);
324
325   sh2->m68krcycles_done += C_SH2_TO_M68K(*sh2, done);
326   sh2->state &= ~SH2_STATE_RUN;
327   pevt_log_sh2_o(sh2, EVT_RUN_END);
328   elprintf(EL_32X, "%csh2 -run %u %d",
329     sh2->is_slave?'s':'m', sh2->m68krcycles_done, done);
330 }
331
332 // sync other sh2 to this one
333 // note: recursive call
334 void p32x_sync_other_sh2(SH2 *sh2, unsigned int m68k_target)
335 {
336   SH2 *osh2 = &sh2s[sh2->is_slave ^ 1];
337   int left_to_event;
338   int m68k_cycles;
339
340   if (osh2->state & SH2_STATE_RUN)
341     return;
342
343   m68k_cycles = m68k_target - osh2->m68krcycles_done;
344   if (m68k_cycles < 200)
345     return;
346
347   if (osh2->state & SH2_IDLE_STATES) {
348     osh2->m68krcycles_done = m68k_target;
349     return;
350   }
351
352   elprintf(EL_32X, "%csh2 sync to %u %d",
353     osh2->is_slave?'s':'m', m68k_target, m68k_cycles);
354
355   run_sh2(osh2, m68k_cycles);
356
357   // there might be new event to schedule current sh2 to
358   if (event_time_next) {
359     left_to_event = event_time_next - m68k_target;
360     left_to_event *= 3;
361     if (sh2_cycles_left(sh2) > left_to_event) {
362       if (left_to_event < 1)
363         left_to_event = 1;
364       sh2_end_run(sh2, left_to_event);
365     }
366   }
367 }
368
369 #define sync_sh2s_normal p32x_sync_sh2s
370 //#define sync_sh2s_lockstep p32x_sync_sh2s
371
372 /* most timing is in 68k clock */
373 void sync_sh2s_normal(unsigned int m68k_target)
374 {
375   unsigned int now, target, timer_cycles;
376   int cycles;
377
378   elprintf(EL_32X, "sh2 sync to %u", m68k_target);
379
380   if (!(Pico32x.regs[0] & P32XS_nRES)) {
381     msh2.m68krcycles_done = ssh2.m68krcycles_done = m68k_target;
382     return; // rare
383   }
384
385   now = msh2.m68krcycles_done;
386   if (CYCLES_GT(now, ssh2.m68krcycles_done))
387     now = ssh2.m68krcycles_done;
388   timer_cycles = now;
389
390   while (CYCLES_GT(m68k_target, now))
391   {
392     if (event_time_next && CYCLES_GE(now, event_time_next))
393       run_events(now);
394
395     target = m68k_target;
396     if (event_time_next && CYCLES_GT(target, event_time_next))
397       target = event_time_next;
398
399     while (CYCLES_GT(target, now))
400     {
401       elprintf(EL_32X, "sh2 exec to %u %d,%d/%d, flags %x", target,
402         target - msh2.m68krcycles_done, target - ssh2.m68krcycles_done,
403         m68k_target - now, Pico32x.emu_flags);
404
405       if (!(ssh2.state & SH2_IDLE_STATES)) {
406         cycles = target - ssh2.m68krcycles_done;
407         if (cycles > 0) {
408           run_sh2(&ssh2, cycles);
409
410           if (event_time_next && CYCLES_GT(target, event_time_next))
411             target = event_time_next;
412         }
413       }
414
415       if (!(msh2.state & SH2_IDLE_STATES)) {
416         cycles = target - msh2.m68krcycles_done;
417         if (cycles > 0) {
418           run_sh2(&msh2, cycles);
419
420           if (event_time_next && CYCLES_GT(target, event_time_next))
421             target = event_time_next;
422         }
423       }
424
425       now = target;
426       if (!(msh2.state & SH2_IDLE_STATES)) {
427         if (CYCLES_GT(now, msh2.m68krcycles_done))
428           now = msh2.m68krcycles_done;
429       }
430       if (!(ssh2.state & SH2_IDLE_STATES)) {
431         if (CYCLES_GT(now, ssh2.m68krcycles_done))
432           now = ssh2.m68krcycles_done;
433       }
434     }
435
436     p32x_timers_do(now - timer_cycles);
437     timer_cycles = now;
438   }
439
440   // advance idle CPUs
441   if (msh2.state & SH2_IDLE_STATES) {
442     if (CYCLES_GT(m68k_target, msh2.m68krcycles_done))
443       msh2.m68krcycles_done = m68k_target;
444   }
445   if (ssh2.state & SH2_IDLE_STATES) {
446     if (CYCLES_GT(m68k_target, ssh2.m68krcycles_done))
447       ssh2.m68krcycles_done = m68k_target;
448   }
449 }
450
451 #define STEP_68K 24
452
453 void sync_sh2s_lockstep(unsigned int m68k_target)
454 {
455   unsigned int mcycles;
456   
457   mcycles = msh2.m68krcycles_done;
458   if (ssh2.m68krcycles_done < mcycles)
459     mcycles = ssh2.m68krcycles_done;
460
461   while (mcycles < m68k_target) {
462     mcycles += STEP_68K;
463     sync_sh2s_normal(mcycles);
464   }
465 }
466
467 #define CPUS_RUN(m68k_cycles,s68k_cycles) do { \
468   SekRunM68k(m68k_cycles); \
469   if (Pico32x.emu_flags & (P32XF_68KCPOLL|P32XF_68KVPOLL)) \
470     p32x_sync_sh2s(SekCyclesDoneT2()); \
471 } while (0)
472
473 #define PICO_32X
474 #include "../pico_cmn.c"
475
476 void PicoFrame32x(void)
477 {
478   Pico32x.vdp_regs[0x0a/2] &= ~P32XV_VBLK; // get out of vblank
479   if ((Pico32x.vdp_regs[0] & P32XV_Mx) != 0) // no forced blanking
480     Pico32x.vdp_regs[0x0a/2] &= ~P32XV_PEN; // no palette access
481
482   p32x_sh2_poll_event(&msh2, SH2_STATE_VPOLL, 0);
483   p32x_sh2_poll_event(&ssh2, SH2_STATE_VPOLL, 0);
484
485   PicoFrameStart();
486   PicoFrameHints();
487   sh2_drc_frame();
488
489   elprintf(EL_32X, "poll: %02x %02x %02x",
490     Pico32x.emu_flags & 3, msh2.state, ssh2.state);
491 }
492
493 // calculate multipliers against 68k clock (7670442)
494 // normally * 3, but effectively slower due to high latencies everywhere
495 // however using something lower breaks MK2 animations
496 void Pico32xSetClocks(int msh2_hz, int ssh2_hz)
497 {
498   float m68k_clk = (float)(OSC_NTSC / 7);
499   if (msh2_hz > 0) {
500     msh2.mult_m68k_to_sh2 = (int)((float)msh2_hz * (1 << CYCLE_MULT_SHIFT) / m68k_clk);
501     msh2.mult_sh2_to_m68k = (int)(m68k_clk * (1 << CYCLE_MULT_SHIFT) / (float)msh2_hz);
502   }
503   if (ssh2_hz > 0) {
504     ssh2.mult_m68k_to_sh2 = (int)((float)ssh2_hz * (1 << CYCLE_MULT_SHIFT) / m68k_clk);
505     ssh2.mult_sh2_to_m68k = (int)(m68k_clk * (1 << CYCLE_MULT_SHIFT) / (float)ssh2_hz);
506   }
507 }
508
509 void Pico32xStateLoaded(int is_early)
510 {
511   if (is_early) {
512     Pico32xMemStateLoaded();
513     return;
514   }
515
516   SekCycleCnt = 0;
517   sh2s[0].m68krcycles_done = sh2s[1].m68krcycles_done = SekCycleCntT;
518   p32x_update_irls(NULL, SekCycleCntT);
519   p32x_pwm_state_loaded();
520   run_events(SekCycleCntT);
521 }
522
523 // vim:shiftwidth=2:ts=2:expandtab