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