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