home *** CD-ROM | disk | FTP | other *** search
/ Frostbyte's 1980s DOS Shareware Collection / floppyshareware.zip / floppyshareware / BOUT / SNIP9-91.ZIP / UCLOCK.C < prev    next >
C/C++ Source or Header  |  1991-09-13  |  4KB  |  107 lines

  1. /*
  2. **  UCLOCK.C
  3. **
  4. **  Contains routines to perform microsecond accuracy timing
  5. **  operations.
  6. **
  7. **  Adapted from public domain source originally by David L. Fox
  8. **  Modified by Bob Stout
  9. */
  10.  
  11. #include "uclock.h"
  12.  
  13. /* Constants */
  14.  
  15. #define CONTVAL   0x34    /* == 00110100 Control byte for 8253 timer.   */
  16.                           /* Sets timer 0 to 2-byte read/write,         */
  17.                           /* mode 2, binary.                            */
  18. #define T0DATA    0x40    /* Timer 0 data port address.                 */
  19. #define TMODE     0x43    /* Timer mode port address.                   */
  20. #define BIOS_DS   0x40    /* BIOS data segment.                         */
  21. #define B_TIKP    0x6c    /* Address of BIOS (18.2/s) tick count.       */
  22. #define SCALE    10000    /* Scale factor for timer ticks.              */
  23.  
  24. /* The following values assume 18.2 BIOS ticks per second resulting from
  25.    the 8253 being clocked at 1.19 MHz. */
  26.  
  27. #define us_BTIK  54925    /* Micro sec per BIOS clock tick.             */
  28. #define f_BTIK    4595    /* Fractional part of usec per BIOS tick.     */
  29. #define us_TTIK   8381    /* Usec per timer tick * SCALE. (4/4.77 MHz)  */
  30.  
  31. static int init = 0;
  32.  
  33. /*
  34. **  usec_clock()
  35. **
  36. **  An analog of the clock() function, usec_clock() returns a number of
  37. **  type uclock_t (defined in RBS.H) which represents the number of
  38. **  microseconds past midnight. Analogous to CLK_TCK is UCLK_TCK, the
  39. **  number which a usec_clock() reading must be divided by to yield
  40. **  a number of seconds.
  41. */
  42.  
  43. uclock_t usec_clock(void)
  44. {
  45.       unsigned char msb, lsb;
  46.       unsigned int tim_ticks;
  47.       static uclock_t last, init_count;
  48.       static uclock_t far *c_ptr;
  49.       uclock_t count, us_tmp;
  50.  
  51.       if (!init)
  52.       {
  53.             c_ptr = (uclock_t far *)MK_FP(BIOS_DS, B_TIKP);
  54.             init  = 1;        /* First call, we have to set up timer.   */
  55.             int_off();
  56.             outp(TMODE, CONTVAL);   /* Write new control byte.          */
  57.             outp(T0DATA, 0);        /* Initial count = 65636.           */
  58.             outp(T0DATA, 0);
  59.             init_count = *c_ptr;
  60.             int_on();
  61.             return 0;               /* First call returns zero.         */
  62.       }
  63.  
  64.       /* Read PIT channel 0 count - see text                            */
  65.  
  66.       int_off();        /* Don't want an interrupt while getting time.  */
  67.       outp(TMODE, 0);                           /* Latch count.         */
  68.       lsb = (unsigned char)inp(T0DATA);         /* Read count.          */
  69.       msb = (unsigned char)inp(T0DATA);
  70.  
  71.       /* Get BIOS tick count (read BIOS ram directly for speed and
  72.          to avoid turning on interrupts).                               */
  73.  
  74.       count =  *c_ptr;
  75.       int_on();                     /* Interrupts back on.              */
  76.       if ((-1) == init)             /* Restart count                    */
  77.       {
  78.             init_count = count;
  79.             init = 1;
  80.       }
  81.  
  82.       /* Merge PIT channel 0 count with BIOS tick count                 */
  83.  
  84.       if (count < init_count)
  85.             count += last;
  86.       else  last = count;
  87.       count -= init_count;
  88.       tim_ticks = (unsigned)(-1) - ((msb << 8) | lsb);
  89.       us_tmp    = count * us_BTIK;
  90.       return (us_tmp + ((long)tim_ticks * us_TTIK + us_tmp % SCALE) / SCALE);
  91. }
  92.  
  93. /*
  94. **  restart_uclock()
  95. **
  96. **  Since usec_clock() bases its return value on a differential value,
  97. **  a potential exists for problems in programs which run continuously
  98. **  for more than 24 hours. In such an application, it's necessary, at
  99. **  least once a day, to reset usec_clock's starting count.
  100. */
  101.  
  102. void restart_uclock(void)
  103. {
  104.       if (init)
  105.             init = -1;
  106. }
  107.