home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
ins_msc
/
imc9106
/
stopwatc.c
< prev
next >
Wrap
Text File
|
1991-05-09
|
10KB
|
232 lines
/*********************************************************************
* 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 );
}