diff options
Diffstat (limited to 'trunk/src/emu/cpu/sh4/sh4tmu.c')
-rw-r--r-- | trunk/src/emu/cpu/sh4/sh4tmu.c | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/trunk/src/emu/cpu/sh4/sh4tmu.c b/trunk/src/emu/cpu/sh4/sh4tmu.c new file mode 100644 index 00000000000..d4f4a318082 --- /dev/null +++ b/trunk/src/emu/cpu/sh4/sh4tmu.c @@ -0,0 +1,324 @@ +/* SH3/4 Timer Unit */ + +#include "emu.h" +#include "debugger.h" +#include "sh4.h" +#include "sh4comn.h" +#include "sh3comn.h" +#include "sh4tmu.h" + +static const int tcnt_div[8] = { 4, 16, 64, 256, 1024, 1, 1, 1 }; + +/*------------------------------------------------- + sh4_scale_up_mame_time - multiply a attotime by + a (constant+1) where 0 <= constant < 2^32 +-------------------------------------------------*/ + +INLINE attotime sh4_scale_up_mame_time(attotime _time1, UINT32 factor1) +{ + return _time1 * factor1 + _time1; +} + +static UINT32 compute_ticks_timer(emu_timer *timer, int hertz, int divisor) +{ + double ret; + + ret=((timer->remaining().as_double() * (double)hertz) / (double)divisor) - 1; + return (UINT32)ret; +} + +static void sh4_timer_recompute(sh4_state *sh4, int which) +{ + double ticks; + + UINT32 tcnt = 0; + UINT32 tcr = 0; + switch (which) + { + case 0: + tcr = sh4->SH4_TCR0; + tcnt = sh4->SH4_TCNT0; + break; + + case 1: + tcr = sh4->SH4_TCR1; + tcnt = sh4->SH4_TCNT1; + break; + + case 2: + tcr = sh4->SH4_TCR2; + tcnt = sh4->SH4_TCNT2; + break; + } + + ticks = tcnt; + sh4->timer[which]->adjust(sh4_scale_up_mame_time(attotime::from_hz(sh4->pm_clock) * tcnt_div[tcr & 7], ticks), which); +} + + +TIMER_CALLBACK( sh4_timer_callback ) +{ + sh4_state *sh4 = (sh4_state *)ptr; + int which = param; + + switch (which) + { + case 0: + sh4->SH4_TCNT0 = sh4->SH4_TCOR0; + break; + + case 1: + sh4->SH4_TCNT1 = sh4->SH4_TCOR1; + break; + + case 2: + sh4->SH4_TCNT2 = sh4->SH4_TCOR2; + break; + + } + + sh4_timer_recompute(sh4, which); + + switch (which) + { + case 0: + sh4->SH4_TCR0 |= 0x100; + break; + + case 1: + sh4->SH4_TCR1 |= 0x100; + break; + + case 2: + sh4->SH4_TCR2 |= 0x100; + break; + + } + + switch (which) + { + case 0: + if (sh4->SH4_TCR0 & 0x20) + { + sh4_exception_request(sh4, SH4_INTC_TUNI0); + // logerror("SH4_INTC_TUNI0 requested\n"); + } + break; + + case 1: + if (sh4->SH4_TCR1 & 0x20) + { + sh4_exception_request(sh4, SH4_INTC_TUNI1); + // logerror("SH4_INTC_TUNI1 requested\n"); + } + break; + + case 2: + if (sh4->SH4_TCR2 & 0x20) + { + sh4_exception_request(sh4, SH4_INTC_TUNI2); + // logerror("SH4_INTC_TUNI2 requested\n"); + } + break; + + } +} + + +UINT32 sh4_handle_tcnt0_addr_r(sh4_state *sh4, UINT32 mem_mask) +{ + if (sh4->SH4_TSTR & 1) + return compute_ticks_timer(sh4->timer[0], sh4->pm_clock, tcnt_div[sh4->SH4_TCR0 & 7]); + else + return sh4->SH4_TCNT0; +} + +UINT32 sh4_handle_tcnt1_addr_r(sh4_state *sh4, UINT32 mem_mask) +{ + if (sh4->SH4_TSTR & 2) + return compute_ticks_timer(sh4->timer[1], sh4->pm_clock, tcnt_div[sh4->SH4_TCR1 & 7]); + else + return sh4->SH4_TCNT1; +} + +UINT32 sh4_handle_tcnt2_addr_r(sh4_state *sh4, UINT32 mem_mask) +{ + if (sh4->SH4_TSTR & 4) + return compute_ticks_timer(sh4->timer[2], sh4->pm_clock, tcnt_div[sh4->SH4_TCR2 & 7]); + else + return sh4->SH4_TCNT2; +} + +UINT32 sh4_handle_tcor0_addr_r(sh4_state *sh4, UINT32 mem_mask) +{ + return sh4->SH4_TCOR0; +} + +UINT32 sh4_handle_tcor1_addr_r(sh4_state *sh4, UINT32 mem_mask) +{ + return sh4->SH4_TCOR1; +} + +UINT32 sh4_handle_tcor2_addr_r(sh4_state *sh4, UINT32 mem_mask) +{ + return sh4->SH4_TCOR2; +} + +UINT32 sh4_handle_tcr0_addr_r(sh4_state *sh4, UINT32 mem_mask) +{ + return sh4->SH4_TCR0; +} + +UINT32 sh4_handle_tcr1_addr_r(sh4_state *sh4, UINT32 mem_mask) +{ + return sh4->SH4_TCR1; +} + +UINT32 sh4_handle_tcr2_addr_r(sh4_state *sh4, UINT32 mem_mask) +{ + return sh4->SH4_TCR2; +} + +UINT32 sh4_handle_tstr_addr_r(sh4_state *sh4, UINT32 mem_mask) +{ + return sh4->SH4_TSTR; +} + +UINT32 sh4_handle_tocr_addr_r(sh4_state *sh4, UINT32 mem_mask) +{ + return sh4->SH4_TOCR; +} + +UINT32 sh4_handle_tcpr2_addr_r(sh4_state *sh4, UINT32 mem_mask) +{ + return sh4->SH4_TCPR2; +} + + +void sh4_handle_tstr_addr_w(sh4_state *sh4, UINT32 data, UINT32 mem_mask) +{ + UINT32 old2 = sh4->SH4_TSTR; + COMBINE_DATA(&sh4->SH4_TSTR); + + if (old2 & 1) + sh4->SH4_TCNT0 = compute_ticks_timer(sh4->timer[0], sh4->pm_clock, tcnt_div[sh4->SH4_TCR0 & 7]); + if ((sh4->SH4_TSTR & 1) == 0) { + sh4->timer[0]->adjust(attotime::never); + } else + sh4_timer_recompute(sh4, 0); + + if (old2 & 2) + sh4->SH4_TCNT1 = compute_ticks_timer(sh4->timer[1], sh4->pm_clock, tcnt_div[sh4->SH4_TCR1 & 7]); + if ((sh4->SH4_TSTR & 2) == 0) { + sh4->timer[1]->adjust(attotime::never); + } else + sh4_timer_recompute(sh4, 1); + + if (old2 & 4) + sh4->SH4_TCNT2 = compute_ticks_timer(sh4->timer[2], sh4->pm_clock, tcnt_div[sh4->SH4_TCR2 & 7]); + if ((sh4->SH4_TSTR & 4) == 0) { + sh4->timer[2]->adjust(attotime::never); + } else + sh4_timer_recompute(sh4, 2); +} + +void sh4_handle_tcr0_addr_w(sh4_state *sh4, UINT32 data, UINT32 mem_mask) +{ + UINT32 old2 = sh4->SH4_TCR0; + COMBINE_DATA(&sh4->SH4_TCR0); + if (sh4->SH4_TSTR & 1) + { + sh4->SH4_TCNT0 = compute_ticks_timer(sh4->timer[0], sh4->pm_clock, tcnt_div[old2 & 7]); + sh4_timer_recompute(sh4, 0); + } + if (!(sh4->SH4_TCR0 & 0x20) || !(sh4->SH4_TCR0 & 0x100)) + sh4_exception_unrequest(sh4, SH4_INTC_TUNI0); +} + +void sh4_handle_tcr1_addr_w(sh4_state *sh4, UINT32 data, UINT32 mem_mask) +{ + UINT32 old2 = sh4->SH4_TCR1; + COMBINE_DATA(&sh4->SH4_TCR1); + if (sh4->SH4_TSTR & 2) + { + sh4->SH4_TCNT1 = compute_ticks_timer(sh4->timer[1], sh4->pm_clock, tcnt_div[old2 & 7]); + sh4_timer_recompute(sh4, 1); + } + if (!(sh4->SH4_TCR1 & 0x20) || !(sh4->SH4_TCR1 & 0x100)) + sh4_exception_unrequest(sh4, SH4_INTC_TUNI1); +} + +void sh4_handle_tcr2_addr_w(sh4_state *sh4, UINT32 data, UINT32 mem_mask) +{ + UINT32 old2 = sh4->SH4_TCR2; + COMBINE_DATA(&sh4->SH4_TCR2); + if (sh4->SH4_TSTR & 4) + { + sh4->SH4_TCNT2 = compute_ticks_timer(sh4->timer[2], sh4->pm_clock, tcnt_div[old2 & 7]); + sh4_timer_recompute(sh4, 2); + } + if (!(sh4->SH4_TCR2 & 0x20) || !(sh4->SH4_TCR2 & 0x100)) + sh4_exception_unrequest(sh4, SH4_INTC_TUNI2); +} + +void sh4_handle_tcor0_addr_w(sh4_state *sh4, UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&sh4->SH4_TCOR0); + if (sh4->SH4_TSTR & 1) + { + sh4->SH4_TCNT0 = compute_ticks_timer(sh4->timer[0], sh4->pm_clock, tcnt_div[sh4->SH4_TCR0 & 7]); + sh4_timer_recompute(sh4, 0); + } +} + +void sh4_handle_tcor1_addr_w(sh4_state *sh4, UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&sh4->SH4_TCOR1); + if (sh4->SH4_TSTR & 2) + { + sh4->SH4_TCNT1 = compute_ticks_timer(sh4->timer[1], sh4->pm_clock, tcnt_div[sh4->SH4_TCR1 & 7]); + sh4_timer_recompute(sh4, 1); + } +} + +void sh4_handle_tcor2_addr_w(sh4_state *sh4, UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&sh4->SH4_TCOR2); + if (sh4->SH4_TSTR & 4) + { + sh4->SH4_TCNT2 = compute_ticks_timer(sh4->timer[2], sh4->pm_clock, tcnt_div[sh4->SH4_TCR2 & 7]); + sh4_timer_recompute(sh4, 2); + } +} + +void sh4_handle_tcnt0_addr_w(sh4_state *sh4, UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&sh4->SH4_TCNT0); + if (sh4->SH4_TSTR & 1) + sh4_timer_recompute(sh4, 0); +} + +void sh4_handle_tcnt1_addr_w(sh4_state *sh4, UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&sh4->SH4_TCNT1); + if (sh4->SH4_TSTR & 2) + sh4_timer_recompute(sh4, 1); +} + +void sh4_handle_tcnt2_addr_w(sh4_state *sh4, UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&sh4->SH4_TCNT2); + if (sh4->SH4_TSTR & 4) + sh4_timer_recompute(sh4, 2); +} + +void sh4_handle_tocr_addr_w(sh4_state *sh4, UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&sh4->SH4_TOCR); +} + +void sh4_handle_tcpr2_addr_w(sh4_state *sh4, UINT32 data, UINT32 mem_mask) +{ + COMBINE_DATA(&sh4->SH4_TCPR2); +} + |