2 /*--------------------------------------------------------------------*/
3 /*--- Implementation of the floating point instruction set. ---*/
5 /*--------------------------------------------------------------------*/
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
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 ------------------------------------------------------------------ */
39 UInt
fp_get_tos ( void )
41 return (m_fpu_state
.env
[FP_ENV_STAT
] >> FP_F_TOS_LO
) & 7;
45 UInt
read_bit_array ( UChar
* arr
, UInt n
)
47 UChar c
= arr
[n
>> 3];
53 void write_bit_array ( UChar
* arr
, UInt n
, UInt b
)
55 UChar c
= arr
[n
>> 3];
62 /* Read an IEEE double from the memory image of an Intel 80-bit
63 extended floating-point number.
66 double fp_double_from_extended ( UChar
* e_lsb
)
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];
77 bexp
= 0; /* preserve zeroes */
80 bexp
= 0x7FF; /* preserve Infs/Nans */
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 ) );
97 /* Given an IEEE double, create the memory image of an Intel 80-bit
98 extended floating-point number.
101 void fp_extended_from_double ( UChar
* e_lsb
, double d
)
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);
112 bexp
= 0; /* preserve zeroes */
115 bexp
= 0x7FFF; /* preserve Infs/Nans */
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
,
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. */
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 )
143 for (st
= 0; st
< 8; st
++) {
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 )
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 ------------------------------------------------------------------ */
167 void setFMem ( UInt addr
, double f
)
169 * ((float*)addr
) = (float)f
;
174 double getFMem ( UInt addr
)
176 return (double) (* ((float*)addr
));
181 void setDMem ( UInt addr
, double f
)
183 * ((double*)addr
) = f
;
188 double getDMem ( UInt addr
)
190 return (* ((double*)addr
));
195 void setTMem ( UInt addr
, double f
)
197 fp_extended_from_double ( (Addr
)addr
, f
);
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
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;
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;
229 void fp_set_statusword_flag_to ( UInt flagno
, UInt bit
)
231 if (flagno
< 0 || flagno
> 15) panic("fp_set_statusword_flag_to");
233 m_fpu_state
.env
[FP_ENV_STAT
] |= (1 << flagno
);
235 m_fpu_state
.env
[FP_ENV_STAT
] &= ~(1 << flagno
);
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);
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);
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
);
269 UInt
fp_STno_to_regno ( UInt stregno
)
271 UInt regno
= fp_get_tos();
272 assert(regno
>= 0 && regno
< 8);
274 if (regno
>= 8) regno
-= 8;
275 assert(regno
>= 0 && regno
< 8);
281 void fp_dec_tos ( void )
283 fp_set_tos ( fp_STno_to_regno ( 7 ));
288 void fp_inc_tos ( void )
290 fp_set_tos ( fp_STno_to_regno ( 1 ));
295 Bool
fp_is_empty_tag ( UInt tag
)
297 return tag
== FP_TAG_EMPTY
;
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;
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
) );
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
));
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
);
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
) );
347 void fp_set_reg_ST ( UInt str
, double d
)
350 if (str
< 0 || str
> 7) panic("fp_set_reg_ST");
351 r
= fp_STno_to_regno(str
);
357 double fp_get_reg ( UInt r
)
360 if (r
< 0 || r
> 7) panic("fp_get_reg");
361 d
= m_fpu_data_regs
[r
];
367 double fp_get_reg_ST ( UInt str
)
370 if (str
< 0 || str
> 7) panic("fp_get_reg_ST");
371 r
= fp_STno_to_regno(str
);
372 return fp_get_reg(r
);
377 void fp_set_tos_reg ( double d
)
379 fp_set_reg ( fp_get_tos(), d
);
384 double fp_get_tos_reg ( void )
386 return fp_get_reg ( fp_get_tos() );
391 void fp_set_tos_reg_QNaN ( void )
393 fp_set_reg ( fp_get_tos(), NAN
/* see <nan.h> */ );
398 double fp_pop ( void )
400 double d
= fp_get_tos_reg();
401 fp_set_tag ( fp_get_tos(), FP_TAG_EMPTY
);
406 /* Push d and update flags. */
409 void fp_push ( double d
)
411 if (fp_is_empty_tag(fp_get_tag_ST(7))) {
414 fp_set_statusword_flag_to(FP_F_C1
, d
== 0.0);
417 fp_set_tos_reg_QNaN();
418 fp_set_stack_overflow();
423 void fp_set_statusword_flags_COM ( double vd_dst
, double vd_src
)
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;
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);
437 void fp_set_statusword_flags_COM_STACKF ( void )
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);
446 double fp_calc_yl2xp1 ( double st_0
, double st_1
)
449 st_0
= log(st_0
) / log(2.0);
455 double fp_calc_yl2x ( double st_0
, double st_1
)
457 st_0
= log(st_0
) / log(2.0);
463 double fp_calc_2xm1 ( double st_0
)
465 st_0
= st_0
* 0.69314718055994530942;
472 double fp_calc_scale ( double st_0
, double st_1
)
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; };
484 if (st_1
< -2.0*308.0) st_1
= -2.0*308.0;
485 n
= ((Int
)(floor(-st_1
)));
487 if (n
> 2*308) n
= 2*308;
488 while (n
> 0) { n
--; st_0
*= 0.5; };
494 void fp_calc_fprem ( Int
* qq
, double* result
, double st_0
, double st_1
)
496 double tmp
= st_0
/ st_1
;
498 *qq
= - (Int
)floor(-tmp
);
500 *qq
= (Int
)floor(tmp
);
501 *result
= st_0
- (st_1
* (double)(*qq
));
506 void printFpuState ( void )
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
] );
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
)] );
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
]) );
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
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.
574 enum { Fp_Add
, Fp_Sub
, Fp_Mul
, Fp_Div
, Fp_SubR
, Fp_DivR
}
578 char* fp_Op_name ( Fp_Op 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*/
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":"",
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
);
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");
612 fp_set_stack_underflow();
614 fp_set_reg_ST(a_dst
,vd_dst
);
615 if (pop
) (void)fp_pop();
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"),
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
);
631 fp_set_statusword_flags_COM_STACKF();
632 fp_set_stack_underflow();
641 void fp_do_op_mem_ST_0 ( UInt a_src
,
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
);
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");
662 fp_set_stack_underflow();
664 fp_set_reg_ST(0,vd_dst
);
668 void fp_do_COM_mem_ST_0 ( UInt a_src
,
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
);
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
)
690 UInt a_addr
, a_src
, a_dst
;
695 double vd_addr
, vd_src
, vd_dst
;
700 Bool ppFpuState
= False
;
703 printf("\n\nBEFORE\n");
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 );
717 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
719 if (first_opcode
== 0xD8) {
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
);
729 case 0: /* FADD single-real */
730 fp_do_op_mem_ST_0 ( a_addr
, IFDB(t_addr CC
)
734 case 1: /* FMUL single-real */
735 fp_do_op_mem_ST_0 ( a_addr
, IFDB(t_addr CC
)
739 case 2: /* FCOM single-real */
740 fp_do_COM_mem_ST_0 ( a_addr
, IFDB(t_addr CC
)
744 case 3: /* FCOMP single-real */
745 fp_do_COM_mem_ST_0 ( a_addr
, IFDB(t_addr CC
)
749 case 4: /* FSUB single-real */
750 fp_do_op_mem_ST_0 ( a_addr
, IFDB(t_addr CC
)
754 case 5: /* FSUBR single-real */
755 fp_do_op_mem_ST_0 ( a_addr
, IFDB(t_addr CC
)
759 case 6: /* FDIV single-real */
760 fp_do_op_mem_ST_0 ( a_addr
, IFDB(t_addr CC
)
764 case 7: /* FDIVR single-real */
765 fp_do_op_mem_ST_0 ( a_addr
, IFDB(t_addr CC
)
770 printf("unhandled opc_aux = 0x%2x\n", opc_aux
);
771 panic("do_one_insn_fp: first_opcode == 0xD8");
775 /* The entire modRM byte is an opcode extension. */
779 case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
780 fp_do_op_ST_ST ( modrm
- 0xC0, 0, Fp_Add
, False
);
783 case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
784 fp_do_op_ST_ST ( modrm
- 0xC8, 0, Fp_Mul
, False
);
787 case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
788 fp_do_COM_ST_ST ( modrm
- 0xD0, 0, 0 );
791 case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
792 fp_do_COM_ST_ST ( modrm
- 0xD8, 0, 1 );
795 case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
796 fp_do_op_ST_ST ( modrm
- 0xE0, 0, Fp_Sub
, False
);
799 case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
800 fp_do_op_ST_ST ( modrm
- 0xE8, 0, Fp_SubR
, False
);
803 case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
804 fp_do_op_ST_ST ( modrm
- 0xF0, 0, Fp_Div
, False
);
807 case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
808 fp_do_op_ST_ST ( modrm
- 0xF8, 0, Fp_DivR
, False
);
817 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
819 if (first_opcode
== 0xD9) {
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
);
829 case 0: /* FLD single-real */
830 IFDB( if (dis
) printf("\tfldF\t%s\n",t_addr
); )
831 vd_addr
= getFMem(a_addr
);
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);
841 fp_set_stack_underflow();
843 setFMem(a_addr
,vd_addr
);
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))) {
851 vd_addr
= fp_pop(); /* then throw away result */
853 fp_set_stack_underflow();
855 setFMem(a_addr
,vd_addr
);
859 IFDB( if (dis
) printf("\tfldcw\t%s\n",t_addr
); )
860 m_fpu_state
.env
[FP_ENV_CTRL
] = (UShort
)getIMem2(a_addr
);
864 IFDB( if (dis
) printf("\tfnstcw\t%s\n",t_addr
); )
865 setIMem2(a_addr
,(UInt
)m_fpu_state
.env
[FP_ENV_CTRL
]);
869 printf("unhandled opc_aux = 0x%2x\n", opc_aux
);
870 panic("do_one_insn_fp: first_opcode == 0xD9");
874 /* The entire modRM byte is an opcode extension. */
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
);
886 fp_set_stack_underflow();
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);
901 fp_set_stack_underflow();
903 fp_set_reg_ST(a_dst
,vd_src
);
904 fp_set_reg_ST(0,vd_dst
);
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);
913 fp_set_stack_underflow();
915 fp_set_reg_ST(0,vd_dst
);
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));
924 fp_set_stack_underflow();
926 fp_set_reg_ST(0,vd_dst
);
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));
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 */
941 vis_dst
= 2; /* C320 = 010 */
942 fp_set_statusword_flag_to(FP_F_C1
,
943 vd_dst
< 0.0 ? 1 : 0);
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);
954 case 0xE8: /* FLD1 */
958 case 0xEC: /* FLDLG2 */
959 IFDB( t_dst
= "lg2"; )
960 vd_dst
= 0.301029995663981143;
962 case 0xED: /* FLDLN2 */
963 IFDB( t_dst
= "ln2"; )
964 vd_dst
= 0.69314718055994530942;
966 case 0xEE: /* FLDZ */
971 IFDB( if (dis
) printf("\tfld%s\n",t_dst
); )
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));
981 fp_set_stack_underflow();
983 fp_set_reg_ST(0,vd_dst
);
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));
994 fp_set_stack_underflow();
996 fp_set_reg_ST(1,vd_dst
);
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))) {
1005 fp_get_reg_ST(1), fp_get_reg_ST(0));
1008 fp_set_stack_underflow();
1010 fp_set_reg_ST(1,vd_dst
);
1014 case 0xF8: { /* FPREM */
1015 /* Very incomplete implementation. */
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);
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
);
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));
1042 fp_set_stack_underflow();
1044 fp_set_reg_ST(1,vd_dst
);
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));
1054 fp_set_stack_underflow();
1056 fp_set_reg_ST(0,vd_dst
);
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));
1065 fp_set_stack_underflow();
1067 fp_set_reg_ST(0,vd_dst
);
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));
1078 fp_set_stack_underflow();
1080 fp_set_reg_ST(0,vd_dst
);
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));
1089 fp_set_stack_underflow();
1091 fp_set_reg_ST(0,vd_dst
);
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));
1100 fp_set_stack_underflow();
1102 fp_set_reg_ST(0,vd_dst
);
1111 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
1113 if (first_opcode
== 0xDA) {
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
);
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 */
1131 fp_set_reg_ST(0, NAN
);
1132 fp_set_stack_underflow();
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 */
1144 fp_set_reg_ST(0, NAN
);
1145 fp_set_stack_underflow();
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 */
1158 fp_set_statusword_flags_COM_STACKF();
1159 fp_set_stack_underflow();
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 */
1172 fp_set_statusword_flags_COM_STACKF();
1173 fp_set_stack_underflow();
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 */
1186 fp_set_reg_ST(0, NAN
);
1187 fp_set_stack_underflow();
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 */
1199 fp_set_reg_ST(0, NAN
);
1200 fp_set_stack_underflow();
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 */
1212 fp_set_reg_ST(0, NAN
);
1213 fp_set_stack_underflow();
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 */
1225 fp_set_reg_ST(0, NAN
);
1226 fp_set_stack_underflow();
1231 printf("unhandled opc_aux = 0x%2x\n", opc_aux
);
1232 panic("do_one_insn_fp: first_opcode == 0xDA");
1236 /* The entire modRM byte is an opcode extension. */
1240 case 0xE9: /* FUCOMPP %st(0),%st(1) */
1241 /* seems the wrong way round. */
1242 fp_do_COM_ST_ST ( 1, 0, 2 );
1251 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
1253 if (first_opcode
== 0xDB) {
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
);
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
);
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 */
1277 vis_addr
= (Int
)vd_addr
;
1279 vis_addr
= 0x80000000; /* 32-bit indefinite */
1280 fp_set_stack_underflow();
1282 setIMem4(a_addr
,vis_addr
);
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))) {
1289 if (vd_addr
<= -2147483648.5 ||
1290 vd_addr
>= 2147483647.5)
1291 vis_addr
= 0x80000000; /* 32-bit int indefinite */
1293 vis_addr
= (Int
)vd_addr
;
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
);
1302 case 5: /* FLD extended-real */
1303 IFDB( if (dis
) printf("\tfldT\t%s\n",t_addr
); )
1304 vd_addr
= getTMem(a_addr
);
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))) {
1313 vd_addr
= fp_pop(); /* then throw away result */
1315 fp_set_stack_underflow();
1317 setTMem(a_addr
,vd_addr
);
1321 printf("unhandled opc_aux = 0x%2x\n", opc_aux
);
1322 panic("do_one_insn_fp: first_opcode == 0xDB");
1326 /* The entire modRM byte is an opcode extension. */
1335 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
1337 if (first_opcode
== 0xDC) {
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
);
1347 case 0: /* FADD double-real */
1348 fp_do_op_mem_ST_0 ( a_addr
, IFDB(t_addr CC
) Fp_Add
, True
);
1351 case 1: /* FMUL double-real */
1352 fp_do_op_mem_ST_0 ( a_addr
, IFDB(t_addr CC
) Fp_Mul
, True
);
1355 case 2: /* FCOM double-real */
1356 fp_do_COM_mem_ST_0 ( a_addr
, IFDB(t_addr CC
) True
, False
);
1359 case 3: /* FCOMP double-real */
1360 fp_do_COM_mem_ST_0 ( a_addr
, IFDB(t_addr CC
) True
, True
);
1363 case 4: /* FSUB double-real */
1364 fp_do_op_mem_ST_0 ( a_addr
, IFDB(t_addr CC
) Fp_Sub
, True
);
1367 case 5: /* FSUBR double-real */
1368 fp_do_op_mem_ST_0 ( a_addr
, IFDB(t_addr CC
) Fp_SubR
, True
);
1371 case 6: /* FDIV double-real */
1372 fp_do_op_mem_ST_0 ( a_addr
, IFDB(t_addr CC
) Fp_Div
, True
);
1375 case 7: /* FDIVR double-real */
1376 fp_do_op_mem_ST_0 ( a_addr
, IFDB(t_addr CC
) Fp_DivR
, True
);
1380 printf("unhandled opc_aux = 0x%2x\n", opc_aux
);
1381 panic("do_one_insn_fp: first_opcode == 0xDC");
1385 /* The entire modRM byte is an opcode extension. */
1389 case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
1390 fp_do_op_ST_ST ( 0, modrm
- 0xC0, Fp_Add
, False
);
1393 case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
1394 fp_do_op_ST_ST ( 0, modrm
- 0xC8, Fp_Mul
, False
);
1397 case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
1398 fp_do_op_ST_ST ( 0, modrm
- 0xE0, Fp_SubR
, False
);
1401 case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
1402 fp_do_op_ST_ST ( 0, modrm
- 0xE8, Fp_Sub
, False
);
1405 case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
1406 fp_do_op_ST_ST ( 0, modrm
- 0xF8, Fp_Div
, False
);
1415 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
1417 if (first_opcode
== 0xDD) {
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
);
1427 case 0: /* FLD double-real */
1428 IFDB( if (dis
) printf("\tfldD\t%s\n",t_addr
); )
1429 vd_addr
= getDMem(a_addr
);
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);
1439 fp_set_stack_underflow();
1441 setDMem(a_addr
,vd_addr
);
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))) {
1449 vd_addr
= fp_pop(); /* then throw away result */
1451 fp_set_stack_underflow();
1453 setDMem(a_addr
,vd_addr
);
1456 printf("unhandled opc_aux = 0x%2x\n", opc_aux
);
1457 panic("do_one_insn_fp: first_opcode == 0xDD");
1461 /* The entire modRM byte is an opcode extension. */
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
);
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",
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);
1480 fp_set_stack_underflow();
1482 fp_set_reg_ST(a_dst
,vd_dst
);
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",
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);
1494 fp_set_stack_underflow();
1496 fp_set_reg_ST(a_dst
,vd_dst
);
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",
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
);
1510 fp_set_statusword_flags_COM_STACKF();
1511 fp_set_stack_underflow();
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",
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
);
1525 fp_set_statusword_flags_COM_STACKF();
1526 fp_set_stack_underflow();
1537 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
1539 if (first_opcode
== 0xDE) {
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
);
1549 printf("unhandled opc_aux = 0x%2x\n", opc_aux
);
1550 panic("do_one_insn_fp: first_opcode == 0xDE");
1554 /* The entire modRM byte is an opcode extension. */
1558 case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
1559 fp_do_op_ST_ST ( 0, modrm
- 0xC0, Fp_Add
, True
);
1562 case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
1563 fp_do_op_ST_ST ( 0, modrm
- 0xC8, Fp_Mul
, True
);
1566 case 0xD9: /* FCOMPP %st(0),%st(1) */
1567 /* seems the wrong way round. */
1568 fp_do_COM_ST_ST ( 1, 0, 2 );
1571 case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
1572 fp_do_op_ST_ST ( 0, modrm
- 0xE0, Fp_SubR
, True
);
1575 case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
1576 fp_do_op_ST_ST ( 0, modrm
- 0xE8, Fp_Sub
, True
);
1579 case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
1580 fp_do_op_ST_ST ( 0, modrm
- 0xF0, Fp_DivR
, True
);
1583 case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
1584 fp_do_op_ST_ST ( 0, modrm
- 0xF8, Fp_Div
, True
);
1593 /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
1595 if (first_opcode
== 0xDF) {
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
);
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
);
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))) {
1615 if (vd_addr
<= -32768.50 ||
1616 vd_addr
>= 32767.50)
1617 vis_addr
= 0x00008000; /* 16-bit int indefinite */
1619 vis_addr
= (Short
)vd_addr
;
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
);
1628 case 5: { /* FILD m64int */
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
) );
1639 case 7: { /* FISTP m64int */
1641 IFDB( if (dis
) printf("\tfistpq\t%s\n",t_addr
); )
1642 if (!fp_is_empty_tag(fp_get_tag_ST(0))) {
1644 if (vd_addr
<= -9223372036854775808.5 ||
1645 vd_addr
>= 9223372036854775807.5)
1646 vis_addr64
= 0x8000000000000000LL
;
1647 /* 64-bit int indefinite */
1649 vis_addr64
= (Long
)vd_addr
;
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)
1662 printf("unhandled opc_aux = 0x%2x\n", opc_aux
);
1663 panic("do_one_insn_fp: first_opcode == 0xDF");
1667 /* The entire modRM byte is an opcode extension. */
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
]);
1682 /* -+-+-+-+-+-+-+-+-+-+-+-+ Unhandled ESC opcode +-+-+-+ */
1683 else goto unhandled
;
1687 printf("\nAFTER\n");
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");
1703 /*--------------------------------------------------------------------*/
1704 /*--- end hd_fpu.c ---*/
1705 /*--------------------------------------------------------------------*/