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

  1. /*********************************************************************
  2. * STOPWATC.C - Ths file contains all of the functions comprising the *
  3. *     high-resolution timer. The timer uses the 8253 chip to extend  *
  4. *     the accuracy of the BIOS master clock count to a few uSecs.    *
  5. *********************************************************************/
  6.  
  7. #include <stdio.h>      /* printf()                                 */
  8. #include <conio.h>      /* outp(), inp()                            */
  9. #include <dos.h>        /* disable(), enable()                      */
  10. #include "stopwatc.h"
  11.  
  12. static void HRMode2( void );
  13. static void HRMode3( void );
  14. static void nop( void );
  15.  
  16. HRstruct HR;            /* Global structure containing HRTimer data */
  17.  
  18. /*********************************************************************
  19. * HRMode2 - Switch counter 0 to mode 2 and load initial value 65536  *
  20. *********************************************************************/
  21. void HRMode2( void )
  22.     {
  23.     _disable();                   /* Disable interrupts             */
  24.     outp(0x43, 0x34);             /* Counter 0, Mode 2, LSB/MSB     */
  25.     outp(0x40, 0x00);             /* Load low word of valu          */
  26.     outp(0x40, 0x00);             /* Load high word of value        */
  27.     _enable();                    /* Re-enable interrupts           */
  28.     }
  29.  
  30. /*********************************************************************
  31. * HRMode3 - Switch counter 0 to mode 3 and load initial value 65536  *
  32. *********************************************************************/
  33. void HRMode3( void )
  34.     {
  35.     _disable();                   /* Disable interrupts             */
  36.     outp(0x43, 0x36);             /* Counter 0, Mode 3, LSB/MSB     */
  37.     outp(0x40, 0x00);             /* Load low word of value         */
  38.     outp(0x40, 0x00);             /* Load high word of value        */
  39.     _enable();                    /* Re-enable interrupts           */
  40.     }
  41.  
  42. /*********************************************************************
  43. * TimeHRTimer - This function determines the average overhead of the *
  44. *     high-resolution timing process by calling StartTimer() and     *
  45. /*    StopTimer() back-to-back 1024 times and averaging the results. *
  46. *********************************************************************/
  47. void TimeHRTimer( double *TimerAvg )
  48.     {
  49.     ULONG Start, Stop;
  50.     ULONG Timers=0, TimerSum=0;
  51.  
  52.     printf( "Timing StopWatch ...\n" );
  53.  
  54.     /*----Time 1024 iterations of the Start/Stop process in---------*/
  55.     /*----which no BIOS timer ticks occur---------------------------*/
  56.     while ( Timers < 1024 )
  57.         {
  58.         Start = StartTimer();
  59.         Stop = StopTimer();
  60.         if ( !HR.NumTicks )       /* Use if no timer ticks occurred */
  61.             {
  62.             ++Timers;             /* Increment counter              */
  63.             TimerSum += Stop - Start;  /* Add to total              */
  64.             }
  65.         }
  66.  
  67.     *TimerAvg = (double)TimerSum / (double)Timers;
  68.     }
  69.  
  70. /*********************************************************************
  71. * TimeBIOSTicker - This function determines the average execution    *
  72. *     time of the BIOS time-of-day interrupt. It compares the time   *
  73. *     required to perform a control loop when no ticks occur against *
  74. *     the time to perform the same loop when ticks do occur. From    *
  75. *     this, it establishes a good estimate of the ticks average      *
  76. *     execution time. The number of iterations of the control loop   *
  77. *     is determine by the manifest constant DELAY, shown below.      *
  78. *********************************************************************/
  79.  
  80.                   /* On very slow or very fast machines you may need*/
  81. #define DELAY 128 /* to change this value to keep a reasonable ratio*/
  82.                   /* between loops with and without timer ticks.    */
  83.  
  84. void TimeBIOSTicker( double *TickerAvg )
  85.     {
  86.     int i;
  87.     ULONG Start, Stop, TotalTicks=0;
  88.     ULONG Tickers=0, TickerSum=0, Timers=0, TimerSum=0;
  89.  
  90.     printf( "Timing BIOS Ticker ...\n" );
  91.  
  92.     /*----Perform controlled loop until we've sampled 64 loops------*/
  93.     /*----in which one or more BIOS ticks occurred------------------*/
  94.     while ( Tickers < 64 )
  95.         {
  96.         Start = StartTimer();
  97.         for ( i=0; i<DELAY; i++ ) /* Loop long enough to incur some */
  98.             nop();                /* timer ticks.                   */
  99.         Stop = StopTimer();
  100.  
  101.         if ( HR.NumTicks )        /* If timer ticks >= 1 then save  */
  102.             {                     /* numbers for later calculations */
  103.             ++Tickers;            /* Increment counter              */
  104.             TotalTicks += HR.NumTicks; /* Add # of ticks to total   */
  105.             TickerSum += Stop - Start; /* Add to total for ticks    */
  106.             }
  107.         else                      /* If no timer ticks, save numbers*/
  108.             {                     /* for control data               */
  109.             ++Timers;             /* Increment counter              */
  110.             TimerSum += Stop - Start;  /* Add to total for no ticks */
  111.             }
  112.         }
  113.  
  114.     /*----Calculate time per loop with tick(s)----------------------*/
  115.     *TickerAvg = (double)TickerSum/(double)Tickers;
  116.  
  117.     /*----Divide by number of tickers per loop with tick(s)---------*/
  118.     *TickerAvg /= (double)Tickers/(double)TotalTicks;
  119.  
  120.     /*----Subtract overhead of one control loop---------------------*/
  121.     *TickerAvg -= (double)TimerSum/(double)Timers;
  122.     }
  123.  
  124. /*********************************************************************
  125. * HRInit - Performs HRTIMER initialization tasks.                    *
  126. *********************************************************************/
  127. void HRInit( int Mode )
  128.     {
  129.     double TimerAvg, TickerAvg;
  130.  
  131.     printf( "Initializing StopWatch ...\n" );
  132.  
  133.     /*----Switch PIT counter 0 to mode 2----------------------------*/
  134.     HRMode2();
  135.  
  136.     /*----Determine average HRTimer overhead------------------------*/
  137.     TimeHRTimer( &TimerAvg );
  138.  
  139.     /*----If timing code, determine average BIOS ticker overhead----*/
  140.     if ( Mode == CODETIME )
  141.         TimeBIOSTicker( &TickerAvg );
  142.     else
  143.         TickerAvg = 0.0;
  144.  
  145.     /* Round up overhead values and store in global HR structure----*/
  146.     HR.TimerOverhead = (ULONG)(TimerAvg + 0.5);
  147.     HR.TickerOverhead = (ULONG)(TickerAvg + 0.5);
  148.     }
  149.  
  150. /*********************************************************************
  151. * HRTerm - Performs HRTimer termination functions.                   *
  152. *********************************************************************/
  153. void HRTerm( void )
  154. {
  155.     HRMode3();                    /* Reset PIT counter 0 to mode 3  */
  156. }
  157.  
  158. /*********************************************************************
  159. * nop - This function is used for delay while determining overheads. *
  160. *********************************************************************/
  161. static void nop( void )
  162. {
  163.     return;
  164. }
  165.  
  166. /*********************************************************************
  167. * StopWatch - High-Resolution Timing Function                        *
  168. *********************************************************************/
  169. ULONG StopWatch( int Flag )
  170.     {
  171.     ULONG Ticker, Overhead;
  172.     volatile ULONG far * BiosTicker = (ULONG far *)0x0040006cL;
  173.     union {
  174.         UINT i;
  175.         struct { UCHAR l, h; } c;
  176.         } A, B;
  177.  
  178.     _disable();                   /* Turn off interrupts            */
  179.     outp(0x43, 0x00);             /* Latch PIT counter 0            */
  180.     Ticker = *BiosTicker;         /* Get BIOS's master clock count  */
  181.     A.c.l = inp(0x40);            /* Read low byte of counter 0     */
  182.     A.c.h = inp(0x40);            /* Read high byte of counter 0    */
  183.     _enable();                    /* Turn interrupts back on        */
  184.     A.i = 65535 - (--A.i);        /* Normalize counter value        */
  185.  
  186.     HR.StopTicker = Ticker;       /* Save initial master clock count*/
  187.     B.i = A.i;                    /* Copy normalized counter to B.i */
  188.  
  189.     while ( B.i < 64 )            /* If new cycle, wait a while     */
  190.         {                         /* to ensure MCC has been updated */
  191.         _disable();               /* Turn off interrupts            */
  192.         outp(0x43, 0x00);         /* Latch PIT counter 0            */
  193.         Ticker = *BiosTicker;     /* Get BIOS's master clock count  */
  194.         B.c.l = inp(0x40);        /* Read low byte of counter 0     */
  195.         B.c.h = inp(0x40);        /* Read high byte of counter 0    */
  196.         _enable();                /* Turn interrupts back on        */
  197.         B.i = 65535 - (--B.i);    /* Normalize counter value        */
  198.         }
  199.  
  200.     HR.Interval = 0;              /* Preset return value to zero    */
  201.     /*----Perform START processing. Use last counter 0 value taken  */
  202.     if ( Flag == START )          /* START TIME INTERVAL PROCESSING */
  203.         {
  204.         HR.StartTicker = Ticker;  /* Save starting ticker value     */
  205.         HR.StartCounter = B.i;    /* Save starting counter 0 value  */
  206.         HR.StartTime = B.i;       /* Save relative starting time    */
  207.         }
  208.     /*----Perform STOP processing. Use first counter 0 value taken  */
  209.     else if ( Flag == STOP )
  210.         {
  211.         /*----Calculate the number of elapsed ticks during interval-*/
  212.         HR.NumTicks = HR.StopTicker - HR.StartTicker;
  213.  
  214.         HR.StopTicker = Ticker;   /* Save ending ticker value       */
  215.         HR.StopCounter = A.i;     /* Save ending counter 0 value    */
  216.  
  217.         /*----Build stop time from ticker and counter 0 value-------*/        
  218.         HR.StopTime = ((HR.StopTicker - HR.StartTicker) << 16) | A.i;
  219.  
  220.         /*----Calculate total timer and ticker overhead incurred----*/
  221.         Overhead = HR.TimerOverhead + HR.NumTicks * HR.TickerOverhead;
  222.  
  223.         /*----Calculate elapsed time or zero, whichever's greater---*/
  224.         if ( HR.StopTime - HR.StartTime >= Overhead )
  225.             HR.Interval = HR.StopTime - HR.StartTime - Overhead;
  226.         }
  227.     else
  228.         printf( "\nStopWatch: bad flag argument=%u\n", Flag );
  229.  
  230.     return( HR.Interval );
  231.     }
  232.