1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include <mach.h> 5 #define Extern extern 6 #include "power.h" 7 8 ulong setfpscr(void); 9 void setfpcc(double); 10 void farith(ulong); 11 void farith2(ulong); 12 void fariths(ulong); 13 void fcmp(ulong); 14 void mtfsb1(ulong); 15 void mcrfs(ulong); 16 void mtfsb0(ulong); 17 void mtfsf(ulong); 18 void mtfsfi(ulong); 19 void mffs(ulong); 20 void mtfsf(ulong); 21 22 Inst op59[] = { 23 [18] {fariths, "fdivs", Ifloat}, 24 [20] {fariths, "fsubs", Ifloat}, 25 [21] {fariths, "fadds", Ifloat}, 26 [22] {unimp, "fsqrts", Ifloat}, 27 [24] {unimp, "fres", Ifloat}, 28 [25] {fariths, "fmuls", Ifloat}, 29 [28] {fariths, "fmsubs", Ifloat}, 30 [29] {fariths, "fmadds", Ifloat}, 31 [30] {fariths, "fnmsubs", Ifloat}, 32 [31] {fariths, "fnmadds", Ifloat}, 33 }; 34 35 Inset ops59 = {op59, nelem(op59)}; 36 37 Inst op63a[] = { 38 [12] {farith, "frsp", Ifloat}, 39 [14] {farith, "fctiw", Ifloat}, 40 [15] {farith, "fctiwz", Ifloat}, 41 [18] {farith, "fdiv", Ifloat}, 42 [20] {farith, "fsub", Ifloat}, 43 [21] {farith, "fadd", Ifloat}, 44 [22] {unimp, "frsqrt", Ifloat}, 45 [23] {unimp, "fsel", Ifloat}, 46 [25] {farith, "fmul", Ifloat}, 47 [26] {unimp, "frsqrte", Ifloat}, 48 [28] {farith, "fmsub", Ifloat}, 49 [29] {farith, "fmadd", Ifloat}, 50 [30] {farith, "fnmsub", Ifloat}, 51 [31] {farith, "fnmadd", Ifloat}, 52 }; 53 54 Inset ops63a= {op63a, nelem(op63a)}; 55 56 Inst op63b[] = { 57 [0] {fcmp, "fcmpu", Ifloat}, 58 [32] {fcmp, "fcmpo", Ifloat}, 59 [38] {mtfsb1, "mtfsb1", Ifloat}, 60 [40] {farith2, "fneg", Ifloat}, 61 [64] {mcrfs, "mcrfs", Ifloat}, 62 [70] {mtfsb0, "mtfsb0", Ifloat}, 63 [72] {farith2, "fmr", Ifloat}, 64 [134] {mtfsfi, "mtfsfi", Ifloat}, 65 [136] {farith2, "fnabs", Ifloat}, 66 [264] {farith2, "fabs", Ifloat}, 67 [583] {mffs, "mffs", Ifloat}, 68 [711] {mtfsf, "mtfsf", Ifloat}, 69 }; 70 71 Inset ops63b = {op63b, nelem(op63b)}; 72 73 void 74 fpreginit(void) 75 { 76 int i; 77 78 /* Normally initialised by the kernel */ 79 reg.fd[27] = 4503601774854144.0; 80 reg.fd[29] = 0.5; 81 reg.fd[28] = 0.0; 82 reg.fd[30] = 1.0; 83 reg.fd[31] = 2.0; 84 for(i = 0; i < 27; i++) 85 reg.fd[i] = reg.fd[28]; 86 } 87 88 static double 89 v2fp(uvlong v) 90 { 91 FPdbleword f; 92 93 f.hi = v>>32; 94 f.lo = v; 95 return f.x; 96 } 97 98 static uvlong 99 fp2v(double d) 100 { 101 FPdbleword f; 102 103 f.x = d; 104 return ((uvlong)f.hi<<32) | f.lo; 105 } 106 107 void 108 lfs(ulong ir) 109 { 110 ulong ea; 111 int imm, ra, rd, upd; 112 union { 113 ulong i; 114 float f; 115 } u; 116 117 getairr(ir); 118 ea = imm; 119 upd = (ir&(1L<<26))!=0; 120 if(ra) { 121 ea += reg.r[ra]; 122 if(upd) 123 reg.r[ra] = ea; 124 } else { 125 if(upd) 126 undef(ir); 127 } 128 if(trace) 129 itrace("%s\tf%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea); 130 131 u.i = getmem_w(ea); 132 reg.fd[rd] = u.f; 133 } 134 135 void 136 lfsx(ulong ir) 137 { 138 ulong ea; 139 int rd, ra, rb, upd; 140 union { 141 ulong i; 142 float f; 143 } u; 144 145 getarrr(ir); 146 ea = reg.r[rb]; 147 upd = ((ir>>1)&0x3FF)==567; 148 if(ra){ 149 ea += reg.r[ra]; 150 if(upd) 151 reg.r[ra] = ea; 152 if(trace) 153 itrace("%s\tf%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea); 154 } else { 155 if(upd) 156 undef(ir); 157 if(trace) 158 itrace("%s\tf%d,(r%d) ea=%lux", ci->name, rd, rb, ea); 159 } 160 161 u.i = getmem_w(ea); 162 reg.fd[rd] = u.f; 163 } 164 165 void 166 lfd(ulong ir) 167 { 168 ulong ea; 169 int imm, ra, rd, upd; 170 171 getairr(ir); 172 ea = imm; 173 upd = (ir&(1L<<26))!=0; 174 if(ra) { 175 ea += reg.r[ra]; 176 if(upd) 177 reg.r[ra] = ea; 178 } else { 179 if(upd) 180 undef(ir); 181 } 182 if(trace) 183 itrace("%s\tf%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea); 184 185 reg.fd[rd] = v2fp(getmem_v(ea)); 186 } 187 188 void 189 lfdx(ulong ir) 190 { 191 ulong ea; 192 int rd, ra, rb, upd; 193 194 getarrr(ir); 195 ea = reg.r[rb]; 196 upd = ((ir>>1)&0x3FF)==631; 197 if(ra){ 198 ea += reg.r[ra]; 199 if(upd) 200 reg.r[ra] = ea; 201 if(trace) 202 itrace("%s\tf%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea); 203 } else { 204 if(upd) 205 undef(ir); 206 if(trace) 207 itrace("%s\tf%d,(r%d) ea=%lux", ci->name, rd, rb, ea); 208 } 209 210 reg.fd[rd] = v2fp(getmem_v(ea)); 211 } 212 213 void 214 stfs(ulong ir) 215 { 216 ulong ea; 217 int imm, ra, rd, upd; 218 union { 219 float f; 220 ulong w; 221 } u; 222 223 getairr(ir); 224 ea = imm; 225 upd = (ir&(1L<<26))!=0; 226 if(ra) { 227 ea += reg.r[ra]; 228 if(upd) 229 reg.r[ra] = ea; 230 } else { 231 if(upd) 232 undef(ir); 233 } 234 if(trace) 235 itrace("%s\tf%d,%ld(r%d) %lux=%g", 236 ci->name, rd, imm, ra, ea, reg.fd[rd]); 237 u.f = reg.fd[rd]; /* BUG: actual PPC conversion is more subtle than this */ 238 putmem_w(ea, u.w); 239 } 240 241 void 242 stfsx(ulong ir) 243 { 244 ulong ea; 245 int rd, ra, rb, upd; 246 union { 247 float f; 248 ulong w; 249 } u; 250 251 getarrr(ir); 252 ea = reg.r[rb]; 253 upd = getxo(ir)==695; 254 if(ra){ 255 ea += reg.r[ra]; 256 if(upd) 257 reg.r[ra] = ea; 258 if(trace) 259 itrace("%s\tf%d,(r%d+r%d) %lux=%g", ci->name, rd, ra, rb, ea, (float)reg.fd[rd]); 260 } else { 261 if(upd) 262 undef(ir); 263 if(trace) 264 itrace("%s\tf%d,(r%d) %lux=%g", ci->name, rd, rb, ea, (float)reg.fd[rd]); 265 } 266 267 u.f = reg.fd[rd]; /* BUG: actual PPC conversion is more subtle than this */ 268 putmem_w(ea, u.w); 269 } 270 271 void 272 stfd(ulong ir) 273 { 274 ulong ea; 275 int imm, ra, rd, upd; 276 277 getairr(ir); 278 ea = imm; 279 upd = (ir&(1L<<26))!=0; 280 if(ra) { 281 ea += reg.r[ra]; 282 if(upd) 283 reg.r[ra] = ea; 284 } else { 285 if(upd) 286 undef(ir); 287 } 288 if(trace) 289 itrace("%s\tf%d,%ld(r%d) %lux=%g", 290 ci->name, rd, imm, ra, ea, reg.fd[rd]); 291 292 putmem_v(ea, fp2v(reg.fd[rd])); 293 } 294 295 void 296 stfdx(ulong ir) 297 { 298 ulong ea; 299 int rd, ra, rb, upd; 300 301 getarrr(ir); 302 ea = reg.r[rb]; 303 upd = ((ir>>1)&0x3FF)==759; 304 if(ra){ 305 ea += reg.r[ra]; 306 if(upd) 307 reg.r[ra] = ea; 308 if(trace) 309 itrace("%s\tf%d,(r%d+r%d) %lux=%g", ci->name, rd, ra, rb, ea, reg.fd[rd]); 310 } else { 311 if(upd) 312 undef(ir); 313 if(trace) 314 itrace("%s\tf%d,(r%d) %lux=%g", ci->name, rd, rb, ea, reg.fd[rd]); 315 } 316 317 putmem_v(ea, fp2v(reg.fd[rd])); 318 } 319 320 void 321 mcrfs(ulong ir) 322 { 323 ulong rd, ra, rb; 324 static ulong fpscr0[] ={ 325 FPS_FX|FPS_OX, 326 FPS_UX|FPS_ZX|FPS_XX|FPS_VXSNAN, 327 FPS_VXISI|FPS_VXIDI|FPS_VXZDZ|FPS_VXIMZ, 328 FPS_VXVC, 329 0, 330 FPS_VXCVI, 331 }; 332 333 getarrr(ir); 334 if(rb || ra&3 || rd&3) 335 undef(ir); 336 ra >>= 2; 337 rd >>= 2; 338 reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, getCR(ra, reg.fpscr)); 339 reg.fpscr &= ~fpscr0[ra]; 340 if(trace) 341 itrace("mcrfs\tcrf%d,crf%d\n", rd, ra); 342 } 343 344 void 345 mffs(ulong ir) 346 { 347 int rd, ra, rb; 348 FPdbleword d; 349 350 getarrr(ir); 351 if(ra || rb) 352 undef(ir); 353 d.hi = 0xFFF80000UL; 354 d.lo = reg.fpscr; 355 reg.fd[rd] = d.x; 356 /* it's anyone's guess how CR1 should be set when ir&1 */ 357 reg.cr &= ~mkCR(1, 0xE); /* leave SO, reset others */ 358 if(trace) 359 itrace("mffs%s\tfr%d\n", ir&1?".":"", rd); 360 } 361 362 void 363 mtfsb1(ulong ir) 364 { 365 int rd, ra, rb; 366 367 getarrr(ir); 368 if(ra || rb) 369 undef(ir); 370 reg.fpscr |= (1L << (31-rd)); 371 /* BUG: should set summary bits */ 372 if(ir & 1) 373 reg.cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */ 374 if(trace) 375 itrace("mtfsb1%s\tfr%d\n", ir&1?".":"", rd); 376 } 377 378 void 379 mtfsb0(ulong ir) 380 { 381 int rd, ra, rb; 382 383 getarrr(ir); 384 if(ra || rb) 385 undef(ir); 386 reg.fpscr &= ~(1L << (31-rd)); 387 if(ir & 1) 388 reg.cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */ 389 if(trace) 390 itrace("mtfsb0%s\tfr%d\n", ir&1?".":"", rd); 391 } 392 393 void 394 mtfsf(ulong ir) 395 { 396 int fm, rb, i; 397 FPdbleword d; 398 ulong v; 399 400 if(ir & ((1L << 25)|(1L << 16))) 401 undef(ir); 402 rb = (ir >> 11) & 0x1F; 403 fm = (ir >> 17) & 0xFF; 404 d.x = reg.fd[rb]; 405 v = d.lo; 406 for(i=0; i<8; i++) 407 if(fm & (1 << (7-i))) 408 reg.fpscr = (reg.fpscr & ~mkCR(i, 0xF)) | mkCR(i, getCR(i, v)); 409 /* BUG: should set FEX and VX `according to the usual rule' */ 410 if(ir & 1) 411 reg.cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */ 412 if(trace) 413 itrace("mtfsf%s\t#%.2x,fr%d", ir&1?".":"", fm, rb); 414 } 415 416 void 417 mtfsfi(ulong ir) 418 { 419 int imm, rd; 420 421 if(ir & ((0x7F << 16)|(1L << 11))) 422 undef(ir); 423 rd = (ir >> 23) & 0xF; 424 imm = (ir >> 12) & 0xF; 425 reg.fpscr = (reg.fpscr & ~mkCR(rd, 0xF)) | mkCR(rd, imm); 426 /* BUG: should set FEX and VX `according to the usual rule' */ 427 if(ir & 1) 428 reg.cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */ 429 if(trace) 430 itrace("mtfsfi%s\tcrf%d,#%x", ir&1?".":"", rd, imm); 431 } 432 433 void 434 fcmp(ulong ir) 435 { 436 int fc, rd, ra, rb; 437 438 getarrr(ir); 439 if(rd & 3) 440 undef(ir); 441 rd >>= 2; 442 SET(fc); 443 switch(getxo(ir)) { 444 default: 445 undef(ir); 446 case 0: 447 if(trace) 448 itrace("fcmpu\tcr%d,f%d,f%d", rd, ra, rb); 449 if(isNaN(reg.fd[ra]) || isNaN(reg.fd[rb])) { 450 fc = CRFU; 451 break; 452 } 453 if(reg.fd[ra] == reg.fd[rb]) { 454 fc = CREQ; 455 break; 456 } 457 if(reg.fd[ra] < reg.fd[rb]) { 458 fc = CRLT; 459 break; 460 } 461 if(reg.fd[ra] > reg.fd[rb]) { 462 fc = CRGT; 463 break; 464 } 465 print("qi: fcmp error\n"); 466 break; 467 case 32: 468 if(trace) 469 itrace("fcmpo\tcr%d,f%d,f%d", rd, ra, rb); 470 if(isNaN(reg.fd[ra]) || isNaN(reg.fd[rb])) { /* BUG: depends whether quiet or signalling ... */ 471 fc = CRFU; 472 Bprint(bioout, "invalid_fp_register\n"); 473 longjmp(errjmp, 0); 474 } 475 if(reg.fd[ra] == reg.fd[rb]) { 476 fc = CREQ; 477 break; 478 } 479 if(reg.fd[ra] < reg.fd[rb]) { 480 fc = CRLT; 481 break; 482 } 483 if(reg.fd[ra] > reg.fd[rb]) { 484 fc = CRGT; 485 break; 486 } 487 print("qi: fcmp error\n"); 488 break; 489 490 } 491 fc >>= 28; 492 reg.cr = (reg.cr & ~mkCR(rd,~0)) | mkCR(rd, fc); 493 reg.fpscr = (reg.fpscr & ~0xF800) | (fc<<11); 494 /* BUG: update FX, VXSNAN, VXVC */ 495 } 496 497 /* 498 * the farith functions probably don't produce the right results 499 * in the presence of NaNs, Infs, etc., esp. wrt exception handling, 500 */ 501 void 502 fariths(ulong ir) 503 { 504 int rd, ra, rb, rc, fmt; 505 char *cc; 506 ulong fpscr; 507 508 fmt = 0; 509 rc = (ir>>6)&0x1F; 510 getarrr(ir); 511 switch(getxo(ir)&0x1F) { /* partial XO decode */ 512 default: 513 undef(ir); 514 case 18: 515 if((float)reg.fd[rb] == 0.0) { 516 Bprint(bioout, "fp_exception ZX\n"); 517 reg.fpscr |= FPS_ZX | FPS_FX; 518 longjmp(errjmp, 0); 519 } 520 reg.fd[rd] = (float)(reg.fd[ra] / reg.fd[rb]); 521 break; 522 case 20: 523 reg.fd[rd] = (float)(reg.fd[ra] - reg.fd[rb]); 524 break; 525 case 21: 526 reg.fd[rd] = (float)(reg.fd[ra] + reg.fd[rb]); 527 break; 528 case 25: 529 reg.fd[rd] = (float)(reg.fd[ra] * reg.fd[rc]); 530 rb = rc; 531 break; 532 case 28: 533 reg.fd[rd] = (float)((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]); 534 fmt = 2; 535 break; 536 case 29: 537 reg.fd[rd] = (float)((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]); 538 fmt = 2; 539 break; 540 case 30: 541 reg.fd[rd] = (float)-((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]); 542 fmt = 2; 543 break; 544 case 31: 545 reg.fd[rd] = (float)-((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]); 546 fmt = 2; 547 break; 548 } 549 if(fmt==1 && ra) 550 undef(ir); 551 fpscr = setfpscr(); 552 setfpcc(reg.fd[rd]); 553 cc = ""; 554 if(ir & 1) { 555 cc = "."; 556 reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28)); 557 } 558 if(trace) { 559 switch(fmt) { 560 case 0: 561 itrace("%s%s\tfr%d,fr%d,fr%d", ci->name, cc, rd, ra, rb); 562 break; 563 case 1: 564 itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb); 565 break; 566 case 2: 567 itrace("%s%s\tfr%d,fr%d,fr%d,fr%d", ci->name, cc, rd, ra, rc, rb); 568 break; 569 } 570 } 571 } 572 573 void 574 farith(ulong ir) 575 { 576 vlong vl; 577 int rd, ra, rb, rc, fmt; 578 char *cc; 579 ulong fpscr; 580 int nocc; 581 double d; 582 583 fmt = 0; 584 nocc = 0; 585 rc = (ir>>6)&0x1F; 586 getarrr(ir); 587 switch(getxo(ir)&0x1F) { /* partial XO decode */ 588 default: 589 undef(ir); 590 case 12: /* frsp */ 591 reg.fd[rd] = (float)reg.fd[rb]; 592 fmt = 1; 593 break; 594 case 14: /* fctiw */ /* BUG: ignores rounding mode */ 595 case 15: /* fctiwz */ 596 d = reg.fd[rb]; 597 if(d >= 0x7fffffff) 598 vl = 0x7fffffff; 599 else if(d < 0x80000000) 600 vl = 0x80000000; 601 else 602 vl = d; 603 reg.fd[rd] = v2fp(vl); 604 fmt = 1; 605 nocc = 1; 606 break; 607 case 18: 608 if(reg.fd[rb] == 0.0) { 609 Bprint(bioout, "fp_exception ZX\n"); 610 reg.fpscr |= FPS_ZX | FPS_FX; 611 longjmp(errjmp, 0); 612 } 613 reg.fd[rd] = reg.fd[ra] / reg.fd[rb]; 614 break; 615 case 20: 616 reg.fd[rd] = reg.fd[ra] - reg.fd[rb]; 617 break; 618 case 21: 619 reg.fd[rd] = reg.fd[ra] + reg.fd[rb]; 620 break; 621 case 25: 622 reg.fd[rd] = reg.fd[ra] * reg.fd[rc]; 623 rb = rc; 624 break; 625 case 28: 626 reg.fd[rd] = (reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]; 627 fmt = 2; 628 break; 629 case 29: 630 reg.fd[rd] = (reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]; 631 fmt = 2; 632 break; 633 case 30: 634 reg.fd[rd] = -((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]); 635 fmt = 2; 636 break; 637 case 31: 638 reg.fd[rd] = -((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]); 639 fmt = 2; 640 break; 641 } 642 if(fmt==1 && ra) 643 undef(ir); 644 fpscr = setfpscr(); 645 if(nocc == 0) 646 setfpcc(reg.fd[rd]); 647 cc = ""; 648 if(ir & 1) { 649 cc = "."; 650 reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28)); 651 } 652 if(trace) { 653 switch(fmt) { 654 case 0: 655 itrace("%s%s\tfr%d,fr%d,fr%d", ci->name, cc, rd, ra, rb); 656 break; 657 case 1: 658 itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb); 659 break; 660 case 2: 661 itrace("%s%s\tfr%d,fr%d,fr%d,fr%d", ci->name, cc, rd, ra, rc, rb); 662 break; 663 } 664 } 665 } 666 667 void 668 farith2(ulong ir) 669 { 670 int rd, ra, rb; 671 char *cc; 672 ulong fpscr; 673 674 getarrr(ir); 675 switch(getxo(ir)) { /* full XO decode */ 676 default: 677 undef(ir); 678 case 40: 679 reg.fd[rd] = -reg.fd[rb]; 680 break; 681 case 72: 682 reg.fd[rd] = reg.fd[rb]; 683 break; 684 case 136: 685 reg.fd[rd] = -fabs(reg.fd[rb]); 686 break; 687 case 264: 688 reg.fd[rd] = fabs(reg.fd[rb]); 689 break; 690 } 691 if(ra) 692 undef(ir); 693 fpscr = setfpscr(); 694 setfpcc(reg.fd[rd]); 695 cc = ""; 696 if(ir & 1) { 697 cc = "."; 698 reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28)); 699 } 700 if(trace) 701 itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb); 702 } 703 704 ulong 705 setfpscr(void) 706 { 707 ulong fps, fpscr; 708 709 fps = getfsr(); 710 fpscr = reg.fpscr; 711 if(fps & FPAOVFL) 712 fpscr |= FPS_OX; 713 if(fps & FPAINEX) 714 fpscr |= FPS_XX; 715 if(fps & FPAUNFL) 716 fpscr |= FPS_UX; 717 if(fps & FPAZDIV) 718 fpscr |= FPS_ZX; 719 if(fpscr != reg.fpscr) { 720 fpscr |= FPS_FX; 721 reg.fpscr = fpscr; 722 } 723 return fpscr; 724 } 725 726 void 727 setfpcc(double r) 728 { 729 int c; 730 731 c = 0; 732 if(r == 0) 733 c |= 2; 734 else if(r < 0) 735 c |= 4; 736 else 737 c |= 8; 738 if(isNaN(r)) 739 c |= 1; 740 reg.fpscr = (reg.fpscr & ~0xF800) | (0<<15) | (c<<11); /* unsure about class bit */ 741 } 742