home *** CD-ROM | disk | FTP | other *** search
- /*********************************************************************
- * STOPWATC.C - Ths file contains all of the functions comprising the *
- * high-resolution timer. The timer uses the 8253 chip to extend *
- * the accuracy of the BIOS master clock count to a few uSecs. *
- *********************************************************************/
-
- #include <stdio.h> /* printf() */
- #include <conio.h> /* outp(), inp() */
- #include <dos.h> /* disable(), enable() */
- #include "stopwatc.h"
-
- static void HRMode2( void );
- static void HRMode3( void );
- static void nop( void );
-
- HRstruct HR; /* Global structure containing HRTimer data */
-
- /*********************************************************************
- * HRMode2 - Switch counter 0 to mode 2 and load initial value 65536 *
- *********************************************************************/
- void HRMode2( void )
- {
- _disable(); /* Disable interrupts */
- outp(0x43, 0x34); /* Counter 0, Mode 2, LSB/MSB */
- outp(0x40, 0x00); /* Load low word of valu */
- outp(0x40, 0x00); /* Load high word of value */
- _enable(); /* Re-enable interrupts */
- }
-
- /*********************************************************************
- * HRMode3 - Switch counter 0 to mode 3 and load initial value 65536 *
- *********************************************************************/
- void HRMode3( void )
- {
- _disable(); /* Disable interrupts */
- outp(0x43, 0x36); /* Counter 0, Mode 3, LSB/MSB */
- outp(0x40, 0x00); /* Load low word of value */
- outp(0x40, 0x00); /* Load high word of value */
- _enable(); /* Re-enable interrupts */
- }
-
- /*********************************************************************
- * TimeHRTimer - This function determines the average overhead of the *
- * high-resolution timing process by calling StartTimer() and *
- /* StopTimer() back-to-back 1024 times and averaging the results. *
- *********************************************************************/
- void TimeHRTimer( double *TimerAvg )
- {
- ULONG Start, Stop;
- ULONG Timers=0, TimerSum=0;
-
- printf( "Timing StopWatch ...\n" );
-
- /*----Time 1024 iterations of the Start/Stop process in---------*/
- /*----which no BIOS timer ticks occur---------------------------*/
- while ( Timers < 1024 )
- {
- Start = StartTimer();
- Stop = StopTimer();
- if ( !HR.NumTicks ) /* Use if no timer ticks occurred */
- {
- ++Timers; /* Increment counter */
- TimerSum += Stop - Start; /* Add to total */
- }
- }
-
- *TimerAvg = (double)TimerSum / (double)Timers;
- }
-
- /*********************************************************************
- * TimeBIOSTicker - This function determines the average execution *
- * time of the BIOS time-of-day interrupt. It compares the time *
- * required to perform a control loop when no ticks occur against *
- * the time to perform the same loop when ticks do occur. From *
- * this, it establishes a good estimate of the ticks average *
- * execution time. The number of iterations of the control loop *
- * is determine by the manifest constant DELAY, shown below. *
- *********************************************************************/
-
- /* On very slow or very fast machines you may need*/
- #define DELAY 128 /* to change this value to keep a reasonable ratio*/
- /* between loops with and without timer ticks. */
-
- void TimeBIOSTicker( double *TickerAvg )
- {
- int i;
- ULONG Start, Stop, TotalTicks=0;
- ULONG Tickers=0, TickerSum=0, Timers=0, TimerSum=0;
-
- printf( "Timing BIOS Ticker ...\n" );
-
- /*----Perform controlled loop until we've sampled 64 loops------*/
- /*----in which one or more BIOS ticks occurred------------------*/
- while ( Tickers < 64 )
- {
- Start = StartTimer();
- for ( i=0; i<DELAY; i++ ) /* Loop long enough to incur some */
- nop(); /* timer ticks. */
- Stop = StopTimer();
-
- if ( HR.NumTicks ) /* If timer ticks >= 1 then save */
- { /* numbers for later calculations */
- ++Tickers; /* Increment counter */
- TotalTicks += HR.NumTicks; /* Add # of ticks to total */
- TickerSum += Stop - Start; /* Add to total for ticks */
- }
- else /* If no timer ticks, save numbers*/
- { /* for control data */
- ++Timers; /* Increment counter */
- TimerSum += Stop - Start; /* Add to total for no ticks */
- }
- }
-
- /*----Calculate time per loop with tick(s)----------------------*/
- *TickerAvg = (double)TickerSum/(double)Tickers;
-
- /*----Divide by number of tickers per loop with tick(s)---------*/
- *TickerAvg /= (double)Tickers/(double)TotalTicks;
-
- /*----Subtract overhead of one control loop---------------------*/
- *TickerAvg -= (double)TimerSum/(double)Timers;
- }
-
- /*********************************************************************
- * HRInit - Performs HRTIMER initialization tasks. *
- *********************************************************************/
- void HRInit( int Mode )
- {
- double TimerAvg, TickerAvg;
-
- printf( "Initializing StopWatch ...\n" );
-
- /*----Switch PIT counter 0 to mode 2----------------------------*/
- HRMode2();
-
- /*----Determine average HRTimer overhead------------------------*/
- TimeHRTimer( &TimerAvg );
-
- /*----If timing code, determine average BIOS ticker overhead----*/
- if ( Mode == CODETIME )
- TimeBIOSTicker( &TickerAvg );
- else
- TickerAvg = 0.0;
-
- /* Round up overhead values and store in global HR structure----*/
- HR.TimerOverhead = (ULONG)(TimerAvg + 0.5);
- HR.TickerOverhead = (ULONG)(TickerAvg + 0.5);
- }
-
- /*********************************************************************
- * HRTerm - Performs HRTimer termination functions. *
- *********************************************************************/
- void HRTerm( void )
- {
- HRMode3(); /* Reset PIT counter 0 to mode 3 */
- }
-
- /*********************************************************************
- * nop - This function is used for delay while determining overheads. *
- *********************************************************************/
- static void nop( void )
- {
- return;
- }
-
- /*********************************************************************
- * StopWatch - High-Resolution Timing Function *
- *********************************************************************/
- ULONG StopWatch( int Flag )
- {
- ULONG Ticker, Overhead;
- volatile ULONG far * BiosTicker = (ULONG far *)0x0040006cL;
- union {
- UINT i;
- struct { UCHAR l, h; } c;
- } A, B;
-
- _disable(); /* Turn off interrupts */
- outp(0x43, 0x00); /* Latch PIT counter 0 */
- Ticker = *BiosTicker; /* Get BIOS's master clock count */
- A.c.l = inp(0x40); /* Read low byte of counter 0 */
- A.c.h = inp(0x40); /* Read high byte of counter 0 */
- _enable(); /* Turn interrupts back on */
- A.i = 65535 - (--A.i); /* Normalize counter value */
-
- HR.StopTicker = Ticker; /* Save initial master clock count*/
- B.i = A.i; /* Copy normalized counter to B.i */
-
- while ( B.i < 64 ) /* If new cycle, wait a while */
- { /* to ensure MCC has been updated */
- _disable(); /* Turn off interrupts */
- outp(0x43, 0x00); /* Latch PIT counter 0 */
- Ticker = *BiosTicker; /* Get BIOS's master clock count */
- B.c.l = inp(0x40); /* Read low byte of counter 0 */
- B.c.h = inp(0x40); /* Read high byte of counter 0 */
- _enable(); /* Turn interrupts back on */
- B.i = 65535 - (--B.i); /* Normalize counter value */
- }
-
- HR.Interval = 0; /* Preset return value to zero */
- /*----Perform START processing. Use last counter 0 value taken */
- if ( Flag == START ) /* START TIME INTERVAL PROCESSING */
- {
- HR.StartTicker = Ticker; /* Save starting ticker value */
- HR.StartCounter = B.i; /* Save starting counter 0 value */
- HR.StartTime = B.i; /* Save relative starting time */
- }
- /*----Perform STOP processing. Use first counter 0 value taken */
- else if ( Flag == STOP )
- {
- /*----Calculate the number of elapsed ticks during interval-*/
- HR.NumTicks = HR.StopTicker - HR.StartTicker;
-
- HR.StopTicker = Ticker; /* Save ending ticker value */
- HR.StopCounter = A.i; /* Save ending counter 0 value */
-
- /*----Build stop time from ticker and counter 0 value-------*/
- HR.StopTime = ((HR.StopTicker - HR.StartTicker) << 16) | A.i;
-
- /*----Calculate total timer and ticker overhead incurred----*/
- Overhead = HR.TimerOverhead + HR.NumTicks * HR.TickerOverhead;
-
- /*----Calculate elapsed time or zero, whichever's greater---*/
- if ( HR.StopTime - HR.StartTime >= Overhead )
- HR.Interval = HR.StopTime - HR.StartTime - Overhead;
- }
- else
- printf( "\nStopWatch: bad flag argument=%u\n", Flag );
-
- return( HR.Interval );
- }