Search
lxdream.org :: lxdream :: r53:f2981805b929
lxdream 0.9.1
released Jun 29
Download Now
changeset53:f2981805b929
parent52:429b7fc6b843
child54:d8b73031289c
authornkeynes
dateThu Dec 29 12:52:29 2005 +0000 (14 years ago)
Rewrite timer to be more accurate, also support cycle precision in the future
src/sh4/sh4core.c
src/sh4/sh4core.h
src/sh4/timer.c
1.1 --- a/src/sh4/sh4core.c Wed Dec 28 22:50:08 2005 +0000
1.2 +++ b/src/sh4/sh4core.c Thu Dec 29 12:52:29 2005 +0000
1.3 @@ -1,5 +1,5 @@
1.4 /**
1.5 - * $Id: sh4core.c,v 1.16 2005-12-26 11:47:15 nkeynes Exp $
1.6 + * $Id: sh4core.c,v 1.17 2005-12-29 12:52:29 nkeynes Exp $
1.7 *
1.8 * SH4 emulation core, and parent module for all the SH4 peripheral
1.9 * modules.
1.10 @@ -37,14 +37,6 @@
1.11 #define EXC_FPDISABLE 0x800
1.12 #define EXV_FPDISABLE 0x100
1.13
1.14 -uint32_t sh4_freq = SH4_BASE_RATE;
1.15 -uint32_t sh4_bus_freq = SH4_BASE_RATE;
1.16 -uint32_t sh4_peripheral_freq = SH4_BASE_RATE / 2;
1.17 -
1.18 -uint32_t sh4_cpu_period = 1000 / SH4_BASE_RATE; /* in nanoseconds */
1.19 -uint32_t sh4_bus_period = 1000 / SH4_BASE_RATE;
1.20 -uint32_t sh4_peripheral_period = 2000 / SH4_BASE_RATE;
1.21 -
1.22 /********************** SH4 Module Definition ****************************/
1.23
1.24 void sh4_init( void );
1.25 @@ -139,8 +131,7 @@
1.26 sh4r.sh4_state = SH4_STATE_RUNNING;;
1.27 }
1.28
1.29 - while( sh4r.icount < target && sh4r.sh4_state == SH4_STATE_RUNNING ) {
1.30 - sh4r.icount++;
1.31 + for( sh4r.slice_cycle = 0; sh4r.slice_cycle < nanosecs; sh4r.slice_cycle += sh4_cpu_period ) {
1.32 if( !sh4_execute_instruction() )
1.33 break;
1.34 #ifdef ENABLE_DEBUG_MODE
1.35 @@ -162,14 +153,14 @@
1.36 * we're doing a hard abort - cut the timeslice back to what we
1.37 * actually executed
1.38 */
1.39 - if( target != sh4r.icount && sh4r.sh4_state == SH4_STATE_RUNNING ) {
1.40 - /* Halted - compute time actually executed */
1.41 - nanosecs = (sh4r.icount - start) * sh4_cpu_period;
1.42 + if( sh4r.slice_cycle != nanosecs && sh4r.sh4_state == SH4_STATE_RUNNING ) {
1.43 + nanosecs = sh4r.slice_cycle;
1.44 }
1.45 if( sh4r.sh4_state != SH4_STATE_STANDBY ) {
1.46 TMU_run_slice( nanosecs );
1.47 SCIF_run_slice( nanosecs );
1.48 }
1.49 + sh4r.icount += sh4r.slice_cycle / sh4_cpu_period;
1.50 return nanosecs;
1.51 }
1.52
1.53 @@ -181,12 +172,14 @@
1.54 void sh4_save_state( FILE *f )
1.55 {
1.56 fwrite( &sh4r, sizeof(sh4r), 1, f );
1.57 + TMU_save_state( f );
1.58 SCIF_save_state( f );
1.59 }
1.60
1.61 int sh4_load_state( FILE * f )
1.62 {
1.63 fread( &sh4r, sizeof(sh4r), 1, f );
1.64 + TMU_load_state( f );
1.65 return SCIF_load_state( f );
1.66 }
1.67
2.1 --- a/src/sh4/sh4core.h Wed Dec 28 22:50:08 2005 +0000
2.2 +++ b/src/sh4/sh4core.h Thu Dec 29 12:52:29 2005 +0000
2.3 @@ -1,5 +1,5 @@
2.4 /**
2.5 - * $Id: sh4core.h,v 1.8 2005-12-26 11:47:15 nkeynes Exp $
2.6 + * $Id: sh4core.h,v 1.9 2005-12-29 12:52:29 nkeynes Exp $
2.7 *
2.8 * This file defines the public functions exported by the SH4 core, except
2.9 * for disassembly functions defined in sh4dasm.h
2.10 @@ -70,6 +70,7 @@
2.11 uint32_t int_pending; /* flag set by the INTC = pending priority level */
2.12 int in_delay_slot; /* flag to indicate the current instruction is in
2.13 * a delay slot (certain rules apply) */
2.14 + uint32_t slice_cycle; /* Current cycle within the timeslice */
2.15 int sh4_state; /* Current power-on state (one of the SH4_STATE_* values ) */
2.16 };
2.17
2.18 @@ -106,6 +107,10 @@
2.19 /* Peripheral functions */
2.20 void DMAC_run_slice( uint32_t );
2.21 void TMU_run_slice( uint32_t );
2.22 +void TMU_update_clocks( void );
2.23 +void TMU_reset( void );
2.24 +void TMU_save_state( FILE * );
2.25 +int TMU_load_state( FILE * );
2.26 void SCIF_reset( void );
2.27 void SCIF_run_slice( uint32_t );
2.28 void SCIF_save_state( FILE *f );
3.1 --- a/src/sh4/timer.c Wed Dec 28 22:50:08 2005 +0000
3.2 +++ b/src/sh4/timer.c Thu Dec 29 12:52:29 2005 +0000
3.3 @@ -1,5 +1,5 @@
3.4 /**
3.5 - * $Id: timer.c,v 1.2 2005-12-25 05:57:00 nkeynes Exp $
3.6 + * $Id: timer.c,v 1.3 2005-12-29 12:52:29 nkeynes Exp $
3.7 *
3.8 * SH4 Timer/Clock peripheral modules (CPG, TMU, RTC), combined together to
3.9 * keep things simple (they intertwine a bit).
3.10 @@ -22,21 +22,59 @@
3.11 #include "clock.h"
3.12 #include "sh4core.h"
3.13 #include "sh4mmio.h"
3.14 +#include "intc.h"
3.15
3.16 /********************************* CPG *************************************/
3.17 +/* This is the base clock from which all other clocks are derived */
3.18 +uint32_t sh4_input_freq = SH4_BASE_RATE;
3.19 +
3.20 +uint32_t sh4_cpu_freq = SH4_BASE_RATE;
3.21 +uint32_t sh4_bus_freq = SH4_BASE_RATE;
3.22 +uint32_t sh4_peripheral_freq = SH4_BASE_RATE / 2;
3.23 +
3.24 +uint32_t sh4_cpu_period = 1000 / SH4_BASE_RATE; /* in nanoseconds */
3.25 +uint32_t sh4_bus_period = 1000 / SH4_BASE_RATE;
3.26 +uint32_t sh4_peripheral_period = 2000 / SH4_BASE_RATE;
3.27
3.28 int32_t mmio_region_CPG_read( uint32_t reg )
3.29 {
3.30 return MMIO_READ( CPG, reg );
3.31 }
3.32
3.33 +/* CPU + bus dividers (note officially only the first 6 values are valid) */
3.34 +int ifc_divider[8] = { 1, 2, 3, 4, 5, 8, 8, 8 };
3.35 +/* Peripheral clock dividers (only first 5 are officially valid) */
3.36 +int pfc_divider[8] = { 2, 3, 4, 6, 8, 8, 8, 8 };
3.37 +
3.38 void mmio_region_CPG_write( uint32_t reg, uint32_t val )
3.39 {
3.40 + uint32_t div;
3.41 + switch( reg ) {
3.42 + case FRQCR: /* Frequency control */
3.43 + div = ifc_divider[(val >> 6) & 0x07];
3.44 + sh4_cpu_freq = sh4_input_freq / div;
3.45 + sh4_cpu_period = 1000 * div / sh4_input_freq;
3.46 + div = ifc_divider[(val >> 3) & 0x07];
3.47 + sh4_bus_freq = sh4_input_freq / div;
3.48 + sh4_bus_period = 1000 * div / sh4_input_freq;
3.49 + div = pfc_divider[val & 0x07];
3.50 + sh4_peripheral_freq = sh4_input_freq / div;
3.51 + sh4_peripheral_period = 1000 * div / sh4_input_freq;
3.52 +
3.53 + /* Update everything that depends on the peripheral frequency */
3.54 + SCIF_update_line_speed();
3.55 + break;
3.56 + case WTCSR: /* Watchdog timer */
3.57 + break;
3.58 + }
3.59 +
3.60 MMIO_WRITE( CPG, reg, val );
3.61 }
3.62
3.63 /********************************** RTC *************************************/
3.64
3.65 +uint32_t rtc_output_period;
3.66 +
3.67 int32_t mmio_region_RTC_read( uint32_t reg )
3.68 {
3.69 return MMIO_READ( RTC, reg );
3.70 @@ -49,38 +87,120 @@
3.71
3.72 /********************************** TMU *************************************/
3.73
3.74 -int timer_divider[3] = {16,16,16};
3.75 +#define TCR_ICPF 0x0200
3.76 +#define TCR_UNF 0x0100
3.77 +#define TCR_UNIE 0x0020
3.78 +
3.79 +struct TMU_timer {
3.80 + uint32_t timer_period;
3.81 + uint32_t timer_remainder; /* left-over cycles from last count */
3.82 + uint32_t timer_run; /* cycles already run from this slice */
3.83 +};
3.84 +
3.85 +struct TMU_timer TMU_timers[3];
3.86
3.87 int32_t mmio_region_TMU_read( uint32_t reg )
3.88 {
3.89 return MMIO_READ( TMU, reg );
3.90 }
3.91
3.92 +void TMU_set_timer_period( int timer, int tcr )
3.93 +{
3.94 + uint32_t period = 1;
3.95 + switch( tcr & 0x07 ) {
3.96 + case 0:
3.97 + period = sh4_peripheral_period << 2 ;
3.98 + break;
3.99 + case 1:
3.100 + period = sh4_peripheral_period << 4;
3.101 + break;
3.102 + case 2:
3.103 + period = sh4_peripheral_period << 6;
3.104 + break;
3.105 + case 3:
3.106 + period = sh4_peripheral_period << 8;
3.107 + break;
3.108 + case 4:
3.109 + period = sh4_peripheral_period << 10;
3.110 + break;
3.111 + case 5:
3.112 + /* Illegal value. */
3.113 + ERROR( "TMU %d period set to illegal value (5)", timer );
3.114 + period = sh4_peripheral_period << 12; /* for something to do */
3.115 + break;
3.116 + case 6:
3.117 + period = rtc_output_period;
3.118 + break;
3.119 + case 7:
3.120 + /* External clock... Hrm? */
3.121 + period = sh4_peripheral_period; /* I dunno... */
3.122 + break;
3.123 + }
3.124 + TMU_timers[timer].timer_period = period;
3.125 +}
3.126
3.127 -int get_timer_div( int val )
3.128 +void TMU_start( int timer )
3.129 {
3.130 - switch( val & 0x07 ) {
3.131 - case 0: return 16; /* assume peripheral clock is IC/4 */
3.132 - case 1: return 64;
3.133 - case 2: return 256;
3.134 - case 3: return 1024;
3.135 - case 4: return 4096;
3.136 + TMU_timers[timer].timer_run = 0;
3.137 + TMU_timers[timer].timer_remainder = 0;
3.138 +}
3.139 +
3.140 +void TMU_stop( int timer )
3.141 +{
3.142 +
3.143 +}
3.144 +
3.145 +/**
3.146 + * Count the specified timer for a given number of nanoseconds.
3.147 + */
3.148 +uint32_t TMU_count( int timer, uint32_t nanosecs )
3.149 +{
3.150 + nanosecs = nanosecs + TMU_timers[timer].timer_remainder -
3.151 + TMU_timers[timer].timer_run;
3.152 + TMU_timers[timer].timer_remainder =
3.153 + nanosecs % TMU_timers[timer].timer_period;
3.154 + uint32_t count = nanosecs / TMU_timers[timer].timer_period;
3.155 + uint32_t value = MMIO_READ( TMU, TCNT0 + 12*timer );
3.156 + uint32_t reset = MMIO_READ( TMU, TCOR0 + 12*timer );
3.157 + if( count > value ) {
3.158 + uint32_t tcr = MMIO_READ( TMU, TCR0 + 12*timer );
3.159 + tcr |= TCR_UNF;
3.160 + count -= value;
3.161 + value = reset - (count % reset);
3.162 + MMIO_WRITE( TMU, TCR0 + 12*timer, tcr );
3.163 + if( tcr & TCR_UNIE )
3.164 + intc_raise_interrupt( INT_TMU_TUNI0 + timer );
3.165 + } else {
3.166 + value -= count;
3.167 }
3.168 - return 1;
3.169 + MMIO_WRITE( TMU, TCNT0 + 12*timer, value );
3.170 + return value;
3.171 }
3.172
3.173 void mmio_region_TMU_write( uint32_t reg, uint32_t val )
3.174 {
3.175 + uint32_t oldval;
3.176 + int i;
3.177 switch( reg ) {
3.178 - case TCR0:
3.179 - timer_divider[0] = get_timer_div(val);
3.180 - break;
3.181 - case TCR1:
3.182 - timer_divider[1] = get_timer_div(val);
3.183 - break;
3.184 - case TCR2:
3.185 - timer_divider[2] = get_timer_div(val);
3.186 - break;
3.187 + case TSTR:
3.188 + oldval = MMIO_READ( TMU, TSTR );
3.189 + for( i=0; i<3; i++ ) {
3.190 + uint32_t tmp = 1<<i;
3.191 + if( (oldval & tmp) == 1 && (val&tmp) == 0 )
3.192 + TMU_stop(i);
3.193 + else if( (oldval&tmp) == 0 && (val&tmp) == 1 )
3.194 + TMU_start(i);
3.195 + }
3.196 + break;
3.197 + case TCR0:
3.198 + TMU_set_timer_period( 0, val );
3.199 + break;
3.200 + case TCR1:
3.201 + TMU_set_timer_period( 1, val );
3.202 + break;
3.203 + case TCR2:
3.204 + TMU_set_timer_period( 2, val );
3.205 + break;
3.206 }
3.207 MMIO_WRITE( TMU, reg, val );
3.208 }
3.209 @@ -88,41 +208,44 @@
3.210 void TMU_run_slice( uint32_t nanosecs )
3.211 {
3.212 int tcr = MMIO_READ( TMU, TSTR );
3.213 - int cycles = nanosecs / sh4_peripheral_period;
3.214 if( tcr & 0x01 ) {
3.215 - int count = cycles / timer_divider[0];
3.216 - int *val = MMIO_REG( TMU, TCNT0 );
3.217 - if( *val < count ) {
3.218 - MMIO_READ( TMU, TCR0 ) |= 0x100;
3.219 - /* interrupt goes here */
3.220 - count -= *val;
3.221 - *val = MMIO_READ( TMU, TCOR0 ) - count;
3.222 - } else {
3.223 - *val -= count;
3.224 - }
3.225 + TMU_count( 0, nanosecs );
3.226 + TMU_timers[0].timer_run = 0;
3.227 }
3.228 if( tcr & 0x02 ) {
3.229 - int count = cycles / timer_divider[1];
3.230 - int *val = MMIO_REG( TMU, TCNT1 );
3.231 - if( *val < count ) {
3.232 - MMIO_READ( TMU, TCR1 ) |= 0x100;
3.233 - /* interrupt goes here */
3.234 - count -= *val;
3.235 - *val = MMIO_READ( TMU, TCOR1 ) - count;
3.236 - } else {
3.237 - *val -= count;
3.238 - }
3.239 + TMU_count( 1, nanosecs );
3.240 + TMU_timers[1].timer_run = 0;
3.241 }
3.242 if( tcr & 0x04 ) {
3.243 - int count = cycles / timer_divider[2];
3.244 - int *val = MMIO_REG( TMU, TCNT2 );
3.245 - if( *val < count ) {
3.246 - MMIO_READ( TMU, TCR2 ) |= 0x100;
3.247 - /* interrupt goes here */
3.248 - count -= *val;
3.249 - *val = MMIO_READ( TMU, TCOR2 ) - count;
3.250 - } else {
3.251 - *val -= count;
3.252 - }
3.253 + TMU_count( 2, nanosecs );
3.254 + TMU_timers[2].timer_run = 0;
3.255 }
3.256 }
3.257 +
3.258 +void TMU_update_clocks()
3.259 +{
3.260 + TMU_set_timer_period( 0, MMIO_READ( TMU, TCR0 ) );
3.261 + TMU_set_timer_period( 1, MMIO_READ( TMU, TCR1 ) );
3.262 + TMU_set_timer_period( 2, MMIO_READ( TMU, TCR2 ) );
3.263 +}
3.264 +
3.265 +void TMU_reset( )
3.266 +{
3.267 + TMU_timers[0].timer_remainder = 0;
3.268 + TMU_timers[0].timer_run = 0;
3.269 + TMU_timers[1].timer_remainder = 0;
3.270 + TMU_timers[1].timer_run = 0;
3.271 + TMU_timers[2].timer_remainder = 0;
3.272 + TMU_timers[2].timer_run = 0;
3.273 + TMU_update_clocks();
3.274 +}
3.275 +
3.276 +void TMU_save_state( FILE *f ) {
3.277 + fwrite( &TMU_timers, sizeof(TMU_timers), 1, f );
3.278 +}
3.279 +
3.280 +int TMU_load_state( FILE *f )
3.281 +{
3.282 + fread( &TMU_timers, sizeof(TMU_timers), 1, f );
3.283 + return 0;
3.284 +}
.