📄 timer.c
字号:
/*-------------------------------------------------------------------------+| timer.c v1.1 - PC386 BSP - 1997/08/07+--------------------------------------------------------------------------+| This file contains the PC386 timer package.+--------------------------------------------------------------------------+| NOTE: It is important that the timer start/stop overhead be determined| when porting or modifying this code.+--------------------------------------------------------------------------+| (C) Copyright 1997 -| - NavIST Group - Real-Time Distributed Systems and Industrial Automation|| http://pandora.ist.utl.pt|| Instituto Superior Tecnico * Lisboa * PORTUGAL+--------------------------------------------------------------------------+| Disclaimer:|| This file is provided "AS IS" without warranty of any kind, either| expressed or implied.+--------------------------------------------------------------------------+| This code is base on:| timer.c,v 1.7 1995/12/19 20:07:43 joel Exp - go32 BSP|| Rosimildo daSilva -ConnectTel, Inc - Fixed infinite loop in the Calibration| routine. I've seen this problems with faster machines ( pentiums ). Sometimes| RTEMS just hangs at startup.|| With the following copyright notice:| **************************************************************************| * COPYRIGHT (c) 1989-1999.| * On-Line Applications Research Corporation (OAR).| *| * The license and distribution terms for this file may be| * found in found in the file LICENSE in this distribution or at| * http://www.rtems.com/license/LICENSE.| **************************************************************************|| $Id: timer.c,v 1.12.6.2 2005/10/05 02:39:35 joel Exp $+--------------------------------------------------------------------------*/#include <stdlib.h>#include <bsp.h>#include <irq.h>/*-------------------------------------------------------------------------+| Constants+--------------------------------------------------------------------------*/#define AVG_OVERHEAD 0 /* 0.1 microseconds to start/stop timer. */#define LEAST_VALID 1 /* Don't trust a value lower than this. */#define SLOW_DOWN_IO 0x80 /* io which does nothing */#define TWO_MS (uint32_t)(2000) /* TWO_MS = 2000us (sic!) */#define MSK_NULL_COUNT 0x40 /* bit counter available for reading */#define CMD_READ_BACK_STATUS 0xE2 /* command read back status *//*-------------------------------------------------------------------------+| Global Variables+--------------------------------------------------------------------------*/volatile uint32_t Ttimer_val;rtems_boolean Timer_driver_Find_average_overhead = TRUE;volatile unsigned int fastLoop1ms, slowLoop1ms;void (*Timer_initialize_function)(void) = 0;uint32_t (*Read_timer_function)(void) = 0;void (*Timer_exit_function)(void) = 0;/*-------------------------------------------------------------------------+| External Prototypes+--------------------------------------------------------------------------*/extern void timerisr(void); /* timer (int 08h) Interrupt Service Routine (defined in 'timerisr.s') */extern int x86_capability;/* * forward declarations */void Timer_exit();/*-------------------------------------------------------------------------+| Pentium optimized timer handling.+--------------------------------------------------------------------------*//*-------------------------------------------------------------------------+| Function: rdtsc| Description: Read the value of PENTIUM on-chip cycle counter.| Global Variables: None.| Arguments: None.| Returns: Value of PENTIUM on-chip cycle counter.+--------------------------------------------------------------------------*/static inline unsigned long longrdtsc(void){ /* Return the value of the on-chip cycle counter. */ unsigned long long result; asm volatile(".byte 0x0F, 0x31" : "=A" (result)); return result;} /* rdtsc *//*-------------------------------------------------------------------------+| Function: Timer_exit| Description: Timer cleanup routine at RTEMS exit. NOTE: This routine is| not really necessary, since there will be a reset at exit.| Global Variables: None.| Arguments: None.| Returns: Nothing.+--------------------------------------------------------------------------*/voidtsc_timer_exit(void){} /* tsc_timer_exit *//*-------------------------------------------------------------------------+| Function: Timer_initialize| Description: Timer initialization routine.| Global Variables: Ttimer_val.| Arguments: None.| Returns: Nothing.+--------------------------------------------------------------------------*/voidtsc_timer_initialize(void){ static rtems_boolean First = TRUE; if (First) { First = FALSE; atexit(Timer_exit); /* Try not to hose the system at exit. */ } Ttimer_val = rdtsc(); /* read starting time */} /* tsc_timer_initialize *//*-------------------------------------------------------------------------+| Function: Read_timer| Description: Read hardware timer value.| Global Variables: Ttimer_val, Timer_driver_Find_average_overhead.| Arguments: None.| Returns: Nothing.+--------------------------------------------------------------------------*/uint32_ttsc_read_timer(void){ register uint32_t total; total = (uint32_t)(rdtsc() - Ttimer_val); if (Timer_driver_Find_average_overhead) return total; else if (total < LEAST_VALID) return 0; /* below timer resolution */ else return (total - AVG_OVERHEAD);} /* tsc_read_timer *//*-------------------------------------------------------------------------+| Non-Pentium timer handling.+--------------------------------------------------------------------------*/#define US_PER_ISR 250 /* Number of micro-seconds per timer interruption *//*-------------------------------------------------------------------------+| Function: Timer_exit| Description: Timer cleanup routine at RTEMS exit. NOTE: This routine is| not really necessary, since there will be a reset at exit.| Global Variables: None.| Arguments: None.| Returns: Nothing.+--------------------------------------------------------------------------*/static voidtimerOff(const rtems_raw_irq_connect_data* used){ /* * disable interrrupt at i8259 level */ BSP_irq_disable_at_i8259s(used->idtIndex - BSP_IRQ_VECTOR_BASE); /* reset timer mode to standard (DOS) value */ outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN); outport_byte(TIMER_CNTR0, 0); outport_byte(TIMER_CNTR0, 0);} /* Timer_exit */static voidtimerOn(const rtems_raw_irq_connect_data* used){ /* load timer for US_PER_ISR microsecond period */ outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_16BIT|TIMER_RATEGEN); outport_byte(TIMER_CNTR0, US_TO_TICK(US_PER_ISR) >> 0 & 0xff); outport_byte(TIMER_CNTR0, US_TO_TICK(US_PER_ISR) >> 8 & 0xff); /* * enable interrrupt at i8259 level */ BSP_irq_enable_at_i8259s(used->idtIndex - BSP_IRQ_VECTOR_BASE);}static inttimerIsOn(const rtems_raw_irq_connect_data *used){ return BSP_irq_enabled_at_i8259s(used->idtIndex - BSP_IRQ_VECTOR_BASE);}static rtems_raw_irq_connect_data timer_raw_irq_data = { BSP_PERIODIC_TIMER + BSP_IRQ_VECTOR_BASE, timerisr, timerOn, timerOff, timerIsOn};/*-------------------------------------------------------------------------+| Function: Timer_exit| Description: Timer cleanup routine at RTEMS exit. NOTE: This routine is| not really necessary, since there will be a reset at exit.| Global Variables: None.| Arguments: None.| Returns: Nothing.+--------------------------------------------------------------------------*/voidi386_timer_exit(void){ i386_delete_idt_entry (&timer_raw_irq_data);} /* Timer_exit *//*-------------------------------------------------------------------------+| Function: Timer_initialize| Description: Timer initialization routine.| Global Variables: Ttimer_val.| Arguments: None.| Returns: Nothing.+--------------------------------------------------------------------------*/voidi386_timer_initialize(void){ static rtems_boolean First = TRUE; if (First) { First = FALSE; atexit(Timer_exit); /* Try not to hose the system at exit. */ if (!i386_set_idt_entry (&timer_raw_irq_data)) { printk("raw handler connexion failed\n"); rtems_fatal_error_occurred(1); } } /* wait for ISR to be called at least once */ Ttimer_val = 0; while (Ttimer_val == 0) continue; Ttimer_val = 0;} /* Timer_initialize *//*-------------------------------------------------------------------------+| Function: Read_timer| Description: Read hardware timer value.| Global Variables: Ttimer_val, Timer_driver_Find_average_overhead.| Arguments: None.| Returns: Nothing.+--------------------------------------------------------------------------*/uint32_ti386_read_timer(void){ register uint32_t total, clicks; register uint8_t lsb, msb; outport_byte(TIMER_MODE, TIMER_SEL0|TIMER_LATCH); inport_byte(TIMER_CNTR0, lsb); inport_byte(TIMER_CNTR0, msb); clicks = (msb << 8) | lsb; total = (Ttimer_val * US_PER_ISR) + (US_PER_ISR - TICK_TO_US(clicks)); if (Timer_driver_Find_average_overhead) return total; else if (total < LEAST_VALID) return 0; /* below timer resolution */ else return (total - AVG_OVERHEAD);}/* * General timer functions using either TSC-based implementation * or interrupt-based implementation */voidTimer_initialize(void){ static rtems_boolean First = TRUE; if (First) { if (x86_capability & (1 << 4) ) {#if defined(DEBUG) printk("TSC: timer initialization\n");#endif Timer_initialize_function = &tsc_timer_initialize; Read_timer_function = &tsc_read_timer; Timer_exit_function = &tsc_timer_exit;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -