home *** CD-ROM | disk | FTP | other *** search
/ Stars of Shareware: Raytrace & Morphing / SOS-RAYTRACE.ISO / programm / source / crend5 / timer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-08  |  6.7 KB  |  253 lines

  1. /* Timer routines for REND386; written by Dave Stampe, July 1992 */
  2.  
  3. /* Copyright 1992 by Dave Stampe and Bernie Roehl.
  4.    May be freely used to write software for release into the public domain;
  5.    all commercial endeavours MUST contact Bernie Roehl and Dave Stampe
  6.    for permission to incorporate any part of this software into their
  7.    products!
  8.  
  9.      ATTRIBUTION:  If you use any part of this source code or the libraries
  10.      in your projects, you must give attribution to REND386, Dave Stampe,
  11.      and Bernie Roehl in your documentation, source code, and at startup
  12.      of your program.  Let's keep the freeware ball rolling!
  13.  */
  14.  
  15. #include <dos.h>
  16. #include <bios.h>
  17. #include <stdio.h>
  18. #include <conio.h>
  19. #include <stdlib.h>
  20. #include <signal.h>
  21.  
  22. extern void vsync(void);
  23.  
  24. /******************* TIMER INTERRUPT STUFF ****************/
  25.  
  26. #define TIMER_VECT 8        /* timer chip int. vector */
  27. #define UNUSED_VECT 128         /* user vector: used to link to std ISR */
  28.  
  29. #define PIC_CMD 0x20            /* constants for PIC EOI command */
  30. #define NONSPEC_EOI 0x20
  31. #define TIMER_MODE 0x34         /* timer setup command */
  32. #define TIMER_CONTROL 0x43    /* timer control register port */
  33. #define TIMER_0 0x40        /* timer 0 port */
  34.  
  35. #define LATCH_COUNT 0x00    /* command to latch count */
  36.  
  37. #define SYNC_INTERVAL 5          /* how many frames between resynchronization */
  38.  
  39. static void init_SG_timer(int time);
  40. static void reset_SG_timer(void);
  41.  
  42. static void interrupt fast_SG_timer(void);
  43. static void interrupt (*oldint)(void) = NULL; /* old timer ISR vector */
  44.  
  45. unsigned int clock_rate = 0; /* calibrated timer rate for vertical */
  46. static unsigned int clock_rate_hi = 0;
  47. static unsigned int clock_rate_lo = 0;
  48.  
  49. static unsigned int divisor = 0; /* counter to emulate 18.2 Hz tick */
  50.  
  51. static int syncount = SYNC_INTERVAL; /* resync counter */
  52.  
  53. static long int_timer = 0; /* incremented each frame (use for timing) */
  54.  
  55. static void (*frame_interrupt_routine)(int) = NULL;
  56. static void (*glove_interrupt_routine)(void) = NULL;
  57.  
  58. static int glovecount = 0;
  59. static int glove_rate = 2; /* count of how many glove calls per frame */
  60.  
  61. /******************* FIND VERTICAL FRAME RATE *************/
  62.  
  63. #define ADVANCE 100             /* time (microseconds) of advance   */
  64.                                 /* in vert. interrupt.  Will act as */
  65.  
  66. static int find_sega_speed(void)  /* "vertical hold" adjustment       */
  67. {
  68.     unsigned int old, new; /* Routine to compute vertical frame    */
  69.  
  70.     vsync();
  71.     outportb(TIMER_CONTROL, TIMER_MODE);
  72.     outportb(TIMER_0, 0);
  73.     outportb(TIMER_0, 0); /* timer must count modulo 65536 */
  74.  
  75.     disable(); /* time of vert. retrace */
  76.     vsync();
  77.     outportb(TIMER_CONTROL,LATCH_COUNT);
  78.     enable();
  79.     old = inportb(TIMER_0) & 0xFF;
  80.     old |= (inportb(TIMER_0) << 8);
  81.  
  82.     vsync(); /* time 2 vert. retraces later */
  83.     disable();
  84.     vsync();
  85.     outportb(TIMER_CONTROL,LATCH_COUNT);
  86.     enable();
  87.     new = inportb(TIMER_0) & 0xFF;
  88.     new |= (inportb(TIMER_0) << 8);
  89.  
  90.     return ((old-new)>>1) - ADVANCE; /* compute interrupt rate */
  91. }
  92.  
  93.  
  94. long current_time(void)
  95. {
  96.     long i;
  97.  
  98.     disable();
  99.     i = int_timer;
  100.     enable();
  101.     return i;
  102. }
  103.  
  104. void set_current_time(long i)
  105. {
  106.     disable();
  107.     int_timer = i;
  108.     enable();
  109. }
  110.  
  111.  
  112. volatile int interrupts_occurred = 0;
  113.  
  114. static void interrupt fast_SG_timer(void) /* NEW TIMER ISR */
  115. {
  116.     unsigned int olddiv = divisor;
  117.  
  118.     disable();
  119.  
  120.     int_timer++;
  121.     interrupts_occurred++;
  122.  
  123.     if (frame_interrupt_routine == NULL) goto glove;
  124.     else frame_interrupt_routine(glovecount-1);
  125.     if (--glovecount <= 0) glovecount = glove_rate;
  126.     else goto glove;
  127.  
  128.  
  129.     syncount--;
  130.     if (syncount < 0)
  131.     {
  132.         syncount = SYNC_INTERVAL;
  133.         outportb(TIMER_CONTROL, TIMER_MODE); /* stop timer */
  134.         outportb(TIMER_0, 255);
  135.         outportb(TIMER_0, 255);
  136.         enable();
  137.         disable();
  138.         vsync();
  139.         outportb(TIMER_CONTROL, TIMER_MODE); /* restart timer */
  140.         outportb(TIMER_0, clock_rate_lo);
  141.         outportb(TIMER_0, clock_rate_hi);
  142.     }
  143.  
  144.  
  145. glove:
  146.  
  147.     if (glove_interrupt_routine) glove_interrupt_routine();
  148.     divisor += clock_rate; /* dec divide count */
  149.     if (divisor < olddiv) /* simulate 18.2 Hz ISR if time */
  150.         geninterrupt(UNUSED_VECT);
  151.  
  152.     outportb(PIC_CMD, NONSPEC_EOI);
  153.     enable();
  154. }
  155.  
  156.  
  157. static int ticks_per_second = 0;
  158.  
  159. int get_ticks_per_second(void)
  160. {
  161.     return ticks_per_second;
  162. }
  163.  
  164. void tdelay(int d)
  165. {
  166.  long dl = current_time() + (((long)d*ticks_per_second)/1000L);
  167.  while(current_time()<=dl);
  168. }
  169.  
  170.  
  171. static void reset_SG_timer();
  172.  
  173. static void init_SG_timer(int speed) /* SET UP FAST TIMER */
  174. {
  175.     atexit(reset_SG_timer); /* set traps for error, ctrl c, */
  176.     signal(SIGABRT, reset_SG_timer);
  177.     signal(SIGFPE, reset_SG_timer);
  178.     signal(SIGINT, reset_SG_timer);
  179.  
  180.     clock_rate = speed; /* save speed for future work */
  181.     ticks_per_second = 1190000L/speed;
  182.     clock_rate_hi = clock_rate >> 8;
  183.     clock_rate_lo = clock_rate & 255;
  184.  
  185.     divisor = 0; /* set up timers */
  186.     syncount = SYNC_INTERVAL;
  187.     int_timer = 0;
  188.  
  189.     if (getvect(UNUSED_VECT) == NULL)
  190.     { /* setup int's if required(first run) */
  191.         disable();
  192.         oldint = getvect(TIMER_VECT); /* setup ISR vectors */
  193.         setvect(UNUSED_VECT,oldint);
  194.         setvect(TIMER_VECT, fast_SG_timer);
  195.         outportb(TIMER_CONTROL, TIMER_MODE); /* load timer */
  196.         outportb(TIMER_0, clock_rate_lo);
  197.         outportb(TIMER_0, clock_rate_hi);
  198.         enable();
  199.     }
  200. }
  201.  
  202.  
  203. static void reset_SG_timer()   /* RESET PC TO NORMAL */
  204. {
  205.     disable();
  206.     setvect(TIMER_VECT, oldint); /* reset vector */
  207.     outportb(TIMER_CONTROL, TIMER_MODE); /* reset timer */
  208.     outportb(TIMER_0, 0);
  209.     outportb(TIMER_0, 0);
  210.     setvect(UNUSED_VECT,NULL); /* disconnect flag */
  211.     enable();
  212.  
  213.     signal(SIGINT, SIG_DFL);
  214.     signal(SIGABRT, SIG_DFL);
  215.     signal(SIGFPE, SIG_DFL);
  216. }
  217.  
  218. /* SET EVERYTHING UP         */
  219. /* (init. glove, Sega first) */
  220.  
  221. void init_SG_interrupt( void (*sega_switcher)(), /* NULL if no sega/video   */
  222.     void (*glove_handler)(),                     /* NULL if no glove driver */
  223.     int glove_tc)                                /* 1.19*uS (test interval) */
  224. {                                                /* 6500 sugg. ALWAYS (fast timer)  */
  225.     int i_rate;
  226.  
  227.     glove_interrupt_routine = glove_handler;
  228.     frame_interrupt_routine = sega_switcher;
  229.  
  230.     if (sega_switcher == NULL)
  231.         i_rate = glove_tc; /* glove only: use suggested speed */
  232.     else
  233.         {
  234.         i_rate = find_sega_speed(); /* use a multiple of video rate   */
  235.         if (glove_tc != 0)
  236.         {
  237.             glove_rate = i_rate/glove_tc; /* about 2x for 72 fps, 3x for 60 */
  238.  
  239.             if (glove_rate < 1) glove_rate = 1; /* handle no glove driver   */
  240.             if (glove_rate > 20) glove_rate = 20; /* come on now...           */
  241.             i_rate /= glove_rate;
  242.         }
  243.         else i_rate /=3;
  244.     }
  245.     init_SG_timer(i_rate); /* start 'er up! */
  246. }
  247.  
  248. void init_timer()
  249. {
  250.     init_SG_interrupt(NULL,NULL,6500);
  251. }
  252.  
  253.