add a new generic x86 machdep directory

this merges i386 and x86_64 into a single dir.
the few differences use #ifdef __x86_64__.
This commit is contained in:
rofl0r 2014-01-30 23:45:41 +01:00
parent ba2582df1e
commit ce51f99dc8
7 changed files with 898 additions and 0 deletions

View File

@ -0,0 +1,10 @@
AM_CPPFLAGS = @UAE_CPPFLAGS@
AM_CPPFLAGS += -I$(top_srcdir)/src/include -I$(top_builddir)/src -I$(top_srcdir)/src
AM_CFLAGS = @UAE_CFLAGS@
AM_CXXFLAGS = @UAE_CXXFLAGS@
noinst_LIBRARIES = libmachdep.a
libmachdep_a_SOURCES = support.c
noinst_HEADERS = machdep.h m68k.h m68kops.h maccess.h rpt.h

97
src/md-x86-gcc/m68k.h Normal file
View File

@ -0,0 +1,97 @@
/*
* UAE - The Un*x Amiga Emulator
*
* MC68000 emulation - machine dependent bits
*
* Copyright 1996 Bernd Schmidt
* Copyright 2004-2007 Richard Drummond
*/
/*
* Machine dependent structure for holding the 68k CCR flags
*/
struct flag_struct {
unsigned int cznv;
unsigned int x;
};
extern struct flag_struct regflags;
/*
* The bits in the cznv field in the above structure are assigned to
* allow the easy mirroring of the x86 condition flags. (For example,
* from the AX register - the x86 overflow flag can be copied to AL
* with a setto %AL instr and the other flags copied to AH with an
* lahf instr).
*
* The 68k CZNV flags are thus assigned in cznv as:
*
* <--AL--> <--AH-->
* 76543210 FEDCBA98 --------- ---------
* xxxxxxxV NZxxxxxC xxxxxxxxx xxxxxxxxx
*/
#define FLAGBIT_N 15
#define FLAGBIT_Z 14
#define FLAGBIT_C 8
#define FLAGBIT_V 0
#define FLAGBIT_X 8
#define FLAGVAL_N (1 << FLAGBIT_N)
#define FLAGVAL_Z (1 << FLAGBIT_Z)
#define FLAGVAL_C (1 << FLAGBIT_C)
#define FLAGVAL_V (1 << FLAGBIT_V)
#define FLAGVAL_X (1 << FLAGBIT_X)
#define SET_ZFLG(y) (regflags.cznv = (regflags.cznv & ~FLAGVAL_Z) | (((y) ? 1 : 0) << FLAGBIT_Z))
#define SET_CFLG(y) (regflags.cznv = (regflags.cznv & ~FLAGVAL_C) | (((y) ? 1 : 0) << FLAGBIT_C))
#define SET_VFLG(y) (regflags.cznv = (regflags.cznv & ~FLAGVAL_V) | (((y) ? 1 : 0) << FLAGBIT_V))
#define SET_NFLG(y) (regflags.cznv = (regflags.cznv & ~FLAGVAL_N) | (((y) ? 1 : 0) << FLAGBIT_N))
#define SET_XFLG(y) (regflags.x = ((y) ? 1 : 0) << FLAGBIT_X)
#define GET_ZFLG() ((regflags.cznv >> FLAGBIT_Z) & 1)
#define GET_CFLG() ((regflags.cznv >> FLAGBIT_C) & 1)
#define GET_VFLG() ((regflags.cznv >> FLAGBIT_V) & 1)
#define GET_NFLG() ((regflags.cznv >> FLAGBIT_N) & 1)
#define GET_XFLG() ((regflags.x >> FLAGBIT_X) & 1)
#define CLEAR_CZNV() (regflags.cznv = 0)
#define GET_CZNV (regflags.cznv)
#define IOR_CZNV(X) (regflags.cznv |= (X))
#define SET_CZNV(X) (regflags.cznv = (X))
#define COPY_CARRY() (regflags.x = regflags.cznv)
/*
* Test CCR condition
*/
STATIC_INLINE int cctrue (int cc)
{
uae_u32 cznv = regflags.cznv;
switch (cc) {
case 0: return 1; /* T */
case 1: return 0; /* F */
case 2: return (cznv & (FLAGVAL_C | FLAGVAL_Z)) == 0; /* !CFLG && !ZFLG HI */
case 3: return (cznv & (FLAGVAL_C | FLAGVAL_Z)) != 0; /* CFLG || ZFLG LS */
case 4: return (cznv & FLAGVAL_C) == 0; /* !CFLG CC */
case 5: return (cznv & FLAGVAL_C) != 0; /* CFLG CS */
case 6: return (cznv & FLAGVAL_Z) == 0; /* !ZFLG NE */
case 7: return (cznv & FLAGVAL_Z) != 0; /* ZFLG EQ */
case 8: return (cznv & FLAGVAL_V) == 0; /* !VFLG VC */
case 9: return (cznv & FLAGVAL_V) != 0; /* VFLG VS */
case 10: return (cznv & FLAGVAL_N) == 0; /* !NFLG PL */
case 11: return (cznv & FLAGVAL_N) != 0; /* NFLG MI */
case 12: return (((cznv << (FLAGBIT_N - FLAGBIT_V)) ^ cznv) & FLAGVAL_N) == 0; /* NFLG == VFLG GE */
case 13: return (((cznv << (FLAGBIT_N - FLAGBIT_V)) ^ cznv) & FLAGVAL_N) != 0; /* NFLG != VFLG LT */
case 14: cznv &= (FLAGVAL_N | FLAGVAL_Z | FLAGVAL_V); /* ZFLG && (NFLG == VFLG) GT */
return (((cznv << (FLAGBIT_N - FLAGBIT_V)) ^ cznv) & (FLAGVAL_N | FLAGVAL_Z)) == 0;
case 15: cznv &= (FLAGVAL_N | FLAGVAL_Z | FLAGVAL_V); /* ZFLG && (NFLG != VFLG) LE */
return (((cznv << (FLAGBIT_N - FLAGBIT_V)) ^ cznv) & (FLAGVAL_N | FLAGVAL_Z)) != 0;
}
abort ();
return 0;
}
#define USE_X86_FPUCW 1

242
src/md-x86-gcc/m68kops.h Normal file
View File

@ -0,0 +1,242 @@
/*
* E-UAE - The portable Amiga Emulator
*
* MC68000 emulation - machine-dependent optimized operations
*
* (c) 2004-2007 Richard Drummond
*/
#ifndef EUAE_MACHDEP_M68KOPS_H
#define EUAE_MACHDEP_M68KOPS_H
/*
* Optimized code which uses the host CPU's condition flags to evaluate
* 68K CCR flags for certain operations.
*
* These are used by various opcode handlers when
* gencpu has been built with OPTIMIZED_FLAGS defined
*/
/*
* Test operations
*
* Evaluate operand and set Z and N flags. Always clear C and V.
*/
/* Is there any way to do this without declaring *all* memory clobbered?
I.e. any way to tell gcc that some byte-sized value is in %al? */
//#if defined(__APPLE__) && !defined(__x86_64__)
#ifndef __x86_64__
#define optflag_testl(v) \
__asm__ __volatile__ ("andl %0,%0\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,_regflags\n\t" \
"movb %%ah,_regflags+1\n\t" \
:: "r" (v) : "%eax","cc","memory")
#define optflag_testw(v) \
__asm__ __volatile__ ("andw %w0,%w0\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,_regflags\n\t" \
"movb %%ah,_regflags+1\n\t" \
:: "r" (v) : "%eax","cc","memory")
#define optflag_testb(v) \
__asm__ __volatile__ ("andb %b0,%b0\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,_regflags\n\t" \
"movb %%ah,_regflags+1\n\t" \
:: "q" (v) : "%eax","cc","memory")
#define optflag_addl(v, s, d) do { \
__asm__ __volatile__ ("addl %k1,%k0\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,_regflags\n\t" \
"movb %%ah,_regflags+1\n\t" \
:"=r" (v) : "rmi" (s), "0" (d) : "%eax","cc","memory"); \
regflags.x = regflags.cznv; \
} while (0)
#define optflag_addw(v, s, d) do { \
__asm__ __volatile__ ("addw %w1,%w0\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,_regflags\n\t" \
"movb %%ah,_regflags+1\n\t" \
: "=r" (v) : "rmi" (s), "0" (d) : "%eax","cc","memory"); \
regflags.x = regflags.cznv; \
} while (0)
#define optflag_addb(v, s, d) do { \
__asm__ __volatile__ ("addb %b1,%b0\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,_regflags\n\t" \
"movb %%ah,_regflags+1\n\t" \
:"=q" (v) : "qmi" (s), "0" (d) : "%eax","cc","memory"); \
regflags.x = regflags.cznv; \
} while (0)
#define optflag_subl(v, s, d) do { \
__asm__ __volatile__ ("subl %k1,%k0\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,_regflags\n\t" \
"movb %%ah,_regflags+1\n\t" \
: "=r" (v) : "rmi" (s), "0" (d) : "%eax","cc","memory"); \
regflags.x = regflags.cznv; \
} while (0)
#define optflag_subw(v, s, d) do { \
__asm__ __volatile__ ("subw %w1,%w0\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,_regflags\n\t" \
"movb %%ah,_regflags+1\n\t" \
: "=r" (v) : "rmi" (s), "0" (d) : "%eax","cc","memory"); \
regflags.x = regflags.cznv; \
} while (0)
#define optflag_subb(v, s, d) do { \
__asm__ __volatile__ ("subb %b1,%b0\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,_regflags\n\t" \
"movb %%ah,_regflags+1\n\t" \
: "=q" (v) : "qmi" (s), "0" (d) : "%eax","cc","memory"); \
regflags.x = regflags.cznv; \
} while (0)
#define optflag_cmpl(s, d) \
__asm__ __volatile__ ("cmpl %k0,%k1\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,_regflags\n\t" \
"movb %%ah,_regflags+1\n\t" \
:: "rmi" (s), "r" (d) : "%eax","cc","memory")
#define optflag_cmpw(s, d) \
__asm__ __volatile__ ("cmpw %w0,%w1\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,_regflags\n\t" \
"movb %%ah,_regflags+1\n\t" \
:: "rmi" (s), "r" (d) : "%eax","cc","memory");
#define optflag_cmpb(s, d) \
__asm__ __volatile__ ("cmpb %b0,%b1\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,_regflags\n\t" \
"movb %%ah,_regflags+1\n\t" \
:: "qmi" (s), "q" (d) : "%eax","cc","memory")
#else /*ifdef apple*/
#define optflag_testl(v) \
__asm__ __volatile__ ("andl %0,%0\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,regflags\n\t" \
"movb %%ah,regflags+1\n\t" \
:: "r" (v) : "%eax","cc","memory")
#define optflag_testw(v) \
__asm__ __volatile__ ("andw %w0,%w0\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,regflags\n\t" \
"movb %%ah,regflags+1\n\t" \
:: "r" (v) : "%eax","cc","memory")
#define optflag_testb(v) \
__asm__ __volatile__ ("andb %b0,%b0\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,regflags\n\t" \
"movb %%ah,regflags+1\n\t" \
:: "q" (v) : "%eax","cc","memory")
#define optflag_addl(v, s, d) do { \
__asm__ __volatile__ ("addl %k1,%k0\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,regflags\n\t" \
"movb %%ah,regflags+1\n\t" \
:"=r" (v) : "rmi" (s), "0" (d) : "%eax","cc","memory"); \
regflags.x = regflags.cznv; \
} while (0)
#define optflag_addw(v, s, d) do { \
__asm__ __volatile__ ("addw %w1,%w0\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,regflags\n\t" \
"movb %%ah,regflags+1\n\t" \
: "=r" (v) : "rmi" (s), "0" (d) : "%eax","cc","memory"); \
regflags.x = regflags.cznv; \
} while (0)
#define optflag_addb(v, s, d) do { \
__asm__ __volatile__ ("addb %b1,%b0\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,regflags\n\t" \
"movb %%ah,regflags+1\n\t" \
:"=q" (v) : "qmi" (s), "0" (d) : "%eax","cc","memory"); \
regflags.x = regflags.cznv; \
} while (0)
#define optflag_subl(v, s, d) do { \
__asm__ __volatile__ ("subl %k1,%k0\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,regflags\n\t" \
"movb %%ah,regflags+1\n\t" \
: "=r" (v) : "rmi" (s), "0" (d) : "%eax","cc","memory"); \
regflags.x = regflags.cznv; \
} while (0)
#define optflag_subw(v, s, d) do { \
__asm__ __volatile__ ("subw %w1,%w0\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,regflags\n\t" \
"movb %%ah,regflags+1\n\t" \
: "=r" (v) : "rmi" (s), "0" (d) : "%eax","cc","memory"); \
regflags.x = regflags.cznv; \
} while (0)
#define optflag_subb(v, s, d) do { \
__asm__ __volatile__ ("subb %b1,%b0\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,regflags\n\t" \
"movb %%ah,regflags+1\n\t" \
: "=q" (v) : "qmi" (s), "0" (d) : "%eax","cc","memory"); \
regflags.x = regflags.cznv; \
} while (0)
#define optflag_cmpl(s, d) \
__asm__ __volatile__ ("cmpl %k0,%k1\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,regflags\n\t" \
"movb %%ah,regflags+1\n\t" \
:: "rmi" (s), "r" (d) : "%eax","cc","memory")
#define optflag_cmpw(s, d) \
__asm__ __volatile__ ("cmpw %w0,%w1\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,regflags\n\t" \
"movb %%ah,regflags+1\n\t" \
:: "rmi" (s), "r" (d) : "%eax","cc","memory");
#define optflag_cmpb(s, d) \
__asm__ __volatile__ ("cmpb %b0,%b1\n\t" \
"lahf\n\t" \
"seto %%al\n\t" \
"movb %%al,regflags\n\t" \
"movb %%ah,regflags+1\n\t" \
:: "qmi" (s), "q" (d) : "%eax","cc","memory")
#endif /*ifdef apple*/
#endif /* EUAE_MACHDEP_M68KOPS_H */

159
src/md-x86-gcc/maccess.h Normal file
View File

@ -0,0 +1,159 @@
/*
* UAE - The Un*x Amiga Emulator
*
* Memory access functions
*
* Copyright 1996 Bernd Schmidt
*/
STATIC_INLINE uae_u32 do_get_mem_long (uae_u32 *a)
{
uae_u32 retval;
__asm__ ("bswap %0" : "=r" (retval) : "0" (*a) : "cc");
return retval;
}
STATIC_INLINE uae_u32 do_get_mem_word (uae_u16 *a)
{
#if 0
uae_u8 *b = (uae_u8 *)a;
return (*b << 8) | (*(b+1));
#endif
uae_u32 retval;
#ifdef X86_PPRO_OPT
__asm__ ("movzwl %w1,%k0\n\tshll $16,%k0\n\tbswap %k0\n" : "=&r" (retval) : "m" (*a) : "cc");
#else
__asm__ ("xorl %k0,%k0\n\tmovw %w1,%w0\n\trolw $8,%w0" : "=&r" (retval) : "m" (*a) : "cc");
#endif
return retval;
}
#define do_get_mem_byte(a) ((uae_u32)*((uae_u8 *)a))
STATIC_INLINE void do_put_mem_long (uae_u32 *a, uae_u32 v)
{
__asm__ ("bswap %0" : "=r" (v) : "0" (v) : "cc");
*a = v;
}
STATIC_INLINE void do_put_mem_word (uae_u16 *a, uae_u32 v)
{
#ifdef X86_PPRO_OPT
__asm__ ("bswap %0" : "=&r" (v) : "0" (v << 16) : "cc");
#else
__asm__ ("rolw $8,%w0" : "=r" (v) : "0" (v) : "cc");
#endif
*a = v;
}
#define do_put_mem_byte(a,v) (*(uae_u8 *)(a) = (v))
#define call_mem_get_func(func,addr) ((*func)(addr))
#define call_mem_put_func(func,addr,v) ((*func)(addr,v))
#define ALIGN_POINTER_TO32(p) ((~(unsigned long)(p)) & 3)
#ifndef __x86_64__
#undef NO_INLINE_MEMORY_ACCESS
#undef MD_HAVE_MEM_1_FUNCS
#ifdef MD_HAVE_MEM_1_FUNCS
STATIC_INLINE uae_u32 longget_1 (uae_cptr addr)
{
uae_u32 result;
__asm__ ("andl $0x00FFFFFF,%1\n"
"\tcmpb $0,(%1,%3)\n"
"\tleal 1f,%%ecx\n"
"\tje longget_stub\n"
"\taddl address_space,%1\n"
"\tmovl (%1),%0\n"
"\tbswap %0\n"
"\t1:"
: "=c" (result), "=d" (addr) : "1" (addr), "r" (good_address_map) : "cc");
return result;
}
STATIC_INLINE uae_u32 wordget_1 (uae_cptr addr)
{
uae_u32 result;
__asm__ ("andl $0x00FFFFFF,%1\n"
"\tcmpb $0,(%1,%3)\n"
"\tleal 1f,%%ecx\n"
"\tje wordget_stub\n"
"\taddl address_space,%1\n"
"\tmovzwl (%1),%0\n"
"\trolw $8,%w0\n"
"\t1:"
: "=c" (result), "=d" (addr) : "1" (addr), "r" (good_address_map) : "cc");
return result;
}
STATIC_INLINE uae_u32 byteget_1 (uae_cptr addr)
{
uae_u32 result;
__asm__ ("andl $0x00FFFFFF,%1\n"
"\tcmpb $0,(%1,%3)\n"
"\tleal 1f,%%ecx\n"
"\tje byteget_stub\n"
"\taddl address_space,%1\n"
"\tmovzbl (%1),%0\n"
"\t1:"
: "=c" (result), "=d" (addr) : "1" (addr), "r" (good_address_map) : "cc");
return result;
}
STATIC_INLINE void longput_1 (uae_cptr addr, uae_u32 l)
{
__asm__ __volatile__("andl $0x00FFFFFF,%0\n"
"\tcmpb $0,(%0,%3)\n"
"\tleal 1f,%%ecx\n"
"\tje longput_stub\n"
"\taddl address_space,%0\n"
"\tbswap %1\n"
"\tmovl %1,(%0)\n"
"\t1:"
: "=d" (addr), "=b" (l) : "0" (addr), "r" (good_address_map), "1" (l) : "cc", "memory", "ecx");
}
STATIC_INLINE void wordput_1 (uae_cptr addr, uae_u32 w)
{
__asm__ __volatile__("andl $0x00FFFFFF,%0\n"
"\tcmpb $0,(%0,%3)\n"
"\tleal 1f,%%ecx\n"
"\tje wordput_stub\n"
"\taddl address_space,%0\n"
"\trolw $8,%1\n"
"\tmovw %w1,(%0)\n"
"\t1:"
: "=d" (addr), "=b" (w) : "0" (addr), "r" (good_address_map), "1" (w) : "cc", "memory", "ecx");
}
STATIC_INLINE void byteput_1 (uae_cptr addr, uae_u32 b)
{
__asm__ __volatile__("andl $0x00FFFFFF,%0\n"
"\tcmpb $0,(%0,%3)\n"
"\tleal 1f,%%ecx\n"
"\tje byteput_stub\n"
"\taddl address_space,%0\n"
"\tmovb %b1,(%0)\n"
"\t1:"
: "=d" (addr), "=b" (b) : "0" (addr), "r" (good_address_map), "1" (b) : "cc", "memory", "ecx");
}
#endif
/* Not the best place for this, but then there's no good place for a kludge
* like this... */
#define HAVE_UAE_U24
typedef struct {
unsigned char a, b, c;
} __attribute__ ((packed)) uae_u24;
STATIC_INLINE uae_u24 uae24_convert (uae_u32 v)
{
return *(uae_u24 *)&v;
}
#endif

24
src/md-x86-gcc/machdep.h Normal file
View File

@ -0,0 +1,24 @@
/*
* E-UAE - The portable Amiga Emulator
*
* Processor-specific definitions
*
* Copyright 2005 Richard Drummond
*/
#ifndef MACHDEP_MACHDEP_H
#define MACHDEP_MACHDEP_H
#define MACHDEP_X86
#ifdef __x86_64__
#define MACHDEP_NAME "amd64"
#else
#define MACHDEP_NAME "x86"
#endif
#define HAVE_MACHDEP_TIMER
typedef uae_s64 frame_time_t;
#define MAX_FRAME_TIME 9223372036854775807LL
#endif

71
src/md-x86-gcc/rpt.h Normal file
View File

@ -0,0 +1,71 @@
/*
* E-UAE - The portable Amiga Emulator
*
* Read timestamp counter on an AMD64
*
* Copyright 2005 Richard Drummond
*
* Derived from the i386 version:
* Copyright 1997, 1998 Bernd Schmidt
* Copyright 2003-2005 Richard Drummond
*/
#ifndef EUAE_MACHDEP_RPT_H
#define EUAE_MACHDEP_RPT_H
STATIC_INLINE uae_s64 read_processor_time (void)
{
#ifndef __x86_64__
uae_u32 foo1, foo2;
#else
uae_s64 foo1, foo2;
#endif
uae_s64 tsc;
/* Don't assume the assembler knows rdtsc */
__asm__ __volatile__ (".byte 0x0f,0x31" : "=a" (foo1), "=d" (foo2) :);
tsc = (((uae_u64) foo2) << 32ULL) | (uae_u64) foo1;
#ifdef __linux__
/* Hack to synchronize syncbase and re-compute
* vsynctime when TSC frequency changes */
/* How many times per second tsc will be synced */
#define TSC_SYNC_FREQUENCY 8
{
extern frame_time_t linux_get_tsc_freq (void);
extern void compute_vsynctime (void);
// extern frame_time_t syncbaseo;
extern int syncbase;
static frame_time_t next_tsc_synctime;
static frame_time_t prev_syncbase;
if (tsc > next_tsc_synctime) {
uae_s64 new_tsc_freq = linux_get_tsc_freq ();
if (new_tsc_freq > 0) {
syncbase = new_tsc_freq;
next_tsc_synctime = tsc + (syncbase / TSC_SYNC_FREQUENCY);
if (syncbase != prev_syncbase) {
prev_syncbase = syncbase;
compute_vsynctime ();
}
}
}
}
#endif
return tsc;
}
STATIC_INLINE frame_time_t machdep_gethrtime (void)
{
return read_processor_time ();
}
frame_time_t machdep_gethrtimebase (void);
int machdep_inithrtimer (void);
#endif /* EUAE_MACHDEP_RPT_H */

295
src/md-x86-gcc/support.c Normal file
View File

@ -0,0 +1,295 @@
/*
* UAE - The Un*x Amiga Emulator
*
* Miscellaneous machine dependent support functions and definitions
*
* Copyright 1996 Bernd Schmidt
* Copyright 2003-2005 Richard Drummond
*/
#include "sysconfig.h"
#include "sysdeps.h"
#include "cfgfile.h"
#include "sleep.h"
#include "rpt.h"
#include "m68k.h"
#include "events.h"
#include "custom.h"
#ifndef USE_UNDERSCORE
#define LARGE_ALIGNMENT ".align 16\n"
#else
#define LARGE_ALIGNMENT ".align 4,0x90\n"
#endif
struct flag_struct regflags;
#include <signal.h>
/* internal prototypes */
void machdep_save_options (struct zfile *, const struct uae_prefs *);
int machdep_parse_option (struct uae_prefs *, const char *, const char *);
void machdep_default_options (struct uae_prefs *);
#ifdef __linux__
frame_time_t linux_get_tsc_freq (void);
/*
* Extract x86/AMD64 timestamp counter frequency
* from /proc/cpuinfo.
*
* TODO: Make this more robust.
*/
frame_time_t linux_get_tsc_freq (void)
{
int cpuinfo_fd;
char buffer[1024];
static uae_s64 tsc_freq = 0;
if(tsc_freq) return tsc_freq;
cpuinfo_fd = open ("/proc/cpuinfo", O_RDONLY);
if (cpuinfo_fd >= 0) {
char *ptr = &buffer[0];
int size_read = read (cpuinfo_fd, ptr, 1024);
while (size_read > 0) {
if (strncmp (ptr, "bogomips\t: ", 11) != 0) {
while ((size_read-- > 0) && (*ptr != '\n'))
ptr++;
size_read--;
ptr++;
continue;
} else {
ptr += 11;
tsc_freq = atoll (ptr) * 1000000 / 2;
}
}
}
close (cpuinfo_fd);
return tsc_freq;
}
#endif
#ifdef __BEOS__
# include <be/kernel/OS.h>
/*
* Get timestamp counter frequency from the kernel
*/
static frame_time_t beos_get_tsc_freq (void)
{
system_info info;
get_system_info (&info);
return info.cpu_clock_speed;
}
#endif
#ifdef __APPLE__
frame_time_t apple_get_tsc_freq (void)
{
int sysctl_hw;
char buffer[1024];
uae_s64 tsc_freq = 0;
sysctl_hw = open ("sysctl -a hw", O_RDONLY);
if (sysctl_hw >= 0) {
char *ptr = &buffer[0];
int size_read = read (sysctl_hw, ptr, 1024);
while (size_read > 0) {
if (strncmp (ptr, "hw.cpufrequency: ", 17) != 0) {
while ((size_read-- > 0) && (*ptr != '\n'))
ptr++;
size_read--;
ptr++;
continue;
} else {
ptr += 17;
tsc_freq = atoll (ptr) * 1000000 / 2;
}
}
}
close (sysctl_hw);
return tsc_freq;
}
#endif
static volatile frame_time_t last_time, best_time;
static frame_time_t timebase;
static volatile int loops_to_go;
#if defined HAVE_SETITIMER || defined HAVE_ALARM
# define USE_ALARM
# ifndef HAVE_SETITIMER
# define TIME_UNIT 1000000
# else
# define TIME_UNIT 100000
# endif
#else
# define TIME_DELAY 200
# define TIME_UNIT (TIME_DELAY*1000)
#endif
#ifndef HAVE_SYNC
# define sync()
#endif
#ifdef USE_ALARM
static void set_the_alarm (void)
{
# ifndef HAVE_SETITIMER
alarm (1);
# else
struct itimerval t;
t.it_value.tv_sec = 0;
t.it_value.tv_usec = TIME_UNIT;
t.it_interval.tv_sec = 0;
t.it_interval.tv_usec = TIME_UNIT;
setitimer (ITIMER_REAL, &t, NULL);
# endif
}
static int first_loop = 1;
#ifdef __cplusplus
static RETSIGTYPE alarmhandler(...)
#else
static RETSIGTYPE alarmhandler(int foo)
#endif
{
frame_time_t bar;
bar = read_processor_time ();
if (! first_loop && bar - last_time < best_time)
best_time = bar - last_time;
first_loop = 0;
if (--loops_to_go > 0) {
signal (SIGALRM, alarmhandler);
last_time = read_processor_time ();
set_the_alarm ();
} else {
alarm (0);
signal (SIGALRM, SIG_IGN);
}
}
#endif /* USE_ALARM */
#include <setjmp.h>
static jmp_buf catch_test;
#ifdef __cplusplus
static RETSIGTYPE illhandler (...)
#else
static RETSIGTYPE illhandler (int foo)
#endif
{
// rpt_available = 0;
longjmp (catch_test, 1);
}
int machdep_inithrtimer (void)
{
static int done = 0;
if (!done) {
// rpt_available = 1;
write_log ("Testing the RDTSC instruction ... ");
signal (SIGILL, illhandler);
if (setjmp (catch_test) == 0)
read_processor_time ();
signal (SIGILL, SIG_DFL);
write_log ("done.\n");
/* if (! rpt_available) {
write_log ("Your processor does not support the RDTSC instruction.\n");
return 0;
}*/
timebase = 0;
#ifdef __linux__
timebase = linux_get_tsc_freq ();
#else
#ifdef __BEOS__
timebase = beos_get_tsc_freq ();
#endif
#ifdef __APPLE__
// timebase = apple_get_tsc_freq ();
#endif
#endif
if (timebase <= 0) {
write_log ("Calibrating TSC frequency...");
flush_log ();
best_time = MAX_FRAME_TIME;
loops_to_go = 5;
#ifdef USE_ALARM
signal (SIGALRM, alarmhandler);
#endif
/* We want exact values... */
sync (); sync (); sync ();
#ifdef USE_ALARM
last_time = read_processor_time ();
set_the_alarm ();
while (loops_to_go != 0)
uae_msleep (10);
#else
int i = loops_to_go;
frame_time_t bar;
while (i-- > 0) {
last_time = read_processor_time ();
uae_msleep (TIME_DELAY);
bar = read_processor_time ();
if (i != loops_to_go && bar - last_time < best_time)
best_time = bar - last_time;
}
#endif
timebase = best_time * (1000000.0 / TIME_UNIT);
}
write_log ("TSC frequency: %f MHz\n", timebase / 1000000.0);
done = 1;
}
return done;
}
frame_time_t machdep_gethrtimebase (void)
{
return timebase;
}
int machdep_init (void)
{
return 1;
}
/*
* Handle processor-specific cfgfile options
*/
void machdep_save_options (struct zfile *f, const struct uae_prefs *p)
{
// cfgfile_write (f, MACHDEP_NAME ".use_tsc=%s\n", p->use_processor_clock ? "yes" : "no");
}
int machdep_parse_option (struct uae_prefs *p, const char *option, const char *value)
{
// return cfgfile_yesno (option, value, "use_tsc", &p->use_processor_clock);
return 0;
}
void machdep_default_options (struct uae_prefs *p)
{
}