Search
lxdream.org :: lxdream/src/sh4/timer.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/timer.c
changeset 1124:aacaae9812ea
prev975:007bf7eb944f
next1127:4b8194e3974c
author nkeynes
date Sat Sep 11 09:58:22 2010 +1000 (9 years ago)
permissions -rw-r--r--
last change GTK: Force file extension when creating files
file annotate diff log raw
1.1 --- a/src/sh4/timer.c Mon Jan 26 07:26:24 2009 +0000
1.2 +++ b/src/sh4/timer.c Sat Sep 11 09:58:22 2010 +1000
1.3 @@ -42,7 +42,7 @@
1.4
1.5 uint32_t sh4_cpu_period = 1000 / SH4_BASE_RATE; /* in nanoseconds */
1.6 uint32_t sh4_bus_period = 2* 1000 / SH4_BASE_RATE;
1.7 -uint32_t sh4_peripheral_period = 4 * 2000 / SH4_BASE_RATE;
1.8 +uint32_t sh4_peripheral_period = 4 * 1000 / SH4_BASE_RATE;
1.9
1.10 MMIO_REGION_READ_FN( CPG, reg )
1.11 {
1.12 @@ -112,13 +112,29 @@
1.13
1.14 /********************************** TMU *************************************/
1.15
1.16 +#define TCR_ICPF 0x0200
1.17 +#define TCR_UNF 0x0100
1.18 +#define TCR_UNIE 0x0020
1.19 +
1.20 +#define TCR_IRQ_ACTIVE (TCR_UNF|TCR_UNIE)
1.21 +
1.22 #define TMU_IS_RUNNING(timer) (MMIO_READ(TMU,TSTR) & (1<<timer))
1.23
1.24 +struct TMU_timer {
1.25 + uint32_t timer_period;
1.26 + uint32_t timer_remainder; /* left-over cycles from last count */
1.27 + uint32_t timer_run; /* cycles already run from this slice */
1.28 +};
1.29 +
1.30 +static struct TMU_timer TMU_timers[3];
1.31 +
1.32 uint32_t TMU_count( int timer, uint32_t nanosecs );
1.33 +void TMU_schedule_timer( int timer );
1.34
1.35 void TMU_event_callback( int eventid )
1.36 {
1.37 TMU_count( eventid - EVENT_TMU0, sh4r.slice_cycle );
1.38 + assert( MMIO_READ( TMU, TCR0 + (eventid - EVENT_TMU0)*12 ) & 0x100 );
1.39 }
1.40
1.41 void TMU_init(void)
1.42 @@ -128,19 +144,16 @@
1.43 register_event_callback( EVENT_TMU2, TMU_event_callback );
1.44 }
1.45
1.46 -#define TCR_ICPF 0x0200
1.47 -#define TCR_UNF 0x0100
1.48 -#define TCR_UNIE 0x0020
1.49 +void TMU_dump(unsigned timer)
1.50 +{
1.51 + fprintf(stderr, "Timer %d: %s %08x/%08x %dns run: %08X - %08X\n",
1.52 + timer, TMU_IS_RUNNING(timer) ? "running" : "stopped",
1.53 + MMIO_READ(TMU, TCNT0 + (timer*12)), MMIO_READ(TMU, TCOR0 + (timer*12)),
1.54 + TMU_timers[timer].timer_period,
1.55 + TMU_timers[timer].timer_run,
1.56 + TMU_timers[timer].timer_remainder );
1.57 +}
1.58
1.59 -#define TCR_IRQ_ACTIVE (TCR_UNF|TCR_UNIE)
1.60 -
1.61 -struct TMU_timer {
1.62 - uint32_t timer_period;
1.63 - uint32_t timer_remainder; /* left-over cycles from last count */
1.64 - uint32_t timer_run; /* cycles already run from this slice */
1.65 -};
1.66 -
1.67 -static struct TMU_timer TMU_timers[3];
1.68
1.69 void TMU_set_timer_control( int timer, int tcr )
1.70 {
1.71 @@ -188,17 +201,31 @@
1.72 period = sh4_peripheral_period; /* I dunno... */
1.73 break;
1.74 }
1.75 - TMU_timers[timer].timer_period = period;
1.76 +
1.77 + if( period != TMU_timers[timer].timer_period ) {
1.78 + if( TMU_IS_RUNNING(timer) ) {
1.79 + /* If we're changing clock speed while counting, sync up and reschedule */
1.80 + TMU_count(timer, sh4r.slice_cycle);
1.81 + TMU_timers[timer].timer_period = period;
1.82 + TMU_schedule_timer(timer);
1.83 + } else {
1.84 + TMU_timers[timer].timer_period = period;
1.85 + }
1.86 + }
1.87
1.88 MMIO_WRITE( TMU, TCR0 + (12*timer), tcr );
1.89 }
1.90
1.91 void TMU_schedule_timer( int timer )
1.92 {
1.93 - uint64_t duration = (uint64_t)((uint32_t)(MMIO_READ( TMU, TCNT0 + 12*timer )+1)) *
1.94 + uint64_t duration = ((uint64_t)((uint32_t)(MMIO_READ( TMU, TCNT0 + 12*timer )))+1) *
1.95 (uint64_t)TMU_timers[timer].timer_period - TMU_timers[timer].timer_remainder;
1.96 event_schedule_long( EVENT_TMU0+timer, (uint32_t)(duration / 1000000000),
1.97 (uint32_t)(duration % 1000000000) );
1.98 +// if( timer == 2 ) {
1.99 +// WARN( "Schedule timer %d: %lldns", timer, duration );
1.100 +// TMU_dump(timer);
1.101 +// }
1.102 }
1.103
1.104 void TMU_start( int timer )
1.105 @@ -230,6 +257,8 @@
1.106 uint32_t count = run_ns / TMU_timers[timer].timer_period;
1.107 uint32_t value = MMIO_READ( TMU, TCNT0 + 12*timer );
1.108 uint32_t reset = MMIO_READ( TMU, TCOR0 + 12*timer );
1.109 +// if( timer == 2 )
1.110 +// WARN( "Counting timer %d: %d ns, %d ticks", timer, run_ns, count );
1.111 if( count > value ) {
1.112 uint32_t tcr = MMIO_READ( TMU, TCR0 + 12*timer );
1.113 tcr |= TCR_UNF;
1.114 @@ -239,6 +268,8 @@
1.115 if( tcr & TCR_UNIE )
1.116 intc_raise_interrupt( INT_TMU_TUNI0 + timer );
1.117 MMIO_WRITE( TMU, TCNT0 + 12*timer, value );
1.118 +// if( timer == 2 )
1.119 +// WARN( "Underflowed timer %d", timer );
1.120 TMU_schedule_timer(timer);
1.121 } else {
1.122 value -= count;
.