mirror of
https://github.com/RaySollium99/picodrive.git
synced 2025-09-05 15:27:46 -04:00
32x: implement dreq1, improve dmac
This commit is contained in:
parent
a7f82a776a
commit
df63f1a6ff
4 changed files with 314 additions and 94 deletions
124
pico/32x/pwm.c
124
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; \
|
||||
if (cycles_diff >= pwm_cycles) \
|
||||
consume_fifo_do((cycles), cycles_diff); \
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
static void consume_fifo_do(unsigned int cycles, int cycles_diff)
|
||||
#define consume_fifo(m68k_cycles) { \
|
||||
int cycles_diff = ((m68k_cycles) * 3) - Pico32x.pwm_cycle_p; \
|
||||
if (cycles_diff >= pwm_cycles) \
|
||||
consume_fifo_do(m68k_cycles, 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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue