1 #include "sysconfig.h"
2 #include "sysdeps.h"
3 #include "uae/time.h"
4 #include "custom.h"
5 #include "options.h"
6 #include "events.h"
7 #include "uae.h"
8
9 #ifdef _WIN32
10
11 #include <process.h>
12
13 static int userdtsc = 0;
14 static int qpcdivisor = 0;
15 static SYSTEM_INFO si;
16
read_processor_time_qpf(void)17 static frame_time_t read_processor_time_qpf(void)
18 {
19 LARGE_INTEGER counter;
20 frame_time_t t;
21 QueryPerformanceCounter(&counter);
22 if (qpcdivisor == 0)
23 t = (frame_time_t) (counter.LowPart);
24 else
25 t = (frame_time_t) (counter.QuadPart >> qpcdivisor);
26 if (!t)
27 t++;
28 return t;
29 }
30
read_processor_time_rdtsc(void)31 static frame_time_t read_processor_time_rdtsc(void)
32 {
33 frame_time_t foo = 0;
34 #if defined(X86_MSVC_ASSEMBLY)
35 frame_time_t bar;
36 __asm
37 {
38 rdtsc
39 mov foo, eax
40 mov bar, edx
41 }
42 /* very high speed CPU's RDTSC might overflow without this.. */
43 foo >>= 6;
44 foo |= bar << 26;
45 if (!foo)
46 foo++;
47 #endif
48 return foo;
49 }
50
uae_time(void)51 uae_time_t uae_time(void)
52 {
53 uae_time_t t;
54 #if 0
55 static int cnt;
56
57 cnt++;
58 if (cnt > 1000000) {
59 write_log(_T("**************\n"));
60 cnt = 0;
61 }
62 #endif
63 if (userdtsc)
64 t = read_processor_time_rdtsc();
65 else
66 t = read_processor_time_qpf();
67 return t;
68 }
69
read_system_time(void)70 uae_u32 read_system_time(void)
71 {
72 return GetTickCount();
73 }
74
75 static volatile int dummythread_die;
76
dummythread(void * dummy)77 static void _cdecl dummythread(void *dummy)
78 {
79 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
80 while (!dummythread_die);
81 }
82
win32_read_processor_time(void)83 static uae_u64 win32_read_processor_time(void)
84 {
85 #if defined(X86_MSVC_ASSEMBLY)
86 uae_u32 foo, bar;
87 __asm
88 {
89 cpuid
90 rdtsc
91 mov foo, eax
92 mov bar, edx
93 }
94 return (((uae_u64)bar) << 32) | foo;
95 #else
96 return 0;
97 #endif
98 }
99
figure_processor_speed_rdtsc(void)100 static void figure_processor_speed_rdtsc(void)
101 {
102 static int freqset;
103 uae_u64 clockrate;
104 int oldpri;
105 HANDLE th;
106
107 if (freqset)
108 return;
109 th = GetCurrentThread ();
110 freqset = 1;
111 oldpri = GetThreadPriority(th);
112 SetThreadPriority(th, THREAD_PRIORITY_HIGHEST);
113 dummythread_die = -1;
114 _beginthread(&dummythread, 0, 0);
115 sleep_millis(500);
116 clockrate = win32_read_processor_time();
117 sleep_millis(500);
118 clockrate = (win32_read_processor_time() - clockrate) * 2;
119 dummythread_die = 0;
120 SetThreadPriority(th, oldpri);
121 write_log(_T("CLOCKFREQ: RDTSC %.2fMHz\n"), clockrate / 1000000.0);
122 syncbase = clockrate >> 6;
123 }
124
figure_processor_speed_qpf(void)125 static void figure_processor_speed_qpf(void)
126 {
127 LARGE_INTEGER freq;
128 static LARGE_INTEGER freq2;
129 uae_u64 qpfrate;
130
131 if (!QueryPerformanceFrequency (&freq))
132 return;
133 if (freq.QuadPart == freq2.QuadPart)
134 return;
135 freq2.QuadPart = freq.QuadPart;
136 qpfrate = freq.QuadPart;
137 /* limit to 10MHz */
138 qpcdivisor = 0;
139 while (qpfrate >= 10000000) {
140 qpfrate >>= 1;
141 qpcdivisor++;
142 }
143 write_log(_T("CLOCKFREQ: QPF %.2fMHz (%.2fMHz, DIV=%d)\n"),
144 freq.QuadPart / 1000000.0,
145 qpfrate / 1000000.0, 1 << qpcdivisor);
146 syncbase = (int) qpfrate;
147 }
148
uae_time_calibrate(void)149 void uae_time_calibrate(void)
150 {
151 if (si.dwNumberOfProcessors > 1) {
152 userdtsc = 0;
153 }
154 if (userdtsc) {
155 figure_processor_speed_rdtsc();
156 }
157 if (!userdtsc) {
158 figure_processor_speed_qpf();
159 }
160 }
161
uae_time_use_rdtsc(bool enable)162 void uae_time_use_rdtsc(bool enable)
163 {
164 userdtsc = enable;
165 }
166
167 #elif defined(USE_GLIB)
168
169 #include <glib.h>
170
171 static gint64 epoch;
172
uae_time(void)173 uae_time_t uae_time(void)
174 {
175 return (uae_time_t) g_get_monotonic_time();
176 }
177
uae_time_calibrate(void)178 void uae_time_calibrate(void)
179 {
180
181 }
182
183 #endif
184
185 #ifdef FSUAE
186
uae_deterministic_amiga_time(int * days,int * mins,int * ticks)187 void uae_deterministic_amiga_time(int *days, int *mins, int *ticks)
188 {
189 // FIXME: Would be nice if the netplay server could broadcast a suitable
190 // start time.
191 // FIXME: Also integrate this with battery clock emulation
192 // FIXME: This works quite well for PAL (ticks = 1/50 sec). Should tune for
193 // NTSC...
194
195 long t = vsync_counter;
196
197 int ticks_per_min = 50 * 60;
198 int ticks_per_day = 24 * 60 * ticks_per_min;
199
200 *days = t / ticks_per_day;
201 t -= *days * ticks_per_day;
202 *mins = t / ticks_per_min;
203 t -= *mins * ticks_per_min;
204 *ticks = t;
205 // Start at day one so time looks more valid for certain programs?
206 // *days += 1;
207 }
208
209 #endif
210
uae_time_init(void)211 void uae_time_init(void)
212 {
213 static bool initialized = false;
214 if (initialized) {
215 return;
216 }
217 #ifdef _WIN32
218 GetSystemInfo(&si);
219 #endif
220 uae_time_calibrate();
221 initialized = true;
222 }
223