ReactOS  0.4.13-dev-92-gf251225
clock.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: GPL - See COPYING in the top level directory
3  * PROJECT: ReactOS Virtual DOS Machine
4  * FILE: subsystems/mvdm/ntvdm/clock.c
5  * PURPOSE: Clock for VDM
6  * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7  * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8  */
9 
10 /* INCLUDES *******************************************************************/
11 
12 #include "ntvdm.h"
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 #include "emulator.h"
18 #include "clock.h"
19 
20 #include "cpu/cpu.h"
21 #include "hardware/cmos.h"
22 #include "hardware/ps2.h"
23 #include "hardware/pit.h"
24 #include "hardware/video/svga.h"
25 #include "hardware/mouse.h"
26 
27 /* DEFINES ********************************************************************/
28 
29 /*
30  * Activate IPS_DISPLAY if you want to display the
31  * number of instructions per second.
32  */
33 // #define IPS_DISPLAY
34 
35 /* Processor speed */
36 #define STEPS_PER_CYCLE 1024
37 
38 /* VARIABLES ******************************************************************/
39 
42 // static ULONG StartTickCount;
47 
49 ULONGLONG CurrentIps = 20000000ULL; // 20 MIPS is a good estimate
50 
51 /* PRIVATE FUNCTIONS **********************************************************/
52 
53 static VOID FASTCALL IpsCallback(ULONGLONG ElapsedTime)
54 {
55 #ifdef IPS_DISPLAY
56  static INT NumCalls = 0;
57 #endif
58 
59  ULONGLONG NewIps = 10ULL * (CurrentCycleCount - LastCycles) / ElapsedTime;
60  CurrentIps = (CurrentIps + NewIps) >> 1;
61 
62 #ifdef IPS_DISPLAY
63  NumCalls++;
64  if (NumCalls == 10)
65  {
66  DPRINT1("NTVDM: %I64u Instructions Per Second\n", CurrentIps);
67  NumCalls = 0;
68  }
69 #endif
70 
72 }
73 
74 /* PUBLIC FUNCTIONS ***********************************************************/
75 
77 {
78  extern BOOLEAN CpuRunning;
79  UINT i;
82 
83  while (VdmRunning && CpuRunning)
84  {
85  /* Get the current counters */
90 
91  /* Continue CPU emulation */
92  for (i = 0; VdmRunning && CpuRunning && (i < STEPS_PER_CYCLE); i++)
93  {
94  CpuStep();
96  }
97 
98  Entry = Timers.Flink;
99  while (Entry != &Timers)
100  {
101  ULONGLONG Ticks = (ULONGLONG)-1;
102 
104  Entry = Entry->Flink;
105 
106  ASSERT((Timer->EnableCount > 0) && (Timer->Flags & HARDWARE_TIMER_ENABLED));
107 
108  if (Timer->Delay)
109  {
110  if (Timer->Flags & HARDWARE_TIMER_PRECISE)
111  {
112  /* Use the performance counter for precise timers */
113  if (Counter.QuadPart <= Timer->LastTick.QuadPart) continue;
114  Ticks = (Counter.QuadPart - Timer->LastTick.QuadPart) / Timer->Delay;
115  }
116  else
117  {
118  /* Use the regular tick count for normal timers */
119  if (CurrentTickCount <= Timer->LastTick.LowPart) continue;
120  Ticks = (CurrentTickCount - Timer->LastTick.LowPart) / (ULONG)Timer->Delay;
121  }
122 
123  if (Ticks == 0) continue;
124  }
125 
126  Timer->Callback(Ticks);
127 
128  if (Timer->Flags & HARDWARE_TIMER_ONESHOT)
129  {
130  /* Disable this timer */
132  }
133 
134  /* Update the time of the last timer tick */
135  Timer->LastTick.QuadPart += Ticks * Timer->Delay;
136  }
137 
138  /* Yield execution to other threads */
139  // FIXME: Disabled because it causes timing issues (slowdowns).
140  // NtYieldExecution();
141  }
142 }
143 
145 {
147 
148  Timer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*Timer));
149  if (Timer == NULL) return NULL;
150 
151  Timer->Flags = Flags & ~HARDWARE_TIMER_ENABLED;
152  Timer->EnableCount = 0;
153  Timer->Callback = Callback;
154  Timer->LastTick.QuadPart = 0;
156 
158  return Timer;
159 }
160 
162 {
163  /* Increment the count */
164  Timer->EnableCount++;
165 
166  /* Check if the count is above 0 but the timer isn't enabled */
167  if ((Timer->EnableCount > 0) && !(Timer->Flags & HARDWARE_TIMER_ENABLED))
168  {
169  if (Timer->Flags & HARDWARE_TIMER_PRECISE)
170  {
171  NtQueryPerformanceCounter(&Timer->LastTick, NULL);
172  }
173  else
174  {
175  Timer->LastTick.LowPart = GetTickCount();
176  }
177 
178  Timer->Flags |= HARDWARE_TIMER_ENABLED;
179  InsertTailList(&Timers, &Timer->Link);
180  }
181 }
182 
184 {
185  /* Decrement the count */
186  Timer->EnableCount--;
187 
188  /* Check if the count is 0 or less but the timer is enabled */
189  if ((Timer->EnableCount <= 0) && (Timer->Flags & HARDWARE_TIMER_ENABLED))
190  {
191  /* Disable the timer */
192  Timer->Flags &= ~HARDWARE_TIMER_ENABLED;
193  RemoveEntryList(&Timer->Link);
194  }
195 }
196 
198 {
199  if (Timer->Flags & HARDWARE_TIMER_PRECISE)
200  {
201  /* Convert the delay from nanoseconds to performance counter ticks */
202  Timer->Delay = (NewDelay * Frequency.QuadPart + 500000000ULL) / 1000000000ULL;
203  }
204  else
205  {
206  Timer->Delay = NewDelay / 1000000ULL;
207  }
208 }
209 
211 {
212  if (Timer)
213  {
214  if (Timer->Flags & HARDWARE_TIMER_ENABLED) RemoveEntryList(&Timer->Link);
215  RtlFreeHeap(RtlGetProcessHeap(), 0, Timer);
216  }
217 }
218 
220 {
222 
223  /* Initialize the performance counter (needed for hardware timers) */
224  /* Find the starting performance */
226  if (Frequency.QuadPart == 0)
227  {
228  wprintf(L"FATAL: Performance counter not available\n");
229  return FALSE;
230  }
231 
232  /* Find the starting tick count */
233  // StartTickCount = GetTickCount();
234 
236  if (IpsTimer == NULL)
237  {
238  wprintf(L"FATAL: Cannot create IPS timer.\n");
239  return FALSE;
240  }
241 
242  return TRUE;
243 }
#define TRUE
Definition: types.h:120
BOOLEAN CpuRunning
Definition: cpu.c:40
struct _Entry Entry
Definition: kefuncs.h:640
static ULONGLONG LastCycles
Definition: clock.c:45
VOID(FASTCALL * PHARDWARE_TIMER_PROC)(ULONGLONG ElapsedTime)
Definition: clock.h:22
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:603
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:445
NTSTATUS NTAPI NtQueryPerformanceCounter(OUT PLARGE_INTEGER PerformanceCounter, OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL)
Definition: profile.c:278
VOID DisableHardwareTimer(PHARDWARE_TIMER Timer)
Definition: clock.c:183
#define wprintf(...)
Definition: whoami.c:18
#define InsertTailList(ListHead, Entry)
#define FASTCALL
Definition: nt_native.h:50
ULONGLONG CurrentCycleCount
Definition: clock.c:48
int32_t INT
Definition: typedefs.h:56
static int Link(const char **args)
Definition: vfdcmd.c:2414
static LIST_ENTRY Timers
Definition: clock.c:40
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
static VOID FASTCALL IpsCallback(ULONGLONG ElapsedTime)
Definition: clock.c:53
unsigned char BOOLEAN
PHARDWARE_TIMER CreateHardwareTimer(ULONG Flags, ULONGLONG Delay, PHARDWARE_TIMER_PROC Callback)
Definition: clock.c:144
smooth NULL
Definition: ftsmooth.c:416
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
#define ULL(a, b)
Definition: format_msg.c:27
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:585
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
uint64_t ULONGLONG
Definition: typedefs.h:65
#define HARDWARE_TIMER_PRECISE
Definition: clock.h:17
#define HARDWARE_TIMER_ENABLED
Definition: clock.h:15
#define STEPS_PER_CYCLE
Definition: clock.c:36
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define HARDWARE_TIMER_ONESHOT
Definition: clock.h:16
static const WCHAR L[]
Definition: oid.c:1250
BOOLEAN ClockInitialize(VOID)
Definition: clock.c:219
static LARGE_INTEGER StartPerfCount
Definition: clock.c:41
VOID SetHardwareTimerDelay(PHARDWARE_TIMER Timer, ULONGLONG NewDelay)
Definition: clock.c:197
static ULONG CurrentTickCount
Definition: clock.c:44
ULONGLONG CurrentIps
Definition: clock.c:49
Definition: typedefs.h:117
UINT Timer
Definition: capclock.c:11
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
unsigned int UINT
Definition: ndis.h:50
#define HEAP_ZERO_MEMORY
Definition: compat.h:123
static LARGE_INTEGER Frequency
Definition: clock.c:41
#define DPRINT1
Definition: precomp.h:8
VOID ClockUpdate(VOID)
Definition: clock.c:76
static LARGE_INTEGER Counter
Definition: clock.c:43
#define HZ_TO_NS(Freq)
Definition: clock.h:20
unsigned int ULONG
Definition: retypes.h:1
VOID EnableHardwareTimer(PHARDWARE_TIMER Timer)
Definition: clock.c:161
VOID CpuStep(VOID)
Definition: cpu.c:108
static PHARDWARE_TIMER IpsTimer
Definition: clock.c:46
BOOLEAN VdmRunning
Definition: emulator.c:49
LPFNPSPCALLBACK Callback
Definition: desk.c:111
base of all file and directory entries
Definition: entries.h:82
VOID DestroyHardwareTimer(PHARDWARE_TIMER Timer)
Definition: clock.c:210
LONGLONG QuadPart
Definition: typedefs.h:112