Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

258 lines
8.4 KiB

  1. //**************************************************************************
  2. //
  3. // TIMER.C -- Xena Gaming Project
  4. //
  5. // Version 3.XX
  6. //
  7. // Copyright (c) 1997 Microsoft Corporation. All rights reserved.
  8. //
  9. // @doc
  10. // @module TIMER.C | Timing routines to support device input/output
  11. //**************************************************************************
  12. #include "msgame.h"
  13. //---------------------------------------------------------------------------
  14. // Definitions
  15. //---------------------------------------------------------------------------
  16. #define MILLI_SECONDS 1000L
  17. #define MICRO_SECONDS 1000000L
  18. #define TIMER_RESOLUTION 25L
  19. #define TIMER_CALIBRATE_TRIES 4L
  20. #define TIMER_CALIBRATE_TIMER 25000L
  21. #define TIMER_CALIBRATE_PORT 2500L
  22. //---------------------------------------------------------------------------
  23. // Private Data
  24. //---------------------------------------------------------------------------
  25. static ULONG PerformanceFrequency = 0L;
  26. static ULONG CalibratedResolution = 0L;
  27. //---------------------------------------------------------------------------
  28. // @func Converts system ticks into microseconds
  29. // @parm ULONG | Ticks | System ticks in system time
  30. // @rdesc Returns time in microseconds
  31. // @comm Private function
  32. //---------------------------------------------------------------------------
  33. static ULONG TIMER_TimeInMicroseconds (ULONG Ticks)
  34. {
  35. ULONG Remainder;
  36. LARGE_INTEGER Microseconds;
  37. Microseconds = RtlEnlargedUnsignedMultiply (Ticks, MICRO_SECONDS);
  38. Microseconds = RtlExtendedLargeIntegerDivide (Microseconds, PerformanceFrequency, &Remainder);
  39. return (Microseconds.LowPart);
  40. }
  41. //---------------------------------------------------------------------------
  42. // @func Times a fixed delay loop of instructions
  43. // @rdesc Returns delay in microseconds
  44. // @comm Private function
  45. //---------------------------------------------------------------------------
  46. static ULONG TIMER_CalibrateOnTimer (VOID)
  47. {
  48. ULONG Calibration;
  49. LARGE_INTEGER StopTicks;
  50. LARGE_INTEGER StartTicks;
  51. PORTIO_MaskInterrupts ();
  52. StartTicks = KeQueryPerformanceCounter (NULL);
  53. __asm
  54. {
  55. mov ecx, TIMER_CALIBRATE_TIMER
  56. CalibrationLoop:
  57. xchg al, ah
  58. xchg al, ah
  59. dec ecx
  60. jne CalibrationLoop
  61. }
  62. StopTicks = KeQueryPerformanceCounter (NULL);
  63. PORTIO_UnMaskInterrupts ();
  64. Calibration = TIMER_TimeInMicroseconds (StopTicks.LowPart-StartTicks.LowPart);
  65. MsGamePrint ((DBG_VERBOSE, "TIMER: TIMER_CalibrateOnTimer Returning %ld uSecs\n", Calibration));
  66. return (Calibration);
  67. }
  68. //---------------------------------------------------------------------------
  69. // @func Times a fixed delay loop of port I/O calls
  70. // @parm PGAMEPORT | PortInfo | Gameport parameters
  71. // @rdesc Returns delay in microseconds
  72. // @comm Private function
  73. //---------------------------------------------------------------------------
  74. static ULONG TIMER_CalibrateOnPort (PGAMEPORT PortInfo)
  75. {
  76. ULONG Calibration;
  77. LARGE_INTEGER StopTicks;
  78. LARGE_INTEGER StartTicks;
  79. if (!PORTIO_AcquirePort (PortInfo))
  80. {
  81. MsGamePrint ((DBG_SEVERE, "TIMER: TIMER_CalibrateOnPort Could Not Acquire Port\n"));
  82. return (0);
  83. }
  84. PORTIO_MaskInterrupts ();
  85. StartTicks = KeQueryPerformanceCounter (NULL);
  86. __asm
  87. {
  88. mov ecx, TIMER_CALIBRATE_PORT
  89. mov edx, PortInfo
  90. CalibrationLoop:
  91. push edx
  92. call PORTIO_Read
  93. test al, al
  94. dec ecx
  95. jne CalibrationLoop
  96. }
  97. StopTicks = KeQueryPerformanceCounter (NULL);
  98. PORTIO_UnMaskInterrupts ();
  99. PORTIO_ReleasePort (PortInfo);
  100. Calibration = TIMER_TimeInMicroseconds (StopTicks.LowPart-StartTicks.LowPart);
  101. MsGamePrint ((DBG_VERBOSE, "TIMER: TIMER_CalibrateOnPort Returning %ld uSecs\n", Calibration));
  102. return (Calibration);
  103. }
  104. //---------------------------------------------------------------------------
  105. // @func Retrieves current system time in milliseconds
  106. // @rdesc Returns current system time in milliseconds
  107. // @comm Public function
  108. //---------------------------------------------------------------------------
  109. ULONG TIMER_GetTickCount (VOID)
  110. {
  111. ULONG Remainder;
  112. LARGE_INTEGER TickCount;
  113. TickCount = KeQueryPerformanceCounter (NULL);
  114. TickCount = RtlExtendedIntegerMultiply (TickCount, MILLI_SECONDS);
  115. TickCount = RtlExtendedLargeIntegerDivide (TickCount, PerformanceFrequency, &Remainder);
  116. return (TickCount.LowPart);
  117. }
  118. //---------------------------------------------------------------------------
  119. // @func Calibrates the system processor speed for timing delays
  120. // @rdesc Returns NT status code (Success always)
  121. // @comm Public function
  122. //---------------------------------------------------------------------------
  123. NTSTATUS TIMER_Calibrate (VOID)
  124. {
  125. ULONG Tries;
  126. ULONG Rounding;
  127. ULONG Accumulator;
  128. LARGE_INTEGER Frequency;
  129. KeQueryPerformanceCounter (&Frequency);
  130. PerformanceFrequency = Frequency.LowPart;
  131. MsGamePrint ((DBG_VERBOSE, "TIMER: PerformanceFrequency is %ld hz\n", PerformanceFrequency));
  132. for (Accumulator = 0, Tries = 0; Tries < TIMER_CALIBRATE_TRIES; Tries++)
  133. Accumulator += TIMER_CalibrateOnTimer ();
  134. Rounding = (Accumulator % TIMER_CALIBRATE_TRIES) >= (TIMER_CALIBRATE_TRIES/2) ? 1 : 0;
  135. Accumulator = (Accumulator / TIMER_CALIBRATE_TRIES) + Rounding;
  136. MsGamePrint ((DBG_VERBOSE, "TIMER: Average Timer Calibration is %ld usecs\n", Accumulator));
  137. Rounding = ((TIMER_RESOLUTION*TIMER_CALIBRATE_TIMER)/Accumulator) >= (Accumulator/2) ? 1 : 0;
  138. CalibratedResolution = ((TIMER_RESOLUTION*TIMER_CALIBRATE_TIMER)/Accumulator) + Rounding;
  139. MsGamePrint ((DBG_VERBOSE, "TIMER: Calibrated Timer Resolution on %lu msecs is %ld loops\n", TIMER_RESOLUTION, CalibratedResolution));
  140. return (STATUS_SUCCESS);
  141. }
  142. //---------------------------------------------------------------------------
  143. // @func Calibrates delays for the system processor speed during port access
  144. // @parm PGAMEPORT | PortInfo | Gameport parameters
  145. // @parm ULONG | Microseconds | Delay in microseconds to calibrate
  146. // @rdesc Returns delay in counts for microseconds during port access
  147. // @comm Public function
  148. //---------------------------------------------------------------------------
  149. ULONG TIMER_CalibratePort (PGAMEPORT PortInfo, ULONG Microseconds)
  150. {
  151. ULONG Tries;
  152. ULONG Errors;
  153. ULONG Calibration;
  154. ULONG Rounding;
  155. ULONG Accumulator;
  156. LARGE_INTEGER Frequency;
  157. KeQueryPerformanceCounter (&Frequency);
  158. PerformanceFrequency = Frequency.LowPart;
  159. MsGamePrint ((DBG_VERBOSE, "TIMER: PerformanceFrequency is %ld hz\n", PerformanceFrequency));
  160. for (Accumulator = 0, Tries = 0, Errors = 0; Tries < TIMER_CALIBRATE_TRIES; Tries++)
  161. {
  162. Calibration = TIMER_CalibrateOnPort (PortInfo);
  163. if (!Calibration)
  164. Errors++;
  165. else Accumulator += Calibration;
  166. }
  167. Tries -= Errors;
  168. if (Tries)
  169. {
  170. Rounding = (Accumulator % Tries) >= (Tries/2) ? 1 : 0;
  171. Accumulator = (Accumulator / Tries) + Rounding;
  172. MsGamePrint ((DBG_VERBOSE, "TIMER: Average Port Calibration is %ld usecs\n", Accumulator));
  173. Rounding = ((Microseconds*TIMER_CALIBRATE_PORT)/Accumulator) >= (CalibratedResolution/2) ? 1 : 0;
  174. Accumulator = ((Microseconds*TIMER_CALIBRATE_PORT)/Accumulator) + Rounding;
  175. MsGamePrint ((DBG_VERBOSE, "TIMER: Calibrated Port Resolution on %lu msecs is %ld loops\n", Microseconds, Accumulator));
  176. }
  177. else Accumulator++;
  178. return (Accumulator);
  179. }
  180. //---------------------------------------------------------------------------
  181. // @func Convert delays in microseconds to loop counts based on the system processor speed
  182. // @parm ULONG | Microseconds | Delay in microseconds to calibrate
  183. // @rdesc Returns delay in loop counts
  184. // @comm Public function
  185. //---------------------------------------------------------------------------
  186. ULONG TIMER_GetDelay (ULONG Microseconds)
  187. {
  188. ULONG Delay;
  189. ULONG Rounding;
  190. Rounding = ((Microseconds*CalibratedResolution)%TIMER_RESOLUTION)>(TIMER_RESOLUTION/2) ? 1 : 0;
  191. Delay = ((Microseconds*CalibratedResolution)/TIMER_RESOLUTION) + Rounding;
  192. return (Delay?Delay:1);
  193. }
  194. //---------------------------------------------------------------------------
  195. // @func Delays in loop counts based on the system processor speed
  196. // @parm ULONG | Delay | Calibrated delay in loop counts
  197. // @comm Public function
  198. //---------------------------------------------------------------------------
  199. VOID TIMER_DelayMicroSecs (ULONG Delay)
  200. {
  201. __asm
  202. {
  203. mov ecx, Delay
  204. DelayLoop:
  205. xchg al, ah
  206. xchg al, ah
  207. dec ecx
  208. jne DelayLoop
  209. }
  210. }