m8260Timer.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:20k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* m8260Timer.c - Motorola MPC8260 Timer Library */
  2. /* Copyright 1984-2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01j,25oct01,g_h  Move the initialization of sysDecClkFrequency to the function 
  8.  sysClkRateSet, remove #include "ads8260.h", part of SPR 71123.
  9. 01i,24oct01,g_h  Add #ifdef INCLUDE_AUX_CLK around AUX clock routines 
  10.  and variables to prevent compilation warnings, part of SPR 71123.
  11. 01h,15sep01,dat  Using new vxDecReload function
  12. 01g,16sep99,ms_  m8260Timer.h comes from drv/timer
  13. 01f,09sep99,ms_  change bsp name from vads8260 to ads8260
  14. 01e,15jul99,ms_  make compliant with our coding standards
  15. 01d,02may99,ms_  add aux clock and timestamp facility
  16. 01c,17apr99,ms_  final EAR cleanup
  17. 01b,14apr99,ms_  use interrupt numbers instead of vectors
  18. 01a,28jan99,ms_  adapted from ppc860Timer.c version 01a
  19. */
  20. /*
  21. DESCRIPTION
  22. This library provides MPC8260 system clock, auxiliary clock, and timestamp
  23. support.
  24. The PowerPC decrementer timer is used to implement the system clock, the CPM
  25. TIMER2 is used for a 16-bit auxiliary clock, and CPM timers TIMER3 and TIMER4
  26. are cascaded into a free-running 32-bit timer for timestamp support.
  27. The macro DEC_CLOCK_FREQ, the frequency of the decrementer input clock, must
  28. be defined before using this module. The macro DEC_CLK_TO_INC, the ratio
  29. between the number of decrementer input clock cycles and one counter
  30. increment, may be redefined prior to including this file in sysLib.c.
  31. The macros SYS_CLK_RATE_MIN and SYS_CLK_RATE_MAX must be defined to 
  32. provide parameter checking for sysClkRateSet() the routine.
  33. The auxiliary clock period is modified by programming the Timer Reference
  34. Register. The input is the general system clock, which can be optionally
  35. divided by 16. The prescaler is always used to divide by 256. The Timer
  36. Reference Register is 16 bits. This information dictates the minimum and 
  37. maximum auxiliarly clock rates.
  38. The slowest rate is when the general system clock is divided by 16 and the 
  39. value for the Reference register is the highest i.e. 65535. This gives us 
  40. a minimum auxiliarly clock rate of 
  41. .CS
  42. SYS_CPU_FREQ / (256 * 65535 * 16) 
  43. = 40000000 / 268431360
  44. = .15
  45. .CE
  46. We define AUX_CLK_RATE_MIN as 1
  47. The highest rate is when the general system clock is not divided by
  48. 16, and the reference register is set to its minimum value i.e. 1.
  49. This tells us the maximum auxiliary clock rate:
  50. .CS
  51. SYS_CPU_FREQ / 256
  52. = 40000000 / 256
  53. = 156250
  54. .CE
  55. We define AUX_CLK_RATE_MAX as 8000
  56. INCLUDE FILES: timerDev.h, vxPpcLib.h
  57.    
  58. SEE ALSO:
  59. .pG "Configuration"
  60. */
  61. /* includes */
  62. #include "arch/ppc/vxPpcLib.h"
  63. #include "drv/timer/timerDev.h"
  64. #include "drv/timer/m8260Timer.h"
  65. /* local defines */
  66. #ifndef DEC_CLK_TO_INC
  67. #define DEC_CLK_TO_INC 4 /* # bus clks per increment */
  68. #endif
  69. #ifndef DEC_CLOCK_FREQ
  70. #define DEC_CLOCK_FREQ OSCILLATOR_FREQ /* Set to system default */
  71. #endif /* DEC_CLOCK_FREQ */
  72. #ifndef SYS_CPU_FREQ
  73. #define SYS_CPU_FREQ OSCILLATOR_FREQ /* Set to system default */
  74. #endif /* SYS_CPU_FREQ */
  75. /* extern declarations */
  76. IMPORT STATUS excIntConnect (VOIDFUNCPTR *, VOIDFUNCPTR);
  77. /* locals */
  78. LOCAL int  sysClkTicksPerSecond  = 60;   /* default 60 ticks/second */
  79. LOCAL FUNCPTR sysClkRoutine = NULL;
  80. LOCAL int sysClkArg = 0;
  81. LOCAL BOOL sysClkConnectFirstTime = TRUE;
  82. LOCAL int       decCountVal = 10000000; /* default dec value */
  83. LOCAL BOOL sysClkRunning  = FALSE;
  84. LOCAL int  sysDecClkFrequency = 0;
  85. #ifdef INCLUDE_AUX_CLK
  86. LOCAL FUNCPTR sysAuxClkRoutine        = NULL;
  87. LOCAL int     sysAuxClkArg            = 0;
  88. LOCAL BOOL    sysAuxClkRunning        = FALSE;
  89. LOCAL BOOL    sysAuxClkIntConnected   = FALSE;
  90. LOCAL int     sysAuxClkTicksPerSecond = 60;
  91. #endif /* INCLUDE_AUX_CLK */
  92. #ifdef        INCLUDE_TIMESTAMP
  93. LOCAL BOOL    sysTimestampRunning     = FALSE;   /* timestamp running flag */
  94. LOCAL FUNCPTR sysTimestampRoutine     = NULL;
  95. LOCAL int     sysTimestampArg         = 0;
  96. LOCAL BOOL    sysTimestampIntConnected = FALSE;
  97. #endif        /* INCLUDE_TIMESTAMP */
  98. /*******************************************************************************
  99. *
  100. * sysClkInt - clock interrupt handler
  101. *
  102. * This routine handles the clock interrupt on the PowerPC architecture. It is
  103. * attached to the decrementer vector by the routine sysClkConnect().
  104. *
  105. * RETURNS : N/A
  106. */
  107. LOCAL void sysClkInt (void)
  108.     {
  109.     vxDecReload (decCountVal); /* reload the decrementer */
  110.     /* execute the system clock routine */
  111.     if (sysClkRunning && (sysClkRoutine != NULL))
  112. (*(FUNCPTR) sysClkRoutine) (sysClkArg);
  113.     }
  114. /*******************************************************************************
  115. *
  116. * sysClkConnect - connect a routine to the system clock interrupt
  117. *
  118. * This routine specifies the interrupt service routine to be called at each
  119. * clock interrupt.  Normally, it is called from usrRoot() in usrConfig.c to
  120. * connect usrClock() to the system clock interrupt.
  121. *
  122. * RETURNS: OK, or ERROR if the routine cannot be connected to the interrupt.
  123. *
  124. * SEE ALSO: intConnect(), usrClock(), sysClkEnable()
  125. */
  126.     
  127. STATUS sysClkConnect
  128.     (
  129.     FUNCPTR  routine, /* routine to connect */
  130.     int  arg /* argument for the routine */
  131.     )
  132.     {
  133.     if (sysClkConnectFirstTime)
  134. {
  135. sysHwInit2();
  136. sysClkConnectFirstTime = FALSE;
  137.         excIntConnect ((VOIDFUNCPTR *) _EXC_OFF_DECR, (VOIDFUNCPTR) sysClkInt);
  138. }
  139.     sysClkRoutine = routine;
  140.     sysClkArg = arg;
  141.     return (OK);
  142.     }
  143. /******************************************************************************
  144. *
  145. * sysClkEnable - turn on system clock interrupts
  146. *
  147. * This routine enables system clock interrupts.
  148. *
  149. * RETURNS: N/A
  150. *
  151. * SEE ALSO: sysClkConnect(), sysClkDisable(), sysClkRateSet()
  152. */
  153. void sysClkEnable (void)
  154.     {
  155.     if (!sysClkRunning)
  156. {
  157. sysClkRunning = TRUE;
  158. vxDecSet (decCountVal);
  159. }
  160.     }
  161. /******************************************************************************
  162. *
  163. * sysClkDisable - turn off system clock interrupts
  164. *
  165. * This routine disables system clock interrupts.
  166. *
  167. * RETURNS: N/A
  168. *
  169. * SEE ALSO: sysClkEnable()
  170. */
  171. void sysClkDisable (void)
  172.     {
  173.     if (sysClkRunning)
  174. sysClkRunning = FALSE;
  175.     }
  176. /******************************************************************************
  177. *
  178. * sysClkRateGet - get the system clock rate
  179. *
  180. * This routine returns the system clock rate.
  181. *
  182. * RETURNS: The number of ticks per second of the system clock.
  183. *
  184. * SEE ALSO: sysClkEnable(), sysClkRateSet()
  185. */
  186. int sysClkRateGet (void)
  187.     {
  188.     return (sysClkTicksPerSecond);
  189.     }
  190. /******************************************************************************
  191. *
  192. * sysClkRateSet - set the system clock rate
  193. *
  194. * This routine sets the interrupt rate of the system clock.  It is called
  195. * by usrRoot() in usrConfig.c.
  196. *
  197. * RETURNS: OK, or ERROR if the tick rate is invalid or the timer cannot be set.
  198. *
  199. * SEE ALSO: sysClkEnable(), sysClkRateGet()
  200. */
  201.    
  202. STATUS sysClkRateSet
  203.     (
  204.     int  ticksPerSecond  /* number of clock interrupts per second */
  205.     )
  206.     {
  207.     if (ticksPerSecond < SYS_CLK_RATE_MIN || ticksPerSecond > SYS_CLK_RATE_MAX)
  208.         return (ERROR);
  209.     /* save the clock speed */
  210.     sysClkTicksPerSecond = ticksPerSecond;
  211.     /* Calibrate the clock, if needed. */
  212. #ifdef PPC_TMR_RATE_SET_ADJUST
  213.     PPC_TMR_RATE_SET_ADJUST;
  214. #endif
  215.     sysDecClkFrequency = DEC_CLOCK_FREQ / DEC_CLK_TO_INC;
  216.     /* 
  217.      * compute the value to load in the decrementer. The new value will be
  218.      * loaded into the decrementer after the current period
  219.      */
  220.     decCountVal = sysDecClkFrequency / ticksPerSecond;
  221.     return (OK);
  222.     }
  223. #ifdef INCLUDE_AUX_CLK
  224. /*******************************************************************************
  225. *
  226. * sysAuxClkInt - auxiliary clock interrupt handler
  227. *
  228. * This routine handles the auxiliary clock interrupt.  It calls a user routine
  229. * if one was specified by the routine sysAuxClkConnect().
  230. */
  231. LOCAL void sysAuxClkInt (void)
  232.     {
  233.     UINT32 immrVal = vxImmrGet();
  234.     *M8260_TER2(immrVal) = M8260_TER_REF | M8260_TER_CAP; /* clear all events */
  235.     if (sysAuxClkRoutine != NULL)
  236.         (*sysAuxClkRoutine) (sysAuxClkArg);
  237.     }
  238. /*******************************************************************************
  239. *
  240. * sysAuxClkConnect - connect a routine to the auxiliary clock interrupt
  241. *
  242. * This routine specifies the interrupt service routine to be called at each
  243. * auxiliary clock interrupt.  It does not enable auxiliary clock
  244. * interrupts.
  245. *
  246. * RETURNS: OK, or ERROR if the routine cannot be connected to the interrupt.
  247. *
  248. * SEE ALSO: intConnect(), sysAuxClkEnable()
  249. */
  250. STATUS sysAuxClkConnect
  251.     (
  252.     FUNCPTR routine, /* routine called at each aux. clock interrupt */
  253.     int     arg /* argument to auxiliary clock interrupt routine */
  254.     )
  255.     {
  256.     /* connect the ISR to the TIMER2 exception */
  257.     sysAuxClkRoutine   = routine;
  258.     sysAuxClkArg       = arg;
  259.     return (OK);
  260.     }
  261. /*******************************************************************************
  262. *
  263. * sysAuxClkDisable - turn off auxiliary clock interrupts
  264. *
  265. * This routine disables auxiliary clock interrupts.
  266. *
  267. * RETURNS: N/A
  268. *
  269. * SEE ALSO: sysAuxClkEnable()
  270. */
  271. void sysAuxClkDisable (void)
  272.     {
  273.     UINT32 immrVal = vxImmrGet();
  274.     if (sysAuxClkRunning)
  275. {
  276. m8260IntDisable(INUM_TIMER2);
  277. *M8260_TGCR1(immrVal) |= M8260_TGCR_STP2; /* stop timer */
  278. sysAuxClkRunning = FALSE; /* clock is no longer running */
  279. }
  280.     }
  281. /*******************************************************************************
  282. *
  283. * sysAuxClkEnable - turn on auxiliary clock interrupts
  284. *
  285. * This routine enables auxiliary clock interrupts.
  286. * The timer is used in "reference mode" i.e. a value is programmed into 
  287. * the reference register and an interrupt occurs when the timer reaches
  288. * that value. 
  289. *
  290. * RETURNS: N/A
  291. *
  292. * SEE ALSO: sysAuxClkConnect(), sysAuxClkDisable(), sysAuxClkRateSet()
  293. */
  294. void sysAuxClkEnable (void)
  295.     {
  296.     UINT32 immrVal = vxImmrGet();
  297.     /* 
  298.      * Calculate the preliminary value for the Reference register. This 
  299.      * does not yet take into account whether we will divide the general 
  300.      * system clock by 16 or not. The 8 bit left shift accounts for 
  301.      * the prescaler which will always be set to 0xFF i.e. the clock 
  302.      * will further be divided by 256.
  303.      *
  304.      */
  305.     UINT32  tempDiv = SYS_CPU_FREQ / (sysAuxClkTicksPerSecond << 8);
  306.     /* 
  307.      * Enable the auxiliary clock only if it is not already running 
  308.      * and if the required reference value will fit in the reference register
  309.      * if the general system clock is divided by 16.
  310.      */
  311.     if ((!sysAuxClkRunning) && (tempDiv < ((1 << (M8260_TRR_SIZE-1)) * 16)))
  312. {
  313.         /* 
  314.  * start and hold in reset (i.e. disable) timer2 
  315.  * Note that RST is active low while STP is active high
  316.  */
  317. *M8260_TGCR1(immrVal) &= ~M8260_TGCR_STP2; /* clear stop bit */
  318. *M8260_TGCR1(immrVal) &= ~M8260_TGCR_RST2; /* clear reset bit */
  319. *M8260_TCN2(immrVal) = 0x0; /* clear the timer counter */
  320. /* 
  321.  * If the preliminary value for the Reference register is small
  322.  * enough, we don't need to divide the general system clock by 16,
  323.  * and the preliminary value for the Reference register is the
  324.  * value used 
  325.  */
  326.         
  327. if (tempDiv < (1 << (M8260_TRR_SIZE-1)))
  328.     {
  329.     *M8260_TRR2(immrVal) = (UINT16) tempDiv;
  330.             *M8260_TMR2(immrVal) = (
  331. (M8260_TMR_ICLK_IN_GEN  & M8260_TMR_ICLK_MSK) |    /* int clk */
  332. M8260_TMR_ORI |                                 /* int on ref */
  333.         M8260_TMR_FRR |                                 /* free run */
  334.         (M8260_TMR_PS_MSK & M8260_TMR_PS_MAX)); /* max prscl  */
  335.     }
  336. else
  337.     {
  338.             *M8260_TRR2(immrVal) = (UINT16) (tempDiv / 16);
  339.             *M8260_TMR2(immrVal) = (M8260_TMR_ICLK_IN_GEN_DIV16 | 
  340.            M8260_TMR_ORI |
  341.                                    M8260_TMR_FRR | 
  342.    (M8260_TMR_PS_MSK & M8260_TMR_PS_MAX));
  343.     }
  344.  
  345. /* clear all timer events */
  346. *M8260_TER2(immrVal) = M8260_TER_REF | M8260_TER_CAP;
  347. /* enable timer interrupt */
  348. m8260IntEnable(INUM_TIMER2);
  349.         if (! sysAuxClkIntConnected)
  350.             {
  351.             (void) intConnect (INUM_TO_IVEC(INUM_TIMER2), 
  352.        (VOIDFUNCPTR) sysAuxClkInt, 0);
  353.             sysAuxClkIntConnected = TRUE;
  354.             }
  355.         
  356. /* Enable timer by removing reset, which is active low */
  357. *M8260_TGCR1(immrVal) |= M8260_TGCR_RST2; /* set reset bit */
  358. sysAuxClkRunning = TRUE;
  359. }
  360.     }
  361. /*******************************************************************************
  362. *
  363. * sysAuxClkRateGet - get the auxiliary clock rate
  364. *
  365. * This routine returns the interrupt rate of the auxiliary clock.
  366. *
  367. * RETURNS: The number of ticks per second of the auxiliary clock.
  368. *
  369. * SEE ALSO: sysAuxClkEnable(), sysAuxClkRateSet()
  370. */
  371. int sysAuxClkRateGet (void)
  372.     {
  373.     return (sysAuxClkTicksPerSecond);
  374.     }
  375. /*******************************************************************************
  376. *
  377. * sysAuxClkRateSet - set the auxiliary clock rate
  378. *
  379. * This routine sets the interrupt rate of the auxiliary clock.
  380. * It does not enable auxiliary clock interrupts.
  381. *
  382. * RETURNS: OK, or ERROR if the tick rate is invalid or the timer cannot be
  383. * set.
  384. *
  385. * SEE ALSO: sysAuxClkEnable(), sysAuxClkRateGet()
  386. */
  387. STATUS sysAuxClkRateSet
  388.     (
  389.     int ticksPerSecond     /* number of clock interrupts per second */
  390.     )
  391.     {
  392.     if (ticksPerSecond < AUX_CLK_RATE_MIN || ticksPerSecond > AUX_CLK_RATE_MAX)
  393. return (ERROR);
  394.     sysAuxClkTicksPerSecond = ticksPerSecond;
  395.     if (sysAuxClkRunning)
  396. {
  397. sysAuxClkDisable ();
  398. sysAuxClkEnable ();
  399. }
  400.     return (OK);
  401.     }
  402. #endif /* INCLUDE_AUX_CLK */
  403. #ifdef  INCLUDE_TIMESTAMP
  404. /*******************************************************************************
  405. *
  406. * sysTimestampInt - timestamp timer interrupt handler
  407. *
  408. * This rountine handles the timestamp timer interrupt.  A user routine is
  409. * called, if one was connected by sysTimestampConnect().
  410. *
  411. * RETURNS: N/A
  412. *
  413. * SEE ALSO: sysTimestampConnect()
  414. */
  415. LOCAL void sysTimestampInt (void)
  416.     {
  417.     UINT32 immrVal = vxImmrGet();
  418.     *M8260_TER4(immrVal) |= M8260_TER_REF; /* clear event register */
  419.     if (sysTimestampRoutine != NULL)    /* call user routine */
  420.         (*sysTimestampRoutine) (sysTimestampArg);
  421.     }
  422. /*******************************************************************************
  423. *
  424. * sysTimestampConnect - connect a user routine to the timestamp timer interrupt
  425. *
  426. * This routine specifies the user interrupt routine to be called at each
  427. * timestamp timer interrupt.  It does not enable the timestamp timer itself.
  428. *
  429. * RETURNS: OK, or ERROR if sysTimestampInt() interrupt handler is not used.
  430. */
  431. STATUS sysTimestampConnect
  432.     (
  433.     FUNCPTR routine,    /* routine called at each timestamp timer interrupt */
  434.     int arg             /* argument with which to call routine */
  435.     )
  436.     {
  437.     sysTimestampRoutine = routine;
  438.     sysTimestampArg = arg;
  439.     return (OK);
  440.     }
  441. /*******************************************************************************
  442. *
  443. * sysTimestampEnable - initialize and enable the timestamp timer
  444. *
  445. * This routine connects interrupts, and enables the timer device
  446. *
  447. * RETURNS: TRUE always
  448. */
  449. STATUS sysTimestampEnable (void)
  450.     {
  451.     UINT32 immrVal = vxImmrGet();
  452.     if (sysTimestampRunning)
  453.         {
  454.         *M8260_TCN3(immrVal) = (UINT32) 0; /* clear the counter */
  455.         return (OK);
  456.         }
  457.     if (! sysTimestampIntConnected)
  458.         {
  459.         (void) intConnect (INUM_TO_IVEC(INUM_TIMER4), 
  460.                                 (VOIDFUNCPTR) sysTimestampInt, 
  461. 0);
  462.         sysTimestampIntConnected = FALSE;
  463.         }
  464.     sysTimestampRunning = TRUE;
  465.     /* cascade timer 3 and 4 in order to get a 32 bit timer */
  466.     *M8260_TGCR2(immrVal) |= M8260_TGCR_CAS4;
  467.     /* start and hold in reset (i.e. disable) timers 3 and 4 */
  468.     
  469.     *M8260_TGCR2(immrVal) &= ~(M8260_TGCR_RST4 | M8260_TGCR_RST3 | 
  470.                               M8260_TGCR_STP4 | M8260_TGCR_STP3 );
  471.     /*
  472.      * When timers 3 and 4 are cascaded, TMR4 is the mode register, 
  473.      * while TMR3 is ignored.  Set prescaler to 0 to divide the clock 
  474.      * (SYS_CPU_FREQ) by 1.
  475.      */
  476.     *M8260_TMR4(immrVal) = M8260_TMR_PS_MIN | M8260_TMR_ICLK_IN_GEN | 
  477.    M8260_TMR_ORI | M8260_TMR_FRR;
  478.     *M8260_TMR3(immrVal) = M8260_TMR_ICLK_IN_CAS;
  479.     /* 
  480.      * when cascaded, the combined TRR, TCR, and TCN must be referenced
  481.      * with 32-bit bus cycles 
  482.      */
  483.     *((UINT32 *)M8260_TRR3(immrVal)) = (UINT32) sysTimestampPeriod ();
  484.     *((UINT32 *)M8260_TCN3(immrVal)) = (UINT32) 0;
  485.     /* clear all timer events */
  486.     *M8260_TER4(immrVal) = M8260_TER_REF | M8260_TER_CAP;
  487.     /* enable timer interrupt */
  488.     m8260IntEnable(INUM_TIMER4);
  489.    /* enable timer 3 and 4 */
  490.    *M8260_TGCR2(immrVal) |= (M8260_TGCR_RST3 | M8260_TGCR_RST4);
  491.     return (OK);
  492.     }
  493. /*******************************************************************************
  494. *
  495. * sysTimestampDisable - turn off auxiliary clock interrupts
  496. *
  497. * This routine disables auxiliary clock interrupts.
  498. *
  499. * RETURNS: OK, always
  500. *
  501. * SEE ALSO: sysTimestampEnable()
  502. */
  503. STATUS sysTimestampDisable (void)
  504.     {
  505.     UINT32 immrVal = vxImmrGet();
  506.     if (sysTimestampRunning)
  507.         {
  508. m8260IntDisable(INUM_TIMER3); /* disable interrupt */
  509. m8260IntDisable(INUM_TIMER4); /* disable interrupt */
  510. *M8260_TGCR2(immrVal) |= M8260_TGCR_STP3; /* stop timer */
  511. *M8260_TGCR2(immrVal) |= M8260_TGCR_STP4; /* stop timer */
  512.         sysTimestampRunning = FALSE;            /* clock is no longer running */
  513.         }
  514.     return (OK);
  515.     }
  516. /*******************************************************************************
  517. *
  518. * sysTimestampPeriod - get the period of a timestamp timer 
  519. *
  520. * This routine gets the period of the timestamp timer, in ticks.  The
  521. * period, or terminal count, is the number of ticks to which the timestamp
  522. * timer counts before rolling over and restarting the counting process.
  523. *
  524. * RETURNS: The period of the timestamp timer in counter ticks.
  525. */
  526. UINT32 sysTimestampPeriod (void)
  527.     {
  528.     /*
  529.      * The period of the timestamp depends on the clock rate of the on-chip
  530.      * timer (ie the Decrementer reload value).
  531.      */
  532.     
  533.     return (0xffffffff); /* highest period -> freerunning */
  534.     }
  535. /*******************************************************************************
  536. *
  537. * sysTimestampFreq - get a timestamp timer clock frequency
  538. *
  539. * This routine gets the frequency of the timer clock, in ticks per 
  540. * second.  The rate of the timestamp timer is set explicitly by the 
  541. * hardware and typically cannot be altered.
  542. *
  543. * RETURNS: The timestamp timer clock frequency, in ticks per second.
  544. */
  545. UINT32 sysTimestampFreq (void)
  546.     {
  547.     UINT32 immrVal = vxImmrGet();
  548.     /* Get the prescaler value from TMR4. TMR3 is ignored in cascade mode. */
  549.     return (SYS_CPU_FREQ / ((*M8260_TMR4(immrVal) >> 8) + 1));
  550.     }
  551. /*******************************************************************************
  552. *
  553. * sysTimestamp - get a timestamp timer tick count
  554. *
  555. * This routine returns the current value of the timestamp timer tick counter.
  556. * The tick count can be converted to seconds by dividing it by the return of
  557. * sysTimestampFreq().
  558. *
  559. * This routine should be called with interrupts locked.  If interrupts are
  560. * not locked, sysTimestampLock() should be used instead.
  561. *
  562. * RETURNS: The current timestamp timer tick count.
  563. *
  564. * SEE ALSO: sysTimestampFreq(), sysTimestampLock()
  565. */
  566. UINT32 sysTimestamp (void)
  567.     {
  568.     UINT32 immrVal = vxImmrGet();
  569.     
  570.     return (*((UINT32 *) M8260_TCN3(immrVal)));
  571.     }
  572. /*******************************************************************************
  573. *
  574. * sysTimestampLock - lock interrupts and get the timestamp timer tick count
  575. *
  576. * This routine locks interrupts when the tick counter must be stopped 
  577. * in order to read it or when two independent counters must be read.  
  578. * It then returns the current value of the timestamp timer tick
  579. * counter.
  580. * The tick count can be converted to seconds by dividing it by the return of
  581. * sysTimestampFreq().
  582. *
  583. * If interrupts are already locked, sysTimestamp() should be
  584. * used instead.
  585. *
  586. * RETURNS: The current timestamp timer tick count.
  587. *
  588. * SEE ALSO: sysTimestampFreq(), sysTimestamp()
  589. */
  590. UINT32 sysTimestampLock (void)
  591.     {
  592.     UINT32 immrVal = vxImmrGet();
  593.     return (*((UINT32 *) M8260_TCN3(immrVal)));
  594.     }
  595. #endif  /* INCLUDE_TIMESTAMP */