19 |
*/ |
*/ |
20 |
#include "exec-i386.h" |
#include "exec-i386.h" |
21 |
|
|
22 |
|
const CPU86_LDouble f15rk[7] = |
23 |
|
{ |
24 |
|
0.00000000000000000000L, |
25 |
|
1.00000000000000000000L, |
26 |
|
3.14159265358979323851L, /*pi*/ |
27 |
|
0.30102999566398119523L, /*lg2*/ |
28 |
|
0.69314718055994530943L, /*ln2*/ |
29 |
|
1.44269504088896340739L, /*l2e*/ |
30 |
|
3.32192809488736234781L, /*l2t*/ |
31 |
|
}; |
32 |
|
|
33 |
|
/* thread support */ |
34 |
|
|
35 |
|
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; |
36 |
|
|
37 |
|
void cpu_lock(void) |
38 |
|
{ |
39 |
|
spin_lock(&global_cpu_lock); |
40 |
|
} |
41 |
|
|
42 |
|
void cpu_unlock(void) |
43 |
|
{ |
44 |
|
spin_unlock(&global_cpu_lock); |
45 |
|
} |
46 |
|
|
47 |
|
void cpu_loop_exit(void) |
48 |
|
{ |
49 |
|
/* NOTE: the register at this point must be saved by hand because |
50 |
|
longjmp restore them */ |
51 |
|
#ifdef reg_EAX |
52 |
|
env->regs[R_EAX] = EAX; |
53 |
|
#endif |
54 |
|
#ifdef reg_ECX |
55 |
|
env->regs[R_ECX] = ECX; |
56 |
|
#endif |
57 |
|
#ifdef reg_EDX |
58 |
|
env->regs[R_EDX] = EDX; |
59 |
|
#endif |
60 |
|
#ifdef reg_EBX |
61 |
|
env->regs[R_EBX] = EBX; |
62 |
|
#endif |
63 |
|
#ifdef reg_ESP |
64 |
|
env->regs[R_ESP] = ESP; |
65 |
|
#endif |
66 |
|
#ifdef reg_EBP |
67 |
|
env->regs[R_EBP] = EBP; |
68 |
|
#endif |
69 |
|
#ifdef reg_ESI |
70 |
|
env->regs[R_ESI] = ESI; |
71 |
|
#endif |
72 |
|
#ifdef reg_EDI |
73 |
|
env->regs[R_EDI] = EDI; |
74 |
|
#endif |
75 |
|
longjmp(env->jmp_env, 1); |
76 |
|
} |
77 |
|
|
78 |
#if 0 |
#if 0 |
79 |
/* full interrupt support (only useful for real CPU emulation, not |
/* full interrupt support (only useful for real CPU emulation, not |
80 |
finished) - I won't do it any time soon, finish it if you want ! */ |
finished) - I won't do it any time soon, finish it if you want ! */ |
164 |
raise_interrupt(exception_index, 0, 0, 0); |
raise_interrupt(exception_index, 0, 0, 0); |
165 |
} |
} |
166 |
|
|
167 |
|
#ifdef BUGGY_GCC_DIV64 |
168 |
|
/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we |
169 |
|
call it from another function */ |
170 |
|
uint32_t div64(uint32_t *q_ptr, uint64_t num, uint32_t den) |
171 |
|
{ |
172 |
|
*q_ptr = num / den; |
173 |
|
return num % den; |
174 |
|
} |
175 |
|
|
176 |
|
int32_t idiv64(int32_t *q_ptr, int64_t num, int32_t den) |
177 |
|
{ |
178 |
|
*q_ptr = num / den; |
179 |
|
return num % den; |
180 |
|
} |
181 |
|
#endif |
182 |
|
|
183 |
|
void helper_divl_EAX_T0(uint32_t eip) |
184 |
|
{ |
185 |
|
unsigned int den, q, r; |
186 |
|
uint64_t num; |
187 |
|
|
188 |
|
num = EAX | ((uint64_t)EDX << 32); |
189 |
|
den = T0; |
190 |
|
if (den == 0) { |
191 |
|
EIP = eip; |
192 |
|
raise_exception(EXCP00_DIVZ); |
193 |
|
} |
194 |
|
#ifdef BUGGY_GCC_DIV64 |
195 |
|
r = div64(&q, num, den); |
196 |
|
#else |
197 |
|
q = (num / den); |
198 |
|
r = (num % den); |
199 |
|
#endif |
200 |
|
EAX = q; |
201 |
|
EDX = r; |
202 |
|
} |
203 |
|
|
204 |
|
void helper_idivl_EAX_T0(uint32_t eip) |
205 |
|
{ |
206 |
|
int den, q, r; |
207 |
|
int64_t num; |
208 |
|
|
209 |
|
num = EAX | ((uint64_t)EDX << 32); |
210 |
|
den = T0; |
211 |
|
if (den == 0) { |
212 |
|
EIP = eip; |
213 |
|
raise_exception(EXCP00_DIVZ); |
214 |
|
} |
215 |
|
#ifdef BUGGY_GCC_DIV64 |
216 |
|
r = idiv64(&q, num, den); |
217 |
|
#else |
218 |
|
q = (num / den); |
219 |
|
r = (num % den); |
220 |
|
#endif |
221 |
|
EAX = q; |
222 |
|
EDX = r; |
223 |
|
} |
224 |
|
|
225 |
|
void helper_cmpxchg8b(void) |
226 |
|
{ |
227 |
|
uint64_t d; |
228 |
|
int eflags; |
229 |
|
|
230 |
|
eflags = cc_table[CC_OP].compute_all(); |
231 |
|
d = ldq((uint8_t *)A0); |
232 |
|
if (d == (((uint64_t)EDX << 32) | EAX)) { |
233 |
|
stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX); |
234 |
|
eflags |= CC_Z; |
235 |
|
} else { |
236 |
|
EDX = d >> 32; |
237 |
|
EAX = d; |
238 |
|
eflags &= ~CC_Z; |
239 |
|
} |
240 |
|
CC_SRC = eflags; |
241 |
|
} |
242 |
|
|
243 |
/* We simulate a pre-MMX pentium as in valgrind */ |
/* We simulate a pre-MMX pentium as in valgrind */ |
244 |
#define CPUID_FP87 (1 << 0) |
#define CPUID_FP87 (1 << 0) |
245 |
#define CPUID_VME (1 << 1) |
#define CPUID_VME (1 << 1) |
353 |
env->segs[seg_reg] = selector; |
env->segs[seg_reg] = selector; |
354 |
} |
} |
355 |
|
|
356 |
|
/* rdtsc */ |
357 |
|
#ifndef __i386__ |
358 |
|
uint64_t emu_time; |
359 |
|
#endif |
360 |
|
|
361 |
|
void helper_rdtsc(void) |
362 |
|
{ |
363 |
|
uint64_t val; |
364 |
|
#ifdef __i386__ |
365 |
|
asm("rdtsc" : "=A" (val)); |
366 |
|
#else |
367 |
|
/* better than nothing: the time increases */ |
368 |
|
val = emu_time++; |
369 |
|
#endif |
370 |
|
EAX = val; |
371 |
|
EDX = val >> 32; |
372 |
|
} |
373 |
|
|
374 |
void helper_lsl(void) |
void helper_lsl(void) |
375 |
{ |
{ |
376 |
unsigned int selector, limit; |
unsigned int selector, limit; |