Bug 497723 - forgot to restore callgrind output cleanup
[valgrind.git] / VEX / useful / hd_fpu.c
blob9655f12f846d548f7036dae6ec7face72c2132fc
2 /*--------------------------------------------------------------------*/
3 /*--- Implementation of the floating point instruction set. ---*/
4 /*--- hd_fpu.c ---*/
5 /*--------------------------------------------------------------------*/
7 /*
8 This file is part of Heimdall, an x86 protected-mode emulator
9 designed for debugging and profiling binaries on x86-Unixes.
11 Copyright (C) 2000 Julian Seward
12 jseward@acm.org
13 Julian_Seward@muraroa.demon.co.uk
15 This program is free software; you can redistribute it and/or
16 modify it under the terms of the GNU General Public License as
17 published by the Free Software Foundation; either version 2 of the
18 License, or (at your option) any later version.
20 This program is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, see <http://www.gnu.org/licenses/>.
28 The GNU General Public License is contained in the file LICENSE.
31 #include "hd_include.h"
34 /* ---------------------------------------------------------------------
35 Packing and unpacking the FPU data registers.
36 ------------------------------------------------------------------ */
38 INLINE
39 UInt fp_get_tos ( void )
41 return (m_fpu_state.env[FP_ENV_STAT] >> FP_F_TOS_LO) & 7;
44 static
45 UInt read_bit_array ( UChar* arr, UInt n )
47 UChar c = arr[n >> 3];
48 c >>= (n&7);
49 return c & 1;
52 static
53 void write_bit_array ( UChar* arr, UInt n, UInt b )
55 UChar c = arr[n >> 3];
56 c &= ~(1 << (n&7));
57 b &= 1;
58 c |= (b << (n&7));
59 arr[n >> 3] = c;
62 /* Read an IEEE double from the memory image of an Intel 80-bit
63 extended floating-point number.
65 static
66 double fp_double_from_extended ( UChar* e_lsb )
68 int i;
69 double d;
70 UChar* d_lsb = (UChar*)(&d);
72 UInt sign = e_lsb[9] >> 7;
73 Int bexp = ((UInt)e_lsb[9] << 8) | (UInt)e_lsb[8];
74 bexp &= 0x7fff;
76 if (bexp == 0)
77 bexp = 0; /* preserve zeroes */
78 else
79 if (bexp == 0x7FFF)
80 bexp = 0x7FF; /* preserve Infs/Nans */
81 else {
82 bexp -= (16383 - 1023);
83 if (bexp < 0) bexp = 0;
84 if (bexp > 0x7FF) bexp = 0x7FF;
87 d_lsb[6] = (bexp & 0xF) << 4;
88 d_lsb[7] = ((bexp >> 4) & 0x7F) | ((sign & 0x1) << 7);
90 for (i = 0; i < 52; i++)
91 write_bit_array ( d_lsb,
93 read_bit_array ( e_lsb, i+11 ) );
94 return d;
97 /* Given an IEEE double, create the memory image of an Intel 80-bit
98 extended floating-point number.
100 static
101 void fp_extended_from_double ( UChar* e_lsb, double d )
103 int i;
104 UChar* d_lsb = (UChar*)(&d);
106 UInt sign = d_lsb[7] >> 7;
107 Int bexp = ((UInt)d_lsb[7] << 4) |
108 ((((UInt)d_lsb[6]) >> 4) & 0xF);
109 bexp &= 0x7ff;
111 if (bexp == 0)
112 bexp = 0; /* preserve zeroes */
113 else
114 if (bexp == 0x7FF)
115 bexp = 0x7FFF; /* preserve Infs/Nans */
116 else
117 bexp += (16383 - 1023);
119 e_lsb[9] = ((bexp >> 8) & 0x7F) | ((sign & 0x1) << 7);
120 e_lsb[8] = bexp & 0xFF;
122 for (i = 0; i < 52; i++)
123 write_bit_array ( e_lsb,
124 i+11,
125 read_bit_array ( d_lsb, i ) );
126 for (i = 0; i < 11; i++)
127 write_bit_array ( e_lsb, i, 0 );
129 /* this isn't really right, but I can't get fpclassify to work. */
130 i = 0;
131 if (isnan(d) || isinf(d) || d != 0.0) i = 1;
132 write_bit_array ( e_lsb, 63, i );
135 /* For the transition Real CPU -> Simulated CPU, copy the
136 .reg values in m_fpu_state, which are in stack order, to
137 the m_fpu_data_regs array, in register (non-stack) order.
139 void fp_unpack_data_regs ( void )
141 Int reg, st;
142 reg = fp_get_tos();
143 for (st = 0; st < 8; st++) {
144 m_fpu_data_regs[reg]
145 = fp_double_from_extended ( &m_fpu_state.reg[FP_REG(st)] );
146 if (reg == 7) reg = 0; else reg++;
150 void fp_repack_data_regs ( void )
152 Int reg, st;
153 st = fp_get_tos();
154 for (reg = 0; reg < 8; reg++) {
155 fp_extended_from_double ( &m_fpu_state.reg[FP_REG(reg)],
156 m_fpu_data_regs[st] );
157 if (st == 7) st = 0; else st++;
161 /* ---------------------------------------------------------------------
162 Helper functions for the floating point unit.
163 ------------------------------------------------------------------ */
165 static
166 INLINE
167 void setFMem ( UInt addr, double f )
169 * ((float*)addr) = (float)f;
172 static
173 INLINE
174 double getFMem ( UInt addr )
176 return (double) (* ((float*)addr));
179 static
180 INLINE
181 void setDMem ( UInt addr, double f )
183 * ((double*)addr) = f;
186 static
187 INLINE
188 double getDMem ( UInt addr )
190 return (* ((double*)addr));
193 static
194 INLINE
195 void setTMem ( UInt addr, double f )
197 fp_extended_from_double ( (Addr)addr, f );
200 static
201 INLINE
202 double getTMem ( UInt addr )
204 return fp_double_from_extended ( (Addr)addr );
207 #define fp_extended_from_double ERROR__fp_extended_from_double_used
208 #define fp_double_from_extended ERROR__fp_double_from_extended_used
210 static
211 INLINE
212 UInt fp_get_statusword_flag ( UInt flagno )
214 if (flagno < 0 || flagno > 15) panic("fp_get_statusword_flag");
215 return (m_fpu_state.env[FP_ENV_STAT] >> flagno) & 0x1;
218 #if DEBUG
219 static
220 UInt fp_get_controlword_flag ( UInt flagno )
222 if (flagno < 0 || flagno > 15) panic("fp_get_controlword_flag");
223 return (m_fpu_state.env[FP_ENV_CTRL] >> flagno) & 0x1;
225 #endif
227 static
228 INLINE
229 void fp_set_statusword_flag_to ( UInt flagno, UInt bit )
231 if (flagno < 0 || flagno > 15) panic("fp_set_statusword_flag_to");
232 if (bit)
233 m_fpu_state.env[FP_ENV_STAT] |= (1 << flagno);
234 else
235 m_fpu_state.env[FP_ENV_STAT] &= ~(1 << flagno);
238 static
239 void fp_set_stack_overflow ( void )
241 fprintf(stderr, "--- FP STACK OVERFLOW!\n" );
242 fp_set_statusword_flag_to(FP_E_INVAL,1);
243 fp_set_statusword_flag_to(FP_E_STACKF,1);
244 fp_set_statusword_flag_to(FP_F_C1,1);
247 static
248 void fp_set_stack_underflow ( void )
250 fprintf(stderr, "--- FP STACK UNDERFLOW!\n" );
251 fp_set_statusword_flag_to(FP_E_INVAL,1);
252 fp_set_statusword_flag_to(FP_E_STACKF,1);
253 fp_set_statusword_flag_to(FP_F_C1,0);
256 static
257 INLINE
258 void fp_set_tos ( UInt tos )
260 if (tos < 0 || tos > 7) panic("fp_set_tos");
261 fp_set_statusword_flag_to(FP_F_TOS_LO,0);
262 fp_set_statusword_flag_to(FP_F_TOS_LO+1,0);
263 fp_set_statusword_flag_to(FP_F_TOS_HI,0);
264 m_fpu_state.env[FP_ENV_STAT] |= (tos << FP_F_TOS_LO);
267 static
268 INLINE
269 UInt fp_STno_to_regno ( UInt stregno )
271 UInt regno = fp_get_tos();
272 assert(regno >= 0 && regno < 8);
273 regno += stregno;
274 if (regno >= 8) regno -= 8;
275 assert(regno >= 0 && regno < 8);
276 return regno;
279 static
280 INLINE
281 void fp_dec_tos ( void )
283 fp_set_tos ( fp_STno_to_regno ( 7 ));
286 static
287 INLINE
288 void fp_inc_tos ( void )
290 fp_set_tos ( fp_STno_to_regno ( 1 ));
293 static
294 INLINE
295 Bool fp_is_empty_tag ( UInt tag )
297 return tag == FP_TAG_EMPTY;
300 static
301 INLINE
302 UInt fp_get_tag ( UInt regno )
304 if (regno < 0 || regno > 7) panic("fp_get_tag");
305 return (m_fpu_state.env[FP_ENV_TAG] >> (2*regno)) & 3;
308 static
309 INLINE
310 UInt fp_get_tag_ST ( UInt stregno )
312 if (stregno < 0 || stregno > 7) panic("fp_get_tag_ST");
313 return fp_get_tag ( fp_STno_to_regno(stregno) );
316 static
317 INLINE
318 void fp_set_tag ( UInt regno, UInt val )
320 if (regno < 0 || regno > 7 ||
321 val < 0 || val > 3) panic("fp_get_tag");
322 m_fpu_state.env[FP_ENV_TAG] &= ~(3 << (2*regno));
323 m_fpu_state.env[FP_ENV_TAG] |= (val << (2*regno));
326 static
327 INLINE
328 void fp_set_tag_ST ( UInt stregno, UInt val )
330 if (stregno < 0 || stregno > 7) panic("fp_set_tag_ST");
331 fp_set_tag ( fp_STno_to_regno(stregno), val );
335 static
336 INLINE
337 void fp_set_reg ( UInt r, double d )
339 if (r < 0 || r > 7) panic("fp_set_reg");
340 m_fpu_data_regs[r] = d;
341 fp_set_tag ( r, d==0.0 ? FP_TAG_ZERO
342 : (finite(d) ? FP_TAG_VALID : FP_TAG_SPEC) );
345 static
346 INLINE
347 void fp_set_reg_ST ( UInt str, double d )
349 UInt r;
350 if (str < 0 || str > 7) panic("fp_set_reg_ST");
351 r = fp_STno_to_regno(str);
352 fp_set_reg ( r, d );
355 static
356 INLINE
357 double fp_get_reg ( UInt r )
359 double d;
360 if (r < 0 || r > 7) panic("fp_get_reg");
361 d = m_fpu_data_regs[r];
362 return d;
365 static
366 INLINE
367 double fp_get_reg_ST ( UInt str )
369 UInt r;
370 if (str < 0 || str > 7) panic("fp_get_reg_ST");
371 r = fp_STno_to_regno(str);
372 return fp_get_reg(r);
375 static
376 INLINE
377 void fp_set_tos_reg ( double d )
379 fp_set_reg ( fp_get_tos(), d );
382 static
383 INLINE
384 double fp_get_tos_reg ( void )
386 return fp_get_reg ( fp_get_tos() );
389 static
390 INLINE
391 void fp_set_tos_reg_QNaN ( void )
393 fp_set_reg ( fp_get_tos(), NAN /* see <nan.h> */ );
396 static
397 INLINE
398 double fp_pop ( void )
400 double d = fp_get_tos_reg();
401 fp_set_tag ( fp_get_tos(), FP_TAG_EMPTY );
402 fp_inc_tos();
403 return d;
406 /* Push d and update flags. */
407 static
408 INLINE
409 void fp_push ( double d )
411 if (fp_is_empty_tag(fp_get_tag_ST(7))) {
412 fp_dec_tos();
413 fp_set_tos_reg(d);
414 fp_set_statusword_flag_to(FP_F_C1, d == 0.0);
415 } else {
416 fp_dec_tos();
417 fp_set_tos_reg_QNaN();
418 fp_set_stack_overflow();
422 static
423 void fp_set_statusword_flags_COM ( double vd_dst, double vd_src )
425 UInt vis_dst;
426 if (isnan(vd_src) || isnan(vd_dst)) vis_dst = 7;
427 else if (vd_dst > vd_src) vis_dst = 0;
428 else if (vd_dst < vd_src) vis_dst = 1;
429 else if (vd_dst == vd_src) vis_dst = 4;
430 else vis_dst = 7;
431 fp_set_statusword_flag_to(FP_F_C3, (vis_dst >> 2) & 1);
432 fp_set_statusword_flag_to(FP_F_C2, (vis_dst >> 1) & 1);
433 fp_set_statusword_flag_to(FP_F_C0, vis_dst & 1);
436 static
437 void fp_set_statusword_flags_COM_STACKF ( void )
439 UInt vis_dst = 7;
440 fp_set_statusword_flag_to(FP_F_C3, (vis_dst >> 2) & 1);
441 fp_set_statusword_flag_to(FP_F_C2, (vis_dst >> 1) & 1);
442 fp_set_statusword_flag_to(FP_F_C0, vis_dst & 1);
445 static
446 double fp_calc_yl2xp1 ( double st_0, double st_1 )
448 st_0 += 1.0;
449 st_0 = log(st_0) / log(2.0);
450 st_0 *= st_1;
451 return st_0;
454 static
455 double fp_calc_yl2x ( double st_0, double st_1 )
457 st_0 = log(st_0) / log(2.0);
458 st_0 *= st_1;
459 return st_0;
462 static
463 double fp_calc_2xm1 ( double st_0 )
465 st_0 = st_0 * 0.69314718055994530942;
466 st_0 = exp(st_0);
467 st_0 = st_0 - 1.0;
468 return st_0;
471 static
472 double fp_calc_scale ( double st_0, double st_1 )
474 Int n = 0;
475 if (st_1 > 0.0) {
476 if (st_1 > 2.0*308.0) st_1 = 2.0*308.0;
477 n = (Int)(floor(st_1));
478 if (n < 0) n = 0; /* impossible, but ... */
479 if (n > 2*308) n = 2*308; /* limit exponent change */
480 while (n > 0) { n--; st_0 *= 2.0; };
482 else
483 if (st_1 < 0.0) {
484 if (st_1 < -2.0*308.0) st_1 = -2.0*308.0;
485 n = ((Int)(floor(-st_1)));
486 if (n < 0) n = 0;
487 if (n > 2*308) n = 2*308;
488 while (n > 0) { n--; st_0 *= 0.5; };
490 return st_0;
493 static
494 void fp_calc_fprem ( Int* qq, double* result, double st_0, double st_1 )
496 double tmp = st_0 / st_1;
497 if (tmp < 0)
498 *qq = - (Int)floor(-tmp);
499 else
500 *qq = (Int)floor(tmp);
501 *result = st_0 - (st_1 * (double)(*qq));
504 #if DEBUG
505 static
506 void printFpuState ( void )
508 Int i;
509 assert(sizeof(Fpu_State)==108);
510 for (i = 7; i >= 0; i--) {
511 printf ( " %s fpreg%d: 0x",
512 (UInt)i == fp_get_tos() ? "**" : " ", i );
513 //for (j = FP_REG(i+1)-1; j >= FP_REG(i); j--)
514 // printf ( "%2x", (UInt)m_fpu_state.reg[j]);
515 printf ( " %5s ", fp_tag_names[fp_get_tag(i)] );
516 printf ( "%20.16e\n", fp_get_reg(i) );
518 printf(" fctrl: 0x%4x masked: ",
519 (UInt)m_fpu_state.env[FP_ENV_CTRL] );
520 for (i = FP_E_INVAL; i <= FP_E_LOS; i++)
521 if (fp_get_controlword_flag(i))
522 printf ( "%s ", fp_exception_names[i] );
523 printf ( "\n" );
525 printf(" fstat: 0x%4x except:",
526 (UInt)m_fpu_state.env[FP_ENV_STAT] );
527 for (i = FP_E_INVAL; i <= FP_E_LOS; i++)
528 if (fp_get_statusword_flag(i))
529 printf ( "%s ", fp_exception_names[i] );
530 printf ( " top: %d ", fp_get_tos() );
531 printf ( "c3210: %d%d%d%d",
532 fp_get_statusword_flag(FP_F_C3),
533 fp_get_statusword_flag(FP_F_C2),
534 fp_get_statusword_flag(FP_F_C1),
535 fp_get_statusword_flag(FP_F_C0) );
536 printf ( " STACKF: %d\n", fp_get_statusword_flag(FP_E_STACKF) );
538 printf(" ftag: 0x%4x ", (UInt)m_fpu_state.env[FP_ENV_TAG] );
539 for (i = 7; i >= 0; i--)
540 printf ( "%s ", fp_tag_names[fp_get_tag(i)] );
541 printf("\n");
543 printf(" fip: 0x%8x\n",
544 (((UInt)m_fpu_state.env[FP_ENV_IP+1]) << 16) |
545 ((UInt)m_fpu_state.env[FP_ENV_IP]) );
546 printf(" fcs: 0x%4x\n",
547 ((UInt)m_fpu_state.env[FP_ENV_CS]) );
548 printf(" fopoff: 0x%8x\n",
549 (((UInt)m_fpu_state.env[FP_ENV_OPOFF+1]) << 16) |
550 ((UInt)m_fpu_state.env[FP_ENV_OPOFF]) );
551 printf(" fopsel: 0x%4x\n",
552 ((UInt)m_fpu_state.env[FP_ENV_OPSEL]) );
554 #endif
556 /* ---------------------------------------------------------------------
557 Implementation of the floating point instruction set.
558 ------------------------------------------------------------------ */
560 /* A pretty nasty kludge. Arithmetic is done using standard IEEE
561 doubles, which means that programs which rely on the extra accuracy
562 supplied by Intel's internal 80-bit format will get different
563 results.
565 To make exception handling tractable, we assume that the FPU is
566 running with all exceptions masked, so we do the "default fixup"
567 action for all exceptions. Fortunately that's fairly simple.
569 Support for non-normal numbers (infinities, nans, denorms, etc) is
570 minimal and probably wrong.
573 typedef
574 enum { Fp_Add, Fp_Sub, Fp_Mul, Fp_Div, Fp_SubR, Fp_DivR }
575 Fp_Op;
577 #if DEBUG
578 char* fp_Op_name ( Fp_Op op )
580 switch (op) {
581 case Fp_Add: return "add"; case Fp_Sub: return "sub";
582 case Fp_Mul: return "mul"; case Fp_Div: return "div";
583 case Fp_SubR: return "subr"; case Fp_DivR: return "divr";
584 default: panic("fp_Op_name");
586 return NULL; /*notreached*/
588 #endif
590 static
591 void fp_do_op_ST_ST ( UInt a_src, UInt a_dst, Fp_Op op, Bool pop )
593 double vd_src, vd_dst;
594 IFDB( if (dis) printf("\tf%s%s\t%%st(%d),%%st(%d)\n",
595 fp_Op_name(op), pop?"p":"",
596 a_src, a_dst ); )
597 if (!fp_is_empty_tag(fp_get_tag_ST(a_src)) &&
598 !fp_is_empty_tag(fp_get_tag_ST(a_dst))) {
599 vd_dst = fp_get_reg_ST(a_dst);
600 vd_src = fp_get_reg_ST(a_src);
601 switch (op) {
602 case Fp_Add: vd_dst = vd_dst + vd_src; break;
603 case Fp_Sub: vd_dst = vd_dst - vd_src; break;
604 case Fp_Mul: vd_dst = vd_dst * vd_src; break;
605 case Fp_Div: vd_dst = vd_dst / vd_src; break;
606 case Fp_SubR: vd_dst = vd_src - vd_dst; break;
607 case Fp_DivR: vd_dst = vd_src / vd_dst; break;
608 default: panic("fp_do_op_ST_ST");
610 } else {
611 vd_dst = NAN;
612 fp_set_stack_underflow();
614 fp_set_reg_ST(a_dst,vd_dst);
615 if (pop) (void)fp_pop();
618 static
619 void fp_do_COM_ST_ST ( UInt a_src, UInt a_dst, UInt nPops )
621 double vd_src, vd_dst;
622 IFDB( if (dis) printf("\tfcom%s\t%%st(%d),%%st(%d)\n",
623 nPops==0 ? "" : (nPops==1 ? "p" : "pp"),
624 a_src, a_dst ); )
625 if (!fp_is_empty_tag(fp_get_tag_ST(a_src)) &&
626 !fp_is_empty_tag(fp_get_tag_ST(a_dst))) {
627 vd_dst = fp_get_reg_ST(a_dst);
628 vd_src = fp_get_reg_ST(a_src);
629 fp_set_statusword_flags_COM(vd_dst,vd_src);
630 } else {
631 fp_set_statusword_flags_COM_STACKF();
632 fp_set_stack_underflow();
634 while (nPops > 0) {
635 (void)fp_pop();
636 nPops--;
640 static
641 void fp_do_op_mem_ST_0 ( UInt a_src,
642 IFDB(Text t_src CC)
643 Fp_Op op, Bool dbl )
645 double vd_src, vd_dst;
646 IFDB( if (dis) printf("\tf%s%c\t%s,%%st(0)\n",
647 fp_Op_name(op), dbl?'D':'F', t_src ); )
648 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
649 vd_dst = fp_get_reg_ST(0);
650 vd_src = dbl ? getDMem(a_src) : getFMem(a_src);
651 switch (op) {
652 case Fp_Add: vd_dst = vd_dst + vd_src; break;
653 case Fp_Sub: vd_dst = vd_dst - vd_src; break;
654 case Fp_Mul: vd_dst = vd_dst * vd_src; break;
655 case Fp_Div: vd_dst = vd_dst / vd_src; break;
656 case Fp_SubR: vd_dst = vd_src - vd_dst; break;
657 case Fp_DivR: vd_dst = vd_src / vd_dst; break;
658 default: panic("fp_do_op_mem_ST_0");
660 } else {
661 vd_dst = NAN;
662 fp_set_stack_underflow();
664 fp_set_reg_ST(0,vd_dst);
667 static
668 void fp_do_COM_mem_ST_0 ( UInt a_src,
669 IFDB( Text t_src CC)
670 Bool dbl, Bool pop )
672 double vd_src, vd_dst;
673 IFDB( if (dis) printf("\tfcom%s%c\t%s,%%st(0)\n",
674 pop?"p":"", dbl?'D':'F', t_src ); )
675 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
676 vd_dst = fp_get_reg_ST(0);
677 vd_src = dbl ? getDMem(a_src) : getFMem(a_src);
678 fp_set_statusword_flags_COM(vd_dst,vd_src);
679 } else {
680 fp_set_statusword_flags_COM_STACKF();
681 fp_set_stack_underflow();
683 if (pop) (void)fp_pop();
687 Addr do_one_insn_fp ( Addr r_eip, UChar first_opcode )
689 UChar modrm;
690 UInt a_addr, a_src, a_dst;
691 UInt opc_aux;
692 Bool isreg;
693 Int vis_addr;
694 Int vis_dst;
695 double vd_addr, vd_src, vd_dst;
697 # if DEBUG
698 Text t_opc_aux;
699 Text t_addr, t_dst;
700 Bool ppFpuState = False;
702 if (ppFpuState) {
703 printf("\n\nBEFORE\n");
704 printFpuState();
705 printf("\n");
707 # endif
709 /* assert that we are running with all exceptions masked */
710 assert( (m_fpu_state.env[FP_ENV_CTRL] & 0x3F) == 0x3F );
711 /* and the implication is that there are no unmasked exceptions
712 reported by the exception status flag. */
713 assert( fp_get_statusword_flag(FP_E_SUMMARY) == 0 );
715 modrm = *r_eip;
717 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
719 if (first_opcode == 0xD8) {
720 if (modrm < 0xC0) {
721 /* bits 5,4,3 are an opcode extension, and the modRM also
722 specifies an address. */
723 opc_aux = regno_from_modRM ( r_eip, 4 IFDB(CC &t_opc_aux) );
724 r_eip = amode_from_modRM ( r_eip, 4, &a_addr
725 IFDB(CC &t_addr), &isreg );
726 assert(!isreg);
727 switch (opc_aux) {
729 case 0: /* FADD single-real */
730 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC)
731 Fp_Add, False );
732 break;
734 case 1: /* FMUL single-real */
735 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC)
736 Fp_Mul, False );
737 break;
739 case 2: /* FCOM single-real */
740 fp_do_COM_mem_ST_0 ( a_addr, IFDB(t_addr CC)
741 False, False );
742 break;
744 case 3: /* FCOMP single-real */
745 fp_do_COM_mem_ST_0 ( a_addr, IFDB(t_addr CC)
746 False, True );
747 break;
749 case 4: /* FSUB single-real */
750 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC)
751 Fp_Sub, False );
752 break;
754 case 5: /* FSUBR single-real */
755 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC)
756 Fp_SubR, False );
757 break;
759 case 6: /* FDIV single-real */
760 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC)
761 Fp_Div, False );
762 break;
764 case 7: /* FDIVR single-real */
765 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC)
766 Fp_DivR, False );
767 break;
769 default:
770 printf("unhandled opc_aux = 0x%2x\n", opc_aux);
771 panic("do_one_insn_fp: first_opcode == 0xD8");
772 break;
774 } else {
775 /* The entire modRM byte is an opcode extension. */
776 r_eip++;
777 switch (modrm) {
779 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
780 fp_do_op_ST_ST ( modrm - 0xC0, 0, Fp_Add, False );
781 break;
783 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
784 fp_do_op_ST_ST ( modrm - 0xC8, 0, Fp_Mul, False );
785 break;
787 case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
788 fp_do_COM_ST_ST ( modrm - 0xD0, 0, 0 );
789 break;
791 case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
792 fp_do_COM_ST_ST ( modrm - 0xD8, 0, 1 );
793 break;
795 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
796 fp_do_op_ST_ST ( modrm - 0xE0, 0, Fp_Sub, False );
797 break;
799 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
800 fp_do_op_ST_ST ( modrm - 0xE8, 0, Fp_SubR, False );
801 break;
803 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
804 fp_do_op_ST_ST ( modrm - 0xF0, 0, Fp_Div, False );
805 break;
807 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
808 fp_do_op_ST_ST ( modrm - 0xF8, 0, Fp_DivR, False );
809 break;
811 default:
812 goto unhandled;
817 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
818 else
819 if (first_opcode == 0xD9) {
820 if (modrm < 0xC0) {
821 /* bits 5,4,3 are an opcode extension, and the modRM also
822 specifies an address. */
823 opc_aux = regno_from_modRM ( r_eip, 4 IFDB(CC &t_opc_aux) );
824 r_eip = amode_from_modRM ( r_eip, 4, &a_addr
825 IFDB(CC &t_addr), &isreg );
826 assert(!isreg);
827 switch (opc_aux) {
829 case 0: /* FLD single-real */
830 IFDB( if (dis) printf("\tfldF\t%s\n",t_addr); )
831 vd_addr = getFMem(a_addr);
832 fp_push(vd_addr);
833 break;
835 case 2: /* FST single-real */
836 IFDB( if (dis) printf("\tfstF\t%s\n",t_addr); )
837 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
838 vd_addr = fp_get_reg_ST(0);
839 } else {
840 vd_addr = NAN;
841 fp_set_stack_underflow();
843 setFMem(a_addr,vd_addr);
844 break;
846 case 3: /* FSTP single-real */
847 IFDB( if (dis) printf("\tfstpF\t%s\n",t_addr); )
848 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
849 vd_addr = fp_pop();
850 } else {
851 vd_addr = fp_pop(); /* then throw away result */
852 vd_addr = NAN;
853 fp_set_stack_underflow();
855 setFMem(a_addr,vd_addr);
856 break;
858 case 5: /* FLDCW */
859 IFDB( if (dis) printf("\tfldcw\t%s\n",t_addr); )
860 m_fpu_state.env[FP_ENV_CTRL] = (UShort)getIMem2(a_addr);
861 break;
863 case 7: /* FNSTCW */
864 IFDB( if (dis) printf("\tfnstcw\t%s\n",t_addr); )
865 setIMem2(a_addr,(UInt)m_fpu_state.env[FP_ENV_CTRL]);
866 break;
868 default:
869 printf("unhandled opc_aux = 0x%2x\n", opc_aux);
870 panic("do_one_insn_fp: first_opcode == 0xD9");
871 break;
873 } else {
874 /* The entire modRM byte is an opcode extension. */
875 r_eip++;
876 switch (modrm) {
878 case 0xC0 ... 0xC7: /* FLD %st(?) */
879 a_dst = (UInt)modrm - 0xC0;
880 IFDB( if (dis) printf("\tfld\t%%st(%d)\n",a_dst); )
881 if (!fp_is_empty_tag(fp_get_tag_ST(a_dst)) &&
882 fp_is_empty_tag(fp_get_tag_ST(7))) {
883 vd_dst = fp_get_reg_ST(a_dst);
884 } else {
885 vd_dst = NAN;
886 fp_set_stack_underflow();
888 fp_push(vd_dst);
889 break;
891 case 0xC8 ... 0xCF: /* FXCH %st(?) */
892 a_dst = (UInt)modrm - 0xC8;
893 IFDB( if (dis) printf("\tfxch\t%%st(%d)\n",a_dst); )
894 if (!fp_is_empty_tag(fp_get_tag_ST(a_dst)) &&
895 !fp_is_empty_tag(fp_get_tag_ST(0))) {
896 vd_dst = fp_get_reg_ST(a_dst);
897 vd_src = fp_get_reg_ST(0);
898 } else {
899 vd_dst = NAN;
900 vd_src = NAN;
901 fp_set_stack_underflow();
903 fp_set_reg_ST(a_dst,vd_src);
904 fp_set_reg_ST(0,vd_dst);
905 break;
907 case 0xE0: /* FCHS */
908 IFDB( if (dis) printf("\tfchs\n"); )
909 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
910 vd_dst = - fp_get_reg_ST(0);
911 } else {
912 vd_dst = NAN;
913 fp_set_stack_underflow();
915 fp_set_reg_ST(0,vd_dst);
916 break;
918 case 0xE1: /* FABS */
919 IFDB( if (dis) printf("\tfabs\n"); )
920 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
921 vd_dst = fabs(fp_get_reg_ST(0));
922 } else {
923 vd_dst = NAN;
924 fp_set_stack_underflow();
926 fp_set_reg_ST(0,vd_dst);
927 break;
929 case 0xE5:
930 /* An approximation to the correct behaviour */
931 IFDB( if (dis) printf("\tfxam\n"); )
932 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
933 vd_dst = fabs(fp_get_reg_ST(0));
934 if (isnan(vd_dst))
935 vis_dst = 1; /* C320 = 001 */
936 else if (isinf(vd_dst))
937 vis_dst = 3; /* C320 = 011 */
938 else if (vd_dst == 0.0 || vd_dst == -0.0)
939 vis_dst = 4; /* C320 = 100 */
940 else
941 vis_dst = 2; /* C320 = 010 */
942 fp_set_statusword_flag_to(FP_F_C1,
943 vd_dst < 0.0 ? 1 : 0);
944 } else {
945 vis_dst = 5; /* C320 = 101 */
946 /* no idea if this is right */
947 fp_set_statusword_flag_to(FP_F_C1, 0);
949 fp_set_statusword_flag_to(FP_F_C3, (vis_dst >> 2) & 1);
950 fp_set_statusword_flag_to(FP_F_C2, (vis_dst >> 1) & 1);
951 fp_set_statusword_flag_to(FP_F_C0, vis_dst & 1);
952 break;
954 case 0xE8: /* FLD1 */
955 IFDB( t_dst = "1"; )
956 vd_dst = 1.0;
957 goto do_fld_CONST;
958 case 0xEC: /* FLDLG2 */
959 IFDB( t_dst = "lg2"; )
960 vd_dst = 0.301029995663981143;
961 goto do_fld_CONST;
962 case 0xED: /* FLDLN2 */
963 IFDB( t_dst = "ln2"; )
964 vd_dst = 0.69314718055994530942;
965 goto do_fld_CONST;
966 case 0xEE: /* FLDZ */
967 IFDB( t_dst = "z"; )
968 vd_dst = 0.0;
969 goto do_fld_CONST;
970 do_fld_CONST:
971 IFDB( if (dis) printf("\tfld%s\n",t_dst); )
972 fp_push(vd_dst);
973 break;
975 case 0xF0: /* F2XM1 */
976 IFDB( if (dis) printf("\tf2xm1\n"); )
977 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
978 vd_dst = fp_calc_2xm1(fp_get_reg_ST(0));
979 } else {
980 vd_dst = NAN;
981 fp_set_stack_underflow();
983 fp_set_reg_ST(0,vd_dst);
984 break;
986 case 0xF1: /* FYL2X */
987 IFDB( if (dis) printf("\tfyl2x\n"); )
988 if (!fp_is_empty_tag(fp_get_tag_ST(0)) &&
989 !fp_is_empty_tag(fp_get_tag_ST(1))) {
990 vd_dst = fp_calc_yl2x(
991 fp_get_reg_ST(0), fp_get_reg_ST(1));
992 } else {
993 vd_dst = NAN;
994 fp_set_stack_underflow();
996 fp_set_reg_ST(1,vd_dst);
997 (void)fp_pop();
998 break;
1000 case 0xF3: /* FPATAN */
1001 IFDB( if (dis) printf("\tfpatan\n"); )
1002 if (!fp_is_empty_tag(fp_get_tag_ST(0)) &&
1003 !fp_is_empty_tag(fp_get_tag_ST(1))) {
1004 vd_dst = atan2(
1005 fp_get_reg_ST(1), fp_get_reg_ST(0));
1006 } else {
1007 vd_dst = NAN;
1008 fp_set_stack_underflow();
1010 fp_set_reg_ST(1,vd_dst);
1011 (void)fp_pop();
1012 break;
1014 case 0xF8: { /* FPREM */
1015 /* Very incomplete implementation. */
1016 Int qq;
1017 IFDB( if (dis) printf("\tfprem\n"); )
1018 if (!fp_is_empty_tag(fp_get_tag_ST(0)) &&
1019 !fp_is_empty_tag(fp_get_tag_ST(1))) {
1020 fp_calc_fprem( &qq, &vd_dst,
1021 fp_get_reg_ST(0), fp_get_reg_ST(1) );
1022 fp_set_statusword_flag_to(FP_F_C0, (qq & 4) ? 1 : 0);
1023 fp_set_statusword_flag_to(FP_F_C1, (qq & 1) ? 1 : 0);
1024 fp_set_statusword_flag_to(FP_F_C2, 0); /* reduction complete */
1025 fp_set_statusword_flag_to(FP_F_C3, (qq & 2) ? 1 : 0);
1026 } else {
1027 vd_dst = NAN;
1028 fp_set_stack_underflow();
1029 fp_set_statusword_flag_to(FP_F_C1, 0); /* stack underflow */
1031 fp_set_reg_ST(0,vd_dst);
1032 break;
1034 case 0xF9: /* FYL2XP1 */
1035 IFDB( if (dis) printf("\tfyl2xp1\n"); )
1036 if (!fp_is_empty_tag(fp_get_tag_ST(0)) &&
1037 !fp_is_empty_tag(fp_get_tag_ST(1))) {
1038 vd_dst = fp_calc_yl2xp1(
1039 fp_get_reg_ST(0), fp_get_reg_ST(1));
1040 } else {
1041 vd_dst = NAN;
1042 fp_set_stack_underflow();
1044 fp_set_reg_ST(1,vd_dst);
1045 (void)fp_pop();
1046 break;
1048 case 0xFA: /* FSQRT */
1049 IFDB( if (dis) printf("\tfsqrt\n"); )
1050 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1051 vd_dst = sqrt(fp_get_reg_ST(0));
1052 } else {
1053 vd_dst = NAN;
1054 fp_set_stack_underflow();
1056 fp_set_reg_ST(0,vd_dst);
1057 break;
1059 case 0xFC: /* FRNDINT */
1060 IFDB( if (dis) printf("\tfrndint\n"); )
1061 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1062 vd_dst = rint(fp_get_reg_ST(0));
1063 } else {
1064 vd_dst = NAN;
1065 fp_set_stack_underflow();
1067 fp_set_reg_ST(0,vd_dst);
1068 break;
1070 case 0xFD: /* FSCALE */
1071 IFDB( if (dis) printf("\tfscale\n"); )
1072 if (!fp_is_empty_tag(fp_get_tag_ST(0)) &&
1073 !fp_is_empty_tag(fp_get_tag_ST(1))) {
1074 vd_dst = fp_calc_scale(
1075 fp_get_reg_ST(0), fp_get_reg_ST(1));
1076 } else {
1077 vd_dst = NAN;
1078 fp_set_stack_underflow();
1080 fp_set_reg_ST(0,vd_dst);
1081 break;
1083 case 0xFE: /* FSIN */
1084 IFDB( if (dis) printf("\tfsin\n"); )
1085 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1086 vd_dst = sin(fp_get_reg_ST(0));
1087 } else {
1088 vd_dst = NAN;
1089 fp_set_stack_underflow();
1091 fp_set_reg_ST(0,vd_dst);
1092 break;
1094 case 0xFF: /* FCOS */
1095 IFDB( if (dis) printf("\tfcos\n"); )
1096 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1097 vd_dst = cos(fp_get_reg_ST(0));
1098 } else {
1099 vd_dst = NAN;
1100 fp_set_stack_underflow();
1102 fp_set_reg_ST(0,vd_dst);
1103 break;
1105 default:
1106 goto unhandled;
1111 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
1112 else
1113 if (first_opcode == 0xDA) {
1114 if (modrm < 0xC0) {
1115 /* bits 5,4,3 are an opcode extension, and the modRM also
1116 specifies an address. */
1117 opc_aux = regno_from_modRM ( r_eip, 4 IFDB(CC &t_opc_aux) );
1118 r_eip = amode_from_modRM ( r_eip, 4, &a_addr
1119 IFDB(CC &t_addr), &isreg );
1120 assert(!isreg);
1121 switch (opc_aux) {
1123 case 0: /* FIADD m32int */
1124 IFDB( if (dis) printf("\tfiaddl\t%s\n",t_addr); )
1125 vis_addr = getIMem4(a_addr);
1126 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1127 vd_addr = fp_get_reg_ST(0) + (double)vis_addr;
1128 fp_set_reg_ST(0, vd_addr);
1129 /* we should set C1 here */
1130 } else {
1131 fp_set_reg_ST(0, NAN);
1132 fp_set_stack_underflow();
1134 break;
1136 case 1: /* FIMUL m32int */
1137 IFDB( if (dis) printf("\tfimull\t%s\n",t_addr); )
1138 vis_addr = getIMem4(a_addr);
1139 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1140 vd_addr = fp_get_reg_ST(0) * (double)vis_addr;
1141 fp_set_reg_ST(0, vd_addr);
1142 /* we should set C1 here */
1143 } else {
1144 fp_set_reg_ST(0, NAN);
1145 fp_set_stack_underflow();
1147 break;
1149 case 2: /* FICOM m32int */
1150 IFDB( if (dis) printf("\tficoml\t%s\n",t_addr); )
1151 vis_addr = getIMem4(a_addr);
1152 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1153 vd_dst = fp_get_reg_ST(0);
1154 vd_src = (double)vis_addr;
1155 fp_set_statusword_flags_COM(vd_dst,vd_src);
1156 /* we should set C1 here */
1157 } else {
1158 fp_set_statusword_flags_COM_STACKF();
1159 fp_set_stack_underflow();
1161 break;
1163 case 3: /* FICOMP m32int */
1164 IFDB( if (dis) printf("\tficompl\t%s\n",t_addr); )
1165 vis_addr = getIMem4(a_addr);
1166 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1167 vd_dst = fp_get_reg_ST(0);
1168 vd_src = (double)vis_addr;
1169 fp_set_statusword_flags_COM(vd_dst,vd_src);
1170 /* we should set C1 here */
1171 } else {
1172 fp_set_statusword_flags_COM_STACKF();
1173 fp_set_stack_underflow();
1175 (void)fp_pop();
1176 break;
1178 case 4: /* FISUB m32int */
1179 IFDB( if (dis) printf("\tfisubl\t%s\n",t_addr); )
1180 vis_addr = getIMem4(a_addr);
1181 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1182 vd_addr = fp_get_reg_ST(0) - (double)vis_addr;
1183 fp_set_reg_ST(0, vd_addr);
1184 /* we should set C1 here */
1185 } else {
1186 fp_set_reg_ST(0, NAN);
1187 fp_set_stack_underflow();
1189 break;
1191 case 5: /* FISUBR m32int */
1192 IFDB( if (dis) printf("\tfisubrl\t%s\n",t_addr); )
1193 vis_addr = getIMem4(a_addr);
1194 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1195 vd_addr = (double)vis_addr - fp_get_reg_ST(0);
1196 fp_set_reg_ST(0, vd_addr);
1197 /* we should set C1 here */
1198 } else {
1199 fp_set_reg_ST(0, NAN);
1200 fp_set_stack_underflow();
1202 break;
1204 case 6: /* FIDIV m32int */
1205 IFDB( if (dis) printf("\tfidivl\t%s\n",t_addr); )
1206 vis_addr = getIMem4(a_addr);
1207 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1208 vd_addr = fp_get_reg_ST(0) / (double)vis_addr;
1209 fp_set_reg_ST(0, vd_addr);
1210 /* we should set C1 here */
1211 } else {
1212 fp_set_reg_ST(0, NAN);
1213 fp_set_stack_underflow();
1215 break;
1217 case 7: /* FIDIVR m32int */
1218 IFDB( if (dis) printf("\tfidivl\t%s\n",t_addr); )
1219 vis_addr = getIMem4(a_addr);
1220 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1221 vd_addr = (double)vis_addr / fp_get_reg_ST(0);
1222 fp_set_reg_ST(0, vd_addr);
1223 /* we should set C1 here */
1224 } else {
1225 fp_set_reg_ST(0, NAN);
1226 fp_set_stack_underflow();
1228 break;
1230 default:
1231 printf("unhandled opc_aux = 0x%2x\n", opc_aux);
1232 panic("do_one_insn_fp: first_opcode == 0xDA");
1233 break;
1235 } else {
1236 /* The entire modRM byte is an opcode extension. */
1237 r_eip++;
1238 switch (modrm) {
1240 case 0xE9: /* FUCOMPP %st(0),%st(1) */
1241 /* seems the wrong way round. */
1242 fp_do_COM_ST_ST ( 1, 0, 2 );
1243 break;
1245 default:
1246 goto unhandled;
1251 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
1252 else
1253 if (first_opcode == 0xDB) {
1254 if (modrm < 0xC0) {
1255 /* bits 5,4,3 are an opcode extension, and the modRM also
1256 specifies an address. */
1257 opc_aux = regno_from_modRM ( r_eip, 4 IFDB(CC &t_opc_aux) );
1258 r_eip = amode_from_modRM ( r_eip, 4, &a_addr
1259 IFDB(CC &t_addr), &isreg );
1260 assert(!isreg);
1261 switch (opc_aux) {
1263 case 0: /* FILD m32int */
1264 IFDB( if (dis) printf("\tfildl\t%s\n",t_addr); )
1265 vis_addr = getIMem4(a_addr);
1266 fp_push ( (double)vis_addr );
1267 break;
1269 case 2: /* FIST m32 */
1270 IFDB( if (dis) printf("\tfistl\t%s\n",t_addr); )
1271 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1272 vd_addr = fp_get_reg_ST(0);
1273 if (vd_addr <= -2147483648.5 ||
1274 vd_addr >= 2147483647.5)
1275 vis_addr = 0x80000000; /* 32-bit int indefinite */
1276 else
1277 vis_addr = (Int)vd_addr;
1278 } else {
1279 vis_addr = 0x80000000; /* 32-bit indefinite */
1280 fp_set_stack_underflow();
1282 setIMem4(a_addr,vis_addr);
1283 break;
1285 case 3: /* FISTP m32 */
1286 IFDB( if (dis) printf("\tfistpl\t%s\n",t_addr); )
1287 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1288 vd_addr = fp_pop();
1289 if (vd_addr <= -2147483648.5 ||
1290 vd_addr >= 2147483647.5)
1291 vis_addr = 0x80000000; /* 32-bit int indefinite */
1292 else
1293 vis_addr = (Int)vd_addr;
1294 } else {
1295 vd_addr = fp_pop(); /* then throw away result */
1296 vis_addr = 0x80000000; /* 32-bit indefinite */
1297 fp_set_stack_underflow();
1299 setIMem4(a_addr,vis_addr);
1300 break;
1302 case 5: /* FLD extended-real */
1303 IFDB( if (dis) printf("\tfldT\t%s\n",t_addr); )
1304 vd_addr = getTMem(a_addr);
1305 fp_push(vd_addr);
1306 break;
1308 case 7: /* FSTP extended-real */
1309 IFDB( if (dis) printf("\tfstpT\t%s\n",t_addr); )
1310 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1311 vd_addr = fp_pop();
1312 } else {
1313 vd_addr = fp_pop(); /* then throw away result */
1314 vd_addr = NAN;
1315 fp_set_stack_underflow();
1317 setTMem(a_addr,vd_addr);
1318 break;
1320 default:
1321 printf("unhandled opc_aux = 0x%2x\n", opc_aux);
1322 panic("do_one_insn_fp: first_opcode == 0xDB");
1323 break;
1325 } else {
1326 /* The entire modRM byte is an opcode extension. */
1327 r_eip++;
1328 switch (modrm) {
1329 default:
1330 goto unhandled;
1335 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
1336 else
1337 if (first_opcode == 0xDC) {
1338 if (modrm < 0xC0) {
1339 /* bits 5,4,3 are an opcode extension, and the modRM also
1340 specifies an address. */
1341 opc_aux = regno_from_modRM ( r_eip, 4 IFDB(CC &t_opc_aux) );
1342 r_eip = amode_from_modRM ( r_eip, 4, &a_addr
1343 IFDB(CC &t_addr), &isreg );
1344 assert(!isreg);
1345 switch (opc_aux) {
1347 case 0: /* FADD double-real */
1348 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC) Fp_Add, True );
1349 break;
1351 case 1: /* FMUL double-real */
1352 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC) Fp_Mul, True );
1353 break;
1355 case 2: /* FCOM double-real */
1356 fp_do_COM_mem_ST_0 ( a_addr, IFDB(t_addr CC) True, False );
1357 break;
1359 case 3: /* FCOMP double-real */
1360 fp_do_COM_mem_ST_0 ( a_addr, IFDB(t_addr CC) True, True );
1361 break;
1363 case 4: /* FSUB double-real */
1364 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC) Fp_Sub, True );
1365 break;
1367 case 5: /* FSUBR double-real */
1368 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC) Fp_SubR, True );
1369 break;
1371 case 6: /* FDIV double-real */
1372 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC) Fp_Div, True );
1373 break;
1375 case 7: /* FDIVR double-real */
1376 fp_do_op_mem_ST_0 ( a_addr, IFDB(t_addr CC) Fp_DivR, True );
1377 break;
1379 default:
1380 printf("unhandled opc_aux = 0x%2x\n", opc_aux);
1381 panic("do_one_insn_fp: first_opcode == 0xDC");
1382 break;
1384 } else {
1385 /* The entire modRM byte is an opcode extension. */
1386 r_eip++;
1387 switch (modrm) {
1389 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
1390 fp_do_op_ST_ST ( 0, modrm - 0xC0, Fp_Add, False );
1391 break;
1393 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
1394 fp_do_op_ST_ST ( 0, modrm - 0xC8, Fp_Mul, False );
1395 break;
1397 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
1398 fp_do_op_ST_ST ( 0, modrm - 0xE0, Fp_SubR, False );
1399 break;
1401 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
1402 fp_do_op_ST_ST ( 0, modrm - 0xE8, Fp_Sub, False );
1403 break;
1405 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
1406 fp_do_op_ST_ST ( 0, modrm - 0xF8, Fp_Div, False );
1407 break;
1409 default:
1410 goto unhandled;
1415 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
1416 else
1417 if (first_opcode == 0xDD) {
1418 if (modrm < 0xC0) {
1419 /* bits 5,4,3 are an opcode extension, and the modRM also
1420 specifies an address. */
1421 opc_aux = regno_from_modRM ( r_eip, 4 IFDB(CC &t_opc_aux) );
1422 r_eip = amode_from_modRM ( r_eip, 4, &a_addr
1423 IFDB(CC &t_addr), &isreg );
1424 assert(!isreg);
1425 switch (opc_aux) {
1427 case 0: /* FLD double-real */
1428 IFDB( if (dis) printf("\tfldD\t%s\n",t_addr); )
1429 vd_addr = getDMem(a_addr);
1430 fp_push(vd_addr);
1431 break;
1433 case 2: /* FST double-real */
1434 IFDB( if (dis) printf("\tfstD\t%s\n",t_addr); )
1435 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1436 vd_addr = fp_get_reg_ST(0);
1437 } else {
1438 vd_addr = NAN;
1439 fp_set_stack_underflow();
1441 setDMem(a_addr,vd_addr);
1442 break;
1444 case 3: /* FSTP double-real */
1445 IFDB( if (dis) printf("\tfstpD\t%s\n",t_addr); )
1446 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1447 vd_addr = fp_pop();
1448 } else {
1449 vd_addr = fp_pop(); /* then throw away result */
1450 vd_addr = NAN;
1451 fp_set_stack_underflow();
1453 setDMem(a_addr,vd_addr);
1454 break;
1455 default:
1456 printf("unhandled opc_aux = 0x%2x\n", opc_aux);
1457 panic("do_one_insn_fp: first_opcode == 0xDD");
1458 break;
1460 } else {
1461 /* The entire modRM byte is an opcode extension. */
1462 r_eip++;
1463 switch (modrm) {
1465 case 0xC0 ... 0xC7: /* FFREE %st(?) */
1466 a_dst = (UInt)modrm - 0xC0;
1467 IFDB( if (dis) printf("\tffree\t%%st(%d)\n", a_dst); )
1468 fp_set_tag_ST( a_dst, FP_TAG_EMPTY );
1469 break;
1471 case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
1472 a_dst = (UInt)modrm - 0xD0;
1473 IFDB( if (dis) printf("\tfst\t%%st(0),%%st(%d)\n",
1474 a_dst); )
1475 if ( /* don't check the destination tag */
1476 !fp_is_empty_tag(fp_get_tag_ST(0))) {
1477 vd_dst = fp_get_reg_ST(0);
1478 } else {
1479 vd_dst = NAN;
1480 fp_set_stack_underflow();
1482 fp_set_reg_ST(a_dst,vd_dst);
1483 break;
1485 case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
1486 a_dst = (UInt)modrm - 0xD8;
1487 IFDB( if (dis) printf("\tfstp\t%%st(0),%%st(%d)\n",
1488 a_dst); )
1489 if ( /* don't check the destination tag */
1490 !fp_is_empty_tag(fp_get_tag_ST(0))) {
1491 vd_dst = fp_get_reg_ST(0);
1492 } else {
1493 vd_dst = NAN;
1494 fp_set_stack_underflow();
1496 fp_set_reg_ST(a_dst,vd_dst);
1497 (void)fp_pop();
1498 break;
1500 case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
1501 a_src = (UInt)modrm - 0xE0;
1502 IFDB( if (dis) printf("\tfucom\t%%st(0),%%st(%d)\n",
1503 a_src); )
1504 if (!fp_is_empty_tag(fp_get_tag_ST(a_src)) &&
1505 !fp_is_empty_tag(fp_get_tag_ST(0))) {
1506 vd_src = fp_get_reg_ST(a_src);
1507 vd_dst = fp_get_reg_ST(0);
1508 fp_set_statusword_flags_COM(vd_dst,vd_src);
1509 } else {
1510 fp_set_statusword_flags_COM_STACKF();
1511 fp_set_stack_underflow();
1513 break;
1515 case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
1516 a_src = (UInt)modrm - 0xE8;
1517 IFDB( if (dis) printf("\tfucomp\t%%st(0),%%st(%d)\n",
1518 a_src); )
1519 if (!fp_is_empty_tag(fp_get_tag_ST(a_src)) &&
1520 !fp_is_empty_tag(fp_get_tag_ST(0))) {
1521 vd_src = fp_get_reg_ST(a_src);
1522 vd_dst = fp_get_reg_ST(0);
1523 fp_set_statusword_flags_COM(vd_dst,vd_src);
1524 } else {
1525 fp_set_statusword_flags_COM_STACKF();
1526 fp_set_stack_underflow();
1528 (void)fp_pop();
1529 break;
1531 default:
1532 goto unhandled;
1537 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
1538 else
1539 if (first_opcode == 0xDE) {
1540 if (modrm < 0xC0) {
1541 /* bits 5,4,3 are an opcode extension, and the modRM also
1542 specifies an address. */
1543 opc_aux = regno_from_modRM ( r_eip, 4 IFDB(CC &t_opc_aux) );
1544 r_eip = amode_from_modRM ( r_eip, 4, &a_addr
1545 IFDB(CC &t_addr), &isreg );
1546 assert(!isreg);
1547 switch (opc_aux) {
1548 default:
1549 printf("unhandled opc_aux = 0x%2x\n", opc_aux);
1550 panic("do_one_insn_fp: first_opcode == 0xDE");
1551 break;
1553 } else {
1554 /* The entire modRM byte is an opcode extension. */
1555 r_eip++;
1556 switch (modrm) {
1558 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
1559 fp_do_op_ST_ST ( 0, modrm - 0xC0, Fp_Add, True );
1560 break;
1562 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
1563 fp_do_op_ST_ST ( 0, modrm - 0xC8, Fp_Mul, True );
1564 break;
1566 case 0xD9: /* FCOMPP %st(0),%st(1) */
1567 /* seems the wrong way round. */
1568 fp_do_COM_ST_ST ( 1, 0, 2 );
1569 break;
1571 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
1572 fp_do_op_ST_ST ( 0, modrm - 0xE0, Fp_SubR, True );
1573 break;
1575 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
1576 fp_do_op_ST_ST ( 0, modrm - 0xE8, Fp_Sub, True );
1577 break;
1579 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
1580 fp_do_op_ST_ST ( 0, modrm - 0xF0, Fp_DivR, True );
1581 break;
1583 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
1584 fp_do_op_ST_ST ( 0, modrm - 0xF8, Fp_Div, True );
1585 break;
1587 default:
1588 goto unhandled;
1593 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
1594 else
1595 if (first_opcode == 0xDF) {
1596 if (modrm < 0xC0) {
1597 /* bits 5,4,3 are an opcode extension, and the modRM also
1598 specifies an address. */
1599 opc_aux = regno_from_modRM ( r_eip, 4 IFDB(CC &t_opc_aux) );
1600 r_eip = amode_from_modRM ( r_eip, 4, &a_addr
1601 IFDB(CC &t_addr), &isreg );
1602 assert(!isreg);
1603 switch (opc_aux) {
1605 case 0: /* FILD m16int */
1606 IFDB( if (dis) printf("\tfildw\t%s\n",t_addr); )
1607 vis_addr = extend_s_16to32(getIMem2(a_addr));
1608 fp_push ( (double) vis_addr );
1609 break;
1611 case 3: /* FISTP m16 */
1612 IFDB( if (dis) printf("\tfistpw\t%s\n",t_addr); )
1613 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1614 vd_addr = fp_pop();
1615 if (vd_addr <= -32768.50 ||
1616 vd_addr >= 32767.50)
1617 vis_addr = 0x00008000; /* 16-bit int indefinite */
1618 else
1619 vis_addr = (Short)vd_addr;
1620 } else {
1621 vd_addr = fp_pop(); /* then throw away result */
1622 vis_addr = 0x00008000; /* 32-bit indefinite */
1623 fp_set_stack_underflow();
1625 setIMem2(a_addr,vis_addr);
1626 break;
1628 case 5: { /* FILD m64int */
1629 ULong vis_addr64;
1630 IFDB( if (dis) printf("\tfildq\t%s\n",t_addr); )
1631 vis_addr = getIMem4(a_addr+4);
1632 vis_addr64 = ((ULong)vis_addr) << 32;
1633 vis_addr = getIMem4(a_addr);
1634 vis_addr64 += (ULong)vis_addr;
1635 fp_push ( (double) ((Long)vis_addr64) );
1636 break;
1639 case 7: { /* FISTP m64int */
1640 ULong vis_addr64;
1641 IFDB( if (dis) printf("\tfistpq\t%s\n",t_addr); )
1642 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1643 vd_addr = fp_pop();
1644 if (vd_addr <= -9223372036854775808.5 ||
1645 vd_addr >= 9223372036854775807.5)
1646 vis_addr64 = 0x8000000000000000LL;
1647 /* 64-bit int indefinite */
1648 else
1649 vis_addr64 = (Long)vd_addr;
1650 } else {
1651 vd_addr = fp_pop(); /* then throw away result */
1652 vis_addr64 = 0x8000000000000000LL; /* 64-bit indefinite */
1653 fp_set_stack_underflow();
1655 setIMem4(a_addr,vis_addr64 & 0xFFFFFFFFLL);
1656 setIMem4(a_addr+4, (((Long)vis_addr64) >> 32)
1657 & 0xFFFFFFFFLL);
1658 break;
1661 default:
1662 printf("unhandled opc_aux = 0x%2x\n", opc_aux);
1663 panic("do_one_insn_fp: first_opcode == 0xDF");
1664 break;
1666 } else {
1667 /* The entire modRM byte is an opcode extension. */
1668 r_eip++;
1669 switch (modrm) {
1671 case 0xE0: /* FNSTSW %ax */
1672 IFDB( if (dis) printf("\tfnstsw\t%%ax\n"); )
1673 setIReg2(R_EAX, (UInt)m_fpu_state.env[FP_ENV_STAT]);
1674 break;
1676 default:
1677 goto unhandled;
1682 /* -+-+-+-+-+-+-+-+-+-+-+-+ Unhandled ESC opcode +-+-+-+ */
1683 else goto unhandled;
1685 # if DEBUG
1686 if (ppFpuState) {
1687 printf("\nAFTER\n");
1688 printFpuState();
1689 printf("\n");
1691 # endif
1693 return r_eip;
1695 unhandled:
1696 hd_message(Hd_DebugMsg,
1697 "first opcode = 0x%x, modRM = 0x%x",
1698 (UInt)first_opcode, (UInt)modrm );
1699 panic("do_one_insn_fp: unhandled first_opcode/modrm combination");
1700 assert(0);
1703 /*--------------------------------------------------------------------*/
1704 /*--- end hd_fpu.c ---*/
1705 /*--------------------------------------------------------------------*/