ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sysdeps.h
Revision: 1.35
Committed: 2009-08-17T20:42:26Z (14 years, 10 months ago) by asvitkine
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.34: +5 -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 Unix
3     *
4 gbeauche 1.34 * Basilisk II (C) 1997-2008 Christian Bauer
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 cebix 1.3 #include "user_strings_unix.h"
30 cebix 1.1
31     #ifndef STDC_HEADERS
32     #error "You don't have ANSI C header files."
33     #endif
34    
35 cebix 1.2 #ifdef HAVE_UNISTD_H
36     # include <sys/types.h>
37     # include <unistd.h>
38     #endif
39    
40 cebix 1.1 #include <netinet/in.h>
41     #include <assert.h>
42     #include <stdio.h>
43     #include <stdlib.h>
44     #include <string.h>
45    
46 gbeauche 1.24 #ifdef HAVE_PTHREADS
47     # include <pthread.h>
48     #endif
49    
50 cebix 1.1 #ifdef HAVE_FCNTL_H
51     # include <fcntl.h>
52     #endif
53    
54     #ifdef TIME_WITH_SYS_TIME
55     # include <sys/time.h>
56     # include <time.h>
57     #else
58     # ifdef HAVE_SYS_TIME_H
59     # include <sys/time.h>
60     # else
61     # include <time.h>
62     # endif
63     #endif
64    
65 asvitkine 1.35 #if defined(__MACH__)
66     #include <mach/clock.h>
67     #endif
68 cebix 1.1
69 cebix 1.11 #ifdef ENABLE_NATIVE_M68K
70    
71     /* Mac and host address space are the same */
72     #define REAL_ADDRESSING 1
73    
74     /* Using 68k natively */
75     #define EMULATED_68K 0
76    
77     /* Mac ROM is not write protected */
78     #define ROM_IS_WRITE_PROTECTED 0
79 cebix 1.14 #define USE_SCRATCHMEM_SUBTERFUGE 1
80 cebix 1.11
81     #else
82    
83     /* Mac and host address space are distinct */
84 gbeauche 1.13 #ifndef REAL_ADDRESSING
85 cebix 1.1 #define REAL_ADDRESSING 0
86 gbeauche 1.13 #endif
87 cebix 1.1
88 cebix 1.11 /* Using 68k emulator */
89 cebix 1.1 #define EMULATED_68K 1
90    
91 gbeauche 1.13 /* The m68k emulator uses a prefetch buffer ? */
92     #define USE_PREFETCH_BUFFER 0
93    
94 cebix 1.14 /* Mac ROM is write protected when banked memory is used */
95 gbeauche 1.13 #if REAL_ADDRESSING || DIRECT_ADDRESSING
96     # define ROM_IS_WRITE_PROTECTED 0
97     # define USE_SCRATCHMEM_SUBTERFUGE 1
98     #else
99     # define ROM_IS_WRITE_PROTECTED 1
100     #endif
101 cebix 1.1
102 cebix 1.11 #endif
103    
104 gbeauche 1.30 /* Direct Addressing requires Video on SEGV signals in plain X11 mode */
105     #if DIRECT_ADDRESSING && (!ENABLE_VOSF && !USE_SDL_VIDEO)
106 gbeauche 1.13 # undef ENABLE_VOSF
107     # define ENABLE_VOSF 1
108     #endif
109    
110 cebix 1.6 /* ExtFS is supported */
111     #define SUPPORTS_EXTFS 1
112 cebix 1.11
113 cebix 1.20 /* BSD socket API supported */
114     #define SUPPORTS_UDP_TUNNEL 1
115    
116 gbeauche 1.33 /* Use the CPU emulator to check for periodic tasks? */
117     #ifdef HAVE_PTHREADS
118     #define USE_PTHREADS_SERVICES
119     #endif
120     #if EMULATED_68K
121     #if defined(__NetBSD__)
122     #define USE_CPU_EMUL_SERVICES
123     #endif
124     #endif
125     #ifdef USE_CPU_EMUL_SERVICES
126     #undef USE_PTHREADS_SERVICES
127     #endif
128    
129 cebix 1.6
130 cebix 1.1 /* 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 cebix 1.8 #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 cebix 1.8 #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 gbeauche 1.13 #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 cebix 1.1 #endif
173    
174 nigel 1.27 #ifndef HAVE_LOFF_T
175 gbeauche 1.28 typedef off_t loff_t;
176     #endif
177     #ifndef HAVE_CADDR_T
178     typedef char * caddr_t;
179 nigel 1.27 #endif
180    
181 cebix 1.1 /* Time data type for Time Manager emulation */
182     #ifdef HAVE_CLOCK_GETTIME
183     typedef struct timespec tm_time_t;
184 asvitkine 1.35 #elif defined(__MACH__)
185     typedef mach_timespec_t tm_time_t;
186 cebix 1.1 #else
187     typedef struct timeval tm_time_t;
188     #endif
189    
190 gbeauche 1.23 /* Define codes for all the float formats that we know of.
191     * Though we only handle IEEE format. */
192     #define UNKNOWN_FLOAT_FORMAT 0
193     #define IEEE_FLOAT_FORMAT 1
194     #define VAX_FLOAT_FORMAT 2
195     #define IBM_FLOAT_FORMAT 3
196     #define C4X_FLOAT_FORMAT 4
197    
198 cebix 1.1 /* UAE CPU data types */
199     #define uae_s8 int8
200     #define uae_u8 uint8
201     #define uae_s16 int16
202     #define uae_u16 uint16
203     #define uae_s32 int32
204     #define uae_u32 uint32
205 cebix 1.7 #define uae_s64 int64
206     #define uae_u64 uint64
207 cebix 1.1 typedef uae_u32 uaecptr;
208    
209     /* Alignment restrictions */
210 gbeauche 1.25 #if defined(__i386__) || defined(__powerpc__) || defined(__m68k__) || defined(__x86_64__)
211 cebix 1.1 # define CPU_CAN_ACCESS_UNALIGNED
212     #endif
213    
214 cebix 1.12 /* Timing functions */
215     extern uint64 GetTicks_usec(void);
216     extern void Delay_usec(uint32 usec);
217    
218 gbeauche 1.31 /* Spinlocks */
219     #ifdef __GNUC__
220    
221     #if defined(__powerpc__) || defined(__ppc__)
222     #define HAVE_TEST_AND_SET 1
223     static inline int testandset(volatile int *p)
224     {
225     int ret;
226     __asm__ __volatile__("0: lwarx %0,0,%1\n"
227     " xor. %0,%3,%0\n"
228     " bne 1f\n"
229     " stwcx. %2,0,%1\n"
230     " bne- 0b\n"
231     "1: "
232     : "=&r" (ret)
233     : "r" (p), "r" (1), "r" (0)
234     : "cr0", "memory");
235     return ret;
236     }
237     #endif
238    
239     /* FIXME: SheepShaver occasionnally hangs with those locks */
240     #if 0 && (defined(__i386__) || defined(__x86_64__))
241     #define HAVE_TEST_AND_SET 1
242     static inline int testandset(volatile int *p)
243     {
244     long int ret;
245     /* Note: the "xchg" instruction does not need a "lock" prefix */
246     __asm__ __volatile__("xchgl %k0, %1"
247     : "=r" (ret), "=m" (*p)
248     : "0" (1), "m" (*p)
249     : "memory");
250     return ret;
251     }
252     #endif
253    
254     #ifdef __s390__
255     #define HAVE_TEST_AND_SET 1
256     static inline int testandset(volatile int *p)
257     {
258     int ret;
259    
260     __asm__ __volatile__("0: cs %0,%1,0(%2)\n"
261     " jl 0b"
262     : "=&d" (ret)
263     : "r" (1), "a" (p), "0" (*p)
264     : "cc", "memory" );
265     return ret;
266     }
267     #endif
268    
269     #ifdef __alpha__
270     #define HAVE_TEST_AND_SET 1
271     static inline int testandset(volatile int *p)
272     {
273     int ret;
274     unsigned long one;
275    
276     __asm__ __volatile__("0: mov 1,%2\n"
277     " ldl_l %0,%1\n"
278     " stl_c %2,%1\n"
279     " beq %2,1f\n"
280     ".subsection 2\n"
281     "1: br 0b\n"
282     ".previous"
283     : "=r" (ret), "=m" (*p), "=r" (one)
284     : "m" (*p));
285     return ret;
286     }
287     #endif
288    
289     #ifdef __sparc__
290     #define HAVE_TEST_AND_SET 1
291     static inline int testandset(volatile int *p)
292     {
293     int ret;
294    
295     __asm__ __volatile__("ldstub [%1], %0"
296     : "=r" (ret)
297     : "r" (p)
298     : "memory");
299    
300     return (ret ? 1 : 0);
301     }
302     #endif
303    
304     #ifdef __arm__
305     #define HAVE_TEST_AND_SET 1
306     static inline int testandset(volatile int *p)
307     {
308     register unsigned int ret;
309     __asm__ __volatile__("swp %0, %1, [%2]"
310     : "=r"(ret)
311     : "0"(1), "r"(p));
312    
313     return ret;
314     }
315     #endif
316    
317     #endif /* __GNUC__ */
318    
319     typedef volatile int spinlock_t;
320    
321     static const spinlock_t SPIN_LOCK_UNLOCKED = 0;
322    
323     #if HAVE_TEST_AND_SET
324     #define HAVE_SPINLOCKS 1
325     static inline void spin_lock(spinlock_t *lock)
326     {
327     while (testandset(lock));
328     }
329    
330     static inline void spin_unlock(spinlock_t *lock)
331     {
332     *lock = 0;
333     }
334    
335     static inline int spin_trylock(spinlock_t *lock)
336     {
337     return !testandset(lock);
338     }
339     #else
340     static inline void spin_lock(spinlock_t *lock)
341     {
342     }
343    
344     static inline void spin_unlock(spinlock_t *lock)
345     {
346     }
347    
348     static inline int spin_trylock(spinlock_t *lock)
349     {
350     return 1;
351     }
352     #endif
353    
354     /* X11 display fast locks */
355     #ifdef HAVE_SPINLOCKS
356     #define X11_LOCK_TYPE spinlock_t
357     #define X11_LOCK_INIT SPIN_LOCK_UNLOCKED
358     #define XDisplayLock() spin_lock(&x_display_lock)
359     #define XDisplayUnlock() spin_unlock(&x_display_lock)
360     #elif defined(HAVE_PTHREADS)
361     #define X11_LOCK_TYPE pthread_mutex_t
362     #define X11_LOCK_INIT PTHREAD_MUTEX_INITIALIZER
363     #define XDisplayLock() pthread_mutex_lock(&x_display_lock);
364     #define XDisplayUnlock() pthread_mutex_unlock(&x_display_lock);
365     #else
366     #define XDisplayLock()
367     #define XDisplayUnlock()
368     #endif
369     #ifdef X11_LOCK_TYPE
370     extern X11_LOCK_TYPE x_display_lock;
371     #endif
372    
373 cebix 1.22 #ifdef HAVE_PTHREADS
374     /* Centralized pthread attribute setup */
375     void Set_pthread_attr(pthread_attr_t *attr, int priority);
376     #endif
377    
378 cebix 1.1 /* UAE CPU defines */
379     #ifdef WORDS_BIGENDIAN
380    
381     #ifdef CPU_CAN_ACCESS_UNALIGNED
382    
383     /* Big-endian CPUs which can do unaligned accesses */
384     static inline uae_u32 do_get_mem_long(uae_u32 *a) {return *a;}
385     static inline uae_u32 do_get_mem_word(uae_u16 *a) {return *a;}
386     static inline void do_put_mem_long(uae_u32 *a, uae_u32 v) {*a = v;}
387     static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {*a = v;}
388    
389     #else /* CPU_CAN_ACCESS_UNALIGNED */
390    
391     #ifdef sgi
392     /* The SGI MIPSPro compilers can do unaligned accesses given enough hints.
393     * They will automatically inline these routines. */
394     #ifdef __cplusplus
395     extern "C" { /* only the C compiler does unaligned accesses */
396     #endif
397     extern uae_u32 do_get_mem_long(uae_u32 *a);
398     extern uae_u32 do_get_mem_word(uae_u16 *a);
399     extern void do_put_mem_long(uae_u32 *a, uae_u32 v);
400     extern void do_put_mem_word(uae_u16 *a, uae_u32 v);
401     #ifdef __cplusplus
402     }
403     #endif
404    
405     #else /* sgi */
406    
407     /* Big-endian CPUs which can not do unaligned accesses (this is not the most efficient way to do this...) */
408     static inline uae_u32 do_get_mem_long(uae_u32 *a) {uint8 *b = (uint8 *)a; return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];}
409     static inline uae_u32 do_get_mem_word(uae_u16 *a) {uint8 *b = (uint8 *)a; return (b[0] << 8) | b[1];}
410     static inline void do_put_mem_long(uae_u32 *a, uae_u32 v) {uint8 *b = (uint8 *)a; b[0] = v >> 24; b[1] = v >> 16; b[2] = v >> 8; b[3] = v;}
411     static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {uint8 *b = (uint8 *)a; b[0] = v >> 8; b[1] = v;}
412     #endif /* sgi */
413    
414     #endif /* CPU_CAN_ACCESS_UNALIGNED */
415    
416     #else /* WORDS_BIGENDIAN */
417    
418 gbeauche 1.25 #if defined(__i386__) || defined(__x86_64__)
419 cebix 1.1
420     /* Intel x86 */
421     #define X86_PPRO_OPT
422     static inline uae_u32 do_get_mem_long(uae_u32 *a) {uint32 retval; __asm__ ("bswap %0" : "=r" (retval) : "0" (*a) : "cc"); return retval;}
423     #ifdef X86_PPRO_OPT
424     static inline uae_u32 do_get_mem_word(uae_u16 *a) {uint32 retval; __asm__ ("movzwl %w1,%k0\n\tshll $16,%k0\n\tbswapl %k0\n" : "=&r" (retval) : "m" (*a) : "cc"); return retval;}
425     #else
426     static inline uae_u32 do_get_mem_word(uae_u16 *a) {uint32 retval; __asm__ ("xorl %k0,%k0\n\tmovw %w1,%w0\n\trolw $8,%w0" : "=&r" (retval) : "m" (*a) : "cc"); return retval;}
427     #endif
428     #define HAVE_GET_WORD_UNSWAPPED
429     #define do_get_mem_word_unswapped(a) ((uae_u32)*((uae_u16 *)(a)))
430     static inline void do_put_mem_long(uae_u32 *a, uae_u32 v) {__asm__ ("bswap %0" : "=r" (v) : "0" (v) : "cc"); *a = v;}
431     #ifdef X86_PPRO_OPT
432     static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {__asm__ ("bswapl %0" : "=&r" (v) : "0" (v << 16) : "cc"); *a = v;}
433     #else
434     static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {__asm__ ("rolw $8,%0" : "=r" (v) : "0" (v) : "cc"); *a = v;}
435     #endif
436 gbeauche 1.16 #define HAVE_OPTIMIZED_BYTESWAP_32
437     /* bswap doesn't affect condition codes */
438     static inline uae_u32 do_byteswap_32(uae_u32 v) {__asm__ ("bswap %0" : "=r" (v) : "0" (v)); return v;}
439     #define HAVE_OPTIMIZED_BYTESWAP_16
440     #ifdef X86_PPRO_OPT
441     static inline uae_u32 do_byteswap_16(uae_u32 v) {__asm__ ("bswapl %0" : "=&r" (v) : "0" (v << 16) : "cc"); return v;}
442     #else
443     static inline uae_u32 do_byteswap_16(uae_u32 v) {__asm__ ("rolw $8,%0" : "=r" (v) : "0" (v) : "cc"); return v;}
444     #endif
445 cebix 1.1
446     #elif defined(CPU_CAN_ACCESS_UNALIGNED)
447    
448     /* Other little-endian CPUs which can do unaligned accesses */
449     static inline uae_u32 do_get_mem_long(uae_u32 *a) {uint32 x = *a; return (x >> 24) | (x >> 8) & 0xff00 | (x << 8) & 0xff0000 | (x << 24);}
450     static inline uae_u32 do_get_mem_word(uae_u16 *a) {uint16 x = *a; return (x >> 8) | (x << 8);}
451     static inline void do_put_mem_long(uae_u32 *a, uae_u32 v) {*a = (v >> 24) | (v >> 8) & 0xff00 | (v << 8) & 0xff0000 | (v << 24);}
452     static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {*a = (v >> 8) | (v << 8);}
453    
454     #else /* CPU_CAN_ACCESS_UNALIGNED */
455    
456     /* Other little-endian CPUs which can not do unaligned accesses (this needs optimization) */
457     static inline uae_u32 do_get_mem_long(uae_u32 *a) {uint8 *b = (uint8 *)a; return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];}
458     static inline uae_u32 do_get_mem_word(uae_u16 *a) {uint8 *b = (uint8 *)a; return (b[0] << 8) | b[1];}
459     static inline void do_put_mem_long(uae_u32 *a, uae_u32 v) {uint8 *b = (uint8 *)a; b[0] = v >> 24; b[1] = v >> 16; b[2] = v >> 8; b[3] = v;}
460     static inline void do_put_mem_word(uae_u16 *a, uae_u32 v) {uint8 *b = (uint8 *)a; b[0] = v >> 8; b[1] = v;}
461    
462     #endif /* CPU_CAN_ACCESS_UNALIGNED */
463    
464     #endif /* WORDS_BIGENDIAN */
465 gbeauche 1.16
466     #ifndef HAVE_OPTIMIZED_BYTESWAP_32
467     static inline uae_u32 do_byteswap_32(uae_u32 v)
468     { return (((v >> 24) & 0xff) | ((v >> 8) & 0xff00) | ((v & 0xff) << 24) | ((v & 0xff00) << 8)); }
469     #endif
470    
471     #ifndef HAVE_OPTIMIZED_BYTESWAP_16
472     static inline uae_u32 do_byteswap_16(uae_u32 v)
473     { return (((v >> 8) & 0xff) | ((v & 0xff) << 8)); }
474     #endif
475 cebix 1.1
476     #define do_get_mem_byte(a) ((uae_u32)*((uae_u8 *)(a)))
477     #define do_put_mem_byte(a, v) (*(uae_u8 *)(a) = (v))
478    
479     #define call_mem_get_func(func, addr) ((*func)(addr))
480     #define call_mem_put_func(func, addr, v) ((*func)(addr, v))
481     #define __inline__ inline
482     #define CPU_EMU_SIZE 0
483     #undef NO_INLINE_MEMORY_ACCESS
484     #undef MD_HAVE_MEM_1_FUNCS
485     #define ENUMDECL typedef enum
486     #define ENUMNAME(name) name
487     #define write_log printf
488    
489 gbeauche 1.26 #if defined(X86_ASSEMBLY) || defined(X86_64_ASSEMBLY)
490 cebix 1.1 #define ASM_SYM_FOR_FUNC(a) __asm__(a)
491     #else
492     #define ASM_SYM_FOR_FUNC(a)
493     #endif
494    
495     #ifndef REGPARAM
496     # define REGPARAM
497     #endif
498     #define REGPARAM2
499    
500     #endif