7 |
|
* Gwenole Beauchesne |
8 |
|
* |
9 |
|
* Basilisk II (C) 1997-2002 Christian Bauer |
10 |
+ |
* |
11 |
+ |
* Portions related to CPU detection come from linux/arch/i386/kernel/setup.c |
12 |
|
* |
13 |
|
* This program is free software; you can redistribute it and/or modify |
14 |
|
* it under the terms of the GNU General Public License as published by |
1073 |
|
|
1074 |
|
LOWFUNC(NONE,READ,3,raw_mov_l_rR,(W4 d, R4 s, IMM offset)) |
1075 |
|
{ |
1076 |
+ |
Dif(!isbyte(offset)) abort(); |
1077 |
|
emit_byte(0x8b); |
1078 |
|
emit_byte(0x40+8*d+s); |
1079 |
|
emit_byte(offset); |
1082 |
|
|
1083 |
|
LOWFUNC(NONE,READ,3,raw_mov_w_rR,(W2 d, R4 s, IMM offset)) |
1084 |
|
{ |
1085 |
+ |
Dif(!isbyte(offset)) abort(); |
1086 |
|
emit_byte(0x66); |
1087 |
|
emit_byte(0x8b); |
1088 |
|
emit_byte(0x40+8*d+s); |
1092 |
|
|
1093 |
|
LOWFUNC(NONE,READ,3,raw_mov_b_rR,(W1 d, R4 s, IMM offset)) |
1094 |
|
{ |
1095 |
+ |
Dif(!isbyte(offset)) abort(); |
1096 |
|
emit_byte(0x8a); |
1097 |
|
emit_byte(0x40+8*d+s); |
1098 |
|
emit_byte(offset); |
1126 |
|
|
1127 |
|
LOWFUNC(NONE,WRITE,3,raw_mov_l_Ri,(R4 d, IMM i, IMM offset)) |
1128 |
|
{ |
1129 |
+ |
Dif(!isbyte(offset)) abort(); |
1130 |
|
emit_byte(0xc7); |
1131 |
|
emit_byte(0x40+d); |
1132 |
|
emit_byte(offset); |
1136 |
|
|
1137 |
|
LOWFUNC(NONE,WRITE,3,raw_mov_w_Ri,(R4 d, IMM i, IMM offset)) |
1138 |
|
{ |
1139 |
+ |
Dif(!isbyte(offset)) abort(); |
1140 |
|
emit_byte(0x66); |
1141 |
|
emit_byte(0xc7); |
1142 |
|
emit_byte(0x40+d); |
1147 |
|
|
1148 |
|
LOWFUNC(NONE,WRITE,3,raw_mov_b_Ri,(R4 d, IMM i, IMM offset)) |
1149 |
|
{ |
1150 |
+ |
Dif(!isbyte(offset)) abort(); |
1151 |
|
emit_byte(0xc6); |
1152 |
|
emit_byte(0x40+d); |
1153 |
|
emit_byte(offset); |
1157 |
|
|
1158 |
|
LOWFUNC(NONE,WRITE,3,raw_mov_l_Rr,(R4 d, R4 s, IMM offset)) |
1159 |
|
{ |
1160 |
+ |
Dif(!isbyte(offset)) abort(); |
1161 |
|
emit_byte(0x89); |
1162 |
|
emit_byte(0x40+8*s+d); |
1163 |
|
emit_byte(offset); |
1166 |
|
|
1167 |
|
LOWFUNC(NONE,WRITE,3,raw_mov_w_Rr,(R4 d, R2 s, IMM offset)) |
1168 |
|
{ |
1169 |
+ |
Dif(!isbyte(offset)) abort(); |
1170 |
|
emit_byte(0x66); |
1171 |
|
emit_byte(0x89); |
1172 |
|
emit_byte(0x40+8*s+d); |
1176 |
|
|
1177 |
|
LOWFUNC(NONE,WRITE,3,raw_mov_b_Rr,(R4 d, R1 s, IMM offset)) |
1178 |
|
{ |
1179 |
+ |
Dif(!isbyte(offset)) abort(); |
1180 |
|
emit_byte(0x88); |
1181 |
|
emit_byte(0x40+8*s+d); |
1182 |
|
emit_byte(offset); |
2066 |
|
emit_byte(0x90); |
2067 |
|
} |
2068 |
|
|
2069 |
+ |
static __inline__ void raw_emit_nop_filler(int nbytes) |
2070 |
+ |
{ |
2071 |
+ |
/* Source: GNU Binutils 2.12.90.0.15 */ |
2072 |
+ |
/* Various efficient no-op patterns for aligning code labels. |
2073 |
+ |
Note: Don't try to assemble the instructions in the comments. |
2074 |
+ |
0L and 0w are not legal. */ |
2075 |
+ |
static const uae_u8 f32_1[] = |
2076 |
+ |
{0x90}; /* nop */ |
2077 |
+ |
static const uae_u8 f32_2[] = |
2078 |
+ |
{0x89,0xf6}; /* movl %esi,%esi */ |
2079 |
+ |
static const uae_u8 f32_3[] = |
2080 |
+ |
{0x8d,0x76,0x00}; /* leal 0(%esi),%esi */ |
2081 |
+ |
static const uae_u8 f32_4[] = |
2082 |
+ |
{0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */ |
2083 |
+ |
static const uae_u8 f32_5[] = |
2084 |
+ |
{0x90, /* nop */ |
2085 |
+ |
0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */ |
2086 |
+ |
static const uae_u8 f32_6[] = |
2087 |
+ |
{0x8d,0xb6,0x00,0x00,0x00,0x00}; /* leal 0L(%esi),%esi */ |
2088 |
+ |
static const uae_u8 f32_7[] = |
2089 |
+ |
{0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */ |
2090 |
+ |
static const uae_u8 f32_8[] = |
2091 |
+ |
{0x90, /* nop */ |
2092 |
+ |
0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */ |
2093 |
+ |
static const uae_u8 f32_9[] = |
2094 |
+ |
{0x89,0xf6, /* movl %esi,%esi */ |
2095 |
+ |
0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ |
2096 |
+ |
static const uae_u8 f32_10[] = |
2097 |
+ |
{0x8d,0x76,0x00, /* leal 0(%esi),%esi */ |
2098 |
+ |
0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ |
2099 |
+ |
static const uae_u8 f32_11[] = |
2100 |
+ |
{0x8d,0x74,0x26,0x00, /* leal 0(%esi,1),%esi */ |
2101 |
+ |
0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ |
2102 |
+ |
static const uae_u8 f32_12[] = |
2103 |
+ |
{0x8d,0xb6,0x00,0x00,0x00,0x00, /* leal 0L(%esi),%esi */ |
2104 |
+ |
0x8d,0xbf,0x00,0x00,0x00,0x00}; /* leal 0L(%edi),%edi */ |
2105 |
+ |
static const uae_u8 f32_13[] = |
2106 |
+ |
{0x8d,0xb6,0x00,0x00,0x00,0x00, /* leal 0L(%esi),%esi */ |
2107 |
+ |
0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ |
2108 |
+ |
static const uae_u8 f32_14[] = |
2109 |
+ |
{0x8d,0xb4,0x26,0x00,0x00,0x00,0x00, /* leal 0L(%esi,1),%esi */ |
2110 |
+ |
0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ |
2111 |
+ |
static const uae_u8 f32_15[] = |
2112 |
+ |
{0xeb,0x0d,0x90,0x90,0x90,0x90,0x90, /* jmp .+15; lotsa nops */ |
2113 |
+ |
0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90}; |
2114 |
+ |
static const uae_u8 f32_16[] = |
2115 |
+ |
{0xeb,0x0d,0x90,0x90,0x90,0x90,0x90, /* jmp .+15; lotsa nops */ |
2116 |
+ |
0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90}; |
2117 |
+ |
static const uae_u8 *const f32_patt[] = { |
2118 |
+ |
f32_1, f32_2, f32_3, f32_4, f32_5, f32_6, f32_7, f32_8, |
2119 |
+ |
f32_9, f32_10, f32_11, f32_12, f32_13, f32_14, f32_15 |
2120 |
+ |
}; |
2121 |
+ |
|
2122 |
+ |
int nloops = nbytes / 16; |
2123 |
+ |
while (nloops-- > 0) |
2124 |
+ |
emit_block(f32_16, sizeof(f32_16)); |
2125 |
+ |
|
2126 |
+ |
nbytes %= 16; |
2127 |
+ |
if (nbytes) |
2128 |
+ |
emit_block(f32_patt[nbytes - 1], nbytes); |
2129 |
+ |
} |
2130 |
+ |
|
2131 |
|
|
2132 |
|
/************************************************************************* |
2133 |
|
* Flag handling, to and fro UAE flag register * |
2216 |
|
raw_mov_l_rm(target,(uae_u32)live.state[r].mem); |
2217 |
|
} |
2218 |
|
|
2219 |
+ |
#define NATIVE_FLAG_Z 0x40 |
2220 |
+ |
static __inline__ void raw_flags_set_zero(int f, int r, int t) |
2221 |
+ |
{ |
2222 |
+ |
// FIXME: this is really suboptimal |
2223 |
+ |
raw_pushfl(); |
2224 |
+ |
raw_pop_l_r(f); |
2225 |
+ |
raw_and_l_ri(f,~NATIVE_FLAG_Z); |
2226 |
+ |
raw_test_l_rr(r,r); |
2227 |
+ |
raw_mov_l_ri(r,0); |
2228 |
+ |
raw_mov_l_ri(t,NATIVE_FLAG_Z); |
2229 |
+ |
raw_cmov_l_rr(r,t,NATIVE_CC_EQ); |
2230 |
+ |
raw_or_l(f,r); |
2231 |
+ |
raw_push_l_r(f); |
2232 |
+ |
raw_popfl(); |
2233 |
+ |
} |
2234 |
|
|
2235 |
|
static __inline__ void raw_inc_sp(int off) |
2236 |
|
{ |
2706 |
|
x86_processor_string_table[c->x86_processor]); |
2707 |
|
} |
2708 |
|
|
2709 |
+ |
static bool target_check_bsf(void) |
2710 |
+ |
{ |
2711 |
+ |
bool mismatch = false; |
2712 |
+ |
for (int g_ZF = 0; g_ZF <= 1; g_ZF++) { |
2713 |
+ |
for (int g_CF = 0; g_CF <= 1; g_CF++) { |
2714 |
+ |
for (int g_OF = 0; g_OF <= 1; g_OF++) { |
2715 |
+ |
for (int g_SF = 0; g_SF <= 1; g_SF++) { |
2716 |
+ |
for (int value = -1; value <= 1; value++) { |
2717 |
+ |
int flags = (g_SF << 7) | (g_OF << 11) | (g_ZF << 6) | g_CF; |
2718 |
+ |
int tmp = value; |
2719 |
+ |
__asm__ __volatile__ ("push %0; popf; bsf %1,%1; pushf; pop %0" |
2720 |
+ |
: "+r" (flags), "+r" (tmp) : : "flags"); |
2721 |
+ |
int OF = (flags >> 11) & 1; |
2722 |
+ |
int SF = (flags >> 7) & 1; |
2723 |
+ |
int ZF = (flags >> 6) & 1; |
2724 |
+ |
int CF = flags & 1; |
2725 |
+ |
tmp = (value == 0); |
2726 |
+ |
if (ZF != tmp || SF != g_SF || OF != g_OF || CF != g_CF) |
2727 |
+ |
mismatch = true; |
2728 |
+ |
} |
2729 |
+ |
}}}} |
2730 |
+ |
if (mismatch) |
2731 |
+ |
write_log("Target CPU defines all flags on BSF instruction\n"); |
2732 |
+ |
return !mismatch; |
2733 |
+ |
} |
2734 |
+ |
|
2735 |
|
|
2736 |
|
/************************************************************************* |
2737 |
|
* FPU stuff * |