?? timer.c
字號:
/***************************************************************************\
** TIMING CODE MODULE (80x86 specific code!) **
**=========================================================================**
** Written by Ethan Rohrer, (c) Nuthing Software, December 4, 1994 **
** **
** Revision History **
** ---------------- **
** Date Description **
** --------- --------------------------------------------------------- **
** 13 May 94 Initial Release **
** 04 Dec 94 Updated code to conform to current coding standards/style **
** Allowed appl. to specify # of timers as param. to TM_Init **
** Standardized error handling with function _TM_Error **
**=========================================================================**
** This file contains code which makes use of system timer 0. This timer **
** normally operates at a frequency of 1.1932MHz, regardless of the speed **
** of the CPU. Normally, this timer is operating in mode 3 (square wave **
** mode), and it completes a "cycle" in 0.054926 seconds (~1/18.207 **
** seconds). The reason I say "normally" is because it is possible to **
** change the length of the cycle, which changes the timer's frequency. **
** This is NOT what the following code does. **
** **
** System timer 0 has its own 16 bit counter. Here is some simplified **
** pseudo-code of what system timer 0 does with its counter when it is **
** operating in mode 3, and its frequency has not been tampered with: **
** **
** counter = 65536 **
** while (counter != 0) **
** counter -= 2; **
** counter = 65536 **
** while (counter != 0) **
** counter -= 2; **
** **
** You read that right. The counter is decremented from 65536 to 0 **
** TWICE. This is somewhat unfortunate, because we want to read that **
** counter to use for our timing operations because it is very accurate. **
** The counter is decremented 65536 times in one timer cycle (32768 **
** times in each while loop above). So, the time between decrements is: **
** **
** (0.054926 seconds/cycle) / (65536 decrements/cycle) = **
** 0.000000838 seconds/decrement = 838ns/decrement **
** **
** Since the counter is decremented to 0 twice in each timer cycle, we **
** would only be able to time events that take no longer than 0.027463 **
** seconds (one half of the timer cycle, the duration of one of the **
** while loops above). **
** **
** The solution used by the code in this file is to change the timer's **
** operation mode to mode 2. Here is some simplified pseudo-code of what **
** system timer 0 does with its counter when it is operating in mode 2, **
** and its frequency has not been tampered with: **
** **
** counter = 65536 **
** while (counter != 0) **
** counter -= 1; **
** **
** This solves any problems concerning the ambiguity of determining **
** which while loop is executing when we read the counter from the timer. **
** But now, we have a 16 bit value which can only be used to time events **
** which take no longer than 0.054926 seconds (duration of one cycle). **
** **
** The solution used by this code is to make use of another timer: **
** the "large timer", which is a 32-bit value at memory location **
** 0x40:0x6C. Conveniently, this "large timer" is incremented each time **
** system timer 0 completes a cycle (once each 0.054926 seconds). **
** The code in this file generates 32-bit values to represent the **
** time. Obviously, we can't pack in the 16 bit counter and the 32 bit **
** large timer into the 32 bit time type, so we cut off the high order **
** 16 bits of the large timer. The following picture describes how the **
** time value is generated using the timers: **
** **
** 31 0 15 0 **
** ------------------------------------------- ---------------------- **
** | L a r g e T i m e r | | 65535 - Counter | **
** ------------------------------------------- ---------------------- **
** | | | **
** \|/ \|/ \|/ **
** V V V **
** 31 16 15 0 **
** ---------------------- ---------------------- **
** | t T I M E | **
** ---------------------- ---------------------- **
** **
** (Note that we have to use (65535-Counter) because Counter is being **
** decremented by the timer, but time is increasing) **
** **
**=========================================================================**
** USING THIS MODULE **
** Before calling any other timing routine, you must call TM_Init(n), **
** where n specifies the number of timers your application needs. **
** It may be a good idea to call TM_Init() in the initialization **
** portion of your application. **
** **
** To begin timing an event, make a call to TM_StartTimer(tid), **
** where tid is an integer in the range [0..(n-1)] which specifies **
** which of the n timers you are starting. **
** **
** To compute the duration of the event, just call **
** TM_ElapsedTime(tid), where tid is the same integer used in the **
** call to TM_StartTimer(). **
** **
** When you are finished with the timing routines, call TM_Close(). **
** This should fit in nicely with the cleanup section of your **
** application. **
** **
** If your application NEEDS to handle the time computations itself, **
** the function TM_ReadTimer(tid) is also available. This function **
** will return the current time (MOD 1 hour, approximately). I **
** discourage use of this function, but discovered that I need it **
** for another module/library... **
** **
** EXAMPLES **
** A simple delaying routine: **
** void delay( tTIME duration ) **
** { **
** TM_StartTimer(0); **
** while (TM_ElapsedTime(0) < duration) **
** ; **
** } **
** **
** A fixed frame-rate game: **
** TM_Init(1); **
** while (player_not_dead) **
** { **
** TM_StartTimer(0); **
** MoveMonsters(); **
** MovePlayers(); **
** UpdateDisplay(); **
** while (TM_ElapsedTime(0) < frame_duration) **
** ; **
** } **
** TM_Close(); **
\***************************************************************************/
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include "timer.h"
/*-------------------------------- MACROS ---------------------------------*/
/* macro to return the current value of the large timer */
#define TM_LARGE_TIMER (*((unsigned long far *)MK_FP(0x40, 0x6C)))
/*--------------------------- GLOBAL VARIABLES ----------------------------*/
/* starting times for all of the timers this code will support */
tTIME *gpTM_start_time = NULL;
unsigned int gTM_max_timers = 0;
/* flag to let us know if it is ok to run the timing routines */
/* (1 = NOT safe, 0 = safe) */
unsigned char gTM_module_not_initialized = 1;
/*------------------------- Error Message Strings -------------------------*/
#define TM_ERR_STR_GENERAL \
"General (unspecified) error."
#define TM_ERR_STR_UNINITIALIZED \
"Timing routines not yet initialized.\n" \
"(TM_Init() has not been called)"
#define TM_ERR_STR_BAD_TIMER_ID \
"Application specified an invalid timer ID."
#define TM_ERR_STR_ALLOC \
"Unable to allocate dynamic memory."
#define TM_ERR_STR_ZERO_TIMERS \
"Application requested 0 timers.\n" \
"(must request 1 or more timers to use this module)"
/*------------------------- Error Message Indices -------------------------*/
/* (Make sure these indices are accurate according to gpTM_error_text[] */
/* declared below !!) */
#define TM_ERR_GENERAL 0
#define TM_ERR_UNINITIALIZED 1
#define TM_ERR_BAD_TIMER_ID 2
#define TM_ERR_ALLOC 3
#define TM_ERR_ZERO_TIMERS 4
/*------------------------- Error Message Strings -------------------------*/
/* (Make sure the positions of the error messages in this array are */
/* accurately represented by the error messages indices listed above !!) */
char *gpTM_error_text[] =
{
TM_ERR_STR_GENERAL,
TM_ERR_STR_UNINITIALIZED,
TM_ERR_STR_BAD_TIMER_ID,
TM_ERR_STR_ALLOC,
TM_ERR_STR_ZERO_TIMERS
};
/***************************************************************************\
** void _TM_Error( ) **
*****************************************************************************
** ARGUMENTS **
** const char *pCalling_function_name **
** (I) name of the calling function **
** int error_number **
** (I) integer identifier of the error that occurred **
** const char *pCustom_message **
** (I) additional message text to be displayed **
**-------------------------------------------------------------------------**
** RETURNS **
** void **
**-------------------------------------------------------------------------**
** EXAMPLE USAGE (NOT INTENDED FOR EXTERNAL USE) **
** if ( gTM_module_not_initialized ) **
** { **
** _TM_Error ( pFunction_name, TM_ERR_UNINITIALIZED, NULL ); <-<< **
** return; **
** } **
**-------------------------------------------------------------------------**
** DETECTABLE ERROR CONDITIONS **
** None **
**-------------------------------------------------------------------------**
** DESCRIPTION **
** This function will generate a message which will be sent to stderr **
** to inform the user of an error. This message will include the **
** name of the function the error occurred in (if supplied), a canned **
** error string for the error indicated, and a custom string (if **
** supplied) which may provide more details about th error. **
**-------------------------------------------------------------------------**
** LIMITATIONS **
** The message text must not exceed 1024 bytes in size, which can **
** store over 12 80-character lines of text. **
\***************************************************************************/
void _TM_Error ( pCalling_function_name, error_number, pCustom_message )
const char *pCalling_function_name;
int error_number;
const char *pCustom_message;
{
char error_message[1024]; /* buffer for message text */
/*---------------------------------------------------------------------*\
** Insert the "ERROR IN MODULE "TIMER"" header string into our **
** message. **
\*---------------------------------------------------------------------*/
sprintf ( error_message,
"\n******** ERROR IN MODULE \"TIMER\" *********\n" );
/*---------------------------------------------------------------------*\
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -