Home | History | Annotate | Download | only in useful
      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 (at) acm.org
     13       Julian_Seward (at) 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
     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
     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
     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
     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
    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 */
    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 
    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
    169 void setFMem ( UInt addr, double f )
    170 {
    171    * ((float*)addr) = (float)f;
    172 }
    173 
    174 static
    175 INLINE
    176 double getFMem ( UInt addr )
    177 {
    178    return (double) (* ((float*)addr));
    179 }
    180 
    181 static
    182 INLINE
    183 void setDMem ( UInt addr, double f )
    184 {
    185    * ((double*)addr) = f;
    186 }
    187 
    188 static
    189 INLINE
    190 double getDMem ( UInt addr )
    191 {
    192    return (* ((double*)addr));
    193 }
    194 
    195 static
    196 INLINE
    197 void setTMem ( UInt addr, double f )
    198 {
    199    fp_extended_from_double ( (Addr)addr, f );
    200 }
    201 
    202 static
    203 INLINE
    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
    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
    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
    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
    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
    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
    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
    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
    283 void fp_dec_tos ( void )
    284 {
    285    fp_set_tos ( fp_STno_to_regno ( 7 ));
    286 }
    287 
    288 static
    289 INLINE
    290 void fp_inc_tos ( void )
    291 {
    292    fp_set_tos ( fp_STno_to_regno ( 1 ));
    293 }
    294 
    295 static
    296 INLINE
    297 Bool fp_is_empty_tag ( UInt tag )
    298 {
    299    return tag == FP_TAG_EMPTY;
    300 }
    301 
    302 static
    303 INLINE
    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
    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
    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
    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
    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
    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
    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
    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
    379 void fp_set_tos_reg ( double d )
    380 {
    381    fp_set_reg ( fp_get_tos(), d );
    382 }
    383 
    384 static
    385 INLINE
    386 double fp_get_tos_reg ( void )
    387 {
    388    return fp_get_reg ( fp_get_tos() );
    389 }
    390 
    391 static
    392 INLINE
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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 
    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