File indexing completed on 2025-05-11 08:23:40
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028 #include <stdlib.h>
0029 #include <bsp.h>
0030 #include <rtems/btimer.h>
0031 #include <bsp/irq-generic.h>
0032 #include <libcpu/cpuModel.h>
0033
0034
0035
0036
0037 #define AVG_OVERHEAD 0
0038 #define LEAST_VALID 1
0039 #define SLOW_DOWN_IO 0x80
0040
0041 #define TWO_MS (uint32_t)(2000)
0042
0043 #define MSK_NULL_COUNT 0x40
0044
0045 #define CMD_READ_BACK_STATUS 0xE2
0046
0047 RTEMS_INTERRUPT_LOCK_DEFINE( ,
0048 rtems_i386_i8254_access_lock, "rtems_i386_i8254_access_lock" );
0049
0050
0051
0052
0053 volatile uint32_t Ttimer_val;
0054 bool benchmark_timer_find_average_overhead = true;
0055 volatile unsigned int fastLoop1ms, slowLoop1ms;
0056
0057 void (*benchmark_timer_initialize_function)(void) = 0;
0058 benchmark_timer_t (*benchmark_timer_read_function)(void) = 0;
0059 void (*Timer_exit_function)(void) = 0;
0060
0061
0062 extern void timerisr(void);
0063
0064 void Timer_exit(void);
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076 static void tsc_timer_exit(void)
0077 {
0078 }
0079
0080 static void tsc_timer_initialize(void)
0081 {
0082 static bool First = true;
0083
0084 if (First) {
0085 First = false;
0086
0087 atexit(Timer_exit);
0088 }
0089 Ttimer_val = rdtsc();
0090 }
0091
0092
0093
0094
0095 static uint32_t tsc_read_timer(void)
0096 {
0097 register uint32_t total;
0098
0099 total = (uint32_t)(rdtsc() - Ttimer_val);
0100
0101 if (benchmark_timer_find_average_overhead)
0102 return total;
0103
0104 if (total < LEAST_VALID)
0105 return 0;
0106
0107 return (total - AVG_OVERHEAD);
0108 }
0109
0110
0111
0112
0113 #define US_PER_ISR 250
0114
0115
0116
0117
0118
0119 static void timerOff(const rtems_raw_irq_connect_data* used)
0120 {
0121 rtems_interrupt_lock_context lock_context;
0122
0123
0124
0125 bsp_interrupt_vector_disable(used->idtIndex - BSP_IRQ_VECTOR_BASE);
0126
0127 rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context);
0128
0129
0130 outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN);
0131 outport_byte(TIMER_CNTR0, 0);
0132 outport_byte(TIMER_CNTR0, 0);
0133
0134 rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context);
0135 }
0136
0137 static void timerOn(const rtems_raw_irq_connect_data* used)
0138 {
0139 rtems_interrupt_lock_context lock_context;
0140
0141 rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context);
0142
0143
0144 outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN);
0145 outport_byte(TIMER_CNTR0, US_TO_TICK(US_PER_ISR) >> 0 & 0xff);
0146 outport_byte(TIMER_CNTR0, US_TO_TICK(US_PER_ISR) >> 8 & 0xff);
0147
0148 rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context);
0149
0150
0151
0152
0153 bsp_interrupt_vector_enable(used->idtIndex - BSP_IRQ_VECTOR_BASE);
0154 }
0155
0156 static rtems_raw_irq_connect_data timer_raw_irq_data = {
0157 BSP_PERIODIC_TIMER + BSP_IRQ_VECTOR_BASE,
0158 timerisr,
0159 timerOn,
0160 timerOff,
0161 NULL
0162 };
0163
0164
0165
0166
0167
0168
0169
0170 static void i386_timer_exit(void)
0171 {
0172 i386_delete_idt_entry (&timer_raw_irq_data);
0173 }
0174
0175 extern void rtems_irq_prologue_0(void);
0176 static void i386_timer_initialize(void)
0177 {
0178 static bool First = true;
0179
0180 if (First) {
0181 rtems_raw_irq_connect_data raw_irq_data = {
0182 BSP_PERIODIC_TIMER + BSP_IRQ_VECTOR_BASE,
0183 rtems_irq_prologue_0,
0184 NULL,
0185 NULL,
0186 NULL
0187 };
0188
0189 First = false;
0190 i386_delete_idt_entry (&raw_irq_data);
0191
0192 atexit(Timer_exit);
0193 if (!i386_set_idt_entry (&timer_raw_irq_data)) {
0194 printk("raw handler connection failed\n");
0195 rtems_fatal_error_occurred(1);
0196 }
0197 }
0198
0199 Ttimer_val = 0;
0200 while (Ttimer_val == 0)
0201 continue;
0202 Ttimer_val = 0;
0203 }
0204
0205
0206
0207
0208 static uint32_t i386_read_timer(void)
0209 {
0210 register uint32_t total, clicks;
0211 register uint8_t lsb, msb;
0212 rtems_interrupt_lock_context lock_context;
0213
0214 rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context);
0215 outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_LATCH);
0216 inport_byte(TIMER_CNTR0, lsb);
0217 inport_byte(TIMER_CNTR0, msb);
0218 rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context);
0219
0220 clicks = (msb << 8) | lsb;
0221 total = (Ttimer_val * US_PER_ISR) + (US_PER_ISR - TICK_TO_US(clicks));
0222
0223 if (benchmark_timer_find_average_overhead)
0224 return total;
0225
0226 if (total < LEAST_VALID)
0227 return 0;
0228
0229 return (total - AVG_OVERHEAD);
0230 }
0231
0232
0233
0234
0235
0236
0237 void benchmark_timer_initialize(void)
0238 {
0239 static bool First = true;
0240
0241 if (First) {
0242 if (x86_has_tsc()) {
0243 #if defined(DEBUG)
0244 printk("TSC: timer initialization\n");
0245 #endif
0246 benchmark_timer_initialize_function = &tsc_timer_initialize;
0247 benchmark_timer_read_function = &tsc_read_timer;
0248 Timer_exit_function = &tsc_timer_exit;
0249 } else {
0250 #if defined(DEBUG)
0251 printk("ISR: timer initialization\n");
0252 #endif
0253 benchmark_timer_initialize_function = &i386_timer_initialize;
0254 benchmark_timer_read_function = &i386_read_timer;
0255 Timer_exit_function = &i386_timer_exit;
0256 }
0257 First = false;
0258 }
0259 (*benchmark_timer_initialize_function)();
0260 }
0261
0262 uint32_t benchmark_timer_read(void)
0263 {
0264 return (*benchmark_timer_read_function)();
0265 }
0266
0267 void Timer_exit(void)
0268 {
0269 if ( Timer_exit_function )
0270 return (*Timer_exit_function)();
0271 }
0272
0273
0274
0275
0276 void benchmark_timer_disable_subtracting_average_overhead(bool find_flag)
0277 {
0278 benchmark_timer_find_average_overhead = find_flag;
0279 }
0280
0281 static unsigned short lastLoadedValue;
0282
0283
0284
0285
0286
0287
0288 static void loadTimerValue( unsigned short loadedValue )
0289 {
0290 rtems_interrupt_lock_context lock_context;
0291 rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context);
0292 lastLoadedValue = loadedValue;
0293 outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_SQWAVE);
0294 outport_byte(TIMER_CNTR0, loadedValue & 0xff);
0295 outport_byte(TIMER_CNTR0, (loadedValue >> 8) & 0xff);
0296 rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context);
0297 }
0298
0299
0300
0301
0302
0303
0304
0305 static unsigned int readTimer0(void)
0306 {
0307 unsigned short lsb, msb;
0308 unsigned char status;
0309 unsigned int count;
0310 rtems_interrupt_lock_context lock_context;
0311 rtems_interrupt_lock_acquire(&rtems_i386_i8254_access_lock, &lock_context);
0312
0313 outport_byte(
0314 TIMER_MODE,
0315 (TIMER_RD_BACK | (RB_COUNT_0 & ~(RB_NOT_STATUS | RB_NOT_COUNT)))
0316 );
0317 inport_byte(TIMER_CNTR0, status);
0318 inport_byte(TIMER_CNTR0, lsb);
0319 inport_byte(TIMER_CNTR0, msb);
0320
0321 rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context);
0322
0323 count = ( msb << 8 ) | lsb ;
0324 if (status & RB_OUTPUT )
0325 count += lastLoadedValue;
0326
0327 return (2*lastLoadedValue - count);
0328 }
0329
0330 static void Timer0Reset(void)
0331 {
0332 loadTimerValue(0xffff);
0333 readTimer0();
0334 }
0335
0336 static void fastLoop (unsigned int loopCount)
0337 {
0338 unsigned int i;
0339 for( i=0; i < loopCount; i++ )outport_byte( SLOW_DOWN_IO, 0 );
0340 }
0341
0342 static void slowLoop (unsigned int loopCount)
0343 {
0344 unsigned int j;
0345 for (j=0; j <100 ; j++) {
0346 fastLoop (loopCount);
0347 }
0348 }
0349
0350
0351
0352
0353 void
0354 Calibrate_loop_1ms(void)
0355 {
0356 unsigned int offset, offsetTmp, emptyCall, emptyCallTmp, res, i, j;
0357 unsigned int targetClockBits, currentClockBits;
0358 unsigned int slowLoopGranularity, fastLoopGranularity;
0359 rtems_interrupt_level level;
0360 int retries = 0;
0361
0362
0363
0364
0365
0366
0367
0368 rtems_interrupt_local_disable(level);
0369
0370 retry:
0371 if ( ++retries >= 5 ) {
0372 printk( "Calibrate_loop_1ms: too many attempts. giving up!!\n" );
0373 while (1);
0374 }
0375 #ifdef DEBUG_CALIBRATE
0376 printk("Calibrate_loop_1ms is starting, please wait (but not too long.)\n");
0377 #endif
0378 targetClockBits = US_TO_TICK(1000);
0379
0380
0381
0382 Timer0Reset();
0383 readTimer0();
0384
0385
0386
0387 offset = 0xffffffff;
0388 for (i=0; i <1000; i++) {
0389 Timer0Reset();
0390 offsetTmp = readTimer0();
0391 offset += offsetTmp;
0392 }
0393 offset = offset / 1000;
0394
0395
0396
0397 fastLoop (0);
0398 emptyCall = 0;
0399 j = 0;
0400 for (i=0; i <10; i++) {
0401 Timer0Reset();
0402 fastLoop (0);
0403 res = readTimer0();
0404
0405
0406
0407 if (res > offset) {
0408 ++j;
0409 emptyCallTmp = res - offset;
0410 emptyCall += emptyCallTmp;
0411 }
0412 }
0413 if (j == 0) emptyCall = 0;
0414 else emptyCall = emptyCall / j;
0415
0416
0417
0418 Timer0Reset();
0419 fastLoop (10000);
0420 res = readTimer0() - offset;
0421 if (res < emptyCall) {
0422 printk(
0423 "Problem #1 in offset computation in Calibrate_loop_1ms "
0424 " in file libbsp/i386/pc386/timer/timer.c\n"
0425 );
0426 goto retry;
0427 }
0428 fastLoopGranularity = (res - emptyCall) / 10000;
0429
0430
0431
0432 Timer0Reset();
0433 slowLoop(10);
0434 res = readTimer0();
0435 if (res < offset + emptyCall) {
0436 printk(
0437 "Problem #2 in offset computation in Calibrate_loop_1ms "
0438 " in file libbsp/i386/pc386/timer/timer.c\n"
0439 );
0440 goto retry;
0441 }
0442 slowLoopGranularity = (res - offset - emptyCall)/ 10;
0443
0444 if (slowLoopGranularity == 0) {
0445 printk(
0446 "Problem #3 in offset computation in Calibrate_loop_1ms "
0447 " in file libbsp/i386/pc386/timer/timer.c\n"
0448 );
0449 goto retry;
0450 }
0451
0452 targetClockBits += offset;
0453 #ifdef DEBUG_CALIBRATE
0454 printk("offset = %u, emptyCall = %u, targetClockBits = %u\n",
0455 offset, emptyCall, targetClockBits);
0456 printk("slowLoopGranularity = %u fastLoopGranularity = %u\n",
0457 slowLoopGranularity, fastLoopGranularity);
0458 #endif
0459 slowLoop1ms = (targetClockBits - emptyCall) / slowLoopGranularity;
0460 if (slowLoop1ms != 0) {
0461 fastLoop1ms = targetClockBits % slowLoopGranularity;
0462 if (fastLoop1ms > emptyCall) fastLoop1ms -= emptyCall;
0463 }
0464 else
0465 fastLoop1ms = targetClockBits - emptyCall / fastLoopGranularity;
0466
0467 if (slowLoop1ms != 0) {
0468
0469
0470
0471
0472 while(1)
0473 {
0474 int previousSign = 0;
0475 Timer0Reset();
0476 slowLoop(slowLoop1ms);
0477 currentClockBits = readTimer0();
0478 if (currentClockBits > targetClockBits) {
0479 if ((currentClockBits - targetClockBits) < slowLoopGranularity) {
0480
0481 --slowLoop1ms;
0482 break;
0483 }
0484 else {
0485 --slowLoop1ms;
0486 if (slowLoop1ms == 0) break;
0487 if (previousSign == 0) previousSign = 2;
0488 if (previousSign == 1) break;
0489 }
0490 }
0491 else {
0492 if ((targetClockBits - currentClockBits) < slowLoopGranularity) {
0493 break;
0494 }
0495 else {
0496 ++slowLoop1ms;
0497 if (previousSign == 0) previousSign = 1;
0498 if (previousSign == 2) break;
0499 }
0500 }
0501 }
0502 }
0503
0504
0505
0506
0507 if (fastLoopGranularity != 0 ) {
0508 while(1) {
0509 int previousSign = 0;
0510 Timer0Reset();
0511 if (slowLoop1ms != 0) slowLoop(slowLoop1ms);
0512 fastLoop(fastLoop1ms);
0513 currentClockBits = readTimer0();
0514 if (currentClockBits > targetClockBits) {
0515 if ((currentClockBits - targetClockBits) < fastLoopGranularity)
0516 break;
0517 else {
0518 --fastLoop1ms;
0519 if (previousSign == 0) previousSign = 2;
0520 if (previousSign == 1) break;
0521 }
0522 }
0523 else {
0524 if ((targetClockBits - currentClockBits) < fastLoopGranularity)
0525 break;
0526 else {
0527 ++fastLoop1ms;
0528 if (previousSign == 0) previousSign = 1;
0529 if (previousSign == 2) break;
0530 }
0531 }
0532 }
0533 }
0534 #ifdef DEBUG_CALIBRATE
0535 printk("slowLoop1ms = %u, fastLoop1ms = %u\n", slowLoop1ms, fastLoop1ms);
0536 #endif
0537 rtems_interrupt_local_enable(level);
0538
0539 }
0540
0541
0542
0543
0544 void Wait_X_ms( unsigned int timeToWait)
0545 {
0546 unsigned int j;
0547
0548 for (j=0; j<timeToWait ; j++) {
0549 if (slowLoop1ms != 0) slowLoop(slowLoop1ms);
0550 fastLoop(fastLoop1ms);
0551 }
0552 }