1 /* 2 * this doesn't attempt to implement Power architecture floating-point properties 3 * that aren't visible in the Inferno environment. 4 * all arithmetic is done in double precision. 5 * the FP trap status isn't updated. 6 */ 7 #include "u.h" 8 #include "../port/lib.h" 9 #include "mem.h" 10 #include "dat.h" 11 #include "fns.h" 12 #include "io.h" 13 14 #include "ureg.h" 15 16 #include "fpi.h" 17 18 #define REG(x) (*(long*)(((char*)em->ur)+roff[(x)])) 19 #define FR(x) (*(Internal*)em->fr[(x)&0x1F]) 20 #define REGSP 1 /* stack pointer */ 21 22 /* BUG: check fetch (not worthwhile in Inferno) */ 23 #define getulong(a) (*(ulong*)(a)) 24 25 enum { 26 CRLT = 1<<31, 27 CRGT = 1<<30, 28 CREQ = 1<<29, 29 CRSO = 1<<28, 30 CRFU = CRSO, 31 32 CRFX = 1<<27, 33 CRFEX = 1<<26, 34 CRVX = 1<<25, 35 CROX = 1<<24, 36 }; 37 38 #define getCR(x,w) (((w)>>(28-(x*4)))&0xF) 39 #define mkCR(x,v) (((v)&0xF)<<(28-(x*4))) 40 41 #define simm(xx, ii) xx = (short)(ii&0xFFFF); 42 #define getairr(i) rd = (i>>21)&0x1f; ra = (i>>16)&0x1f; simm(imm,i) 43 #define getarrr(i) rd = (i>>21)&0x1f; ra = (i>>16)&0x1f; rb = (i>>11)&0x1f; 44 #define getop(i) ((i>>26)&0x3F) 45 #define getxo(i) ((i>>1)&0x3FF) 46 47 #define FPS_FX (1<<31) /* exception summary (sticky) */ 48 #define FPS_EX (1<<30) /* enabled exception summary */ 49 #define FPS_VX (1<<29) /* invalid operation exception summary */ 50 #define FPS_OX (1<<28) /* overflow exception OX (sticky) */ 51 #define FPS_UX (1<<27) /* underflow exception UX (sticky) */ 52 #define FPS_ZX (1<<26) /* zero divide exception ZX (sticky) */ 53 #define FPS_XX (1<<25) /* inexact exception XX (sticky) */ 54 #define FPS_VXSNAN (1<<24) /* invalid operation exception for SNaN (sticky) */ 55 #define FPS_VXISI (1<<23) /* invalid operation exception for ∞-∞ (sticky) */ 56 #define FPS_VXIDI (1<<22) /* invalid operation exception for ∞/∞ (sticky) */ 57 #define FPS_VXZDZ (1<<21) /* invalid operation exception for 0/0 (sticky) */ 58 #define FPS_VXIMZ (1<<20) /* invalid operation exception for ∞*0 (sticky) */ 59 #define FPS_VXVC (1<<19) /* invalid operation exception for invalid compare (sticky) */ 60 #define FPS_FR (1<<18) /* fraction rounded */ 61 #define FPS_FI (1<<17) /* fraction inexact */ 62 #define FPS_FPRF (1<<16) /* floating point result class */ 63 #define FPS_FPCC (0xF<<12) /* <, >, =, unordered */ 64 #define FPS_VXCVI (1<<8) /* enable exception for invalid integer convert (sticky) */ 65 #define FPS_VE (1<<7) /* invalid operation exception enable */ 66 #define FPS_OE (1<<6) /* enable overflow exceptions */ 67 #define FPS_UE (1<<5) /* enable underflow */ 68 #define FPS_ZE (1<<4) /* enable zero divide */ 69 #define FPS_XE (1<<3) /* enable inexact exceptions */ 70 #define FPS_RN (3<<0) /* rounding mode */ 71 72 typedef struct Emreg Emreg; 73 74 struct Emreg { 75 Ureg* ur; 76 ulong (*fr)[3]; 77 FPenv* ufp; 78 ulong ir; 79 char* name; 80 }; 81 82 int fpemudebug = 0; 83 84 #undef OFR 85 #define OFR(X) ((ulong)&((Ureg*)0)->X) 86 87 static int roff[] = { 88 OFR(r0), OFR(r1), OFR(r2), OFR(r3), 89 OFR(r4), OFR(r5), OFR(r6), OFR(r7), 90 OFR(r8), OFR(r9), OFR(r10), OFR(r11), 91 OFR(r12), OFR(r13), OFR(r14), OFR(r15), 92 OFR(r16), OFR(r17), OFR(r18), OFR(r19), 93 OFR(r20), OFR(r21), OFR(r22), OFR(r23), 94 OFR(r24), OFR(r25), OFR(r26), OFR(r27), 95 OFR(r28), OFR(r29), OFR(r30), OFR(r31), 96 }; 97 98 /* 99 * initial FP register values assumed by qc's code 100 */ 101 static Internal fpreginit[] = { 102 /* s, e, l, h */ 103 {0, 0x400, 0x00000000, 0x08000000}, /* F31=2.0 */ 104 {0, 0x3FF, 0x00000000, 0x08000000}, /* F30=1.0 */ 105 {0, 0x3FE, 0x00000000, 0x08000000}, /* F29=0.5 */ 106 {0, 0x1, 0x00000000, 0x00000000}, /* F28=0.0 */ 107 {0, 0x433, 0x00000000, 0x08000040}, /* F27=FREGCVI */ 108 }; 109 110 static void 111 fadd(Emreg *em, Internal *d, int ra, int rb) 112 { 113 Internal a, b; 114 115 a = FR(ra); 116 b = FR(rb); 117 (a.s == b.s? fpiadd: fpisub)(&b, &a, d); 118 } 119 120 static void 121 fsub(Emreg *em, Internal *d, int ra, int rb) 122 { 123 Internal a, b; 124 125 a = FR(ra); 126 b = FR(rb); 127 b.s ^= 1; 128 (b.s == a.s? fpiadd: fpisub)(&b, &a, d); 129 } 130 131 static void 132 fmul(Emreg *em, Internal *d, int ra, int rb) 133 { 134 Internal a, b; 135 136 a = FR(ra); 137 b = FR(rb); 138 fpimul(&b, &a, d); 139 } 140 141 static void 142 fdiv(Emreg *em, Internal *d, int ra, int rb) 143 { 144 Internal a, b; 145 146 a = FR(ra); 147 b = FR(rb); 148 fpidiv(&b, &a, d); 149 } 150 151 static void 152 fmsub(Emreg *em, Internal *d, int ra, int rc, int rb) 153 { 154 Internal a, c, b, t; 155 156 a = FR(ra); 157 c = FR(rc); 158 b = FR(rb); 159 fpimul(&a, &c, &t); 160 b.s ^= 1; 161 (b.s == t.s? fpiadd: fpisub)(&b, &t, d); 162 } 163 164 static void 165 fmadd(Emreg *em, Internal *d, int ra, int rc, int rb) 166 { 167 Internal a, c, b, t; 168 169 a = FR(ra); 170 c = FR(rc); 171 b = FR(rb); 172 fpimul(&a, &c, &t); 173 (t.s == b.s? fpiadd: fpisub)(&b, &t, d); 174 } 175 176 static ulong setfpscr(Emreg*); 177 static void setfpcc(Emreg*, int); 178 179 static void 180 unimp(Emreg *em, ulong op) 181 { 182 char buf[60]; 183 184 snprint(buf, sizeof(buf), "sys: fp: pc=%lux unimp fp 0x%.8lux", em->ur->pc, op); 185 if(fpemudebug) 186 print("FPE: %s\n", buf); 187 error(buf); 188 /* no return */ 189 } 190 191 /* 192 * floating load/store 193 */ 194 195 static void 196 fpeairr(Emreg *em, ulong ir, void **eap, int *rdp) 197 { 198 ulong ea; 199 long imm; 200 int ra, rd, upd; 201 202 getairr(ir); 203 ea = imm; 204 upd = (ir&(1L<<26))!=0; 205 if(ra) { 206 ea += REG(ra); 207 if(upd){ 208 if(ra == REGSP) 209 panic("fpemu: r1 update"); /* can't do it because we're running on the same stack */ 210 REG(ra) = ea; 211 } 212 } else { 213 if(upd) 214 unimp(em, ir); 215 } 216 *rdp = rd; 217 *eap = (void*)ea; 218 if(fpemudebug) 219 print("%8.8lux %s\tf%d,%ld(r%d) ea=%lux upd=%d\n", em->ur->pc, em->name, rd, imm, ra, ea, upd); 220 } 221 222 static void 223 fpearrr(Emreg *em, ulong ir, int upd, void **eap, int *rdp) 224 { 225 ulong ea; 226 int ra, rb, rd; 227 228 getarrr(ir); 229 ea = REG(rb); 230 if(ra){ 231 ea += REG(ra); 232 if(upd){ 233 if(ra == REGSP) 234 panic("fpemu: r1 update"); 235 REG(ra) = ea; 236 } 237 if(fpemudebug) 238 print("%8.8lux %s\tf%d,(r%d+r%d) ea=%lux upd=%d\n", em->ur->pc, em->name, rd, ra, rb, ea, upd); 239 } else { 240 if(upd) 241 unimp(em, ir); 242 if(fpemudebug) 243 print("%8.8lux %s\tf%d,(r%d) ea=%lux\n", em->ur->pc, em->name, rd, rb, ea); 244 } 245 *eap = (void*)ea; 246 *rdp = rd; 247 } 248 249 static void 250 lfs(Emreg *em, ulong ir) 251 { 252 void *ea; 253 int rd; 254 255 em->name = "lfs"; 256 fpeairr(em, ir, &ea, &rd); 257 fpis2i(&FR(rd), (void*)ea); 258 } 259 260 static void 261 lfsx(Emreg *em, ulong ir) 262 { 263 void *ea; 264 int rd; 265 266 em->name = "lfsx"; 267 fpearrr(em, ir, ((ir>>1)&0x3FF)==567, &ea, &rd); 268 fpis2i(&FR(rd), (void*)ea); 269 } 270 271 static void 272 lfd(Emreg *em, ulong ir) 273 { 274 void *ea; 275 int rd; 276 277 em->name = "lfd"; 278 fpeairr(em, ir, &ea, &rd); 279 fpid2i(&FR(rd), (void*)ea); 280 } 281 282 static void 283 lfdx(Emreg *em, ulong ir) 284 { 285 void *ea; 286 int rd; 287 288 em->name = "lfdx"; 289 fpearrr(em, ir, ((ir>>1)&0x3FF)==631, &ea, &rd); 290 fpid2i(&FR(rd), (void*)ea); 291 } 292 293 static void 294 stfs(Emreg *em, ulong ir) 295 { 296 void *ea; 297 int rd; 298 Internal tmp; 299 300 em->name = "stfs"; 301 fpeairr(em, ir, &ea, &rd); 302 tmp = FR(rd); 303 fpii2s(ea, &tmp); 304 } 305 306 static void 307 stfsx(Emreg *em, ulong ir) 308 { 309 void *ea; 310 int rd; 311 Internal tmp; 312 313 em->name = "stfsx"; 314 fpearrr(em, ir, getxo(ir)==695, &ea, &rd); 315 tmp = FR(rd); 316 fpii2s(ea, &tmp); 317 } 318 319 static void 320 stfd(Emreg *em, ulong ir) 321 { 322 void *ea; 323 int rd; 324 Internal tmp; 325 326 em->name = "stfd"; 327 fpeairr(em, ir, &ea, &rd); 328 tmp = FR(rd); 329 fpii2d(ea, &tmp); 330 } 331 332 static void 333 stfdx(Emreg *em, ulong ir) 334 { 335 void *ea; 336 int rd; 337 Internal tmp; 338 339 em->name = "stfdx"; 340 fpearrr(em, ir, ((ir>>1)&0x3FF)==759, &ea, &rd); 341 tmp = FR(rd); 342 fpii2d(ea, &tmp); 343 } 344 345 static void 346 mcrfs(Emreg *em, ulong ir) 347 { 348 int rd, ra, rb; 349 static ulong fpscr0[] ={ 350 FPS_FX|FPS_OX, 351 FPS_UX|FPS_ZX|FPS_XX|FPS_VXSNAN, 352 FPS_VXISI|FPS_VXIDI|FPS_VXZDZ|FPS_VXIMZ, 353 FPS_VXVC, 354 0, 355 FPS_VXCVI, 356 }; 357 358 getarrr(ir); 359 if(rb || ra&3 || rd&3) 360 unimp(em, ir); 361 ra >>= 2; 362 rd >>= 2; 363 em->ur->cr = (em->ur->cr & ~mkCR(rd, 0xF)) | mkCR(rd, getCR(ra, em->ufp->fpscr)); 364 em->ufp->fpscr &= ~fpscr0[ra]; 365 if(fpemudebug) 366 print("%8.8lux mcrfs\tcrf%d,crf%d\n", em->ur->pc, rd, ra); 367 } 368 369 static void 370 mffs(Emreg *em, ulong ir) 371 { 372 int rd, ra, rb; 373 Double dw; 374 375 getarrr(ir); 376 if(ra || rb) 377 unimp(em, ir); 378 dw.h = 0; 379 dw.l = ((uvlong)0xFFF8000L<<16)|em->ufp->fpscr; 380 fpid2i(&FR(rd), &dw); 381 /* it's anyone's guess how CR1 should be set when ir&1 */ 382 em->ur->cr &= ~mkCR(1, 0xE); /* leave SO, reset others */ 383 if(fpemudebug) 384 print("%8.8lux mffs%s\tfr%d\n", em->ur->pc, ir&1?".":"", rd); 385 } 386 387 static void 388 mtfsb1(Emreg *em, ulong ir) 389 { 390 int rd, ra, rb; 391 392 getarrr(ir); 393 if(ra || rb) 394 unimp(em, ir); 395 em->ufp->fpscr |= (1L << (31-rd)); 396 /* BUG: should set summary bits */ 397 if(ir & 1) 398 em->ur->cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */ 399 if(fpemudebug) 400 print("%8.8lux mtfsb1%s\tfr%d\n", em->ur->pc, ir&1?".":"", rd); 401 } 402 403 static void 404 mtfsb0(Emreg *em, ulong ir) 405 { 406 int rd, ra, rb; 407 408 getarrr(ir); 409 if(ra || rb) 410 unimp(em, ir); 411 em->ufp->fpscr &= ~(1L << (31-rd)); 412 if(ir & 1) 413 em->ur->cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */ 414 if(fpemudebug) 415 print("%8.8lux mtfsb0%s\tfr%d\n", em->ur->pc, ir&1?".":"", rd); 416 } 417 418 static void 419 mtfsf(Emreg *em, ulong ir) 420 { 421 int fm, rb, i; 422 ulong v; 423 Internal b; 424 Double db; 425 426 if(ir & ((1L << 25)|(1L << 16))) 427 unimp(em, ir); 428 rb = (ir >> 11) & 0x1F; 429 fm = (ir >> 17) & 0xFF; 430 b = FR(rb); 431 fpii2d(&db, &b); /* reconstruct hi/lo format to recover low word */ 432 v = db.l; 433 for(i=0; i<8; i++) 434 if(fm & (1 << (7-i))) 435 em->ufp->fpscr = (em->ufp->fpscr & ~mkCR(i, 0xF)) | mkCR(i, getCR(i, v)); 436 /* BUG: should set FEX and VX `according to the usual rule' */ 437 if(ir & 1) 438 em->ur->cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */ 439 if(fpemudebug) 440 print("%8.8lux mtfsf%s\t#%.2x,fr%d\n", em->ur->pc, ir&1?".":"", fm, rb); 441 } 442 443 static void 444 mtfsfi(Emreg *em, ulong ir) 445 { 446 int imm, rd; 447 448 if(ir & ((0x7F << 16)|(1L << 11))) 449 unimp(em, ir); 450 rd = (ir >> 23) & 0xF; 451 imm = (ir >> 12) & 0xF; 452 em->ufp->fpscr = (em->ufp->fpscr & ~mkCR(rd, 0xF)) | mkCR(rd, imm); 453 /* BUG: should set FEX and VX `according to the usual rule' */ 454 if(ir & 1) 455 em->ur->cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */ 456 if(fpemudebug) 457 print("%8.8lux mtfsfi%s\tcrf%d,#%x\n", em->ur->pc, ir&1?".":"", rd, imm); 458 } 459 460 static void 461 fcmp(Emreg *em, ulong ir) 462 { 463 int fc, rd, ra, rb, sig, i; 464 465 getarrr(ir); 466 if(rd & 3) 467 unimp(em, ir); 468 rd >>= 2; 469 sig = 0; 470 switch(getxo(ir)) { 471 default: 472 unimp(em, ir); 473 case 32: 474 if(fpemudebug) 475 print("%8.8lux fcmpo\tcr%d,f%d,f%d\n", em->ur->pc, rd, ra, rb); 476 sig = 1; 477 break; 478 case 0: 479 if(fpemudebug) 480 print("%8.8lux fcmpu\tcr%d,f%d,f%d\n", em->ur->pc, rd, ra, rb); 481 break; 482 } 483 if(IsWeird(&FR(ra)) || IsWeird(&FR(rb))) { 484 if(sig){ 485 ; /* BUG: should trap if not masked ... */ 486 } 487 fc = CRFU; 488 } else { 489 i = fpicmp(&FR(ra), &FR(rb)); 490 if(i > 0) 491 fc = CRGT; 492 else if(i == 0) 493 fc = CREQ; 494 else 495 fc = CRLT; 496 } 497 fc >>= 28; 498 em->ur->cr = (em->ur->cr & ~mkCR(rd,~0)) | mkCR(rd, fc); 499 em->ufp->fpscr = (em->ufp->fpscr & ~0xF800) | (fc<<11); 500 /* BUG: update FX, VXSNAN, VXVC */ 501 } 502 503 static void 504 fariths(Emreg *em, ulong ir) 505 { 506 int rd, ra, rb, rc, fmt; 507 char *cc, *n; 508 ulong fpscr; 509 Internal *d; 510 511 fmt = 0; 512 rc = (ir>>6)&0x1F; 513 getarrr(ir); 514 d = &FR(rd); 515 switch(getxo(ir)&0x1F) { /* partial XO decode */ 516 case 22: /* fsqrts */ 517 case 24: /* fres */ 518 default: 519 unimp(em, ir); 520 return; 521 case 18: 522 if(IsZero(&FR(rb))) { 523 em->ufp->fpscr |= FPS_ZX | FPS_FX; 524 error("sys: fp: zero divide"); 525 } 526 fdiv(em, d, ra, rb); 527 n = "fdivs"; 528 break; 529 case 20: 530 fsub(em, d, ra, rb); 531 n = "fsubs"; 532 break; 533 case 21: 534 fadd(em, d, ra, rb); 535 n = "fadds"; 536 break; 537 case 25: 538 fmul(em, d, ra, rc); 539 rb = rc; 540 n = "fmuls"; 541 break; 542 case 28: 543 fmsub(em, d, ra, rc, rb); 544 fmt = 2; 545 n = "fmsubs"; 546 break; 547 case 29: 548 fmadd(em, d, ra, rc, rb); 549 fmt = 2; 550 n = "fmadds"; 551 break; 552 case 30: 553 fmsub(em, d, ra, rc, rb); 554 d->s ^= 1; 555 fmt = 2; 556 n = "fnmsubs"; 557 break; 558 case 31: 559 fmadd(em, d, ra, rc, rb); 560 d->s ^= 1; 561 fmt = 2; 562 n = "fnmadds"; 563 break; 564 } 565 if(fmt==1 && ra) 566 unimp(em, ir); 567 fpscr = setfpscr(em); 568 setfpcc(em, rd); 569 cc = ""; 570 if(ir & 1) { 571 cc = "."; 572 em->ur->cr = (em->ur->cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28)); 573 } 574 if(fpemudebug) { 575 switch(fmt) { 576 case 0: 577 print("%8.8lux %s%s\tfr%d,fr%d,fr%d\n", em->ur->pc, n, cc, rd, ra, rb); 578 break; 579 case 1: 580 print("%8.8lux %s%s\tfr%d,fr%d\n", em->ur->pc, n, cc, rd, rb); 581 break; 582 case 2: 583 print("%8.8lux %s%s\tfr%d,fr%d,fr%d,fr%d\n", em->ur->pc, n, cc, rd, ra, rc, rb); 584 break; 585 } 586 } 587 } 588 589 static void 590 farith(Emreg *em, ulong ir) 591 { 592 Word w; 593 Double dv; 594 int rd, ra, rb, rc, fmt; 595 char *cc, *n; 596 ulong fpscr; 597 int nocc; 598 Internal *d; 599 600 fmt = 0; 601 nocc = 0; 602 rc = (ir>>6)&0x1F; 603 getarrr(ir); 604 d = &FR(rd); 605 switch(getxo(ir)&0x1F) { /* partial XO decode */ 606 case 22: /* frsqrt */ 607 case 23: /* fsel */ 608 case 26: /* fsqrte */ 609 default: 610 unimp(em, ir); 611 return; 612 case 12: /* frsp */ 613 *d = FR(rb); /* BUG: doesn't round to single precision */ 614 fmt = 1; 615 n = "frsp"; 616 break; 617 case 14: /* fctiw */ /* BUG: ignores rounding mode */ 618 case 15: /* fctiwz */ 619 fpii2w(&w, &FR(rb)); 620 dv.h = 0; 621 dv.l = w; 622 fpid2i(d, &dv); 623 fmt = 1; 624 nocc = 1; 625 n = "fctiw"; 626 break; 627 case 18: 628 if(IsZero(&FR(rb))) { 629 em->ufp->fpscr |= FPS_ZX | FPS_FX; 630 error("sys: fp: zero divide"); 631 } 632 fdiv(em, d, ra, rb); 633 n = "fdiv"; 634 break; 635 case 20: 636 fsub(em, d, ra, rb); 637 n = "fsub"; 638 break; 639 case 21: 640 fadd(em, d, ra, rb); 641 n = "fadd"; 642 break; 643 case 25: 644 fmul(em, d, ra, rc); 645 rb = rc; 646 n = "fmul"; 647 break; 648 case 28: 649 fmsub(em, d, ra, rc, rb); 650 fmt = 2; 651 n = "fmsub"; 652 break; 653 case 29: 654 fmadd(em, d, ra, rc, rb); 655 fmt = 2; 656 n = "fmadd"; 657 break; 658 case 30: 659 fmsub(em, d, ra, rc, rb); 660 d->s ^= 1; 661 fmt = 2; 662 n = "fnmsub"; 663 break; 664 case 31: 665 fmadd(em, d, ra, rc, rb); 666 d->s ^= 1; 667 fmt = 2; 668 n = "fnmadd"; 669 break; 670 } 671 if(fmt==1 && ra) 672 unimp(em, ir); 673 fpscr = setfpscr(em); 674 if(nocc == 0) 675 setfpcc(em, rd); 676 cc = ""; 677 if(ir & 1) { 678 cc = "."; 679 em->ur->cr = (em->ur->cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28)); 680 } 681 if(fpemudebug) { 682 switch(fmt) { 683 case 0: 684 print("%8.8lux %s%s\tfr%d,fr%d,fr%d\n", em->ur->pc, n, cc, rd, ra, rb); 685 break; 686 case 1: 687 print("%8.8lux %s%s\tfr%d,fr%d\n", em->ur->pc, n, cc, rd, rb); 688 break; 689 case 2: 690 print("%8.8lux %s%s\tfr%d,fr%d,fr%d,fr%d\n", em->ur->pc, n, cc, rd, ra, rc, rb); 691 break; 692 } 693 } 694 } 695 696 static void 697 farith2(Emreg *em, ulong ir) 698 { 699 int rd, ra, rb; 700 char *cc, *n; 701 ulong fpscr; 702 Internal *d, *b; 703 704 getarrr(ir); 705 if(ra) 706 unimp(em, ir); 707 d = &FR(rd); 708 b = &FR(rb); 709 switch(getxo(ir)) { /* full XO decode */ 710 default: 711 unimp(em, ir); 712 case 40: 713 *d = *b; 714 d->s ^= 1; 715 n = "fneg"; 716 break; 717 case 72: 718 *d = *b; 719 n = "fmr"; 720 break; 721 case 136: 722 *d = *b; 723 d->s = 1; 724 n = "fnabs"; 725 break; 726 case 264: 727 *d = *b; 728 d->s = 0; 729 n = "fabs"; 730 break; 731 } 732 fpscr = setfpscr(em); 733 setfpcc(em, rd); 734 cc = ""; 735 if(ir & 1) { 736 cc = "."; 737 em->ur->cr = (em->ur->cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28)); 738 } 739 if(fpemudebug) 740 print("%8.8lux %s%s\tfr%d,fr%d\n", em->ur->pc, n, cc, rd, rb); 741 } 742 743 static ulong 744 setfpscr(Emreg *em) 745 { 746 ulong fps, fpscr; 747 748 fps = 0; /* BUG: getfsr() */ 749 fpscr = em->ufp->fpscr; 750 if(fps & FPAOVFL) 751 fpscr |= FPS_OX; 752 if(fps & FPAINEX) 753 fpscr |= FPS_XX; 754 if(fps & FPAUNFL) 755 fpscr |= FPS_UX; 756 if(fps & FPAZDIV) 757 fpscr |= FPS_ZX; 758 if(fpscr != em->ufp->fpscr) { 759 fpscr |= FPS_FX; 760 em->ufp->fpscr = fpscr; 761 } 762 return fpscr; 763 } 764 765 static void 766 setfpcc(Emreg *em, int r) 767 { 768 int c; 769 Internal *d; 770 771 d = &FR(r); 772 c = 0; 773 if(IsZero(d)) 774 c |= 2; 775 else if(d->s == 1) 776 c |= 4; 777 else 778 c |= 8; 779 if(IsNaN(d)) 780 c |= 1; 781 em->ufp->fpscr = (em->ufp->fpscr & ~0xF800) | (0<<15) | (c<<11); /* unsure about class bit */ 782 } 783 784 static uchar op63flag[32] = { 785 [12] 1, [14] 1, [15] 1, [18] 1, [20] 1, [21] 1, [22] 1, 786 [23] 1, [25] 1, [26] 1, [28] 1, [29] 1, [30] 1, [31] 1, 787 }; 788 789 /* 790 * returns the number of FP instructions emulated 791 */ 792 int 793 fpipower(Ureg *ur) 794 { 795 ulong op; 796 int xo; 797 Emreg emreg, *em; 798 FPenv *ufp; 799 int n; 800 801 ufp = &up->env->fpu; /* because all the state is in Osenv, it need not be saved/restored */ 802 em = &emreg; 803 em->ur = ur; 804 em->fr = ufp->emreg; 805 em->ufp = ufp; 806 em->name = nil; 807 if(em->ufp->fpistate != FPACTIVE) { 808 em->ufp->fpistate = FPACTIVE; 809 em->ufp->fpscr = 0; /* TO DO */ 810 for(n = 0; n < nelem(fpreginit); n++) 811 FR(31-n) = fpreginit[n]; 812 } 813 for(n=0;;n++){ 814 op = getulong(ur->pc); 815 em->ir = op; 816 if(fpemudebug > 1) 817 print("%8.8lux %8.8lux: ", ur->pc, op); 818 switch(op>>26){ 819 default: 820 return n; 821 case 48: /* lfs */ 822 case 49: /* lfsu */ 823 lfs(em, op); 824 break; 825 case 50: /* lfd */ 826 case 51: /* lfdu */ 827 lfd(em, op); 828 break; 829 case 52: /* stfs */ 830 case 53: /* stfsu */ 831 stfs(em, op); 832 break; 833 case 54: /* stfd */ 834 case 55: /* stfdu */ 835 stfd(em, op); 836 break; 837 case 31: /* indexed load/store */ 838 xo = getxo(op); 839 if((xo & 0x300) != 0x200) 840 return n; 841 switch(xo){ 842 default: 843 return n; 844 case 535: /* lfsx */ 845 case 567: /* lfsux */ 846 lfsx(em, op); 847 break; 848 case 599: /* lfdx */ 849 case 631: /* lfdux */ 850 lfdx(em, op); 851 break; 852 case 663: /* stfsx */ 853 case 695: /* stfsux */ 854 stfsx(em, op); 855 break; 856 case 727: /* stfdx */ 857 case 759: /* stfdux */ 858 stfdx(em, op); 859 break; 860 } 861 break; 862 case 63: /* double precision */ 863 xo = getxo(op); 864 if(op63flag[xo & 0x1F]){ 865 farith(em, op); 866 break; 867 } 868 switch(xo){ 869 default: 870 return n; 871 case 0: /* fcmpu */ 872 case 32: /* fcmpo */ 873 fcmp(em, op); 874 break; 875 case 40: /* fneg */ 876 case 72: /* fmr */ 877 case 136: /* fnabs */ 878 case 264: /* fabs */ 879 farith2(em, op); 880 break; 881 case 38: 882 mtfsb1(em, op); 883 break; 884 case 64: 885 mcrfs(em, op); 886 break; 887 case 70: 888 mtfsb0(em, op); 889 break; 890 case 134: 891 mtfsfi(em, op); 892 break; 893 case 583: 894 mffs(em, op); 895 break; 896 case 711: 897 mtfsf(em, op); 898 break; 899 } 900 break; 901 case 59: /* single precision */ 902 fariths(em, op); 903 break; 904 } 905 ur->pc += 4; 906 if(anyhigher()) 907 sched(); 908 } 909 return n; 910 } 911 912 /* 913 50: lfd frD,d(rA) 914 51: lfdu frD,d(rA) 915 31,631: lfdux frD,rA,rB 916 31,599: lfdx frD,rA,rB 917 48: lfs frD,d(rA) 918 49: lfsu frD,d(rA) 919 31,567: lfsux frD,rA,rB 920 31,535: lfsx frD,rA,rB 921 922 54: stfd frS,d(rA) 923 55: stfdu frS,d(rA) 924 31,759: stfdux frS,rA,rB 925 31,727: stfdx frS,rA,rB 926 52: stfs frS,d(rA) 927 53: stfsu frS,d(rA) 928 31,695: stfsux frS,rA,rB 929 31,663: stfsx frS,rA,rB 930 931 63,64: mcrfs crfD,crfS 932 63,583: mffs[.] frD 933 63,70: mtfsb0[.] crbD 934 63,38: mtfsb1[.] crbD 935 63,711: mtfsf[.] FM,frB 936 63,134: mtfsfi[.] crfD,IMM 937 */ 938 939 /* 940 float to int: 941 FMOVD g+0(SB),F1 942 FCTIWZ F1,F4 943 FMOVD F4,.rathole+0(SB) 944 MOVW .rathole+4(SB),R7 945 MOVW R7,l+0(SB) 946 */ 947 948 /* 949 int to float: 950 MOVW $1127219200,R9 951 MOVW l+0(SB),R7 952 MOVW R9,.rathole+0(SB) 953 XOR $-2147483648,R7,R6 954 MOVW R6,.rathole+4(SB) 955 FMOVD .rathole+0(SB),F0 956 FSUB F27,F0 957 958 unsigned to float: 959 MOVW ul+0(SB),R5 960 MOVW R9,.rathole+0(SB) 961 XOR $-2147483648,R5,R4 962 MOVW R4,.rathole+4(SB) 963 FMOVD .rathole+0(SB),F3 964 FSUB F27,F3 965 FCMPU F3,F28 966 BGE ,3(PC) 967 FMOVD $4.29496729600000000e+09,F2 968 FADD F2,F3 969 FMOVD F3,g+0(SB) 970 */ 971