added static build option
[qemu] / helper-i386.c
1 /*
2  *  i386 helpers
3  * 
4  *  Copyright (c) 2003 Fabrice Bellard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #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
79 /* 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 ! */
81 void raise_interrupt(int intno, int is_int, int error_code, 
82                      unsigned int next_eip)
83 {
84     SegmentDescriptorTable *dt;
85     uint8_t *ptr;
86     int type, dpl, cpl;
87     uint32_t e1, e2;
88     
89     dt = &env->idt;
90     if (intno * 8 + 7 > dt->limit)
91         raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
92     ptr = dt->base + intno * 8;
93     e1 = ldl(ptr);
94     e2 = ldl(ptr + 4);
95     /* check gate type */
96     type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
97     switch(type) {
98     case 5: /* task gate */
99     case 6: /* 286 interrupt gate */
100     case 7: /* 286 trap gate */
101     case 14: /* 386 interrupt gate */
102     case 15: /* 386 trap gate */
103         break;
104     default:
105         raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
106         break;
107     }
108     dpl = (e2 >> DESC_DPL_SHIFT) & 3;
109     cpl = env->segs[R_CS] & 3;
110     /* check privledge if software int */
111     if (is_int && dpl < cpl)
112         raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
113     /* check valid bit */
114     if (!(e2 & DESC_P_MASK))
115         raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
116 }
117
118 #else
119
120 /*
121  * is_int is TRUE if coming from the int instruction. next_eip is the
122  * EIP value AFTER the interrupt instruction. It is only relevant if
123  * is_int is TRUE.  
124  */
125 void raise_interrupt(int intno, int is_int, int error_code, 
126                      unsigned int next_eip)
127 {
128     SegmentDescriptorTable *dt;
129     uint8_t *ptr;
130     int dpl, cpl;
131     uint32_t e2;
132
133     dt = &env->idt;
134     ptr = dt->base + (intno * 8);
135     e2 = ldl(ptr + 4);
136     
137     dpl = (e2 >> DESC_DPL_SHIFT) & 3;
138     cpl = 3;
139     /* check privledge if software int */
140     if (is_int && dpl < cpl)
141         raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
142
143     /* Since we emulate only user space, we cannot do more than
144        exiting the emulation with the suitable exception and error
145        code */
146     if (is_int)
147         EIP = next_eip;
148     env->exception_index = intno;
149     env->error_code = error_code;
150
151     cpu_loop_exit();
152 }
153
154 #endif
155
156 /* shortcuts to generate exceptions */
157 void raise_exception_err(int exception_index, int error_code)
158 {
159     raise_interrupt(exception_index, 0, error_code, 0);
160 }
161
162 void raise_exception(int exception_index)
163 {
164     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 */
244 #define CPUID_FP87 (1 << 0)
245 #define CPUID_VME  (1 << 1)
246 #define CPUID_DE   (1 << 2)
247 #define CPUID_PSE  (1 << 3)
248 #define CPUID_TSC  (1 << 4)
249 #define CPUID_MSR  (1 << 5)
250 #define CPUID_PAE  (1 << 6)
251 #define CPUID_MCE  (1 << 7)
252 #define CPUID_CX8  (1 << 8)
253 #define CPUID_APIC (1 << 9)
254 #define CPUID_SEP  (1 << 11) /* sysenter/sysexit */
255 #define CPUID_MTRR (1 << 12)
256 #define CPUID_PGE  (1 << 13)
257 #define CPUID_MCA  (1 << 14)
258 #define CPUID_CMOV (1 << 15)
259 /* ... */
260 #define CPUID_MMX  (1 << 23)
261 #define CPUID_FXSR (1 << 24)
262 #define CPUID_SSE  (1 << 25)
263 #define CPUID_SSE2 (1 << 26)
264
265 void helper_cpuid(void)
266 {
267     if (EAX == 0) {
268         EAX = 1; /* max EAX index supported */
269         EBX = 0x756e6547;
270         ECX = 0x6c65746e;
271         EDX = 0x49656e69;
272     } else if (EAX == 1) {
273         /* EAX = 1 info */
274         EAX = 0x52b;
275         EBX = 0;
276         ECX = 0;
277         EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE |
278             CPUID_TSC | CPUID_MSR | CPUID_MCE |
279             CPUID_CX8;
280     }
281 }
282
283 /* only works if protected mode and not VM86 */
284 void load_seg(int seg_reg, int selector, unsigned cur_eip)
285 {
286     SegmentCache *sc;
287     SegmentDescriptorTable *dt;
288     int index;
289     uint32_t e1, e2;
290     uint8_t *ptr;
291
292     sc = &env->seg_cache[seg_reg];
293     if ((selector & 0xfffc) == 0) {
294         /* null selector case */
295         if (seg_reg == R_SS) {
296             EIP = cur_eip;
297             raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
298         } else {
299             /* XXX: each access should trigger an exception */
300             sc->base = NULL;
301             sc->limit = 0;
302             sc->seg_32bit = 1;
303         }
304     } else {
305         if (selector & 0x4)
306             dt = &env->ldt;
307         else
308             dt = &env->gdt;
309         index = selector & ~7;
310         if ((index + 7) > dt->limit) {
311             EIP = cur_eip;
312             raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
313         }
314         ptr = dt->base + index;
315         e1 = ldl(ptr);
316         e2 = ldl(ptr + 4);
317         if (!(e2 & DESC_S_MASK) ||
318             (e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
319             EIP = cur_eip;
320             raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
321         }
322
323         if (seg_reg == R_SS) {
324             if ((e2 & (DESC_CS_MASK | DESC_W_MASK)) == 0) {
325                 EIP = cur_eip;
326                 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
327             }
328         } else {
329             if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
330                 EIP = cur_eip;
331                 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
332             }
333         }
334
335         if (!(e2 & DESC_P_MASK)) {
336             EIP = cur_eip;
337             if (seg_reg == R_SS)
338                 raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
339             else
340                 raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
341         }
342         
343         sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
344         sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000);
345         if (e2 & (1 << 23))
346             sc->limit = (sc->limit << 12) | 0xfff;
347         sc->seg_32bit = (e2 >> 22) & 1;
348 #if 0
349         fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx seg_32bit=%d\n", 
350                 selector, (unsigned long)sc->base, sc->limit, sc->seg_32bit);
351 #endif
352     }
353     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)
375 {
376     unsigned int selector, limit;
377     SegmentDescriptorTable *dt;
378     int index;
379     uint32_t e1, e2;
380     uint8_t *ptr;
381
382     CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
383     selector = T0 & 0xffff;
384     if (selector & 0x4)
385         dt = &env->ldt;
386     else
387         dt = &env->gdt;
388     index = selector & ~7;
389     if ((index + 7) > dt->limit)
390         return;
391     ptr = dt->base + index;
392     e1 = ldl(ptr);
393     e2 = ldl(ptr + 4);
394     limit = (e1 & 0xffff) | (e2 & 0x000f0000);
395     if (e2 & (1 << 23))
396         limit = (limit << 12) | 0xfff;
397     T1 = limit;
398     CC_SRC |= CC_Z;
399 }
400
401 void helper_lar(void)
402 {
403     unsigned int selector;
404     SegmentDescriptorTable *dt;
405     int index;
406     uint32_t e2;
407     uint8_t *ptr;
408
409     CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
410     selector = T0 & 0xffff;
411     if (selector & 0x4)
412         dt = &env->ldt;
413     else
414         dt = &env->gdt;
415     index = selector & ~7;
416     if ((index + 7) > dt->limit)
417         return;
418     ptr = dt->base + index;
419     e2 = ldl(ptr + 4);
420     T1 = e2 & 0x00f0ff00;
421     CC_SRC |= CC_Z;
422 }
423
424 /* FPU helpers */
425
426 #ifndef USE_X86LDOUBLE
427 void helper_fldt_ST0_A0(void)
428 {
429     ST0 = helper_fldt((uint8_t *)A0);
430 }
431
432 void helper_fstt_ST0_A0(void)
433 {
434     helper_fstt(ST0, (uint8_t *)A0);
435 }
436 #endif
437
438 /* BCD ops */
439
440 #define MUL10(iv) ( iv + iv + (iv << 3) )
441
442 void helper_fbld_ST0_A0(void)
443 {
444     uint8_t *seg;
445     CPU86_LDouble fpsrcop;
446     int m32i;
447     unsigned int v;
448
449     /* in this code, seg/m32i will be used as temporary ptr/int */
450     seg = (uint8_t *)A0 + 8;
451     v = ldub(seg--);
452     /* XXX: raise exception */
453     if (v != 0)
454         return;
455     v = ldub(seg--);
456     /* XXX: raise exception */
457     if ((v & 0xf0) != 0)
458         return;
459     m32i = v;  /* <-- d14 */
460     v = ldub(seg--);
461     m32i = MUL10(m32i) + (v >> 4);  /* <-- val * 10 + d13 */
462     m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d12 */
463     v = ldub(seg--);
464     m32i = MUL10(m32i) + (v >> 4);  /* <-- val * 10 + d11 */
465     m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d10 */
466     v = ldub(seg--);
467     m32i = MUL10(m32i) + (v >> 4);  /* <-- val * 10 + d9 */
468     m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d8 */
469     fpsrcop = ((CPU86_LDouble)m32i) * 100000000.0;
470
471     v = ldub(seg--);
472     m32i = (v >> 4);  /* <-- d7 */
473     m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d6 */
474     v = ldub(seg--);
475     m32i = MUL10(m32i) + (v >> 4);  /* <-- val * 10 + d5 */
476     m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d4 */
477     v = ldub(seg--);
478     m32i = MUL10(m32i) + (v >> 4);  /* <-- val * 10 + d3 */
479     m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d2 */
480     v = ldub(seg);
481     m32i = MUL10(m32i) + (v >> 4);  /* <-- val * 10 + d1 */
482     m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d0 */
483     fpsrcop += ((CPU86_LDouble)m32i);
484     if ( ldub(seg+9) & 0x80 )
485         fpsrcop = -fpsrcop;
486     ST0 = fpsrcop;
487 }
488
489 void helper_fbst_ST0_A0(void)
490 {
491     CPU86_LDouble fptemp;
492     CPU86_LDouble fpsrcop;
493     int v;
494     uint8_t *mem_ref, *mem_end;
495
496     fpsrcop = rint(ST0);
497     mem_ref = (uint8_t *)A0;
498     mem_end = mem_ref + 8;
499     if ( fpsrcop < 0.0 ) {
500         stw(mem_end, 0x8000);
501         fpsrcop = -fpsrcop;
502     } else {
503         stw(mem_end, 0x0000);
504     }
505     while (mem_ref < mem_end) {
506         if (fpsrcop == 0.0)
507             break;
508         fptemp = floor(fpsrcop/10.0);
509         v = ((int)(fpsrcop - fptemp*10.0));
510         if  (fptemp == 0.0)  { 
511             stb(mem_ref++, v); 
512             break; 
513         }
514         fpsrcop = fptemp;
515         fptemp = floor(fpsrcop/10.0);
516         v |= (((int)(fpsrcop - fptemp*10.0)) << 4);
517         stb(mem_ref++, v);
518         fpsrcop = fptemp;
519     }
520     while (mem_ref < mem_end) {
521         stb(mem_ref++, 0);
522     }
523 }
524
525 void helper_f2xm1(void)
526 {
527     ST0 = pow(2.0,ST0) - 1.0;
528 }
529
530 void helper_fyl2x(void)
531 {
532     CPU86_LDouble fptemp;
533     
534     fptemp = ST0;
535     if (fptemp>0.0){
536         fptemp = log(fptemp)/log(2.0);   /* log2(ST) */
537         ST1 *= fptemp;
538         fpop();
539     } else { 
540         env->fpus &= (~0x4700);
541         env->fpus |= 0x400;
542     }
543 }
544
545 void helper_fptan(void)
546 {
547     CPU86_LDouble fptemp;
548
549     fptemp = ST0;
550     if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
551         env->fpus |= 0x400;
552     } else {
553         ST0 = tan(fptemp);
554         fpush();
555         ST0 = 1.0;
556         env->fpus &= (~0x400);  /* C2 <-- 0 */
557         /* the above code is for  |arg| < 2**52 only */
558     }
559 }
560
561 void helper_fpatan(void)
562 {
563     CPU86_LDouble fptemp, fpsrcop;
564
565     fpsrcop = ST1;
566     fptemp = ST0;
567     ST1 = atan2(fpsrcop,fptemp);
568     fpop();
569 }
570
571 void helper_fxtract(void)
572 {
573     CPU86_LDoubleU temp;
574     unsigned int expdif;
575
576     temp.d = ST0;
577     expdif = EXPD(temp) - EXPBIAS;
578     /*DP exponent bias*/
579     ST0 = expdif;
580     fpush();
581     BIASEXPONENT(temp);
582     ST0 = temp.d;
583 }
584
585 void helper_fprem1(void)
586 {
587     CPU86_LDouble dblq, fpsrcop, fptemp;
588     CPU86_LDoubleU fpsrcop1, fptemp1;
589     int expdif;
590     int q;
591
592     fpsrcop = ST0;
593     fptemp = ST1;
594     fpsrcop1.d = fpsrcop;
595     fptemp1.d = fptemp;
596     expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
597     if (expdif < 53) {
598         dblq = fpsrcop / fptemp;
599         dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
600         ST0 = fpsrcop - fptemp*dblq;
601         q = (int)dblq; /* cutting off top bits is assumed here */
602         env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
603                                 /* (C0,C1,C3) <-- (q2,q1,q0) */
604         env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
605         env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
606         env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
607     } else {
608         env->fpus |= 0x400;  /* C2 <-- 1 */
609         fptemp = pow(2.0, expdif-50);
610         fpsrcop = (ST0 / ST1) / fptemp;
611         /* fpsrcop = integer obtained by rounding to the nearest */
612         fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
613             floor(fpsrcop): ceil(fpsrcop);
614         ST0 -= (ST1 * fpsrcop * fptemp);
615     }
616 }
617
618 void helper_fprem(void)
619 {
620     CPU86_LDouble dblq, fpsrcop, fptemp;
621     CPU86_LDoubleU fpsrcop1, fptemp1;
622     int expdif;
623     int q;
624     
625     fpsrcop = ST0;
626     fptemp = ST1;
627     fpsrcop1.d = fpsrcop;
628     fptemp1.d = fptemp;
629     expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
630     if ( expdif < 53 ) {
631         dblq = fpsrcop / fptemp;
632         dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
633         ST0 = fpsrcop - fptemp*dblq;
634         q = (int)dblq; /* cutting off top bits is assumed here */
635         env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
636                                 /* (C0,C1,C3) <-- (q2,q1,q0) */
637         env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
638         env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
639         env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
640     } else {
641         env->fpus |= 0x400;  /* C2 <-- 1 */
642         fptemp = pow(2.0, expdif-50);
643         fpsrcop = (ST0 / ST1) / fptemp;
644         /* fpsrcop = integer obtained by chopping */
645         fpsrcop = (fpsrcop < 0.0)?
646             -(floor(fabs(fpsrcop))): floor(fpsrcop);
647         ST0 -= (ST1 * fpsrcop * fptemp);
648     }
649 }
650
651 void helper_fyl2xp1(void)
652 {
653     CPU86_LDouble fptemp;
654
655     fptemp = ST0;
656     if ((fptemp+1.0)>0.0) {
657         fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
658         ST1 *= fptemp;
659         fpop();
660     } else { 
661         env->fpus &= (~0x4700);
662         env->fpus |= 0x400;
663     }
664 }
665
666 void helper_fsqrt(void)
667 {
668     CPU86_LDouble fptemp;
669
670     fptemp = ST0;
671     if (fptemp<0.0) { 
672         env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
673         env->fpus |= 0x400;
674     }
675     ST0 = sqrt(fptemp);
676 }
677
678 void helper_fsincos(void)
679 {
680     CPU86_LDouble fptemp;
681
682     fptemp = ST0;
683     if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
684         env->fpus |= 0x400;
685     } else {
686         ST0 = sin(fptemp);
687         fpush();
688         ST0 = cos(fptemp);
689         env->fpus &= (~0x400);  /* C2 <-- 0 */
690         /* the above code is for  |arg| < 2**63 only */
691     }
692 }
693
694 void helper_frndint(void)
695 {
696     ST0 = rint(ST0);
697 }
698
699 void helper_fscale(void)
700 {
701     CPU86_LDouble fpsrcop, fptemp;
702
703     fpsrcop = 2.0;
704     fptemp = pow(fpsrcop,ST1);
705     ST0 *= fptemp;
706 }
707
708 void helper_fsin(void)
709 {
710     CPU86_LDouble fptemp;
711
712     fptemp = ST0;
713     if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
714         env->fpus |= 0x400;
715     } else {
716         ST0 = sin(fptemp);
717         env->fpus &= (~0x400);  /* C2 <-- 0 */
718         /* the above code is for  |arg| < 2**53 only */
719     }
720 }
721
722 void helper_fcos(void)
723 {
724     CPU86_LDouble fptemp;
725
726     fptemp = ST0;
727     if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
728         env->fpus |= 0x400;
729     } else {
730         ST0 = cos(fptemp);
731         env->fpus &= (~0x400);  /* C2 <-- 0 */
732         /* the above code is for  |arg5 < 2**63 only */
733     }
734 }
735
736 void helper_fxam_ST0(void)
737 {
738     CPU86_LDoubleU temp;
739     int expdif;
740
741     temp.d = ST0;
742
743     env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
744     if (SIGND(temp))
745         env->fpus |= 0x200; /* C1 <-- 1 */
746
747     expdif = EXPD(temp);
748     if (expdif == MAXEXPD) {
749         if (MANTD(temp) == 0)
750             env->fpus |=  0x500 /*Infinity*/;
751         else
752             env->fpus |=  0x100 /*NaN*/;
753     } else if (expdif == 0) {
754         if (MANTD(temp) == 0)
755             env->fpus |=  0x4000 /*Zero*/;
756         else
757             env->fpus |= 0x4400 /*Denormal*/;
758     } else {
759         env->fpus |= 0x400;
760     }
761 }
762
763 void helper_fstenv(uint8_t *ptr, int data32)
764 {
765     int fpus, fptag, exp, i;
766     uint64_t mant;
767     CPU86_LDoubleU tmp;
768
769     fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
770     fptag = 0;
771     for (i=7; i>=0; i--) {
772         fptag <<= 2;
773         if (env->fptags[i]) {
774             fptag |= 3;
775         } else {
776             tmp.d = env->fpregs[i];
777             exp = EXPD(tmp);
778             mant = MANTD(tmp);
779             if (exp == 0 && mant == 0) {
780                 /* zero */
781                 fptag |= 1;
782             } else if (exp == 0 || exp == MAXEXPD
783 #ifdef USE_X86LDOUBLE
784                        || (mant & (1LL << 63)) == 0
785 #endif
786                        ) {
787                 /* NaNs, infinity, denormal */
788                 fptag |= 2;
789             }
790         }
791     }
792     if (data32) {
793         /* 32 bit */
794         stl(ptr, env->fpuc);
795         stl(ptr + 4, fpus);
796         stl(ptr + 8, fptag);
797         stl(ptr + 12, 0);
798         stl(ptr + 16, 0);
799         stl(ptr + 20, 0);
800         stl(ptr + 24, 0);
801     } else {
802         /* 16 bit */
803         stw(ptr, env->fpuc);
804         stw(ptr + 2, fpus);
805         stw(ptr + 4, fptag);
806         stw(ptr + 6, 0);
807         stw(ptr + 8, 0);
808         stw(ptr + 10, 0);
809         stw(ptr + 12, 0);
810     }
811 }
812
813 void helper_fldenv(uint8_t *ptr, int data32)
814 {
815     int i, fpus, fptag;
816
817     if (data32) {
818         env->fpuc = lduw(ptr);
819         fpus = lduw(ptr + 4);
820         fptag = lduw(ptr + 8);
821     }
822     else {
823         env->fpuc = lduw(ptr);
824         fpus = lduw(ptr + 2);
825         fptag = lduw(ptr + 4);
826     }
827     env->fpstt = (fpus >> 11) & 7;
828     env->fpus = fpus & ~0x3800;
829     for(i = 0;i < 7; i++) {
830         env->fptags[i] = ((fptag & 3) == 3);
831         fptag >>= 2;
832     }
833 }
834
835 void helper_fsave(uint8_t *ptr, int data32)
836 {
837     CPU86_LDouble tmp;
838     int i;
839
840     helper_fstenv(ptr, data32);
841
842     ptr += (14 << data32);
843     for(i = 0;i < 8; i++) {
844         tmp = ST(i);
845 #ifdef USE_X86LDOUBLE
846         *(long double *)ptr = tmp;
847 #else
848         helper_fstt(tmp, ptr);
849 #endif        
850         ptr += 10;
851     }
852
853     /* fninit */
854     env->fpus = 0;
855     env->fpstt = 0;
856     env->fpuc = 0x37f;
857     env->fptags[0] = 1;
858     env->fptags[1] = 1;
859     env->fptags[2] = 1;
860     env->fptags[3] = 1;
861     env->fptags[4] = 1;
862     env->fptags[5] = 1;
863     env->fptags[6] = 1;
864     env->fptags[7] = 1;
865 }
866
867 void helper_frstor(uint8_t *ptr, int data32)
868 {
869     CPU86_LDouble tmp;
870     int i;
871
872     helper_fldenv(ptr, data32);
873     ptr += (14 << data32);
874
875     for(i = 0;i < 8; i++) {
876 #ifdef USE_X86LDOUBLE
877         tmp = *(long double *)ptr;
878 #else
879         tmp = helper_fldt(ptr);
880 #endif        
881         ST(i) = tmp;
882         ptr += 10;
883     }
884 }
885