ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/sysdeps.h
Revision: 1.59
Committed: 2009-08-17T20:44:30Z (14 years, 9 months ago) by asvitkine
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.58: +9 -0 lines
Log Message:
[Charles Srstka]
Attached is a set of patches to port the precise timer that is currently used in the Linux and BeOS builds of SheepShaver to Mac OS X (and any other Mach-based operating systems).

Currently, the Linux build uses the clock_gettime() function to get nanosecond-precision time, and falls back on gettimeofday() if it is not present. Unfortunately, Mac OS X does not currently support clock_gettime(), and gettimeofday() has only microsecond granularity. The Mach kernel, however, has a clock_get_time() function that does very nearly the same thing as clock_gettime(). The patches to BasiliskII cause the timing functions such as timer_current_time() to use clock_get_time() instead of gettimeofday() on Mach-based systems that do not support clock_gettime().

The changes to SheepShaver involve the precise timer. The existing code for Linux uses pthreads and real-time signals to handle the timing. Mac OS X unfortunately does not seem to support real-time signals, so Mach calls are again used to suspend and resume the timer thread in order to attempt to duplicate the Linux and BeOS versions of the timer. The code is somewhat ugly right now, as I decided to leave alone the pre-existing style of the source file, which unfortunately involves #ifdefs scattered throughout the file and some duplication of code. A future patch may want to clean this up to separate out the OS-specific code and put it all together at the top of the file. However, for the time being, this seems to work.

This has not been extensively tested, because I have not been able to get my hands on a good test-case app for the classic Mac OS that would run inside the emulator and try out the timer. However, performance does seem to be better than with the pre-existing code, and nothing seems to have blown up as far as I can tell. I did find a game via a Google search -  Cap'n Magneto - that is known to have problems with Basilisk/SheepShaver's legacy 60 Hz timer, and the opening fade-to-color for this game appears to run much more smoothly with the precise timer code in place.

File Contents

# Content
1 /*
2 * sysdeps.h - System dependent definitions for Linux
3 *
4 * SheepShaver (C) 1997-2008 Christian Bauer and Marc Hellwig
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #ifndef SYSDEPS_H
22 #define SYSDEPS_H
23
24 #ifndef __STDC__
25 #error "Your compiler is not ANSI. Get a real one."
26 #endif
27
28 #include "config.h"
29 #include "user_strings_unix.h"
30
31 #ifndef STDC_HEADERS
32 #error "You don't have ANSI C header files."
33 #endif
34
35 #ifdef HAVE_UNISTD_H
36 # include <sys/types.h>
37 # include <unistd.h>
38 #endif
39
40 #include <netinet/in.h>
41 #include <assert.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <stddef.h>
45 #include <string.h>
46 #include <signal.h>
47
48 #ifdef HAVE_PTHREADS
49 # include <pthread.h>
50 #endif
51
52 #ifdef HAVE_FCNTL_H
53 # include <fcntl.h>
54 #endif
55
56 #ifdef TIME_WITH_SYS_TIME
57 # include <sys/time.h>
58 # include <time.h>
59 #else
60 # ifdef HAVE_SYS_TIME_H
61 # include <sys/time.h>
62 # else
63 # include <time.h>
64 # endif
65 #endif
66
67 #ifdef __MACH__
68 #include <mach/mach_types.h>
69 #endif
70
71 // Fix offsetof() on FreeBSD and GCC >= 3.4
72 #if defined(__FreeBSD__) && defined(__cplusplus)
73 #undef offsetof
74 /* The cast to "char &" below avoids problems with user-defined
75 "operator &", which can appear in a POD type. */
76 #define offsetof(TYPE, MEMBER) \
77 (__offsetof__ (reinterpret_cast <size_t> \
78 (&reinterpret_cast <char &> \
79 (static_cast<TYPE *> (0)->MEMBER))))
80 #endif
81
82 // Define for external components
83 #define SHEEPSHAVER 1
84
85 // Always use Real Addressing mode on native architectures
86 // Otherwise, use Direct Addressing mode if NATMEM_OFFSET is set
87 #if !defined(EMULATED_PPC)
88 #define REAL_ADDRESSING 1
89 #include "ppc_asm.tmpl"
90 #elif defined(NATMEM_OFFSET)
91 #define DIRECT_ADDRESSING 1
92 #else
93 #define REAL_ADDRESSING 1
94 #endif
95
96 // Always use the complete non-stubs Ethernet driver
97 #define USE_ETHER_FULL_DRIVER 1
98
99 #define POWERPC_ROM 1
100
101 #if EMULATED_PPC
102 // Mac ROM is write protected when banked memory is used
103 #if REAL_ADDRESSING || DIRECT_ADDRESSING
104 # define ROM_IS_WRITE_PROTECTED 0
105 # define USE_SCRATCHMEM_SUBTERFUGE 1
106 #else
107 # define ROM_IS_WRITE_PROTECTED 1
108 #endif
109 // Configure PowerPC emulator
110 #define PPC_REENTRANT_JIT 1
111 #define PPC_CHECK_INTERRUPTS 1
112 #define PPC_DECODE_CACHE 1
113 #define PPC_FLIGHT_RECORDER 1
114 #define PPC_PROFILE_COMPILE_TIME 0
115 #define PPC_PROFILE_GENERIC_CALLS 0
116 #define PPC_PROFILE_REGS_USE 0
117 #define KPX_MAX_CPUS 1
118 #if ENABLE_DYNGEN
119 #define PPC_ENABLE_JIT 1
120 #endif
121 #if defined(__i386__) || defined(__x86_64__)
122 #define DYNGEN_ASM_OPTS 1
123 #endif
124 #else
125 // Mac ROM is write protected
126 #define ROM_IS_WRITE_PROTECTED 1
127 #define USE_SCRATCHMEM_SUBTERFUGE 0
128 #endif
129
130 // Data types
131 typedef unsigned char uint8;
132 typedef signed char int8;
133 #if SIZEOF_SHORT == 2
134 typedef unsigned short uint16;
135 typedef short int16;
136 #elif SIZEOF_INT == 2
137 typedef unsigned int uint16;
138 typedef int int16;
139 #else
140 #error "No 2 byte type, you lose."
141 #endif
142 #if SIZEOF_INT == 4
143 typedef unsigned int uint32;
144 typedef int int32;
145 #elif SIZEOF_LONG == 4
146 typedef unsigned long uint32;
147 typedef long int32;
148 #else
149 #error "No 4 byte type, you lose."
150 #endif
151 #if SIZEOF_LONG == 8
152 typedef unsigned long uint64;
153 typedef long int64;
154 #define VAL64(a) (a ## l)
155 #define UVAL64(a) (a ## ul)
156 #elif SIZEOF_LONG_LONG == 8
157 typedef unsigned long long uint64;
158 typedef long long int64;
159 #define VAL64(a) (a ## LL)
160 #define UVAL64(a) (a ## uLL)
161 #else
162 #error "No 8 byte type, you lose."
163 #endif
164 #if SIZEOF_VOID_P == 4
165 typedef uint32 uintptr;
166 typedef int32 intptr;
167 #elif SIZEOF_VOID_P == 8
168 typedef uint64 uintptr;
169 typedef int64 intptr;
170 #else
171 #error "Unsupported size of pointer"
172 #endif
173
174 // Define if the host processor supports fast unaligned load/stores
175 #if defined __i386__ || defined __x86_64__
176 #define UNALIGNED_PROFITABLE 1
177 #endif
178
179
180 /**
181 * Helper functions to byteswap data
182 **/
183
184 #if defined(__GNUC__)
185 #if defined(__x86_64__) || defined(__i386__)
186 // Linux/AMD64 currently has no asm optimized bswap_32() in <byteswap.h>
187 #define opt_bswap_32 do_opt_bswap_32
188 static inline uint32 do_opt_bswap_32(uint32 x)
189 {
190 uint32 v;
191 __asm__ __volatile__ ("bswap %0" : "=r" (v) : "0" (x));
192 return v;
193 }
194 #endif
195 #endif
196
197 #ifdef HAVE_BYTESWAP_H
198 #include <byteswap.h>
199 #endif
200
201 #ifdef opt_bswap_16
202 #undef bswap_16
203 #define bswap_16 opt_bswap_16
204 #endif
205 #ifndef bswap_16
206 #define bswap_16 generic_bswap_16
207 #endif
208
209 static inline uint16 generic_bswap_16(uint16 x)
210 {
211 return ((x & 0xff) << 8) | ((x >> 8) & 0xff);
212 }
213
214 #ifdef opt_bswap_32
215 #undef bswap_32
216 #define bswap_32 opt_bswap_32
217 #endif
218 #ifndef bswap_32
219 #define bswap_32 generic_bswap_32
220 #endif
221
222 static inline uint32 generic_bswap_32(uint32 x)
223 {
224 return (((x & 0xff000000) >> 24) |
225 ((x & 0x00ff0000) >> 8) |
226 ((x & 0x0000ff00) << 8) |
227 ((x & 0x000000ff) << 24) );
228 }
229
230 #if defined(__i386__)
231 #define opt_bswap_64 do_opt_bswap_64
232 static inline uint64 do_opt_bswap_64(uint64 x)
233 {
234 return (bswap_32(x >> 32) | (((uint64)bswap_32((uint32)x)) << 32));
235 }
236 #endif
237
238 #ifdef opt_bswap_64
239 #undef bswap_64
240 #define bswap_64 opt_bswap_64
241 #endif
242 #ifndef bswap_64
243 #define bswap_64 generic_bswap_64
244 #endif
245
246 static inline uint64 generic_bswap_64(uint64 x)
247 {
248 return (((x & UVAL64(0xff00000000000000)) >> 56) |
249 ((x & UVAL64(0x00ff000000000000)) >> 40) |
250 ((x & UVAL64(0x0000ff0000000000)) >> 24) |
251 ((x & UVAL64(0x000000ff00000000)) >> 8) |
252 ((x & UVAL64(0x00000000ff000000)) << 8) |
253 ((x & UVAL64(0x0000000000ff0000)) << 24) |
254 ((x & UVAL64(0x000000000000ff00)) << 40) |
255 ((x & UVAL64(0x00000000000000ff)) << 56) );
256 }
257
258 #ifdef WORDS_BIGENDIAN
259 static inline uint16 tswap16(uint16 x) { return x; }
260 static inline uint32 tswap32(uint32 x) { return x; }
261 static inline uint64 tswap64(uint64 x) { return x; }
262 #else
263 static inline uint16 tswap16(uint16 x) { return bswap_16(x); }
264 static inline uint32 tswap32(uint32 x) { return bswap_32(x); }
265 static inline uint64 tswap64(uint64 x) { return bswap_64(x); }
266 #endif
267
268 // spin locks
269 #ifdef __GNUC__
270
271 #if defined(__powerpc__) || defined(__ppc__)
272 #define HAVE_TEST_AND_SET 1
273 static inline int testandset(volatile int *p)
274 {
275 int ret;
276 __asm__ __volatile__("0: lwarx %0,0,%1\n"
277 " xor. %0,%3,%0\n"
278 " bne 1f\n"
279 " stwcx. %2,0,%1\n"
280 " bne- 0b\n"
281 "1: "
282 : "=&r" (ret)
283 : "r" (p), "r" (1), "r" (0)
284 : "cr0", "memory");
285 return ret;
286 }
287 #endif
288
289 #if defined(__i386__) || defined(__x86_64__)
290 #define HAVE_TEST_AND_SET 1
291 static inline int testandset(volatile int *p)
292 {
293 long int ret;
294 /* Note: the "xchg" instruction does not need a "lock" prefix */
295 __asm__ __volatile__("xchgl %k0, %1"
296 : "=r" (ret), "=m" (*p)
297 : "0" (1), "m" (*p)
298 : "memory");
299 return ret;
300 }
301 #endif
302
303 #ifdef __s390__
304 #define HAVE_TEST_AND_SET 1
305 static inline int testandset(volatile int *p)
306 {
307 int ret;
308
309 __asm__ __volatile__("0: cs %0,%1,0(%2)\n"
310 " jl 0b"
311 : "=&d" (ret)
312 : "r" (1), "a" (p), "0" (*p)
313 : "cc", "memory" );
314 return ret;
315 }
316 #endif
317
318 #ifdef __alpha__
319 #define HAVE_TEST_AND_SET 1
320 static inline int testandset(volatile int *p)
321 {
322 int ret;
323 unsigned long one;
324
325 __asm__ __volatile__("0: mov 1,%2\n"
326 " ldl_l %0,%1\n"
327 " stl_c %2,%1\n"
328 " beq %2,1f\n"
329 ".subsection 2\n"
330 "1: br 0b\n"
331 ".previous"
332 : "=r" (ret), "=m" (*p), "=r" (one)
333 : "m" (*p));
334 return ret;
335 }
336 #endif
337
338 #ifdef __sparc__
339 #define HAVE_TEST_AND_SET 1
340 static inline int testandset(volatile int *p)
341 {
342 int ret;
343
344 __asm__ __volatile__("ldstub [%1], %0"
345 : "=r" (ret)
346 : "r" (p)
347 : "memory");
348
349 return (ret ? 1 : 0);
350 }
351 #endif
352
353 #ifdef __arm__
354 #define HAVE_TEST_AND_SET 1
355 static inline int testandset(volatile int *p)
356 {
357 register unsigned int ret;
358 __asm__ __volatile__("swp %0, %1, [%2]"
359 : "=r"(ret)
360 : "0"(1), "r"(p));
361
362 return ret;
363 }
364 #endif
365
366 #endif /* __GNUC__ */
367
368 typedef volatile int spinlock_t;
369
370 static const spinlock_t SPIN_LOCK_UNLOCKED = 0;
371
372 #if defined(HAVE_TEST_AND_SET) && defined(HAVE_PTHREADS)
373 // There is nothing to lock if we are not in an multithreaded environment
374 #define HAVE_SPINLOCKS 1
375 static inline void spin_lock(spinlock_t *lock)
376 {
377 while (testandset(lock));
378 }
379
380 static inline void spin_unlock(spinlock_t *lock)
381 {
382 *lock = 0;
383 }
384
385 static inline int spin_trylock(spinlock_t *lock)
386 {
387 return !testandset(lock);
388 }
389 #else
390 static inline void spin_lock(spinlock_t *lock)
391 {
392 }
393
394 static inline void spin_unlock(spinlock_t *lock)
395 {
396 }
397
398 static inline int spin_trylock(spinlock_t *lock)
399 {
400 return 1;
401 }
402 #endif
403
404 // Time data type for Time Manager emulation
405 #ifdef HAVE_CLOCK_GETTIME
406 typedef struct timespec tm_time_t;
407 #elif defined(__MACH__)
408 typedef mach_timespec_t tm_time_t;
409 #else
410 typedef struct timeval tm_time_t;
411 #endif
412
413 /* Define codes for all the float formats that we know of.
414 * Though we only handle IEEE format. */
415 #define UNKNOWN_FLOAT_FORMAT 0
416 #define IEEE_FLOAT_FORMAT 1
417 #define VAX_FLOAT_FORMAT 2
418 #define IBM_FLOAT_FORMAT 3
419 #define C4X_FLOAT_FORMAT 4
420
421 // High-precision timing
422 #if defined(HAVE_PTHREADS) && defined(HAVE_CLOCK_NANOSLEEP)
423 #define PRECISE_TIMING 1
424 #define PRECISE_TIMING_POSIX 1
425 #elif defined(HAVE_PTHREADS) && defined(__MACH__)
426 #define PRECISE_TIMING 1
427 #define PRECISE_TIMING_MACH 1
428 #endif
429
430 // Timing functions
431 extern uint64 GetTicks_usec(void);
432 extern void Delay_usec(uint32 usec);
433
434 #ifdef HAVE_PTHREADS
435 // Setup pthread attributes
436 extern void Set_pthread_attr(pthread_attr_t *attr, int priority);
437 #endif
438
439 // Various definitions
440 typedef struct rgb_color {
441 uint8 red;
442 uint8 green;
443 uint8 blue;
444 uint8 alpha;
445 } rgb_color;
446
447 // X11 display fast locks
448 #if defined(HAVE_PTHREADS)
449 #define X11_LOCK_TYPE pthread_mutex_t
450 #define X11_LOCK_INIT PTHREAD_MUTEX_INITIALIZER
451 #define XDisplayLock() pthread_mutex_lock(&x_display_lock);
452 #define XDisplayUnlock() pthread_mutex_unlock(&x_display_lock);
453 #elif defined(HAVE_SPINLOCKS)
454 #define X11_LOCK_TYPE spinlock_t
455 #define X11_LOCK_INIT SPIN_LOCK_UNLOCKED
456 #define XDisplayLock() spin_lock(&x_display_lock)
457 #define XDisplayUnlock() spin_unlock(&x_display_lock)
458 #else
459 #define XDisplayLock()
460 #define XDisplayUnlock()
461 #endif
462 #ifdef X11_LOCK_TYPE
463 extern X11_LOCK_TYPE x_display_lock;
464 #endif
465
466 // Macro for calling MacOS routines
467 #define CallMacOS(type, tvect) call_macos((uintptr)tvect)
468 #define CallMacOS1(type, tvect, arg1) call_macos1((uintptr)tvect, (uintptr)arg1)
469 #define CallMacOS2(type, tvect, arg1, arg2) call_macos2((uintptr)tvect, (uintptr)arg1, (uintptr)arg2)
470 #define CallMacOS3(type, tvect, arg1, arg2, arg3) call_macos3((uintptr)tvect, (uintptr)arg1, (uintptr)arg2, (uintptr)arg3)
471 #define CallMacOS4(type, tvect, arg1, arg2, arg3, arg4) call_macos4((uintptr)tvect, (uintptr)arg1, (uintptr)arg2, (uintptr)arg3, (uintptr)arg4)
472 #define CallMacOS5(type, tvect, arg1, arg2, arg3, arg4, arg5) call_macos5((uintptr)tvect, (uintptr)arg1, (uintptr)arg2, (uintptr)arg3, (uintptr)arg4, (uintptr)arg5)
473 #define CallMacOS6(type, tvect, arg1, arg2, arg3, arg4, arg5, arg6) call_macos6((uintptr)tvect, (uintptr)arg1, (uintptr)arg2, (uintptr)arg3, (uintptr)arg4, (uintptr)arg5, (uintptr)arg6)
474 #define CallMacOS7(type, tvect, arg1, arg2, arg3, arg4, arg5, arg6, arg7) call_macos7((uintptr)tvect, (uintptr)arg1, (uintptr)arg2, (uintptr)arg3, (uintptr)arg4, (uintptr)arg5, (uintptr)arg6, (uintptr)arg7)
475
476 #ifdef __cplusplus
477 extern "C" {
478 #endif
479 extern uint32 call_macos(uint32 tvect);
480 extern uint32 call_macos1(uint32 tvect, uint32 arg1);
481 extern uint32 call_macos2(uint32 tvect, uint32 arg1, uint32 arg2);
482 extern uint32 call_macos3(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3);
483 extern uint32 call_macos4(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4);
484 extern uint32 call_macos5(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5);
485 extern uint32 call_macos6(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5, uint32 arg6);
486 extern uint32 call_macos7(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5, uint32 arg6, uint32 arg7);
487 #ifdef __cplusplus
488 }
489 #endif
490
491 #endif