1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include <mach.h> 5 #define Extern extern 6 #include "mips.h" 7 8 void unimp(ulong); 9 void Ifcmp(ulong); 10 void Ifdiv(ulong); 11 void Ifmul(ulong); 12 void Ifadd(ulong); 13 void Ifsub(ulong); 14 void Ifmov(ulong); 15 void Icvtd(ulong); 16 void Icvtw(ulong); 17 void Icvts(ulong); 18 void Ifabs(ulong); 19 void Ifneg(ulong); 20 21 Inst cop1[] = { 22 { Ifadd, "add.f", Ifloat }, 23 { Ifsub, "sub.f", Ifloat }, 24 { Ifmul, "mul.f", Ifloat }, 25 { Ifdiv, "div.f", Ifloat }, 26 { unimp, "", }, 27 { Ifabs, "abs.f", Ifloat }, 28 { Ifmov, "mov.f", Ifloat }, 29 { Ifneg, "neg.f", Ifloat }, 30 { unimp, "", }, 31 { unimp, "", }, 32 { unimp, "", }, 33 { unimp, "", }, 34 { unimp, "", }, 35 { unimp, "", }, 36 { unimp, "", }, 37 { unimp, "", }, 38 { unimp, "", }, 39 { unimp, "", }, 40 { unimp, "", }, 41 { unimp, "", }, 42 { unimp, "", }, 43 { unimp, "", }, 44 { unimp, "", }, 45 { unimp, "", }, 46 { unimp, "", }, 47 { unimp, "", }, 48 { unimp, "", }, 49 { unimp, "", }, 50 { unimp, "", }, 51 { unimp, "", }, 52 { unimp, "", }, 53 { unimp, "", }, 54 { Icvts, "cvt.s", Ifloat }, 55 { Icvtd, "cvt.d", Ifloat }, 56 { unimp, "", }, 57 { unimp, "", }, 58 { Icvtw, "cvt.w", Ifloat }, 59 { unimp, "", }, 60 { unimp, "", }, 61 { unimp, "", }, 62 { unimp, "", }, 63 { unimp, "", }, 64 { unimp, "", }, 65 { unimp, "", }, 66 { unimp, "", }, 67 { unimp, "", }, 68 { unimp, "", }, 69 { unimp, "", }, 70 { Ifcmp, "c.f", Ifloat }, 71 { Ifcmp, "c.un", Ifloat }, 72 { Ifcmp, "c.eq", Ifloat }, 73 { Ifcmp, "c.ueq", Ifloat }, 74 { Ifcmp, "c.olt", Ifloat }, 75 { Ifcmp, "c.ult", Ifloat }, 76 { Ifcmp, "c.ole", Ifloat }, 77 { Ifcmp, "c.ule", Ifloat }, 78 { Ifcmp, "c,sf", Ifloat }, 79 { Ifcmp, "c.ngle",Ifloat }, 80 { Ifcmp, "c.seq", Ifloat }, 81 { Ifcmp, "c.ngl", Ifloat }, 82 { Ifcmp, "c.lt", Ifloat }, 83 { Ifcmp, "c.nge", Ifloat }, 84 { Ifcmp, "c.le", Ifloat }, 85 { Ifcmp, "c.ngt", Ifloat }, 86 { 0 } 87 }; 88 89 void 90 unimp(ulong inst) 91 { 92 print("op %d\n", inst&0x3f); 93 Bprint(bioout, "Unimplemented floating point Trap IR %.8lux\n", inst); 94 longjmp(errjmp, 0); 95 } 96 97 void 98 inval(ulong inst) 99 { 100 Bprint(bioout, "Invalid Operation Exception IR %.8lux\n", inst); 101 longjmp(errjmp, 0); 102 } 103 104 void 105 ifmt(int r) 106 { 107 Bprint(bioout, "Invalid Floating Data Format f%d pc 0x%lux\n", r, reg.pc); 108 longjmp(errjmp, 0); 109 } 110 111 void 112 floatop(int dst, int s1, int s2) 113 { 114 if(reg.ft[s1] == FPd && s1 != 24) 115 ifmt(s1); 116 if(reg.ft[s2] == FPd && s2 != 24) 117 ifmt(s2); 118 reg.ft[dst] = FPs; 119 } 120 121 void 122 doubop(int dst, int s1, int s2) 123 { 124 ulong l; 125 126 if(reg.ft[s1] != FPd) { 127 if(reg.ft[s1] == FPs && s1 != 24) 128 ifmt(s1); 129 l = reg.di[s1]; 130 reg.di[s1] = reg.di[s1+1]; 131 reg.di[s1+1] = l; 132 reg.ft[s1] = FPd; 133 } 134 if(reg.ft[s2] != FPd) { 135 if(reg.ft[s2] == FPs && s2 != 24) 136 ifmt(s2); 137 l = reg.di[s2]; 138 reg.di[s2] = reg.di[s2+1]; 139 reg.di[s2+1] = l; 140 reg.ft[s2] = FPd; 141 } 142 reg.ft[dst] = FPd; 143 } 144 145 void 146 Iswc1(ulong inst) 147 { 148 int off; 149 ulong l; 150 int rt, rb, ert; 151 152 Getrbrt(rb, rt, inst); 153 off = (short)(inst&0xffff); 154 155 if(trace) 156 itrace("swc1\tf%d,0x%x(r%d) ea=%lux", rt, off, rb, reg.r[rb]+off); 157 158 ert = rt&~1; 159 if(reg.ft[ert] == FPd) { 160 l = reg.di[ert]; 161 reg.di[ert] = reg.di[ert+1]; 162 reg.di[ert+1] = l; 163 reg.ft[ert] = FPmemory; 164 } 165 putmem_w(reg.r[rb]+off, reg.di[rt]); 166 } 167 168 void 169 Ifsub(ulong ir) 170 { 171 char fmt; 172 int fs, ft, fd; 173 174 Getf3(fs, ft, fd, ir); 175 176 switch((ir>>21)&0xf) { 177 default: 178 unimp(ir); 179 case 0: /* single */ 180 fmt = 's'; 181 floatop(fd, fs, ft); 182 reg.fl[fd] = reg.fl[fs] - reg.fl[ft]; 183 break; 184 case 1: /* double */ 185 fmt = 'd'; 186 doubop(fd, fs, ft); 187 reg.fd[fd>>1] = reg.fd[fs>>1] - reg.fd[ft>>1]; 188 break; 189 case 4: 190 fmt = 'w'; 191 reg.di[fd] = reg.di[fs] - reg.di[ft]; 192 break; 193 } 194 if(trace) 195 itrace("sub.%c\tf%d,f%d,f%d", fmt, fd, fs, ft); 196 } 197 198 void 199 Ifmov(ulong ir) 200 { 201 char fmt; 202 int fs, fd; 203 204 Getf2(fs, fd, ir); 205 206 switch((ir>>21)&0xf) { 207 default: 208 unimp(ir); 209 case 0: /* single */ 210 fmt = 's'; 211 reg.fl[fd] = reg.fl[fs]; 212 reg.ft[fd] = reg.ft[fs]; 213 break; 214 case 1: /* double */ 215 fmt = 'd'; 216 reg.fd[fd>>1] = reg.fd[fs>>1]; 217 reg.ft[fd] = reg.ft[fs]; 218 break; 219 case 4: 220 fmt = 'w'; 221 reg.di[fd] = reg.di[fs]; 222 reg.ft[fd] = reg.ft[fs]; 223 break; 224 } 225 if(trace) 226 itrace("mov.%c\tf%d,f%d", fmt, fd, fs); 227 } 228 229 void 230 Ifabs(ulong ir) 231 { 232 char fmt; 233 int fs, fd; 234 235 Getf2(fs, fd, ir); 236 237 switch((ir>>21)&0xf) { 238 default: 239 unimp(ir); 240 case 0: /* single */ 241 fmt = 's'; 242 floatop(fd, fs, fs); 243 if(reg.fl[fs] < 0.0) 244 reg.fl[fd] = -reg.fl[fs]; 245 else 246 reg.fl[fd] = reg.fl[fs]; 247 break; 248 case 1: /* double */ 249 fmt = 'd'; 250 doubop(fd, fs, fs); 251 if(reg.fd[fs>>1] < 0.0) 252 reg.fd[fd>>1] = -reg.fd[fs>>1]; 253 else 254 reg.fd[fd>>1] = reg.fd[fs>>1]; 255 break; 256 case 4: 257 fmt = 'w'; 258 if((long)reg.di[fs] < 0) 259 reg.di[fd] = -reg.di[fs]; 260 else 261 reg.di[fd] = reg.di[fs]; 262 break; 263 } 264 if(trace) 265 itrace("abs.%c\tf%d,f%d", fmt, fd, fs); 266 } 267 268 void 269 Ifneg(ulong ir) 270 { 271 char fmt; 272 int fs, fd; 273 274 Getf2(fs, fd, ir); 275 276 switch((ir>>21)&0xf) { 277 default: 278 unimp(ir); 279 case 0: /* single */ 280 fmt = 's'; 281 floatop(fd, fs, fs); 282 reg.fl[fd] = -reg.fl[fs]; 283 break; 284 case 1: /* double */ 285 fmt = 'd'; 286 doubop(fd, fs, fs); 287 reg.fd[fd>>1] = -reg.fd[fs>>1]; 288 break; 289 case 4: 290 fmt = 'w'; 291 reg.di[fd] = -reg.di[fs]; 292 break; 293 } 294 if(trace) 295 itrace("neg.%c\tf%d,f%d", fmt, fd, fs); 296 } 297 298 void 299 Icvtd(ulong ir) 300 { 301 char fmt; 302 int fs, fd; 303 304 Getf2(fs, fd, ir); 305 306 switch((ir>>21)&0xf) { 307 default: 308 unimp(ir); 309 case 0: /* single */ 310 fmt = 's'; 311 floatop(fs, fs, fs); 312 reg.fd[fd>>1] = reg.fl[fs]; 313 reg.ft[fd] = FPd; 314 break; 315 case 1: /* double */ 316 fmt = 'd'; 317 doubop(fd, fs, fs); 318 reg.fd[fd>>1] = reg.fd[fs>>1]; 319 break; 320 case 4: 321 fmt = 'w'; 322 reg.fd[fd>>1] = (long)reg.di[fs]; 323 reg.ft[fd] = FPd; 324 break; 325 } 326 if(trace) 327 itrace("cvt.d.%c\tf%d,f%d", fmt, fd, fs); 328 } 329 330 void 331 Icvts(ulong ir) 332 { 333 char fmt; 334 int fs, fd; 335 336 Getf2(fs, fd, ir); 337 338 switch((ir>>21)&0xf) { 339 default: 340 unimp(ir); 341 case 0: /* single */ 342 fmt = 's'; 343 floatop(fd, fs, fs); 344 reg.fl[fd] = reg.fl[fs]; 345 break; 346 case 1: /* double */ 347 fmt = 'd'; 348 doubop(fs, fs, fs); 349 reg.fl[fd] = reg.fd[fs>>1]; 350 reg.ft[fd] = FPs; 351 break; 352 case 4: 353 fmt = 'w'; 354 reg.fl[fd] = (long)reg.di[fs]; 355 reg.ft[fd] = FPs; 356 break; 357 } 358 if(trace) 359 itrace("cvt.s.%c\tf%d,f%d", fmt, fd, fs); 360 } 361 362 void 363 Icvtw(ulong ir) 364 { 365 long v; 366 char fmt; 367 int fs, fd; 368 369 Getf2(fs, fd, ir); 370 371 switch((ir>>21)&0xf) { 372 default: 373 unimp(ir); 374 case 0: /* single */ 375 fmt = 's'; 376 floatop(fs, fs, fs); 377 v = reg.fl[fs]; 378 break; 379 case 1: /* double */ 380 fmt = 'd'; 381 doubop(fs, fs, fs); 382 v = reg.fd[fs>>1]; 383 break; 384 case 4: 385 fmt = 'w'; 386 v = reg.di[fs]; 387 break; 388 } 389 reg.di[fd] = v; 390 reg.ft[fd] = FPmemory; 391 if(trace) 392 itrace("cvt.w.%c\tf%d,f%d", fmt, fd, fs); 393 } 394 395 void 396 Ifadd(ulong ir) 397 { 398 char fmt; 399 int fs, ft, fd; 400 401 Getf3(fs, ft, fd, ir); 402 403 switch((ir>>21)&0xf) { 404 default: 405 unimp(ir); 406 case 0: /* single */ 407 fmt = 's'; 408 floatop(fd, fs, ft); 409 reg.fl[fd] = reg.fl[fs] + reg.fl[ft]; 410 break; 411 case 1: /* double */ 412 fmt = 'd'; 413 doubop(fd, fs, ft); 414 reg.fd[fd>>1] = reg.fd[fs>>1] + reg.fd[ft>>1]; 415 break; 416 case 4: 417 fmt = 'w'; 418 reg.di[fd] = reg.di[fs] + reg.di[ft]; 419 break; 420 } 421 if(trace) 422 itrace("add.%c\tf%d,f%d,f%d", fmt, fd, fs, ft); 423 } 424 425 void 426 Ifmul(ulong ir) 427 { 428 char fmt; 429 int fs, ft, fd; 430 431 Getf3(fs, ft, fd, ir); 432 433 switch((ir>>21)&0xf) { 434 default: 435 unimp(ir); 436 case 0: /* single */ 437 fmt = 's'; 438 floatop(fd, fs, ft); 439 reg.fl[fd] = reg.fl[fs] * reg.fl[ft]; 440 break; 441 case 1: /* double */ 442 fmt = 'd'; 443 doubop(fd, fs, ft); 444 reg.fd[fd>>1] = reg.fd[fs>>1] * reg.fd[ft>>1]; 445 break; 446 case 4: 447 fmt = 'w'; 448 reg.di[fd] = reg.di[fs] * reg.di[ft]; 449 break; 450 } 451 if(trace) 452 itrace("mul.%c\tf%d,f%d,f%d", fmt, fd, fs, ft); 453 } 454 455 void 456 Ifdiv(ulong ir) 457 { 458 char fmt; 459 int fs, ft, fd; 460 461 Getf3(fs, ft, fd, ir); 462 463 switch((ir>>21)&0xf) { 464 default: 465 unimp(ir); 466 case 0: /* single */ 467 fmt = 's'; 468 floatop(fd, fs, ft); 469 reg.fl[fd] = reg.fl[fs] / reg.fl[ft]; 470 break; 471 case 1: /* double */ 472 fmt = 'd'; 473 doubop(fd, fs, ft); 474 reg.fd[fd>>1] = reg.fd[fs>>1] / reg.fd[ft>>1]; 475 break; 476 case 4: 477 fmt = 'w'; 478 reg.di[fd] = reg.di[fs] / reg.di[ft]; 479 break; 480 } 481 if(trace) 482 itrace("div.%c\tf%d,f%d,f%d", fmt, fd, fs, ft); 483 } 484 485 void 486 Ilwc1(ulong inst) 487 { 488 int rt, rb; 489 int off; 490 491 Getrbrt(rb, rt, inst); 492 off = (short)(inst&0xffff); 493 494 if(trace) 495 itrace("lwc1\tf%d,0x%x(r%d) ea=%lux", rt, off, rb, reg.r[rb]+off); 496 497 reg.di[rt] = getmem_w(reg.r[rb]+off); 498 reg.ft[rt] = FPmemory; 499 } 500 501 void 502 Ibcfbct(ulong inst) 503 { 504 int takeit; 505 int off; 506 ulong npc; 507 508 off = (short)(inst&0xffff); 509 510 takeit = 0; 511 npc = reg.pc + (off<<2) + 4; 512 if(inst&(1<<16)) { 513 if(trace) 514 itrace("bc1t\t0x%lux", npc); 515 516 if(reg.fpsr&FP_CBIT) 517 takeit = 1; 518 } 519 else { 520 if(trace) 521 itrace("bc1f\t0x%lux", npc); 522 523 if((reg.fpsr&FP_CBIT) == 0) 524 takeit = 1; 525 } 526 527 if(takeit) { 528 /* Do the delay slot */ 529 reg.ir = ifetch(reg.pc+4); 530 Statbra(); 531 Iexec(reg.ir); 532 reg.pc = npc-4; 533 } 534 } 535 536 void 537 Imtct(ulong ir) 538 { 539 int rt, fs; 540 541 SpecialGetrtrd(rt, fs, ir); 542 if(ir&(1<<22)) { /* CT */ 543 if(trace) 544 itrace("ctc1\tr%d,f%d", rt, fs); 545 } 546 else { /* MT */ 547 if(trace) 548 itrace("mtc1\tr%d,f%d", rt, fs); 549 550 reg.di[fs] = reg.r[rt]; 551 reg.ft[fs] = FPmemory; 552 } 553 } 554 555 void 556 Imfcf(ulong ir) 557 { 558 int rt, fs; 559 560 SpecialGetrtrd(rt, fs, ir); 561 if(ir&(1<<22)) { /* CF */ 562 if(trace) 563 itrace("cfc1\tr%d,f%d", rt, fs); 564 } 565 else { /* MF */ 566 if(trace) 567 itrace("mfc1\tr%d,f%d", rt, fs); 568 569 reg.r[rt] = reg.di[fs]; 570 } 571 } 572 573 void 574 Icop1(ulong ir) 575 { 576 Inst *i; 577 578 switch((ir>>23)&7) { 579 case 0: 580 Imfcf(ir); 581 break; 582 case 1: 583 Imtct(ir); 584 break; 585 case 2: 586 case 3: 587 Ibcfbct(ir); 588 break; 589 case 4: 590 case 5: 591 case 6: 592 case 7: 593 i = &cop1[ir&0x3f]; 594 i->count++; 595 (*i->func)(ir); 596 } 597 } 598 599 void 600 Ifcmp(ulong ir) 601 { 602 char fmt; 603 int fc; 604 int ft, fs; 605 606 SpecialGetrtrd(ft, fs, ir); 607 608 SET(fc); 609 switch((ir>>21)&0xf) { 610 default: 611 unimp(ir); 612 case 0: /* single */ 613 fmt = 's'; 614 floatop(fs, fs, ft); 615 if(isNaN(reg.fl[fs]) || isNaN(reg.fl[ft])) { 616 fc = FP_U; 617 break; 618 } 619 if(reg.fl[fs] == reg.fl[ft]) { 620 fc = FP_E; 621 break; 622 } 623 if(reg.fl[fs] < reg.fl[ft]) { 624 fc = FP_L; 625 break; 626 } 627 if(reg.fl[fs] > reg.fl[ft]) { 628 fc = FP_G; 629 break; 630 } 631 print("vi: bad in fcmp"); 632 break; 633 case 1: /* double */ 634 fmt = 'd'; 635 doubop(fs, fs, ft); 636 if(isNaN(reg.fd[fs>>1]) || isNaN(reg.fd[ft>>1])) { 637 fc = FP_U; 638 break; 639 } 640 if(reg.fd[fs>>1] == reg.fd[ft>>1]) { 641 fc = FP_E; 642 break; 643 } 644 if(reg.fd[fs>>1] < reg.fd[ft>>1]) { 645 fc = FP_L; 646 break; 647 } 648 if(reg.fd[fs>>1] > reg.fd[ft>>1]) { 649 fc = FP_G; 650 break; 651 } 652 print("vi: bad in fcmp"); 653 break; 654 case 4: 655 fmt = 'w'; 656 if(reg.di[fs] == reg.di[ft]) { 657 fc = FP_E; 658 break; 659 } 660 if(reg.di[fs] < reg.di[ft]) { 661 fc = FP_L; 662 break; 663 } 664 if(reg.di[fs] > reg.di[ft]) { 665 fc = FP_G; 666 break; 667 } 668 break; 669 } 670 671 reg.fpsr &= ~FP_CBIT; 672 switch(ir&0xf) { 673 case 0: 674 if(trace) 675 itrace("c.f.%c\tf%d,f%d", fmt, fs, ft); 676 break; 677 case 1: 678 if(trace) 679 itrace("c.un.%c\tf%d,f%d", fmt, fs, ft); 680 if(fc == FP_U) 681 reg.fpsr |= FP_CBIT; 682 break; 683 case 2: 684 if(trace) 685 itrace("c.eq.%c\tf%d,f%d", fmt, fs, ft); 686 if(fc == FP_E) 687 reg.fpsr |= FP_CBIT; 688 break; 689 case 3: 690 if(trace) 691 itrace("c.ueq.%c\tf%d,f%d", fmt, fs, ft); 692 if(fc == FP_E || fc == FP_U) 693 reg.fpsr |= FP_CBIT; 694 break; 695 case 4: 696 if(trace) 697 itrace("c.lt.%c\tf%d,f%d", fmt, fs, ft); 698 if(fc == FP_L) 699 reg.fpsr |= FP_CBIT; 700 break; 701 case 5: 702 if(trace) 703 itrace("c.ult.%c\tf%d,f%d", fmt, fs, ft); 704 if(fc == FP_L || fc == FP_U) 705 reg.fpsr |= FP_CBIT; 706 break; 707 case 6: 708 if(trace) 709 itrace("c.le.%c\tf%d,f%d", fmt, fs, ft); 710 if(fc == FP_E || fc == FP_L) 711 reg.fpsr |= FP_CBIT; 712 break; 713 case 7: 714 if(trace) 715 itrace("c.ule.%c\tf%d,f%d", fmt, fs, ft); 716 if(fc == FP_E || fc == FP_L || fc == FP_U) 717 reg.fpsr |= FP_CBIT; 718 break; 719 case 8: 720 if(trace) 721 itrace("c.sf.%c\tf%d,f%d", fmt, fs, ft); 722 if(fc == FP_U) 723 inval(ir); 724 break; 725 case 9: 726 if(trace) 727 itrace("c.ngle.%c\tf%d,f%d", fmt, fs, ft); 728 if(fc == FP_U) { 729 reg.fpsr |= FP_CBIT; 730 inval(ir); 731 } 732 break; 733 case 10: 734 if(trace) 735 itrace("c.seq.%c\tf%d,f%d", fmt, fs, ft); 736 if(fc == FP_E) 737 reg.fpsr |= FP_CBIT; 738 if(fc == FP_U) 739 inval(ir); 740 break; 741 case 11: 742 if(trace) 743 itrace("c.ngl.%c\tf%d,f%d", fmt, fs, ft); 744 if(fc == FP_E || fc == FP_U) 745 reg.fpsr |= FP_CBIT; 746 if(fc == FP_U) 747 inval(ir); 748 break; 749 case 12: 750 if(trace) 751 itrace("c.lt.%c\tf%d,f%d", fmt, fs, ft); 752 if(fc == FP_L) 753 reg.fpsr |= FP_CBIT; 754 if(fc == FP_U) 755 inval(ir); 756 break; 757 case 13: 758 if(trace) 759 itrace("c.nge.%c\tf%d,f%d", fmt, fs, ft); 760 if(fc == FP_L || fc == FP_U) 761 reg.fpsr |= FP_CBIT; 762 if(fc == FP_U) 763 inval(ir); 764 break; 765 case 14: 766 if(trace) 767 itrace("c.le.%c\tf%d,f%d", fmt, fs, ft); 768 if(fc == FP_E || fc == FP_L) 769 reg.fpsr |= FP_CBIT; 770 if(fc == FP_U) 771 inval(ir); 772 break; 773 case 15: 774 if(trace) 775 itrace("c.ngt.%c\tf%d,f%d", fmt, fs, ft); 776 if(fc == FP_E || fc == FP_L || fc == FP_U) 777 reg.fpsr |= FP_CBIT; 778 if(fc == FP_U) 779 inval(ir); 780 break; 781 } 782 USED(fmt); 783 } 784