platform ps2, handle audio similar to psp
[picodrive.git] / pico / 32x / 32x.c
CommitLineData
cff531af 1/*
2 * PicoDrive
6a98f03e 3 * (C) notaz, 2009,2010,2013
7bf552b5 4 * (C) irixxxx, 2019-2024
cff531af 5 *
6 * This work is licensed under the terms of MAME license.
7 * See COPYING file in the top-level directory.
8 */
be2c4208 9#include "../pico_int.h"
974fdb5b 10#include "../sound/ym2612.h"
f821bb70 11#include <cpu/sh2/compiler.h>
be2c4208 12
13struct Pico32x Pico32x;
83ff19ec 14SH2 sh2s[2];
be2c4208 15
397ccdc6 16#define SH2_IDLE_STATES (SH2_STATE_CPOLL|SH2_STATE_VPOLL|SH2_STATE_RPOLL|SH2_STATE_SLEEP)
19886062 17
e05b81fc 18static int REGPARM(2) sh2_irq_cb(SH2 *sh2, int level)
4ea707e1 19{
e05b81fc 20 if (sh2->pending_irl > sh2->pending_int_irq) {
f8675e28 21 elprintf_sh2(sh2, EL_32X, "ack/irl %d @ %08x",
22 level, sh2_pc(sh2));
e05b81fc 23 return 64 + sh2->pending_irl / 2;
24 } else {
f8675e28 25 elprintf_sh2(sh2, EL_32X, "ack/int %d/%d @ %08x",
26 level, sh2->pending_int_vector, sh2_pc(sh2));
e05b81fc 27 sh2->pending_int_irq = 0; // auto-clear
28 sh2->pending_level = sh2->pending_irl;
29 return sh2->pending_int_vector;
30 }
4ea707e1 31}
32
c1931173 33// MUST specify active_sh2 when called from sh2 memhandlers
d40a5af4 34void p32x_update_irls(SH2 *active_sh2, unsigned int m68k_cycles)
4ea707e1 35{
36 int irqs, mlvl = 0, slvl = 0;
a8fd6e37 37 int mrun, srun;
4ea707e1 38
eec6905e 39 if ((Pico32x.regs[0] & (P32XS_nRES|P32XS_ADEN)) != (P32XS_nRES|P32XS_ADEN))
40 return;
41
19886062 42 if (active_sh2 != NULL)
43 m68k_cycles = sh2_cycles_done_m68k(active_sh2);
44
aaea8e3e 45 // find top bit = highest irq number (0 <= irl <= 14/2) by binary search
46
4ea707e1 47 // msh2
83416730 48 irqs = Pico32x.sh2irqi[0];
aaea8e3e 49 if (irqs >= 0x10) mlvl += 8, irqs >>= 4;
50 if (irqs >= 0x04) mlvl += 4, irqs >>= 2;
51 if (irqs >= 0x02) mlvl += 2, irqs >>= 1;
4ea707e1 52
53 // ssh2
83416730 54 irqs = Pico32x.sh2irqi[1];
aaea8e3e 55 if (irqs >= 0x10) slvl += 8, irqs >>= 4;
56 if (irqs >= 0x04) slvl += 4, irqs >>= 2;
57 if (irqs >= 0x02) slvl += 2, irqs >>= 1;
4ea707e1 58
d40a5af4 59 mrun = sh2_irl_irq(&msh2, mlvl, msh2.state & SH2_STATE_RUN);
c1931173 60 if (mrun) {
d8a897a6 61 p32x_sh2_poll_event(msh2.poll_addr, &msh2, SH2_IDLE_STATES & ~SH2_STATE_SLEEP, m68k_cycles);
26d58060 62 if (msh2.state & SH2_STATE_RUN)
63 sh2_end_run(&msh2, 0);
c1931173 64 }
19886062 65
d40a5af4 66 srun = sh2_irl_irq(&ssh2, slvl, ssh2.state & SH2_STATE_RUN);
c1931173 67 if (srun) {
d8a897a6 68 p32x_sh2_poll_event(ssh2.poll_addr, &ssh2, SH2_IDLE_STATES & ~SH2_STATE_SLEEP, m68k_cycles);
26d58060 69 if (ssh2.state & SH2_STATE_RUN)
70 sh2_end_run(&ssh2, 0);
c1931173 71 }
19886062 72
a8fd6e37 73 elprintf(EL_32X, "update_irls: m %d/%d, s %d/%d", mlvl, mrun, slvl, srun);
4ea707e1 74}
75
9e1fa0a6 76// the mask register is inconsistent, CMD is supposed to be a mask,
77// while others are actually irq trigger enables?
78// TODO: test on hw..
d40a5af4 79void p32x_trigger_irq(SH2 *sh2, unsigned int m68k_cycles, unsigned int mask)
9e1fa0a6 80{
83416730 81 Pico32x.sh2irqi[0] |= mask & P32XI_VRES;
82 Pico32x.sh2irqi[1] |= mask & P32XI_VRES;
9e1fa0a6 83 Pico32x.sh2irqi[0] |= mask & (Pico32x.sh2irq_mask[0] << 3);
84 Pico32x.sh2irqi[1] |= mask & (Pico32x.sh2irq_mask[1] << 3);
85
86 p32x_update_irls(sh2, m68k_cycles);
87}
88
d40a5af4 89void p32x_update_cmd_irq(SH2 *sh2, unsigned int m68k_cycles)
9e1fa0a6 90{
91 if ((Pico32x.sh2irq_mask[0] & 2) && (Pico32x.regs[2 / 2] & 1))
92 Pico32x.sh2irqi[0] |= P32XI_CMD;
93 else
94 Pico32x.sh2irqi[0] &= ~P32XI_CMD;
95
96 if ((Pico32x.sh2irq_mask[1] & 2) && (Pico32x.regs[2 / 2] & 2))
97 Pico32x.sh2irqi[1] |= P32XI_CMD;
98 else
99 Pico32x.sh2irqi[1] &= ~P32XI_CMD;
100
101 p32x_update_irls(sh2, m68k_cycles);
102}
103
be2c4208 104void Pico32xStartup(void)
105{
106 elprintf(EL_STATUS|EL_32X, "32X startup");
107
93f9619e 108 PicoIn.AHW |= PAHW_32X;
eec6905e 109 // TODO: OOM handling
110 if (Pico32xMem == NULL) {
111 Pico32xMem = plat_mmap(0x06000000, sizeof(*Pico32xMem), 0, 0);
112 if (Pico32xMem == NULL) {
113 elprintf(EL_STATUS, "OOM");
114 return;
115 }
116 memset(Pico32xMem, 0, sizeof(struct Pico32xMem));
83ff19ec 117
eec6905e 118 sh2_init(&msh2, 0, &ssh2);
119 msh2.irq_callback = sh2_irq_cb;
120 sh2_init(&ssh2, 1, &msh2);
121 ssh2.irq_callback = sh2_irq_cb;
122 }
83ff19ec 123 PicoMemSetup32x();
045a4c52 124 p32x_pwm_ctl_changed();
a8fd6e37 125 p32x_timers_recalc();
acd35d4c 126
fa8fb754 127 Pico32x.sh2_regs[0] = P32XS2_ADEN;
128 if (Pico.m.ncart_in)
129 Pico32x.sh2_regs[0] |= P32XS_nCART;
130
be2c4208 131 if (!Pico.m.pal)
974fdb5b 132 Pico32x.vdp_regs[0] |= P32XV_nPAL;
eec6905e 133 else
134 Pico32x.vdp_regs[0] &= ~P32XV_nPAL;
be2c4208 135
2446536b 136 rendstatus_old = -1;
137
3d7abd69 138 Pico32xPrepare();
974fdb5b 139 emu_32x_startup();
be2c4208 140}
141
9f7abd68 142void Pico32xShutdown(void)
143{
eec6905e 144 Pico32x.sh2_regs[0] &= ~P32XS2_ADEN;
9f7abd68 145
146 rendstatus_old = -1;
147
148 PicoIn.AHW &= ~PAHW_32X;
9961d9fd 149 if (PicoIn.AHW & PAHW_MCD)
150 PicoMemSetupCD();
151 else
152 PicoMemSetup();
9f7abd68 153 emu_32x_startup();
154}
155
83ff19ec 156void p32x_reset_sh2s(void)
157{
158 elprintf(EL_32X, "sh2 reset");
159
160 sh2_reset(&msh2);
161 sh2_reset(&ssh2);
cd0ace28 162 sh2_peripheral_reset(&msh2);
163 sh2_peripheral_reset(&ssh2);
83ff19ec 164
165 // if we don't have BIOS set, perform it's work here.
166 // MSH2
167 if (p32x_bios_m == NULL) {
83ff19ec 168 sh2_set_gbr(0, 0x20004000);
83ff19ec 169
805fbe6f 170 if (!Pico.m.ncart_in) { // copy IDL from cartridge
61c4e511 171 unsigned int idl_src, idl_dst, idl_size; // initial data load
172 unsigned int vbr;
61c4e511 173 // initial data
91ea9406 174 idl_src = CPU_BE2(*(u32 *)(Pico.rom + 0x3d4)) & ~0xf0000000;
175 idl_dst = CPU_BE2(*(u32 *)(Pico.rom + 0x3d8)) & ~0xf0000000;
176 idl_size= CPU_BE2(*(u32 *)(Pico.rom + 0x3dc));
439cf7f8 177 // copy in guest memory space
178 idl_src += 0x2000000;
179 idl_dst += 0x6000000;
180 while (idl_size >= 4) {
181 p32x_sh2_write32(idl_dst, p32x_sh2_read32(idl_src, &msh2), &msh2);
182 idl_src += 4, idl_dst += 4, idl_size -= 4;
61c4e511 183 }
61c4e511 184
185 // VBR
91ea9406 186 vbr = CPU_BE2(*(u32 *)(Pico.rom + 0x3e8));
61c4e511 187 sh2_set_vbr(0, vbr);
188
189 // checksum and M_OK
91ea9406 190 Pico32x.regs[0x28 / 2] = *(u16 *)(Pico.rom + 0x18e);
61c4e511 191 }
83ff19ec 192 // program will set M_OK
193 }
194
195 // SSH2
196 if (p32x_bios_s == NULL) {
197 unsigned int vbr;
198
199 // GBR/VBR
91ea9406 200 vbr = CPU_BE2(*(u32 *)(Pico.rom + 0x3ec));
83ff19ec 201 sh2_set_gbr(1, 0x20004000);
202 sh2_set_vbr(1, vbr);
203 // program will set S_OK
204 }
ed4402a7 205
ae214f1c 206 msh2.m68krcycles_done = ssh2.m68krcycles_done = SekCyclesDone();
83ff19ec 207}
208
be2c4208 209void Pico32xInit(void)
210{
974fdb5b 211}
212
213void PicoPower32x(void)
214{
215 memset(&Pico32x, 0, sizeof(Pico32x));
5e49c3a8 216
83ff19ec 217 Pico32x.regs[0] = P32XS_REN|P32XS_nRES; // verified
c9f94534 218 Pico32x.regs[0x10/2] = 0xffff;
4a1fb183 219 Pico32x.vdp_regs[0x0a/2] = P32XV_VBLK|P32XV_PEN;
be2c4208 220}
221
5e49c3a8 222void PicoUnload32x(void)
223{
9961d9fd 224 if (PicoIn.AHW & PAHW_32X)
225 Pico32xShutdown();
9f7abd68 226
eec6905e 227 sh2_finish(&msh2);
228 sh2_finish(&ssh2);
229
5e49c3a8 230 if (Pico32xMem != NULL)
b081408f 231 plat_munmap(Pico32xMem, sizeof(*Pico32xMem));
5e49c3a8 232 Pico32xMem = NULL;
5e49c3a8 233}
234
be2c4208 235void PicoReset32x(void)
236{
93f9619e 237 if (PicoIn.AHW & PAHW_32X) {
ae214f1c 238 p32x_trigger_irq(NULL, SekCyclesDone(), P32XI_VRES);
d8a897a6 239 p32x_sh2_poll_event(msh2.poll_addr, &msh2, SH2_IDLE_STATES, SekCyclesDone());
240 p32x_sh2_poll_event(ssh2.poll_addr, &ssh2, SH2_IDLE_STATES, SekCyclesDone());
045a4c52 241 p32x_pwm_ctl_changed();
a8fd6e37 242 p32x_timers_recalc();
83ff19ec 243 }
be2c4208 244}
245
fdaf9d10 246static void p32x_render_frame(void)
974fdb5b 247{
93f9619e 248 if (Pico32xDrawMode != PDM32X_OFF && !PicoIn.skipFrame) {
5aec752d 249 int offs, lines;
250
251 pprof_start(draw);
252
253 offs = 8; lines = 224;
f55fb314 254 if (Pico.video.reg[1] & 8) {
7a961c19 255 offs = 0;
256 lines = 240;
257 }
258
5a681086 259 if ((Pico32x.vdp_regs[0] & P32XV_Mx) != 0 && // 32x not blanking
e0bcb7a9 260 (!(Pico.video.debug_p & PVD_KILL_32X)))
5a681086 261 {
262 int md_bg = Pico.video.reg[7] & 0x3f;
5a681086 263
264 // we draw full layer (not line-by-line)
265 PicoDraw32xLayer(offs, lines, md_bg);
266 }
52e4a905 267 else if (Pico32xDrawMode == PDM32X_BOTH)
7a961c19 268 PicoDraw32xLayerMdOnly(offs, lines);
5aec752d 269
270 pprof_end(draw);
5a681086 271 }
fdaf9d10 272}
5a681086 273
fdaf9d10 274static void p32x_start_blank(void)
275{
974fdb5b 276 // enter vblank
277 Pico32x.vdp_regs[0x0a/2] |= P32XV_VBLK|P32XV_PEN;
278
4ea707e1 279 // FB swap waits until vblank
974fdb5b 280 if ((Pico32x.vdp_regs[0x0a/2] ^ Pico32x.pending_fb) & P32XV_FS) {
eec6905e 281 Pico32x.vdp_regs[0x0a/2] ^= P32XV_FS;
282 Pico32xSwapDRAM(Pico32x.pending_fb ^ P32XV_FS);
974fdb5b 283 }
4ea707e1 284
7b02a2c3 285 p32x_trigger_irq(NULL, Pico.t.m68c_aim, P32XI_VINT);
d8a897a6 286 p32x_sh2_poll_event(msh2.poll_addr, &msh2, SH2_STATE_VPOLL, Pico.t.m68c_aim);
287 p32x_sh2_poll_event(ssh2.poll_addr, &ssh2, SH2_STATE_VPOLL, Pico.t.m68c_aim);
974fdb5b 288}
289
fdaf9d10 290static void p32x_end_blank(void)
291{
292 // end vblank
293 Pico32x.vdp_regs[0x0a/2] &= ~P32XV_VBLK; // get out of vblank
294 if ((Pico32x.vdp_regs[0] & P32XV_Mx) != 0) // no forced blanking
295 Pico32x.vdp_regs[0x0a/2] &= ~P32XV_PEN; // no palette access
7263343d 296 if (!(Pico32x.sh2_regs[0] & 0x80)) {
297 // NB must precede VInt per hw manual, min 4 SH-2 cycles to pass Mars Check
3167aa9a 298 Pico32x.hint_counter = (int)(-1.5*0x10);
d8a897a6 299 p32x_schedule_hint(NULL, Pico.t.m68c_aim);
7263343d 300 }
c9d5f41b 301
d8a897a6 302 p32x_sh2_poll_event(msh2.poll_addr, &msh2, SH2_STATE_VPOLL, Pico.t.m68c_aim);
303 p32x_sh2_poll_event(ssh2.poll_addr, &ssh2, SH2_STATE_VPOLL, Pico.t.m68c_aim);
fdaf9d10 304}
305
d40a5af4 306void p32x_schedule_hint(SH2 *sh2, unsigned int m68k_cycles)
5ac99d9a 307{
308 // rather rough, 32x hint is useless in practice
309 int after;
5ac99d9a 310 if (!((Pico32x.sh2irq_mask[0] | Pico32x.sh2irq_mask[1]) & 4))
311 return; // nobody cares
fdaf9d10 312 if (!(Pico32x.sh2_regs[0] & 0x80) && (Pico.video.status & PVS_VB2))
5ac99d9a 313 return;
314
7263343d 315 Pico32x.hint_counter += (Pico32x.sh2_regs[4 / 2] + 1) * (int)(488.5*0x10);
316 after = Pico32x.hint_counter >> 4;
317 Pico32x.hint_counter &= 0xf;
5ac99d9a 318 if (sh2 != NULL)
319 p32x_event_schedule_sh2(sh2, P32X_EVENT_HINT, after);
320 else
321 p32x_event_schedule(m68k_cycles, P32X_EVENT_HINT, after);
322}
323
a8fd6e37 324/* events */
a8fd6e37 325static void fillend_event(unsigned int now)
326{
327 Pico32x.vdp_regs[0x0a/2] &= ~P32XV_nFEN;
d8a897a6 328 p32x_sh2_poll_event(msh2.poll_addr, &msh2, SH2_STATE_VPOLL, now);
329 p32x_sh2_poll_event(ssh2.poll_addr, &ssh2, SH2_STATE_VPOLL, now);
a8fd6e37 330}
331
5ac99d9a 332static void hint_event(unsigned int now)
333{
9e1fa0a6 334 p32x_trigger_irq(NULL, now, P32XI_HINT);
5ac99d9a 335 p32x_schedule_hint(NULL, now);
336}
337
a8fd6e37 338typedef void (event_cb)(unsigned int now);
339
ae214f1c 340/* times are in m68k (7.6MHz) cycles */
341unsigned int p32x_event_times[P32X_EVENT_COUNT];
a8fd6e37 342static unsigned int event_time_next;
ae214f1c 343static event_cb *p32x_event_cbs[P32X_EVENT_COUNT] = {
24aab4da 344 p32x_pwm_irq_event, // P32X_EVENT_PWM
345 fillend_event, // P32X_EVENT_FILLEND
346 hint_event, // P32X_EVENT_HINT
a8fd6e37 347};
348
19886062 349// schedule event at some time 'after', in m68k clocks
350void p32x_event_schedule(unsigned int now, enum p32x_event event, int after)
a8fd6e37 351{
19886062 352 unsigned int when;
353
354 when = (now + after) | 1;
a8fd6e37 355
ae214f1c 356 elprintf(EL_32X, "32x: new event #%u %u->%u", event, now, when);
357 p32x_event_times[event] = when;
a8fd6e37 358
19886062 359 if (event_time_next == 0 || CYCLES_GT(event_time_next, when))
a8fd6e37 360 event_time_next = when;
361}
362
19886062 363void p32x_event_schedule_sh2(SH2 *sh2, enum p32x_event event, int after)
364{
365 unsigned int now = sh2_cycles_done_m68k(sh2);
366 int left_to_next;
367
368 p32x_event_schedule(now, event, after);
369
2fa02d5a 370 left_to_next = C_M68K_TO_SH2(sh2, (int)(event_time_next - now));
371 if (sh2_cycles_left(sh2) > left_to_next) {
372 if (left_to_next < 1)
6bb230c7 373 left_to_next = 0;
2fa02d5a 374 sh2_end_run(sh2, left_to_next);
375 }
19886062 376}
377
ae214f1c 378static void p32x_run_events(unsigned int until)
a8fd6e37 379{
380 int oldest, oldest_diff, time;
381 int i, diff;
382
383 while (1) {
384 oldest = -1, oldest_diff = 0x7fffffff;
385
386 for (i = 0; i < P32X_EVENT_COUNT; i++) {
ae214f1c 387 if (p32x_event_times[i]) {
388 diff = p32x_event_times[i] - until;
a8fd6e37 389 if (diff < oldest_diff) {
390 oldest_diff = diff;
391 oldest = i;
392 }
393 }
394 }
395
396 if (oldest_diff <= 0) {
ae214f1c 397 time = p32x_event_times[oldest];
398 p32x_event_times[oldest] = 0;
399 elprintf(EL_32X, "32x: run event #%d %u", oldest, time);
400 p32x_event_cbs[oldest](time);
a8fd6e37 401 }
402 else if (oldest_diff < 0x7fffffff) {
ae214f1c 403 event_time_next = p32x_event_times[oldest];
a8fd6e37 404 break;
405 }
406 else {
407 event_time_next = 0;
408 break;
409 }
410 }
411
412 if (oldest != -1)
ae214f1c 413 elprintf(EL_32X, "32x: next event #%d at %u",
414 oldest, event_time_next);
a8fd6e37 415}
416
d40a5af4 417static void run_sh2(SH2 *sh2, unsigned int m68k_cycles)
19886062 418{
d40a5af4 419 unsigned int cycles, done;
19886062 420
421 pevt_log_sh2_o(sh2, EVT_RUN_START);
422 sh2->state |= SH2_STATE_RUN;
2fa02d5a 423 cycles = C_M68K_TO_SH2(sh2, m68k_cycles);
f8675e28 424 elprintf_sh2(sh2, EL_32X, "+run %u %d @%08x",
425 sh2->m68krcycles_done, cycles, sh2->pc);
19886062 426
2eb21331 427 done = sh2_execute(sh2, cycles);
19886062 428
2fa02d5a 429 sh2->m68krcycles_done += C_SH2_TO_M68K(sh2, done);
19886062 430 sh2->state &= ~SH2_STATE_RUN;
431 pevt_log_sh2_o(sh2, EVT_RUN_END);
f8675e28 432 elprintf_sh2(sh2, EL_32X, "-run %u %d",
433 sh2->m68krcycles_done, done);
19886062 434}
435
436// sync other sh2 to this one
437// note: recursive call
438void p32x_sync_other_sh2(SH2 *sh2, unsigned int m68k_target)
439{
f81107f5 440 SH2 *osh2 = sh2->other_sh2;
19886062 441 int left_to_event;
442 int m68k_cycles;
443
444 if (osh2->state & SH2_STATE_RUN)
445 return;
446
447 m68k_cycles = m68k_target - osh2->m68krcycles_done;
448 if (m68k_cycles < 200)
449 return;
450
451 if (osh2->state & SH2_IDLE_STATES) {
452 osh2->m68krcycles_done = m68k_target;
453 return;
454 }
455
f8675e28 456 elprintf_sh2(osh2, EL_32X, "sync to %u %d",
457 m68k_target, m68k_cycles);
19886062 458
459 run_sh2(osh2, m68k_cycles);
460
461 // there might be new event to schedule current sh2 to
462 if (event_time_next) {
2fa02d5a 463 left_to_event = C_M68K_TO_SH2(sh2, (int)(event_time_next - m68k_target));
19886062 464 if (sh2_cycles_left(sh2) > left_to_event) {
465 if (left_to_event < 1)
6bb230c7 466 left_to_event = 0;
19886062 467 sh2_end_run(sh2, left_to_event);
468 }
469 }
470}
a8fd6e37 471
6c2041fe 472#define STEP_LS 24
86c16afd 473#define STEP_N 528 // at least one line (488)
6c2041fe 474
ed4402a7 475#define sync_sh2s_normal p32x_sync_sh2s
476//#define sync_sh2s_lockstep p32x_sync_sh2s
974fdb5b 477
a8fd6e37 478/* most timing is in 68k clock */
ed4402a7 479void sync_sh2s_normal(unsigned int m68k_target)
480{
86c16afd 481 unsigned int now, target, next, timer_cycles;
19886062 482 int cycles;
ed4402a7 483
a8fd6e37 484 elprintf(EL_32X, "sh2 sync to %u", m68k_target);
ed4402a7 485
9961d9fd 486 if ((Pico32x.regs[0] & (P32XS_nRES|P32XS_ADEN)) != (P32XS_nRES|P32XS_ADEN)) {
27e26273 487 msh2.m68krcycles_done = ssh2.m68krcycles_done = m68k_target;
ed4402a7 488 return; // rare
27e26273 489 }
ed4402a7 490
a8fd6e37 491 now = msh2.m68krcycles_done;
492 if (CYCLES_GT(now, ssh2.m68krcycles_done))
493 now = ssh2.m68krcycles_done;
494 timer_cycles = now;
495
2fa02d5a 496 pprof_start(m68k);
a8fd6e37 497 while (CYCLES_GT(m68k_target, now))
ed4402a7 498 {
a8fd6e37 499 if (event_time_next && CYCLES_GE(now, event_time_next))
ae214f1c 500 p32x_run_events(now);
ed4402a7 501
a8fd6e37 502 target = m68k_target;
503 if (event_time_next && CYCLES_GT(target, event_time_next))
504 target = event_time_next;
a8fd6e37 505 while (CYCLES_GT(target, now))
506 {
86c16afd 507 next = target;
508 if (CYCLES_GT(target, now + STEP_N))
509 next = now + STEP_N;
510 elprintf(EL_32X, "sh2 exec to %u %d,%d/%d, flags %x", next,
511 next - msh2.m68krcycles_done, next - ssh2.m68krcycles_done,
a8fd6e37 512 m68k_target - now, Pico32x.emu_flags);
ed4402a7 513
2fa02d5a 514 pprof_start(ssh2);
19886062 515 if (!(ssh2.state & SH2_IDLE_STATES)) {
86c16afd 516 cycles = next - ssh2.m68krcycles_done;
a8fd6e37 517 if (cycles > 0) {
f53e166c 518 run_sh2(&ssh2, cycles > 20U ? cycles : 20U);
a8fd6e37 519
520 if (event_time_next && CYCLES_GT(target, event_time_next))
521 target = event_time_next;
86c16afd 522 if (CYCLES_GT(next, target))
523 next = target;
a8fd6e37 524 }
ed4402a7 525 }
2fa02d5a 526 pprof_end(ssh2);
ed4402a7 527
2fa02d5a 528 pprof_start(msh2);
19886062 529 if (!(msh2.state & SH2_IDLE_STATES)) {
86c16afd 530 cycles = next - msh2.m68krcycles_done;
a8fd6e37 531 if (cycles > 0) {
f53e166c 532 run_sh2(&msh2, cycles > 20U ? cycles : 20U);
a8fd6e37 533
534 if (event_time_next && CYCLES_GT(target, event_time_next))
535 target = event_time_next;
86c16afd 536 if (CYCLES_GT(next, target))
537 next = target;
a8fd6e37 538 }
ed4402a7 539 }
2fa02d5a 540 pprof_end(msh2);
a8fd6e37 541
86c16afd 542 now = next;
2eb21331 543 if (CYCLES_GT(now, msh2.m68krcycles_done)) {
544 if (!(msh2.state & SH2_IDLE_STATES))
19886062 545 now = msh2.m68krcycles_done;
546 }
2eb21331 547 if (CYCLES_GT(now, ssh2.m68krcycles_done)) {
548 if (!(ssh2.state & SH2_IDLE_STATES))
19886062 549 now = ssh2.m68krcycles_done;
550 }
e7ee5010 551 if (CYCLES_GT(now, timer_cycles+STEP_N)) {
74cc7aeb 552 if (msh2.state & SH2_TIMER_RUN)
553 p32x_timer_do(&msh2, now - timer_cycles);
554 if (ssh2.state & SH2_TIMER_RUN)
555 p32x_timer_do(&ssh2, now - timer_cycles);
86c16afd 556 timer_cycles = now;
557 }
ed4402a7 558 }
a8fd6e37 559
74cc7aeb 560 if (msh2.state & SH2_TIMER_RUN)
561 p32x_timer_do(&msh2, now - timer_cycles);
562 if (ssh2.state & SH2_TIMER_RUN)
563 p32x_timer_do(&ssh2, now - timer_cycles);
a8fd6e37 564 timer_cycles = now;
ed4402a7 565 }
2fa02d5a 566 pprof_end_sub(m68k);
19886062 567
568 // advance idle CPUs
569 if (msh2.state & SH2_IDLE_STATES) {
570 if (CYCLES_GT(m68k_target, msh2.m68krcycles_done))
571 msh2.m68krcycles_done = m68k_target;
572 }
573 if (ssh2.state & SH2_IDLE_STATES) {
574 if (CYCLES_GT(m68k_target, ssh2.m68krcycles_done))
575 ssh2.m68krcycles_done = m68k_target;
576 }
31fbc691 577
578 // everyone is in sync now
579 Pico32x.comm_dirty = 0;
236990cf 580}
acd35d4c 581
ed4402a7 582void sync_sh2s_lockstep(unsigned int m68k_target)
583{
584 unsigned int mcycles;
585
586 mcycles = msh2.m68krcycles_done;
4af2edc3 587 if (CYCLES_GT(mcycles, ssh2.m68krcycles_done))
ed4402a7 588 mcycles = ssh2.m68krcycles_done;
589
4af2edc3 590 while (CYCLES_GT(m68k_target, mcycles)) {
6c2041fe 591 mcycles += STEP_LS;
ed4402a7 592 sync_sh2s_normal(mcycles);
593 }
87accdf7 594}
595
ae214f1c 596#define CPUS_RUN(m68k_cycles) do { \
93f9619e 597 if (PicoIn.AHW & PAHW_MCD) \
fa8fb754 598 pcd_run_cpus(m68k_cycles); \
599 else \
600 SekRunM68k(m68k_cycles); \
601 \
ae214f1c 602 if ((Pico32x.emu_flags & P32XF_Z80_32X_IO) && Pico.m.z80Run \
93f9619e 603 && !Pico.m.z80_reset && (PicoIn.opt & POPT_EN_Z80)) \
ae214f1c 604 PicoSyncZ80(SekCyclesDone()); \
19886062 605 if (Pico32x.emu_flags & (P32XF_68KCPOLL|P32XF_68KVPOLL)) \
ae214f1c 606 p32x_sync_sh2s(SekCyclesDone()); \
ed4402a7 607} while (0)
87accdf7 608
ed4402a7 609#define PICO_32X
fa8fb754 610#define PICO_CD
974fdb5b 611#include "../pico_cmn.c"
612
613void PicoFrame32x(void)
614{
93f9619e 615 if (PicoIn.AHW & PAHW_MCD)
a6523294 616 pcd_prepare_frame();
617
974fdb5b 618 PicoFrameStart();
f9ed9446 619 if (Pico32xDrawMode != PDM32X_BOTH)
620 Pico.est.rendstatus |= PDRAW_SYNC_NEEDED;
974fdb5b 621 PicoFrameHints();
51d86e55 622
19886062 623 elprintf(EL_32X, "poll: %02x %02x %02x",
624 Pico32x.emu_flags & 3, msh2.state, ssh2.state);
974fdb5b 625}
db1d3564 626
ed4402a7 627// calculate multipliers against 68k clock (7670442)
628// normally * 3, but effectively slower due to high latencies everywhere
629// however using something lower breaks MK2 animations
630void Pico32xSetClocks(int msh2_hz, int ssh2_hz)
631{
632 float m68k_clk = (float)(OSC_NTSC / 7);
633 if (msh2_hz > 0) {
634 msh2.mult_m68k_to_sh2 = (int)((float)msh2_hz * (1 << CYCLE_MULT_SHIFT) / m68k_clk);
635 msh2.mult_sh2_to_m68k = (int)(m68k_clk * (1 << CYCLE_MULT_SHIFT) / (float)msh2_hz);
636 }
637 if (ssh2_hz > 0) {
638 ssh2.mult_m68k_to_sh2 = (int)((float)ssh2_hz * (1 << CYCLE_MULT_SHIFT) / m68k_clk);
639 ssh2.mult_sh2_to_m68k = (int)(m68k_clk * (1 << CYCLE_MULT_SHIFT) / (float)ssh2_hz);
640 }
641}
642
27e26273 643void Pico32xStateLoaded(int is_early)
644{
645 if (is_early) {
646 Pico32xMemStateLoaded();
647 return;
648 }
649
7263343d 650 if (CYCLES_GE(sh2s[0].m68krcycles_done - Pico.t.m68c_aim, 500) ||
651 CYCLES_GE(sh2s[1].m68krcycles_done - Pico.t.m68c_aim, 500))
96baa875 652 sh2s[0].m68krcycles_done = sh2s[1].m68krcycles_done = SekCyclesDone();
ae214f1c 653 p32x_update_irls(NULL, SekCyclesDone());
b1a65866 654 p32x_timers_recalc();
df63f1a6 655 p32x_pwm_state_loaded();
ae214f1c 656 p32x_run_events(SekCyclesDone());
27e26273 657}
658
3d7abd69 659void Pico32xPrepare(void)
660{
7263343d 661 if (msh2.mult_m68k_to_sh2 == 0 || msh2.mult_sh2_to_m68k == 0)
662 Pico32xSetClocks(PICO_MSH2_HZ, 0);
663 if (ssh2.mult_m68k_to_sh2 == 0 || ssh2.mult_sh2_to_m68k == 0)
664 Pico32xSetClocks(0, PICO_MSH2_HZ);
665
3d7abd69 666 sh2_execute_prepare(&msh2, PicoIn.opt & POPT_EN_DRC);
667 sh2_execute_prepare(&ssh2, PicoIn.opt & POPT_EN_DRC);
668}
669
ed4402a7 670// vim:shiftwidth=2:ts=2:expandtab