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