/* VTIMER.C - May 6 1995 - J.P.M. Mikkers This module implements a timer multiplexer, allowing multiple timers to be installed using only one hardware timer. Special features: - ability to call the system timer interrupt at the correct rate. - ability to install and use screen synchronized handlers. */ #include #include #include #include #include "mtypes.h" #include "vtimer.h" #define MAXTIMERS 4 #define RESERVEDLINES 5 typedef struct VTIMER{ BOOL active; LONG speed; LONG counter; void (*handler)(void); }VTIMER; static LONG lspeed; // Vertical blank interrupt variables: static LONG vt_vcounter,vt_vspeed; static void (*vt_v0handler)(void); static void (*vt_v1handler)(void); // Old system timer interrupt variables: static LONG vt_ocounter,vt_ospeed; static void (interrupt far *vt_oldhandler)(void); // User timers: static UBYTE vt_flags; static VTIMER vt_timer[MAXTIMERS]; static BOOL vt_initialized=0; static void starttimer1(UWORD speed) { outportb(0x43,0x30); outportb(0x40,speed&0xff); outportb(0x40,speed>>8); } static void starttimer2(void) { outportb(0x61,inportb(0x61) | 0x01); outportb(0x43,0xb4); outportb(0x42,0x00); outportb(0x42,0x00); } static UWORD readtimer1(void) { UWORD n; outportb(0x43,0); n = inportb(0x40); n += inportb(0x40) << 8; return 0x10000L - n; } static UWORD readtimer2(void) { int n; outportb(0x43,0xb0); n = inportb(0x42); n += inportb(0x42) << 8; return 0x10000L - n; } static void WaitVR(void) { while (inp(0x3da) & 8) ; while (!(inp(0x3da) & 8)) ; } static UWORD countlines(void) { UWORD lines=0; UBYTE state; while(!(inportb(0x3da)&8)){ state=inportb(0x3da)&9; while((inportb(0x3da)&9)==state); lines++; } return lines; } static void dummyhandler(void) { } static void interrupt timerint(void) { int t; UWORD adjust; long sspeed=0x10000; UBYTE flags[MAXTIMERS]; BOOL oflag=0; #ifdef __BORLANDC__ pushad(); // borland interrupt fix #endif // Process old system timer? if(vt_flags&VT_CALLOLD){ // Yes, check if it has to be called: vt_ocounter-=lspeed; if(vt_ocounter<=0){ // counter underflow, so set flag to call system timer later: vt_ocounter+=vt_ospeed; oflag=1; } sspeed=vt_ocounter; } // Process vertical retrace interrupt? if(vt_flags&VT_VRSYNC){ // yes, check if vertical retrace is coming soon: vt_vcounter-=lspeed; if(vt_vcounter<=0){ /* counter underflow, so start waiting for the vertical retrace, but first reset the timer so we can check how long the wait and vhandlers take */ starttimer1(0); vt_vcounter+=vt_vspeed; vt_v0handler(); adjust=countlines(); vt_v1handler(); if(adjust>RESERVEDLINES) vt_vspeed+=10; if(adjust reset counter and set flag to call the handler if(vt_timer[t].counter<=0){ vt_timer[t].counter+=vt_timer[t].speed; flags[t]=1; } sspeed=min(vt_timer[t].counter,sspeed); } } lspeed=sspeed; starttimer1(lspeed); enable(); if(oflag){ oflag=0; vt_oldhandler(); } else outportb(0x20,0x20); for(t=0;t