tmu: Correctly schedule next interrupt in underflow, correctly differentiate between large values and underflows

- 32 bit code was "fudgy" on this, so simplified via 64bit counters for edge detection
- Maths to count cycles were wrong
- Let's not do 32 bit wrapped maths after beers without any kind of pen-and-paper design

Should fix #594, also see #645
This commit is contained in:
Stefanos Kornilios Mitsis Poiitidis 2015-05-08 02:28:49 +02:00
parent 7d75ee3839
commit 3fe8f0eb94
1 changed files with 18 additions and 3 deletions

View File

@ -19,6 +19,7 @@ u32 tmu_prescaler_mask[3];
u32 tmu_shift[3];
u32 tmu_mask[3];
u64 tmu_mask64[3];
const u32 tmu_ch_bit[3]={1,2,4};
@ -75,18 +76,28 @@ void UpdateTMU_i(u32 Cycles)
#endif
u32 tmu_ch_base[3];
u64 tmu_ch_base64[3];
u32 read_TMU_TCNTch(u32 ch)
{
return tmu_ch_base[ch] - ((sh4_sched_now64() >> tmu_shift[ch])&tmu_mask[ch]);
}
s64 read_TMU_TCNTch64(u32 ch)
{
return tmu_ch_base64[ch] - ((sh4_sched_now64() >> tmu_shift[ch])&tmu_mask64[ch]);
}
void sched_chan_tick(int ch)
{
//schedule next interrupt
//return TMU_TCOR(ch) << tmu_shift[ch];
u32 togo = read_TMU_TCNTch(ch);
if (togo > SH4_MAIN_CLOCK)
togo = SH4_MAIN_CLOCK;
u32 cycles = togo << tmu_shift[ch];
if (cycles > SH4_MAIN_CLOCK)
@ -103,6 +114,7 @@ void write_TMU_TCNTch(u32 ch, u32 data)
{
//u32 TCNT=read_TMU_TCNTch(ch);
tmu_ch_base[ch]=data+((sh4_sched_now64()>>tmu_shift[ch])&tmu_mask[ch]);
tmu_ch_base64[ch] = data + ((sh4_sched_now64() >> tmu_shift[ch])&tmu_mask64[ch]);
sched_chan_tick(ch);
}
@ -123,6 +135,7 @@ void turn_on_off_ch(u32 ch, bool on)
{
u32 TCNT=read_TMU_TCNTch(ch);
tmu_mask[ch]=on?0xFFFFFFFF:0x00000000;
tmu_mask64[ch] = on ? 0xFFFFFFFFFFFFFFFF : 0x0000000000000000;
write_TMU_TCNTch(ch,TCNT);
sched_chan_tick(ch);
@ -213,13 +226,15 @@ int sched_tmu_cb(int ch, int sch_cycl, int jitter)
if (tmu_mask[ch]) {
u32 tcnt = read_TMU_TCNTch(ch);
s64 tcnt64 = (s64)read_TMU_TCNTch64(ch);
u32 tcor = TMU_TCOR(ch);
u32 cycles = tcor << tmu_shift[ch];
//this is not 100% correct
if (abs((s32)tcnt) <= jitter) {
//64 bit maths to differentiate big values from overflows
if (tcnt64 <= jitter) {
//raise interrupt, timer counted down
TMU_TCR(ch) |= tmu_underflow;
InterruptPend(tmu_intID[ch], 1);
@ -227,7 +242,7 @@ int sched_tmu_cb(int ch, int sch_cycl, int jitter)
//printf("Interrupt for %d, %d cycles\n", ch, sch_cycl);
//schedule next trigger by writing the TCNT register
write_TMU_TCNTch(ch, tcor - tcnt);
write_TMU_TCNTch(ch, tcor + tcnt);
}
else {