X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=picodrive.git;a=blobdiff_plain;f=pico%2F32x%2F32x.c;h=51817c0d70ad307450f2be8a6479822c6d5a5169;hp=f461187671e513a3a29e04702a589ae998361f50;hb=e0bcb7a90d06b295b1ca989b6ad70412912cca5b;hpb=f8675e282e7aa72bc6ab0edbb1dada4395d1c44c diff --git a/pico/32x/32x.c b/pico/32x/32x.c index f461187..51817c0 100644 --- a/pico/32x/32x.c +++ b/pico/32x/32x.c @@ -39,13 +39,13 @@ void p32x_update_irls(SH2 *active_sh2, int m68k_cycles) m68k_cycles = sh2_cycles_done_m68k(active_sh2); // msh2 - irqs = (Pico32x.sh2irqs | Pico32x.sh2irqi[0]) & ((Pico32x.sh2irq_mask[0] << 3) | P32XI_VRES); + irqs = Pico32x.sh2irqs | Pico32x.sh2irqi[0]; while ((irqs >>= 1)) mlvl++; mlvl *= 2; // ssh2 - irqs = (Pico32x.sh2irqs | Pico32x.sh2irqi[1]) & ((Pico32x.sh2irq_mask[1] << 3) | P32XI_VRES); + irqs = Pico32x.sh2irqs | Pico32x.sh2irqi[1]; while ((irqs >>= 1)) slvl++; slvl *= 2; @@ -67,6 +67,33 @@ void p32x_update_irls(SH2 *active_sh2, int m68k_cycles) elprintf(EL_32X, "update_irls: m %d/%d, s %d/%d", mlvl, mrun, slvl, srun); } +// the mask register is inconsistent, CMD is supposed to be a mask, +// while others are actually irq trigger enables? +// TODO: test on hw.. +void p32x_trigger_irq(SH2 *sh2, int m68k_cycles, unsigned int mask) +{ + Pico32x.sh2irqs |= mask & P32XI_VRES; + Pico32x.sh2irqi[0] |= mask & (Pico32x.sh2irq_mask[0] << 3); + Pico32x.sh2irqi[1] |= mask & (Pico32x.sh2irq_mask[1] << 3); + + p32x_update_irls(sh2, m68k_cycles); +} + +void p32x_update_cmd_irq(SH2 *sh2, int m68k_cycles) +{ + if ((Pico32x.sh2irq_mask[0] & 2) && (Pico32x.regs[2 / 2] & 1)) + Pico32x.sh2irqi[0] |= P32XI_CMD; + else + Pico32x.sh2irqi[0] &= ~P32XI_CMD; + + if ((Pico32x.sh2irq_mask[1] & 2) && (Pico32x.regs[2 / 2] & 2)) + Pico32x.sh2irqi[1] |= P32XI_CMD; + else + Pico32x.sh2irqi[1] &= ~P32XI_CMD; + + p32x_update_irls(sh2, m68k_cycles); +} + void Pico32xStartup(void) { elprintf(EL_STATUS|EL_32X, "32X startup"); @@ -82,6 +109,10 @@ void Pico32xStartup(void) p32x_pwm_ctl_changed(); p32x_timers_recalc(); + Pico32x.sh2_regs[0] = P32XS2_ADEN; + if (Pico.m.ncart_in) + Pico32x.sh2_regs[0] |= P32XS_nCART; + if (!Pico.m.pal) Pico32x.vdp_regs[0] |= P32XV_nPAL; @@ -103,28 +134,31 @@ void p32x_reset_sh2s(void) // if we don't have BIOS set, perform it's work here. // MSH2 if (p32x_bios_m == NULL) { - unsigned int idl_src, idl_dst, idl_size; // initial data load - unsigned int vbr; + sh2_set_gbr(0, 0x20004000); - // initial data - idl_src = HWSWAP(*(unsigned int *)(Pico.rom + 0x3d4)) & ~0xf0000000; - idl_dst = HWSWAP(*(unsigned int *)(Pico.rom + 0x3d8)) & ~0xf0000000; - idl_size= HWSWAP(*(unsigned int *)(Pico.rom + 0x3dc)); - if (idl_size > Pico.romsize || idl_src + idl_size > Pico.romsize || - idl_size > 0x40000 || idl_dst + idl_size > 0x40000 || (idl_src & 3) || (idl_dst & 3)) { - elprintf(EL_STATUS|EL_ANOMALY, "32x: invalid initial data ptrs: %06x -> %06x, %06x", - idl_src, idl_dst, idl_size); - } - else - memcpy(Pico32xMem->sdram + idl_dst, Pico.rom + idl_src, idl_size); + if (!(PicoAHW & PAHW_MCD)) { + unsigned int idl_src, idl_dst, idl_size; // initial data load + unsigned int vbr; + + // initial data + idl_src = HWSWAP(*(unsigned int *)(Pico.rom + 0x3d4)) & ~0xf0000000; + idl_dst = HWSWAP(*(unsigned int *)(Pico.rom + 0x3d8)) & ~0xf0000000; + idl_size= HWSWAP(*(unsigned int *)(Pico.rom + 0x3dc)); + if (idl_size > Pico.romsize || idl_src + idl_size > Pico.romsize || + idl_size > 0x40000 || idl_dst + idl_size > 0x40000 || (idl_src & 3) || (idl_dst & 3)) { + elprintf(EL_STATUS|EL_ANOMALY, "32x: invalid initial data ptrs: %06x -> %06x, %06x", + idl_src, idl_dst, idl_size); + } + else + memcpy(Pico32xMem->sdram + idl_dst, Pico.rom + idl_src, idl_size); - // GBR/VBR - vbr = HWSWAP(*(unsigned int *)(Pico.rom + 0x3e8)); - sh2_set_gbr(0, 0x20004000); - sh2_set_vbr(0, vbr); + // VBR + vbr = HWSWAP(*(unsigned int *)(Pico.rom + 0x3e8)); + sh2_set_vbr(0, vbr); - // checksum and M_OK - Pico32x.regs[0x28 / 2] = *(unsigned short *)(Pico.rom + 0x18e); + // checksum and M_OK + Pico32x.regs[0x28 / 2] = *(unsigned short *)(Pico.rom + 0x18e); + } // program will set M_OK } @@ -139,7 +173,7 @@ void p32x_reset_sh2s(void) // program will set S_OK } - msh2.m68krcycles_done = ssh2.m68krcycles_done = SekCyclesDoneT(); + msh2.m68krcycles_done = ssh2.m68krcycles_done = SekCyclesDone(); } void Pico32xInit(void) @@ -156,7 +190,6 @@ void PicoPower32x(void) Pico32x.regs[0] = P32XS_REN|P32XS_nRES; // verified Pico32x.vdp_regs[0x0a/2] = P32XV_VBLK|P32XV_PEN; - Pico32x.sh2_regs[0] = P32XS2_ADEN; } void PicoUnload32x(void) @@ -173,9 +206,7 @@ void PicoUnload32x(void) void PicoReset32x(void) { if (PicoAHW & PAHW_32X) { - msh2.m68krcycles_done = ssh2.m68krcycles_done = SekCyclesDoneT(); - Pico32x.sh2irqs |= P32XI_VRES; - p32x_update_irls(NULL, SekCyclesDoneT2()); + p32x_trigger_irq(NULL, SekCyclesDone(), P32XI_VRES); p32x_sh2_poll_event(&msh2, SH2_IDLE_STATES, 0); p32x_sh2_poll_event(&ssh2, SH2_IDLE_STATES, 0); p32x_pwm_ctl_changed(); @@ -199,7 +230,7 @@ static void p32x_start_blank(void) // XXX: no proper handling of 32col mode.. if ((Pico32x.vdp_regs[0] & P32XV_Mx) != 0 && // 32x not blanking (Pico.video.reg[12] & 1) && // 40col mode - (PicoDrawMask & PDRAW_32X_ON)) + (!(Pico.video.debug_p & PVD_KILL_32X))) { int md_bg = Pico.video.reg[7] & 0x3f; @@ -222,19 +253,29 @@ static void p32x_start_blank(void) Pico32xSwapDRAM(Pico32x.pending_fb ^ 1); } - Pico32x.sh2irqs |= P32XI_VINT; - p32x_update_irls(NULL, SekCyclesDoneT2()); + p32x_trigger_irq(NULL, SekCyclesDone(), P32XI_VINT); p32x_sh2_poll_event(&msh2, SH2_STATE_VPOLL, 0); p32x_sh2_poll_event(&ssh2, SH2_STATE_VPOLL, 0); } -// compare cycles, handling overflows -// check if a > b -#define CYCLES_GT(a, b) \ - ((int)((a) - (b)) > 0) -// check if a >= b -#define CYCLES_GE(a, b) \ - ((int)((a) - (b)) >= 0) +void p32x_schedule_hint(SH2 *sh2, int m68k_cycles) +{ + // rather rough, 32x hint is useless in practice + int after; + + if (!((Pico32x.sh2irq_mask[0] | Pico32x.sh2irq_mask[1]) & 4)) + return; // nobody cares + // note: when Pico.m.scanline is 224, SH2s might + // still be at scanline 93 (or so) + if (!(Pico32x.sh2_regs[0] & 0x80) && Pico.m.scanline > 224) + return; + + after = (Pico32x.sh2_regs[4 / 2] + 1) * 488; + if (sh2 != NULL) + p32x_event_schedule_sh2(sh2, P32X_EVENT_HINT, after); + else + p32x_event_schedule(m68k_cycles, P32X_EVENT_HINT, after); +} /* events */ static void fillend_event(unsigned int now) @@ -244,13 +285,21 @@ static void fillend_event(unsigned int now) p32x_sh2_poll_event(&ssh2, SH2_STATE_VPOLL, now); } +static void hint_event(unsigned int now) +{ + p32x_trigger_irq(NULL, now, P32XI_HINT); + p32x_schedule_hint(NULL, now); +} + typedef void (event_cb)(unsigned int now); -unsigned int event_times[P32X_EVENT_COUNT]; +/* times are in m68k (7.6MHz) cycles */ +unsigned int p32x_event_times[P32X_EVENT_COUNT]; static unsigned int event_time_next; -static event_cb *event_cbs[] = { +static event_cb *p32x_event_cbs[P32X_EVENT_COUNT] = { [P32X_EVENT_PWM] = p32x_pwm_irq_event, [P32X_EVENT_FILLEND] = fillend_event, + [P32X_EVENT_HINT] = hint_event, }; // schedule event at some time 'after', in m68k clocks @@ -260,8 +309,8 @@ void p32x_event_schedule(unsigned int now, enum p32x_event event, int after) when = (now + after) | 1; - elprintf(EL_32X, "new event #%u %u->%u", event, now, when); - event_times[event] = when; + elprintf(EL_32X, "32x: new event #%u %u->%u", event, now, when); + p32x_event_times[event] = when; if (event_time_next == 0 || CYCLES_GT(event_time_next, when)) event_time_next = when; @@ -278,7 +327,7 @@ void p32x_event_schedule_sh2(SH2 *sh2, enum p32x_event event, int after) sh2_end_run(sh2, left_to_next); } -static void run_events(unsigned int until) +static void p32x_run_events(unsigned int until) { int oldest, oldest_diff, time; int i, diff; @@ -287,8 +336,8 @@ static void run_events(unsigned int until) oldest = -1, oldest_diff = 0x7fffffff; for (i = 0; i < P32X_EVENT_COUNT; i++) { - if (event_times[i]) { - diff = event_times[i] - until; + if (p32x_event_times[i]) { + diff = p32x_event_times[i] - until; if (diff < oldest_diff) { oldest_diff = diff; oldest = i; @@ -297,13 +346,13 @@ static void run_events(unsigned int until) } if (oldest_diff <= 0) { - time = event_times[oldest]; - event_times[oldest] = 0; - elprintf(EL_32X, "run event #%d %u", oldest, time); - event_cbs[oldest](time); + time = p32x_event_times[oldest]; + p32x_event_times[oldest] = 0; + elprintf(EL_32X, "32x: run event #%d %u", oldest, time); + p32x_event_cbs[oldest](time); } else if (oldest_diff < 0x7fffffff) { - event_time_next = event_times[oldest]; + event_time_next = p32x_event_times[oldest]; break; } else { @@ -313,7 +362,8 @@ static void run_events(unsigned int until) } if (oldest != -1) - elprintf(EL_32X, "next event #%d at %u", oldest, event_time_next); + elprintf(EL_32X, "32x: next event #%d at %u", + oldest, event_time_next); } static inline void run_sh2(SH2 *sh2, int m68k_cycles) @@ -326,7 +376,7 @@ static inline void run_sh2(SH2 *sh2, int m68k_cycles) elprintf_sh2(sh2, EL_32X, "+run %u %d @%08x", sh2->m68krcycles_done, cycles, sh2->pc); - done = sh2_execute(sh2, cycles); + done = sh2_execute(sh2, cycles, PicoOpt & POPT_EN_DRC); sh2->m68krcycles_done += C_SH2_TO_M68K(*sh2, done); sh2->state &= ~SH2_STATE_RUN; @@ -396,7 +446,7 @@ void sync_sh2s_normal(unsigned int m68k_target) while (CYCLES_GT(m68k_target, now)) { if (event_time_next && CYCLES_GE(now, event_time_next)) - run_events(now); + p32x_run_events(now); target = m68k_target; if (event_time_next && CYCLES_GT(target, event_time_next)) @@ -470,24 +520,39 @@ void sync_sh2s_lockstep(unsigned int m68k_target) } } -#define CPUS_RUN(m68k_cycles,s68k_cycles) do { \ - SekRunM68k(m68k_cycles); \ +#define CPUS_RUN(m68k_cycles) do { \ + if (PicoAHW & PAHW_MCD) \ + pcd_run_cpus(m68k_cycles); \ + else \ + SekRunM68k(m68k_cycles); \ + \ + if ((Pico32x.emu_flags & P32XF_Z80_32X_IO) && Pico.m.z80Run \ + && !Pico.m.z80_reset && (PicoOpt & POPT_EN_Z80)) \ + PicoSyncZ80(SekCyclesDone()); \ if (Pico32x.emu_flags & (P32XF_68KCPOLL|P32XF_68KVPOLL)) \ - p32x_sync_sh2s(SekCyclesDoneT2()); \ + p32x_sync_sh2s(SekCyclesDone()); \ } while (0) #define PICO_32X +#define PICO_CD #include "../pico_cmn.c" void PicoFrame32x(void) { + Pico.m.scanline = 0; + Pico32x.vdp_regs[0x0a/2] &= ~P32XV_VBLK; // get out of vblank if ((Pico32x.vdp_regs[0] & P32XV_Mx) != 0) // no forced blanking Pico32x.vdp_regs[0x0a/2] &= ~P32XV_PEN; // no palette access + if (!(Pico32x.sh2_regs[0] & 0x80)) + p32x_schedule_hint(NULL, SekCyclesDone()); p32x_sh2_poll_event(&msh2, SH2_STATE_VPOLL, 0); p32x_sh2_poll_event(&ssh2, SH2_STATE_VPOLL, 0); + if (PicoAHW & PAHW_MCD) + pcd_prepare_frame(); + PicoFrameStart(); PicoFrameHints(); sh2_drc_frame(); @@ -519,11 +584,10 @@ void Pico32xStateLoaded(int is_early) return; } - SekCycleCnt = 0; - sh2s[0].m68krcycles_done = sh2s[1].m68krcycles_done = SekCycleCntT; - p32x_update_irls(NULL, SekCycleCntT); + sh2s[0].m68krcycles_done = sh2s[1].m68krcycles_done = SekCyclesDone(); + p32x_update_irls(NULL, SekCyclesDone()); p32x_pwm_state_loaded(); - run_events(SekCycleCntT); + p32x_run_events(SekCyclesDone()); } // vim:shiftwidth=2:ts=2:expandtab