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 (15 years, 3 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

# User Rev Content
1 cebix 1.1 /*
2     * sysdeps.h - System dependent definitions for Linux
3     *
4 gbeauche 1.57 * SheepShaver (C) 1997-2008 Christian Bauer and Marc Hellwig
5 cebix 1.1 *
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 gbeauche 1.37 #include <stddef.h>
45 cebix 1.1 #include <string.h>
46     #include <signal.h>
47    
48 gbeauche 1.24 #ifdef HAVE_PTHREADS
49     # include <pthread.h>
50     #endif
51    
52 cebix 1.1 #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 asvitkine 1.59 #ifdef __MACH__
68     #include <mach/mach_types.h>
69     #endif
70    
71 gbeauche 1.37 // 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 gbeauche 1.5 // Define for external components
83     #define SHEEPSHAVER 1
84    
85 gbeauche 1.34 // Always use Real Addressing mode on native architectures
86     // Otherwise, use Direct Addressing mode if NATMEM_OFFSET is set
87 gbeauche 1.35 #if !defined(EMULATED_PPC)
88 gbeauche 1.4 #define REAL_ADDRESSING 1
89 gbeauche 1.39 #include "ppc_asm.tmpl"
90 gbeauche 1.35 #elif defined(NATMEM_OFFSET)
91     #define DIRECT_ADDRESSING 1
92 gbeauche 1.34 #else
93 gbeauche 1.35 #define REAL_ADDRESSING 1
94 gbeauche 1.34 #endif
95 gbeauche 1.4
96 gbeauche 1.48 // Always use the complete non-stubs Ethernet driver
97     #define USE_ETHER_FULL_DRIVER 1
98    
99 gbeauche 1.5 #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 cebix 1.1 #else
107 gbeauche 1.5 # define ROM_IS_WRITE_PROTECTED 1
108     #endif
109 gbeauche 1.9 // Configure PowerPC emulator
110 gbeauche 1.29 #define PPC_REENTRANT_JIT 1
111 gbeauche 1.30 #define PPC_CHECK_INTERRUPTS 1
112 gbeauche 1.14 #define PPC_DECODE_CACHE 1
113 gbeauche 1.10 #define PPC_FLIGHT_RECORDER 1
114 gbeauche 1.17 #define PPC_PROFILE_COMPILE_TIME 0
115 asvitkine 1.58 #define PPC_PROFILE_GENERIC_CALLS 0
116 gbeauche 1.56 #define PPC_PROFILE_REGS_USE 0
117 gbeauche 1.16 #define KPX_MAX_CPUS 1
118 gbeauche 1.33 #if ENABLE_DYNGEN
119     #define PPC_ENABLE_JIT 1
120     #endif
121 gbeauche 1.54 #if defined(__i386__) || defined(__x86_64__)
122 gbeauche 1.28 #define DYNGEN_ASM_OPTS 1
123     #endif
124 gbeauche 1.5 #else
125     // Mac ROM is write protected
126     #define ROM_IS_WRITE_PROTECTED 1
127     #define USE_SCRATCHMEM_SUBTERFUGE 0
128 cebix 1.1 #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 gbeauche 1.3 #define VAL64(a) (a ## l)
155     #define UVAL64(a) (a ## ul)
156 cebix 1.1 #elif SIZEOF_LONG_LONG == 8
157     typedef unsigned long long uint64;
158     typedef long long int64;
159 gbeauche 1.3 #define VAL64(a) (a ## LL)
160     #define UVAL64(a) (a ## uLL)
161 cebix 1.1 #else
162     #error "No 8 byte type, you lose."
163     #endif
164 gbeauche 1.3 #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 gbeauche 1.5 #endif
173    
174 gbeauche 1.53 // 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 gbeauche 1.15 /**
181     * Helper functions to byteswap data
182     **/
183    
184     #if defined(__GNUC__)
185 gbeauche 1.23 #if defined(__x86_64__) || defined(__i386__)
186 gbeauche 1.15 // 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 gbeauche 1.5 #ifdef HAVE_BYTESWAP_H
198     #include <byteswap.h>
199     #endif
200    
201 gbeauche 1.15 #ifdef opt_bswap_16
202     #undef bswap_16
203     #define bswap_16 opt_bswap_16
204     #endif
205 gbeauche 1.5 #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 gbeauche 1.15 #ifdef opt_bswap_32
215     #undef bswap_32
216     #define bswap_32 opt_bswap_32
217     #endif
218 gbeauche 1.5 #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 gbeauche 1.23
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 gbeauche 1.5
238 gbeauche 1.15 #ifdef opt_bswap_64
239     #undef bswap_64
240     #define bswap_64 opt_bswap_64
241     #endif
242 gbeauche 1.5 #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 gbeauche 1.3 #endif
267 cebix 1.1
268 gbeauche 1.6 // spin locks
269     #ifdef __GNUC__
270    
271 gbeauche 1.22 #if defined(__powerpc__) || defined(__ppc__)
272 gbeauche 1.6 #define HAVE_TEST_AND_SET 1
273 gbeauche 1.20 static inline int testandset(volatile int *p)
274 gbeauche 1.6 {
275     int ret;
276 gbeauche 1.22 __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 gbeauche 1.6 "1: "
282     : "=&r" (ret)
283     : "r" (p), "r" (1), "r" (0)
284     : "cr0", "memory");
285     return ret;
286     }
287     #endif
288    
289 gbeauche 1.45 #if defined(__i386__) || defined(__x86_64__)
290 gbeauche 1.6 #define HAVE_TEST_AND_SET 1
291 gbeauche 1.20 static inline int testandset(volatile int *p)
292 gbeauche 1.6 {
293 gbeauche 1.31 long int ret;
294 gbeauche 1.20 /* Note: the "xchg" instruction does not need a "lock" prefix */
295 gbeauche 1.31 __asm__ __volatile__("xchgl %k0, %1"
296     : "=r" (ret), "=m" (*p)
297 gbeauche 1.20 : "0" (1), "m" (*p)
298 gbeauche 1.6 : "memory");
299     return ret;
300     }
301     #endif
302    
303     #ifdef __s390__
304     #define HAVE_TEST_AND_SET 1
305 gbeauche 1.20 static inline int testandset(volatile int *p)
306 gbeauche 1.6 {
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 gbeauche 1.20 static inline int testandset(volatile int *p)
321 gbeauche 1.6 {
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 gbeauche 1.20 static inline int testandset(volatile int *p)
341 gbeauche 1.6 {
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 gbeauche 1.20 static inline int testandset(volatile int *p)
356 gbeauche 1.6 {
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 gbeauche 1.20 typedef volatile int spinlock_t;
369 gbeauche 1.6
370 gbeauche 1.8 static const spinlock_t SPIN_LOCK_UNLOCKED = 0;
371 gbeauche 1.6
372 gbeauche 1.44 #if defined(HAVE_TEST_AND_SET) && defined(HAVE_PTHREADS)
373     // There is nothing to lock if we are not in an multithreaded environment
374 gbeauche 1.32 #define HAVE_SPINLOCKS 1
375 gbeauche 1.6 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 gbeauche 1.32 #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 gbeauche 1.6 #endif
403    
404 cebix 1.1 // Time data type for Time Manager emulation
405     #ifdef HAVE_CLOCK_GETTIME
406     typedef struct timespec tm_time_t;
407 asvitkine 1.59 #elif defined(__MACH__)
408     typedef mach_timespec_t tm_time_t;
409 cebix 1.1 #else
410     typedef struct timeval tm_time_t;
411     #endif
412    
413 gbeauche 1.42 /* 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 gbeauche 1.40 // High-precision timing
422 gbeauche 1.46 #if defined(HAVE_PTHREADS) && defined(HAVE_CLOCK_NANOSLEEP)
423 gbeauche 1.40 #define PRECISE_TIMING 1
424     #define PRECISE_TIMING_POSIX 1
425 asvitkine 1.59 #elif defined(HAVE_PTHREADS) && defined(__MACH__)
426     #define PRECISE_TIMING 1
427     #define PRECISE_TIMING_MACH 1
428 gbeauche 1.40 #endif
429    
430 gbeauche 1.18 // Timing functions
431     extern uint64 GetTicks_usec(void);
432     extern void Delay_usec(uint32 usec);
433    
434 gbeauche 1.43 #ifdef HAVE_PTHREADS
435 cebix 1.2 // Setup pthread attributes
436     extern void Set_pthread_attr(pthread_attr_t *attr, int priority);
437 gbeauche 1.24 #endif
438 cebix 1.2
439 cebix 1.1 // Various definitions
440     typedef struct rgb_color {
441     uint8 red;
442     uint8 green;
443     uint8 blue;
444     uint8 alpha;
445     } rgb_color;
446    
447 gbeauche 1.19 // X11 display fast locks
448 gbeauche 1.44 #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 gbeauche 1.19 #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 cebix 1.1 // Macro for calling MacOS routines
467 gbeauche 1.34 #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 cebix 1.1
476 gbeauche 1.3 #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 cebix 1.1
491     #endif