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