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