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