158 lines
5.0 KiB
Plaintext
158 lines
5.0 KiB
Plaintext
PCTIMER: Millisecond Resolution Timing Library for DJGPP V2
|
|
Version 1.4 Release Notes
|
|
March 15, 1998
|
|
Status: Freeware.
|
|
Distribution status: Has to be distributed as this archive.
|
|
Send comments to: Chih-Hao Tsai (hao520@yahoo.com).
|
|
|
|
|
|
==== A FEW WORDS ON WIN95
|
|
|
|
Although I have only tested PCTIMER with Win95 and CWSDPMI,
|
|
PCTIMER should run on most DPMI servers.
|
|
|
|
However, theoretically, applications running under Win95
|
|
should not touch hardware interrupts. The "correct" method
|
|
of doing millisecond resolution timing under Win95 is to call
|
|
Windows API. The standard Multimedia Timer API can do
|
|
millisecond resolution timing. (You'll need to include
|
|
<mmsystem.h> and link with winmm.lib. But, as far as I know,
|
|
RSXNT does not provide Multimedia API access.)
|
|
|
|
If you need an example on using Windows API to do millisecond
|
|
resolution timing, check this out (I used Visual C++ 4.0):
|
|
|
|
Test Report: Millisecond Resolution Timing with Win95/VC4
|
|
http://www.geocities.com/hao510/w98timer/
|
|
|
|
|
|
==== BASIC LOGIC
|
|
|
|
PCTIMER reprograms the 8454 IC (Programmable Interrupt Timer)
|
|
to get high frequency of System Timer Interrupt (IRQ0) whose
|
|
default frequency is 18.2 Hz. Since the operating systems
|
|
rely heavily on the System Timer Interrupt, increasing its
|
|
frequency could cause instability. PCTIMER hooks both
|
|
protected and real mode int 8h handlers (default handler for
|
|
System Timer Interrupt) reprograms 8254 to get higher
|
|
frequency of interrupts, but calls the original handlers at
|
|
a fixed frequency of 18.2 Hz.
|
|
|
|
|
|
==== RELATIONSHIP BETWEEN PROTECTED & REAL MODE INT 8H
|
|
|
|
According to DJGPP V2 FAQ, hardware interrupts are always
|
|
passed to protected mode first, and only if unhandled are
|
|
they reflected to real mode. In other words, we must at least
|
|
hook protected mode int 8h. To avoid potential loss of ticks
|
|
when the protected mode fails to handle the hardware
|
|
interrupt, we should also hook real mode int 8h.
|
|
|
|
In actual implementation of the two handlers, things become
|
|
much more complex than that.
|
|
|
|
|
|
==== PCTIMER PROTECTED MODE INT8H HANDLER
|
|
|
|
Here is PCTIMER's protected mode int 8h in pseudo code. The
|
|
meanings of pm_termination_flag's values are:
|
|
|
|
TRUE_FAILURE: The handler failed to handle the hardware
|
|
interrupt.
|
|
|
|
CHAIN_TERMINATION: The handler terminated with chaining to
|
|
the old handler. Note that after chaining the old protected
|
|
mode int 8h handler, the *real* mode int 8h *will* get called.
|
|
We need to take care of this.
|
|
|
|
OUTPORTB_TERMINATION: The handler terminated with an
|
|
outportb (0x20, 0x20) instruction. This instruction sends
|
|
a hardware request to the Interrupt Controller to terminate
|
|
the interrupt. This works (although intrusive), but will
|
|
cause the DPMI server to believe that the protected mode
|
|
handler failed to do its job. Therefore, the real mode
|
|
handler *will* get called. We need to take care of this,
|
|
too.
|
|
|
|
(Read the real code for details.)
|
|
|
|
PCTIMER Protected Mode Int 8h Handler (Pseudo-code)
|
|
* pm_termination_flag = TRUE_FAILURE
|
|
* counter++
|
|
* if it is time to chain old handler
|
|
- pm_termination_flag = CHAIN_TERMINATION
|
|
- let the wrapper chains the old handler
|
|
* else
|
|
- pm_termination_flag = OUTPORTB_TERMINATION
|
|
- outportb (0x20, 0x20)
|
|
|
|
|
|
==== PCTIMER REAL MODE INT8H HANDLER
|
|
|
|
The real mode handler is considerably more complex than the
|
|
protected mode one. It depends on pm_termination_flag to
|
|
determine how it should behave. Always set
|
|
pm_termination_flag to TRUE_FAILURE before we leave, so in
|
|
case the protected mode handler should fail, the real mode
|
|
handler can detect it next time.
|
|
|
|
(Read the real code for details.)
|
|
|
|
PCTIMER Real Mode Int 8h Handler (Pseudo-code)
|
|
* if pm_termination_flag = TRUE_FAILURE
|
|
- counter++
|
|
* if it is time to chain the old handler, or if the protected
|
|
mode handler decided to do that (i.e.,
|
|
pm_termination_flag = CHAIN_TERMINATION)
|
|
- call old real mode handler
|
|
- pm_termination_flag = TRUE_FAILURE
|
|
* else
|
|
- outportb (0x20, 0x20)
|
|
- pm_termination_flag = TRUE_FAILURE
|
|
|
|
|
|
==== Example of Usage
|
|
|
|
#include <gccint8.h>
|
|
|
|
void main (void)
|
|
{
|
|
unsigned long int start, finish, elapsed_time;
|
|
|
|
/* initiate the timer with 1/1000 s resolution */
|
|
/* you can use different resolution, but resolution */
|
|
/* higher than 1000 is not recommended. */
|
|
|
|
pctimer_init (1000);
|
|
|
|
start = pctimer_get_ticks ();
|
|
/* do some stuff here */
|
|
finish = pctimer_get_ticks ();
|
|
elapsed_time = pctimer_time (start, finish);
|
|
/* always returns elapsed time in the unit of ms. */
|
|
|
|
pctimer_sleep (200); /* sleep 200 ms */
|
|
pctimer_sound (800, 200); /* 800 Hz sound for 200 ms */
|
|
|
|
/* never forget to exit the timer!!! */
|
|
/* otherwise, the system WILL crash!!! */
|
|
|
|
pctimer_exit ();
|
|
}
|
|
|
|
|
|
==== HISTORY
|
|
3/15/98 Version 1.4
|
|
11/26/95 Version 1.3
|
|
1/29/95 Version 1.2
|
|
1/16/95 Version 1.1
|
|
11/5/94 Version 1.0
|
|
|
|
|
|
==== DISCLAIMER
|
|
|
|
I am not at all responsible for any damages, consequential
|
|
or incidental, and by using PCTIMER, you are agreeing not
|
|
to hold either of the above responsible for any problems
|
|
whatsoever.
|