From df63f1a6ff674808e641b67e3e60027b1e05c781 Mon Sep 17 00:00:00 2001 From: notaz Date: Mon, 5 Aug 2013 00:04:30 +0300 Subject: [PATCH] 32x: implement dreq1, improve dmac --- pico/32x/32x.c | 13 +-- pico/32x/memory.c | 255 +++++++++++++++++++++++++++++++++++++--------- pico/32x/pwm.c | 122 ++++++++++++++++------ pico/pico_int.h | 16 +-- 4 files changed, 313 insertions(+), 93 deletions(-) diff --git a/pico/32x/32x.c b/pico/32x/32x.c index c7f07503..7a4d7b33 100644 --- a/pico/32x/32x.c +++ b/pico/32x/32x.c @@ -230,15 +230,6 @@ static void p32x_start_blank(void) ((int)((a) - (b)) >= 0) /* events */ -static void pwm_irq_event(unsigned int now) -{ - Pico32x.emu_flags &= ~P32XF_PWM_PEND; - p32x_pwm_schedule(now); - - Pico32x.sh2irqs |= P32XI_PWM; - p32x_update_irls(NULL); -} - static void fillend_event(unsigned int now) { Pico32x.vdp_regs[0x0a/2] &= ~P32XV_nFEN; @@ -251,7 +242,7 @@ typedef void (event_cb)(unsigned int now); unsigned int event_times[P32X_EVENT_COUNT]; static unsigned int event_time_next; static event_cb *event_cbs[] = { - [P32X_EVENT_PWM] = pwm_irq_event, + [P32X_EVENT_PWM] = p32x_pwm_irq_event, [P32X_EVENT_FILLEND] = fillend_event, }; @@ -525,7 +516,7 @@ void Pico32xStateLoaded(int is_early) SekCycleCnt = 0; sh2s[0].m68krcycles_done = sh2s[1].m68krcycles_done = SekCycleCntT; p32x_update_irls(NULL); - p32x_timers_recalc(); + p32x_pwm_state_loaded(); run_events(SekCycleCntT); } diff --git a/pico/32x/memory.c b/pico/32x/memory.c index ae0ec10d..6d6bbb76 100644 --- a/pico/32x/memory.c +++ b/pico/32x/memory.c @@ -172,44 +172,212 @@ static u32 sh2_comm_faker(u32 a) #endif // DMAC handling -static struct { - unsigned int sar0, dar0, tcr0; // src addr, dst addr, transfer count - unsigned int chcr0; // chan ctl - unsigned int sar1, dar1, tcr1; // same for chan 1 - unsigned int chcr1; - int pad[4]; +struct dma_chan { + unsigned int sar, dar; // src, dst addr + unsigned int tcr; // transfer count + unsigned int chcr; // chan ctl + // -- dm dm sm sm ts ts ar am al ds dl tb ta ie te de + // ts - transfer size: 1, 2, 4, 16 bytes + // ar - auto request if 1, else dreq signal + // ie - irq enable + // te - transfer end + // de - dma enable + #define DMA_AR (1 << 9) + #define DMA_IE (1 << 2) + #define DMA_TE (1 << 1) + #define DMA_DE (1 << 0) +}; + +struct dmac { + struct dma_chan chan[2]; + unsigned int vcrdma0; + unsigned int unknown0; + unsigned int vcrdma1; + unsigned int unknown1; unsigned int dmaor; -} * dmac0; + // -- pr ae nmif dme + // pr - priority: chan0 > chan1 or round-robin + // ae - address error + // nmif - nmi occurred + // dme - DMA master enable + #define DMA_DME (1 << 0) +}; + +static void dmac_te_irq(SH2 *sh2, struct dma_chan *chan) +{ + char *regs = (void *)Pico32xMem->sh2_peri_regs[sh2->is_slave]; + struct dmac *dmac = (void *)(regs + 0x180); + int level = PREG8(regs, 0xe2) & 0x0f; // IPRA + int vector = (chan == &dmac->chan[0]) ? + dmac->vcrdma0 : dmac->vcrdma1; + + elprintf(EL_32X, "dmac irq %d %d", level, vector); + sh2_internal_irq(sh2, level, vector & 0x7f); +} + +static void dmac_transfer_complete(SH2 *sh2, struct dma_chan *chan) +{ + chan->chcr |= DMA_TE; // DMA has ended normally + + p32x_sh2_poll_event(sh2, SH2_STATE_SLEEP, SekCyclesDoneT()); + if (chan->chcr & DMA_IE) + dmac_te_irq(sh2, chan); +} + +static void dmac_transfer_one(SH2 *sh2, struct dma_chan *chan) +{ + u32 size, d; + + size = (chan->chcr >> 10) & 3; + switch (size) { + case 0: + d = p32x_sh2_read8(chan->sar, sh2); + p32x_sh2_write8(chan->dar, d, sh2); + case 1: + d = p32x_sh2_read16(chan->sar, sh2); + p32x_sh2_write16(chan->dar, d, sh2); + break; + case 2: + d = p32x_sh2_read32(chan->sar, sh2); + p32x_sh2_write32(chan->dar, d, sh2); + break; + case 3: + elprintf(EL_32X|EL_ANOMALY, "TODO: 16byte DMA"); + chan->sar += 16; // always? + chan->tcr -= 4; + return; + } + chan->tcr--; + + size = 1 << size; + if (chan->chcr & (1 << 15)) + chan->dar -= size; + if (chan->chcr & (1 << 14)) + chan->dar += size; + if (chan->chcr & (1 << 13)) + chan->sar -= size; + if (chan->chcr & (1 << 12)) + chan->sar += size; +} -static void dma_68k2sh2_do(void) +static void dreq0_do(SH2 *sh2, struct dma_chan *chan) { unsigned short *dreqlen = &Pico32x.regs[0x10 / 2]; int i; - if (dmac0->tcr0 != *dreqlen) - elprintf(EL_32X|EL_ANOMALY, "tcr0 and dreq len differ: %d != %d", dmac0->tcr0, *dreqlen); + // debug/sanity checks + if (chan->tcr != *dreqlen) + elprintf(EL_32X|EL_ANOMALY, "dreq0: tcr0 and len differ: %d != %d", + chan->tcr, *dreqlen); + // note: DACK is not connected, single addr mode should not be used + if ((chan->chcr & 0x3f08) != 0x0400) + elprintf(EL_32X|EL_ANOMALY, "dreq0: bad control: %04x", chan->chcr); + if (chan->sar != 0x20004012) + elprintf(EL_32X|EL_ANOMALY, "dreq0: bad sar?: %08x\n", chan->sar); // HACK: assume bus is busy and SH2 is halted - msh2.state |= SH2_STATE_SLEEP; - - for (i = 0; i < Pico32x.dmac_ptr && dmac0->tcr0 > 0; i++) { - elprintf(EL_32X, "dmaw [%08x] %04x, left %d", dmac0->dar0, Pico32x.dmac_fifo[i], *dreqlen); - p32x_sh2_write16(dmac0->dar0, Pico32x.dmac_fifo[i], &msh2); - dmac0->dar0 += 2; - dmac0->tcr0--; + sh2->state |= SH2_STATE_SLEEP; + + for (i = 0; i < Pico32x.dmac0_fifo_ptr && chan->tcr > 0; i++) { + elprintf(EL_32X, "dmaw [%08x] %04x, left %d", + chan->dar, Pico32x.dmac_fifo[i], *dreqlen); + p32x_sh2_write16(chan->dar, Pico32x.dmac_fifo[i], sh2); + chan->dar += 2; + chan->tcr--; (*dreqlen)--; } - Pico32x.dmac_ptr = 0; // HACK + if (Pico32x.dmac0_fifo_ptr != i) + memmove(Pico32x.dmac_fifo, &Pico32x.dmac_fifo[i], + (Pico32x.dmac0_fifo_ptr - i) * 2); + Pico32x.dmac0_fifo_ptr -= i; + Pico32x.regs[6 / 2] &= ~P32XS_FULL; if (*dreqlen == 0) Pico32x.regs[6 / 2] &= ~P32XS_68S; // transfer complete - if (dmac0->tcr0 == 0) { - dmac0->chcr0 |= 2; // DMA has ended normally - p32x_sh2_poll_event(&sh2s[0], SH2_STATE_SLEEP, SekCyclesDoneT()); + if (chan->tcr == 0) + dmac_transfer_complete(sh2, chan); + else + sh2_end_run(sh2, 16); +} + +static void dreq1_do(SH2 *sh2, struct dma_chan *chan) +{ + // debug/sanity checks + if ((chan->chcr & 0xc308) != 0x0000) + elprintf(EL_32X|EL_ANOMALY, "dreq1: bad control: %04x", chan->chcr); + if ((chan->dar & ~0xf) != 0x20004030) + elprintf(EL_32X|EL_ANOMALY, "dreq1: bad dar?: %08x\n", chan->dar); + + dmac_transfer_one(sh2, chan); + if (chan->tcr == 0) + dmac_transfer_complete(sh2, chan); +} + +static void dreq0_trigger(void) +{ + struct dmac *mdmac = (void *)&Pico32xMem->sh2_peri_regs[0][0x180 / 4]; + struct dmac *sdmac = (void *)&Pico32xMem->sh2_peri_regs[1][0x180 / 4]; + + elprintf(EL_32X, "dreq0_trigger\n"); + if ((mdmac->dmaor & DMA_DME) && (mdmac->chan[0].chcr & 3) == DMA_DE) { + dreq0_do(&msh2, &mdmac->chan[0]); + } + if ((sdmac->dmaor & DMA_DME) && (sdmac->chan[0].chcr & 3) == DMA_DE) { + dreq0_do(&ssh2, &sdmac->chan[0]); } } +void p32x_dreq1_trigger(void) +{ + struct dmac *mdmac = (void *)&Pico32xMem->sh2_peri_regs[0][0x180 / 4]; + struct dmac *sdmac = (void *)&Pico32xMem->sh2_peri_regs[1][0x180 / 4]; + int hit = 0; + + elprintf(EL_32X, "dreq1_trigger\n"); + if ((mdmac->dmaor & DMA_DME) && (mdmac->chan[1].chcr & 3) == DMA_DE) { + dreq1_do(&msh2, &mdmac->chan[1]); + hit = 1; + } + if ((sdmac->dmaor & DMA_DME) && (sdmac->chan[1].chcr & 3) == DMA_DE) { + dreq1_do(&ssh2, &sdmac->chan[1]); + hit = 1; + } + + if (!hit) + elprintf(EL_32X|EL_ANOMALY, "dreq1: nobody cared"); +} + +// DMA trigger by SH2 register write +static void dmac_trigger(SH2 *sh2, struct dma_chan *chan) +{ + elprintf(EL_32X, "sh2 DMA %08x->%08x, cnt %d, chcr %04x @%06x", + chan->sar, chan->dar, chan->tcr, chan->chcr, sh2->pc); + chan->tcr &= 0xffffff; + + if (chan->chcr & DMA_AR) { + // auto-request transfer + while ((int)chan->tcr > 0) + dmac_transfer_one(sh2, chan); + dmac_transfer_complete(sh2, chan); + return; + } + + // DREQ0 is only sent after first 4 words are written. + // we do multiple of 4 words to avoid messing up alignment + if (chan->sar == 0x20004012) { + if (Pico32x.dmac0_fifo_ptr && (Pico32x.dmac0_fifo_ptr & 3) == 0) { + elprintf(EL_32X, "68k -> sh2 DMA"); + dreq0_trigger(); + } + return; + } + + elprintf(EL_32X|EL_ANOMALY, "unhandled DMA: " + "%08x->%08x, cnt %d, chcr %04x @%06x", + chan->sar, chan->dar, chan->tcr, chan->chcr, sh2->pc); +} + // ------------------------------------------------------------------ // 68k regs @@ -252,7 +420,7 @@ static u32 p32x_reg_read16(u32 a) } if ((a & 0x30) == 0x30) - return p32x_pwm_read16(a, SekCyclesDoneT() * 3); + return p32x_pwm_read16(a, SekCyclesDoneT()); out: return Pico32x.regs[a / 2]; @@ -347,11 +515,11 @@ static void p32x_reg_write16(u32 a, u32 d) elprintf(EL_32X|EL_ANOMALY, "DREQ FIFO w16 without 68S?"); return; } - if (Pico32x.dmac_ptr < DMAC_FIFO_LEN) { - Pico32x.dmac_fifo[Pico32x.dmac_ptr++] = d; - if ((Pico32x.dmac_ptr & 3) == 0 && (dmac0->chcr0 & 3) == 1 && (dmac0->dmaor & 1)) - dma_68k2sh2_do(); - if (Pico32x.dmac_ptr == DMAC_FIFO_LEN) + if (Pico32x.dmac0_fifo_ptr < DMAC_FIFO_LEN) { + Pico32x.dmac_fifo[Pico32x.dmac0_fifo_ptr++] = d; + if ((Pico32x.dmac0_fifo_ptr & 3) == 0) + dreq0_trigger(); + if (Pico32x.dmac0_fifo_ptr == DMAC_FIFO_LEN) r[6 / 2] |= P32XS_FULL; } break; @@ -385,7 +553,7 @@ static void p32x_reg_write16(u32 a, u32 d) } // PWM else if ((a & 0x30) == 0x30) { - p32x_pwm_write16(a, d, SekCyclesDoneT() * 3); + p32x_pwm_write16(a, d, SekCyclesDoneT()); return; } @@ -495,7 +663,7 @@ static u32 p32x_sh2reg_read16(u32 a, int cpuid) return r[a / 2]; } if ((a & 0x30) == 0x30) { - return p32x_pwm_read16(a, sh2_cycles_done_t(&sh2s[cpuid])); + return p32x_pwm_read16(a, sh2_cycles_done_m68k(&sh2s[cpuid])); } return 0; @@ -571,7 +739,7 @@ static void p32x_sh2reg_write16(u32 a, u32 d, int cpuid) } // PWM else if ((a & 0x30) == 0x30) { - p32x_pwm_write16(a, d, sh2_cycles_done_t(&sh2s[cpuid])); + p32x_pwm_write16(a, d, sh2_cycles_done_m68k(&sh2s[cpuid])); return; } @@ -586,8 +754,7 @@ static void p32x_sh2reg_write16(u32 a, u32 d, int cpuid) case 0x1a: Pico32x.sh2irqi[cpuid] &= ~P32XI_CMD; goto irls; case 0x1c: Pico32x.sh2irqs &= ~P32XI_PWM; - if (!(Pico32x.emu_flags & P32XF_PWM_PEND)) - p32x_pwm_schedule_sh2(&sh2s[cpuid]); + p32x_pwm_schedule_sh2(&sh2s[cpuid]); goto irls; } @@ -721,20 +888,16 @@ static void sh2_peripheral_write32(u32 a, u32 d, int id) break; } - if ((a == 0x1b0 || a == 0x18c) && (dmac0->chcr0 & 3) == 1 && (dmac0->dmaor & 1)) { - elprintf(EL_32X, "sh2 DMA %08x -> %08x, cnt %d, chcr %04x @%06x", - dmac0->sar0, dmac0->dar0, dmac0->tcr0, dmac0->chcr0, sh2_pc(id)); - dmac0->tcr0 &= 0xffffff; - - // HACK: assume 68k starts writing soon and end the timeslice - sh2_end_run(&sh2s[id], 16); + // perhaps starting a DMA? + if (a == 0x1b0 || a == 0x18c || a == 0x19c) { + struct dmac *dmac = (void *)&Pico32xMem->sh2_peri_regs[id][0x180 / 4]; + if (!(dmac->dmaor & DMA_DME)) + return; - // DREQ is only sent after first 4 words are written. - // we do multiple of 4 words to avoid messing up alignment - if (dmac0->sar0 == 0x20004012 && Pico32x.dmac_ptr && (Pico32x.dmac_ptr & 3) == 0) { - elprintf(EL_32X, "68k -> sh2 DMA"); - dma_68k2sh2_do(); - } + if ((dmac->chan[0].chcr & (DMA_TE|DMA_DE)) == DMA_DE) + dmac_trigger(&sh2s[id], &dmac->chan[0]); + if ((dmac->chan[1].chcr & (DMA_TE|DMA_DE)) == DMA_DE) + dmac_trigger(&sh2s[id], &dmac->chan[1]); } } @@ -1542,8 +1705,6 @@ void PicoMemSetup32x(void) return; } - dmac0 = (void *)&Pico32xMem->sh2_peri_regs[0][0x180 / 4]; - get_bios(); // cartridge area becomes unmapped diff --git a/pico/32x/pwm.c b/pico/32x/pwm.c index 48dcc598..56849240 100644 --- a/pico/32x/pwm.c +++ b/pico/32x/pwm.c @@ -10,6 +10,7 @@ static int pwm_cycles; static int pwm_mult; static int pwm_ptr; +static int pwm_irq_reload; static int timer_cycles[2]; static int timer_tick_cycles[2]; @@ -17,6 +18,7 @@ static int timer_tick_cycles[2]; // timers. This includes PWM timer in 32x and internal SH2 timers void p32x_timers_recalc(void) { + int control = Pico32x.regs[0x30 / 2]; int cycles = Pico32x.regs[0x32 / 2]; int tmp, i; @@ -24,6 +26,12 @@ void p32x_timers_recalc(void) pwm_cycles = cycles; pwm_mult = 0x10000 / cycles; + pwm_irq_reload = (control & 0x0f00) >> 8; + pwm_irq_reload = ((pwm_irq_reload - 1) & 0x0f) + 1; + + if (Pico32x.pwm_irq_cnt == 0) + Pico32x.pwm_irq_cnt = pwm_irq_reload; + // SH2 timer step for (i = 0; i < 2; i++) { tmp = PREG8(Pico32xMem->sh2_peri_regs[i], 0x80) & 7; @@ -37,29 +45,43 @@ void p32x_timers_recalc(void) } } -#define consume_fifo(cycles) { \ - int cycles_diff = (cycles) - Pico32x.pwm_cycle_p; \ +static void do_pwm_irq(unsigned int m68k_cycles) +{ + Pico32x.sh2irqs |= P32XI_PWM; + p32x_update_irls(NULL); + + if (Pico32x.regs[0x30 / 2] & P32XP_RTP) { + p32x_event_schedule(m68k_cycles, P32X_EVENT_PWM, pwm_cycles / 3 + 1); + // note: might recurse + p32x_dreq1_trigger(); + } +} + +#define consume_fifo(m68k_cycles) { \ + int cycles_diff = ((m68k_cycles) * 3) - Pico32x.pwm_cycle_p; \ if (cycles_diff >= pwm_cycles) \ - consume_fifo_do((cycles), cycles_diff); \ + consume_fifo_do(m68k_cycles, cycles_diff); \ } -static void consume_fifo_do(unsigned int cycles, int cycles_diff) +static void consume_fifo_do(unsigned int m68k_cycles, int sh2_cycles_diff) { + int do_irq = 0; + if (pwm_cycles == 0) return; elprintf(EL_PWM, "pwm: %u: consume %d/%d, %d,%d ptr %d", - cycles, cycles_diff, cycles_diff / pwm_cycles, + m68k_cycles, sh2_cycles_diff, sh2_cycles_diff / pwm_cycles, Pico32x.pwm_p[0], Pico32x.pwm_p[1], pwm_ptr); - if (cycles_diff > pwm_cycles * 9) { + if (sh2_cycles_diff >= pwm_cycles * 17) { // silence/skip - Pico32x.pwm_cycle_p = cycles; + Pico32x.pwm_cycle_p = m68k_cycles * 3; Pico32x.pwm_p[0] = Pico32x.pwm_p[1] = 0; return; } - for (; cycles_diff >= pwm_cycles; cycles_diff -= pwm_cycles) { + while (sh2_cycles_diff >= pwm_cycles) { struct Pico32xMem *mem = Pico32xMem; short *fifo_l = mem->pwm_fifo[0]; short *fifo_r = mem->pwm_fifo[1]; @@ -80,8 +102,20 @@ static void consume_fifo_do(unsigned int cycles, int cycles_diff) mem->pwm[pwm_ptr * 2 ] = fifo_l[0]; mem->pwm[pwm_ptr * 2 + 1] = fifo_r[0]; pwm_ptr = (pwm_ptr + 1) & (PWM_BUFF_LEN - 1); + + sh2_cycles_diff -= pwm_cycles; + + if (--Pico32x.pwm_irq_cnt == 0) { + Pico32x.pwm_irq_cnt = pwm_irq_reload; + // irq also does dreq1, so call it after cycle update + do_irq = 1; + break; + } } - Pico32x.pwm_cycle_p = cycles - cycles_diff; + Pico32x.pwm_cycle_p = m68k_cycles * 3 - sh2_cycles_diff; + + if (do_irq) + do_pwm_irq(m68k_cycles); } void p32x_timers_do(unsigned int m68k_now, unsigned int m68k_slice) @@ -89,7 +123,7 @@ void p32x_timers_do(unsigned int m68k_now, unsigned int m68k_slice) unsigned int cycles = m68k_slice * 3; int cnt, i; - consume_fifo(m68k_now * 3); + //consume_fifo(m68k_now); // WDT timers for (i = 0; i < 2; i++) { @@ -114,42 +148,52 @@ void p32x_timers_do(unsigned int m68k_now, unsigned int m68k_slice) } } -static int p32x_pwm_schedule_(void) +static int p32x_pwm_schedule_(unsigned int m68k_now) { - int tm; + unsigned int sh2_now = m68k_now * 3; + int cycles_diff_sh2; + + if (pwm_cycles == 0) + return 0; + + cycles_diff_sh2 = sh2_now - Pico32x.pwm_cycle_p; + if (cycles_diff_sh2 >= pwm_cycles) + consume_fifo_do(m68k_now, cycles_diff_sh2); - if (Pico32x.emu_flags & P32XF_PWM_PEND) - return 0; // already scheduled if (Pico32x.sh2irqs & P32XI_PWM) return 0; // previous not acked if (!((Pico32x.sh2irq_mask[0] | Pico32x.sh2irq_mask[1]) & 1)) return 0; // masked by everyone - Pico32x.emu_flags |= P32XF_PWM_PEND; - tm = (Pico32x.regs[0x30 / 2] & 0x0f00) >> 8; - tm = ((tm - 1) & 0x0f) + 1; - return pwm_cycles * tm / 3; + cycles_diff_sh2 = sh2_now - Pico32x.pwm_cycle_p; + return (Pico32x.pwm_irq_cnt * pwm_cycles + - cycles_diff_sh2) / 3 + 1; } -void p32x_pwm_schedule(unsigned int now) +void p32x_pwm_schedule(unsigned int m68k_now) { - int after = p32x_pwm_schedule_(); + int after = p32x_pwm_schedule_(m68k_now); if (after != 0) - p32x_event_schedule(now, P32X_EVENT_PWM, after); + p32x_event_schedule(m68k_now, P32X_EVENT_PWM, after); } void p32x_pwm_schedule_sh2(SH2 *sh2) { - int after = p32x_pwm_schedule_(); + int after = p32x_pwm_schedule_(sh2_cycles_done_m68k(sh2)); if (after != 0) p32x_event_schedule_sh2(sh2, P32X_EVENT_PWM, after); } -unsigned int p32x_pwm_read16(unsigned int a, unsigned int cycles) +void p32x_pwm_irq_event(unsigned int m68k_now) +{ + p32x_pwm_schedule(m68k_now); +} + +unsigned int p32x_pwm_read16(unsigned int a, unsigned int m68k_cycles) { unsigned int d = 0; - consume_fifo(cycles); + consume_fifo(m68k_cycles); a &= 0x0e; switch (a) { @@ -174,25 +218,30 @@ unsigned int p32x_pwm_read16(unsigned int a, unsigned int cycles) break; } - elprintf(EL_PWM, "pwm: read %02x %04x (p %d %d), c %u", - a, d, Pico32x.pwm_p[0], Pico32x.pwm_p[1], cycles); + elprintf(EL_PWM, "pwm: %u: r16 %02x %04x (p %d %d)", + m68k_cycles, a, d, Pico32x.pwm_p[0], Pico32x.pwm_p[1]); return d; } -void p32x_pwm_write16(unsigned int a, unsigned int d, unsigned int cycles) +void p32x_pwm_write16(unsigned int a, unsigned int d, + unsigned int m68k_cycles) { - consume_fifo(cycles); + elprintf(EL_PWM, "pwm: %u: w16 %02x %04x (p %d %d)", + m68k_cycles, a & 0x0e, d, Pico32x.pwm_p[0], Pico32x.pwm_p[1]); + + consume_fifo(m68k_cycles); a &= 0x0e; if (a == 0) { // control // supposedly we should stop FIFO when xMd is 0, // but mars test disagrees Pico32x.regs[0x30 / 2] = d; + p32x_timers_recalc(); + Pico32x.pwm_irq_cnt = pwm_irq_reload; // ? } else if (a == 2) { // cycle Pico32x.regs[0x32 / 2] = d & 0x0fff; p32x_timers_recalc(); - Pico32x.pwm_irq_sample_cnt = 0; // resets? } else if (a <= 8) { d = (d - 1) & 0x0fff; @@ -279,4 +328,19 @@ out: pwm_ptr = 0; } +void p32x_pwm_state_loaded(void) +{ + int cycles_diff_sh2; + + p32x_timers_recalc(); + + // for old savestates + cycles_diff_sh2 = SekCycleCntT * 3 - Pico32x.pwm_cycle_p; + if (cycles_diff_sh2 >= pwm_cycles || cycles_diff_sh2 < 0) { + Pico32x.pwm_irq_cnt = pwm_irq_reload; + Pico32x.pwm_cycle_p = SekCycleCntT * 3; + p32x_pwm_schedule(SekCycleCntT); + } +} + // vim:shiftwidth=2:ts=2:expandtab diff --git a/pico/pico_int.h b/pico/pico_int.h index 383739c4..08e37694 100644 --- a/pico/pico_int.h +++ b/pico/pico_int.h @@ -467,12 +467,12 @@ typedef struct #define P32XV_nFEN (1<< 1) #define P32XV_FS (1<< 0) -#define P32XP_FULL (1<<15) // PWM +#define P32XP_RTP (1<<7) // PWM control +#define P32XP_FULL (1<<15) // PWM pulse #define P32XP_EMPTY (1<<14) #define P32XF_68KCPOLL (1 << 0) #define P32XF_68KVPOLL (1 << 1) -#define P32XF_PWM_PEND (1 << 6) #define P32XI_VRES (1 << 14/2) // IRL/2 #define P32XI_VINT (1 << 12/2) @@ -504,11 +504,12 @@ struct Pico32x unsigned char sh2irqi[2]; // individual unsigned int sh2irqs; // common irqs unsigned short dmac_fifo[DMAC_FIFO_LEN]; - unsigned int dmac_ptr; - unsigned int pwm_irq_sample_cnt; + unsigned int dmac0_fifo_ptr; + unsigned int pad; unsigned char comm_dirty_68k; unsigned char comm_dirty_sh2; - unsigned short pad; + unsigned char pwm_irq_cnt; + unsigned char pad1; unsigned short pwm_p[2]; // pwm pos in fifo unsigned int pwm_cycle_p; // pwm play cursor (32x cycles) unsigned int reserved[6]; @@ -586,6 +587,7 @@ unsigned int PicoRead8_io(unsigned int a); unsigned int PicoRead16_io(unsigned int a); void PicoWrite8_io(unsigned int a, unsigned int d); void PicoWrite16_io(unsigned int a, unsigned int d); +void p32x_dreq1_trigger(void); // pico/memory.c PICO_INTERNAL void PicoMemSetupPico(void); @@ -781,8 +783,10 @@ void p32x_pwm_write16(unsigned int a, unsigned int d, unsigned int cycles); void p32x_pwm_update(int *buf32, int length, int stereo); void p32x_timers_do(unsigned int m68k_now, unsigned int m68k_slice); void p32x_timers_recalc(void); -void p32x_pwm_schedule(unsigned int now); +void p32x_pwm_schedule(unsigned int m68k_now); void p32x_pwm_schedule_sh2(SH2 *sh2); +void p32x_pwm_irq_event(unsigned int m68k_now); +void p32x_pwm_state_loaded(void); #else #define Pico32xInit() #define PicoPower32x() -- 2.39.5