1 /*
2 * UAE - The Un*x Amiga Emulator
3 *
4 * Miscellaneous machine dependent support functions and definitions
5 *
6 * Copyright 1996 Bernd Schmidt
7 * Copyright 2003-2005 Richard Drummond
8 */
9
10 #include "sysconfig.h"
11 #include "sysdeps.h"
12
13 #include "cfgfile.h"
14 #include "sleep.h"
15 #include "machdep/rpt.h"
16 #include "machdep/m68k.h"
17 #include "events.h"
18 #include "custom.h"
19
20 #ifndef USE_UNDERSCORE
21 #define LARGE_ALIGNMENT ".align 16\n"
22 #else
23 #define LARGE_ALIGNMENT ".align 4,0x90\n"
24 #endif
25
26 struct flag_struct regflags;
27
28 #include <signal.h>
29
30 /* internal prototypes */
31 void machdep_save_options (struct zfile *, const struct uae_prefs *);
32 int machdep_parse_option (struct uae_prefs *, const char *, const char *);
33 void machdep_default_options (struct uae_prefs *);
34
35 #ifdef __linux__
36 frame_time_t linux_get_tsc_freq (void);
37
38 /*
39 * Extract x86/AMD64 timestamp counter frequency
40 * from /proc/cpuinfo.
41 *
42 * TODO: Make this more robust.
43 */
linux_get_tsc_freq(void)44 frame_time_t linux_get_tsc_freq (void)
45 {
46 int cpuinfo_fd;
47 char buffer[1024];
48 static uae_s64 tsc_freq = 0;
49 if(tsc_freq) return tsc_freq;
50
51 cpuinfo_fd = open ("/proc/cpuinfo", O_RDONLY);
52
53 if (cpuinfo_fd >= 0) {
54 char *ptr = &buffer[0];
55 int size_read = read (cpuinfo_fd, ptr, 1024);
56
57 while (size_read > 0) {
58 if (strncmp (ptr, "bogomips\t: ", 11) != 0) {
59 while ((size_read-- > 0) && (*ptr != '\n'))
60 ptr++;
61 size_read--;
62 ptr++;
63 continue;
64 } else {
65 ptr += 11;
66 tsc_freq = atoll (ptr) * 1000000 / 2;
67 }
68 }
69 }
70 close (cpuinfo_fd);
71
72 return tsc_freq;
73 }
74 #endif
75
76 #ifdef __BEOS__
77
78 # include <be/kernel/OS.h>
79
80 /*
81 * Get timestamp counter frequency from the kernel
82 */
beos_get_tsc_freq(void)83 static frame_time_t beos_get_tsc_freq (void)
84 {
85 system_info info;
86 get_system_info (&info);
87 return info.cpu_clock_speed;
88 }
89 #endif
90
91 #ifdef __APPLE__
apple_get_tsc_freq(void)92 frame_time_t apple_get_tsc_freq (void)
93 {
94 int sysctl_hw;
95 char buffer[1024];
96 uae_s64 tsc_freq = 0;
97
98 sysctl_hw = open ("sysctl -a hw", O_RDONLY);
99
100 if (sysctl_hw >= 0) {
101 char *ptr = &buffer[0];
102 int size_read = read (sysctl_hw, ptr, 1024);
103
104 while (size_read > 0) {
105 if (strncmp (ptr, "hw.cpufrequency: ", 17) != 0) {
106 while ((size_read-- > 0) && (*ptr != '\n'))
107 ptr++;
108 size_read--;
109 ptr++;
110 continue;
111 } else {
112 ptr += 17;
113 tsc_freq = atoll (ptr) * 1000000 / 2;
114 }
115 }
116 }
117 close (sysctl_hw);
118
119 return tsc_freq;
120 }
121 #endif
122
123 static volatile frame_time_t last_time, best_time;
124 static frame_time_t timebase;
125
126 static volatile int loops_to_go;
127
128 #if defined HAVE_SETITIMER || defined HAVE_ALARM
129 # define USE_ALARM
130 # ifndef HAVE_SETITIMER
131 # define TIME_UNIT 1000000
132 # else
133 # define TIME_UNIT 100000
134 # endif
135 #else
136 # define TIME_DELAY 200
137 # define TIME_UNIT (TIME_DELAY*1000)
138 #endif
139
140 #ifndef HAVE_SYNC
141 # define sync()
142 #endif
143
144 #ifdef USE_ALARM
set_the_alarm(void)145 static void set_the_alarm (void)
146 {
147 # ifndef HAVE_SETITIMER
148 alarm (1);
149 # else
150 struct itimerval t;
151 t.it_value.tv_sec = 0;
152 t.it_value.tv_usec = TIME_UNIT;
153 t.it_interval.tv_sec = 0;
154 t.it_interval.tv_usec = TIME_UNIT;
155 setitimer (ITIMER_REAL, &t, NULL);
156 # endif
157 }
158
159 static int first_loop = 1;
160
161 #ifdef __cplusplus
alarmhandler(...)162 static RETSIGTYPE alarmhandler(...)
163 #else
164 static RETSIGTYPE alarmhandler(int foo)
165 #endif
166 {
167 frame_time_t bar;
168 bar = read_processor_time ();
169 if (! first_loop && bar - last_time < best_time)
170 best_time = bar - last_time;
171 first_loop = 0;
172 if (--loops_to_go > 0) {
173 signal (SIGALRM, alarmhandler);
174 last_time = read_processor_time ();
175 set_the_alarm ();
176 } else {
177 alarm (0);
178 signal (SIGALRM, SIG_IGN);
179 }
180 }
181 #endif /* USE_ALARM */
182
183 #include <setjmp.h>
184 static jmp_buf catch_test;
185
186 #ifdef __cplusplus
illhandler(...)187 static RETSIGTYPE illhandler (...)
188 #else
189 static RETSIGTYPE illhandler (int foo)
190 #endif
191 {
192 // rpt_available = 0;
193 longjmp (catch_test, 1);
194 }
195
machdep_inithrtimer(void)196 int machdep_inithrtimer (void)
197 {
198 static int done = 0;
199
200 if (!done) {
201 // rpt_available = 1;
202
203 write_log ("Testing the RDTSC instruction ... ");
204 signal (SIGILL, illhandler);
205 if (setjmp (catch_test) == 0)
206 read_processor_time ();
207 signal (SIGILL, SIG_DFL);
208 write_log ("done.\n");
209
210 /* if (! rpt_available) {
211 write_log ("Your processor does not support the RDTSC instruction.\n");
212 return 0;
213 }*/
214
215 timebase = 0;
216 #ifdef __linux__
217 timebase = linux_get_tsc_freq ();
218 #else
219 #ifdef __BEOS__
220 timebase = beos_get_tsc_freq ();
221 #endif
222 #ifdef __APPLE__
223 // timebase = apple_get_tsc_freq ();
224 #endif
225 #endif
226
227 if (timebase <= 0) {
228 write_log ("Calibrating TSC frequency...");
229 flush_log ();
230
231 best_time = MAX_FRAME_TIME;
232 loops_to_go = 5;
233
234 #ifdef USE_ALARM
235 signal (SIGALRM, alarmhandler);
236 #endif
237
238 /* We want exact values... */
239 sync (); sync (); sync ();
240
241 #ifdef USE_ALARM
242 last_time = read_processor_time ();
243 set_the_alarm ();
244
245 while (loops_to_go != 0)
246 uae_msleep (10);
247 #else
248 int i = loops_to_go;
249 frame_time_t bar;
250
251 while (i-- > 0) {
252 last_time = read_processor_time ();
253 uae_msleep (TIME_DELAY);
254 bar = read_processor_time ();
255 if (i != loops_to_go && bar - last_time < best_time)
256 best_time = bar - last_time;
257 }
258 #endif
259
260 timebase = best_time * (1000000.0 / TIME_UNIT);
261 }
262
263 write_log ("TSC frequency: %f MHz\n", timebase / 1000000.0);
264 done = 1;
265 }
266 return done;
267 }
268
machdep_gethrtimebase(void)269 frame_time_t machdep_gethrtimebase (void)
270 {
271 return timebase;
272 }
273
machdep_init(void)274 int machdep_init (void)
275 {
276 return 1;
277 }
278
279 /*
280 * Handle processor-specific cfgfile options
281 */
machdep_save_options(struct zfile * f,const struct uae_prefs * p)282 void machdep_save_options (struct zfile *f, const struct uae_prefs *p)
283 {
284 // cfgfile_write (f, MACHDEP_NAME ".use_tsc=%s\n", p->use_processor_clock ? "yes" : "no");
285 }
286
machdep_parse_option(struct uae_prefs * p,const char * option,const char * value)287 int machdep_parse_option (struct uae_prefs *p, const char *option, const char *value)
288 {
289 // return cfgfile_yesno (option, value, "use_tsc", &p->use_processor_clock);
290 return 0;
291 }
292
machdep_default_options(struct uae_prefs * p)293 void machdep_default_options (struct uae_prefs *p)
294 {
295 }
296