diff options
Diffstat (limited to 'arch/mips/math-emu/cp1emu.c')
-rw-r--r-- | arch/mips/math-emu/cp1emu.c | 169 |
1 files changed, 158 insertions, 11 deletions
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 9dfcd7fc1bc3..b30bf65c7d7d 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <asm/processor.h> | 48 | #include <asm/processor.h> |
49 | #include <asm/fpu_emulator.h> | 49 | #include <asm/fpu_emulator.h> |
50 | #include <asm/fpu.h> | 50 | #include <asm/fpu.h> |
51 | #include <asm/mips-r2-to-r6-emul.h> | ||
51 | 52 | ||
52 | #include "ieee754.h" | 53 | #include "ieee754.h" |
53 | 54 | ||
@@ -68,7 +69,7 @@ static int fpux_emu(struct pt_regs *, | |||
68 | #define modeindex(v) ((v) & FPU_CSR_RM) | 69 | #define modeindex(v) ((v) & FPU_CSR_RM) |
69 | 70 | ||
70 | /* convert condition code register number to csr bit */ | 71 | /* convert condition code register number to csr bit */ |
71 | static const unsigned int fpucondbit[8] = { | 72 | const unsigned int fpucondbit[8] = { |
72 | FPU_CSR_COND0, | 73 | FPU_CSR_COND0, |
73 | FPU_CSR_COND1, | 74 | FPU_CSR_COND1, |
74 | FPU_CSR_COND2, | 75 | FPU_CSR_COND2, |
@@ -448,6 +449,9 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, | |||
448 | dec_insn.next_pc_inc; | 449 | dec_insn.next_pc_inc; |
449 | /* Fall through */ | 450 | /* Fall through */ |
450 | case jr_op: | 451 | case jr_op: |
452 | /* For R6, JR already emulated in jalr_op */ | ||
453 | if (NO_R6EMU && insn.r_format.opcode == jr_op) | ||
454 | break; | ||
451 | *contpc = regs->regs[insn.r_format.rs]; | 455 | *contpc = regs->regs[insn.r_format.rs]; |
452 | return 1; | 456 | return 1; |
453 | } | 457 | } |
@@ -456,12 +460,18 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, | |||
456 | switch (insn.i_format.rt) { | 460 | switch (insn.i_format.rt) { |
457 | case bltzal_op: | 461 | case bltzal_op: |
458 | case bltzall_op: | 462 | case bltzall_op: |
463 | if (NO_R6EMU && (insn.i_format.rs || | ||
464 | insn.i_format.rt == bltzall_op)) | ||
465 | break; | ||
466 | |||
459 | regs->regs[31] = regs->cp0_epc + | 467 | regs->regs[31] = regs->cp0_epc + |
460 | dec_insn.pc_inc + | 468 | dec_insn.pc_inc + |
461 | dec_insn.next_pc_inc; | 469 | dec_insn.next_pc_inc; |
462 | /* Fall through */ | 470 | /* Fall through */ |
463 | case bltz_op: | ||
464 | case bltzl_op: | 471 | case bltzl_op: |
472 | if (NO_R6EMU) | ||
473 | break; | ||
474 | case bltz_op: | ||
465 | if ((long)regs->regs[insn.i_format.rs] < 0) | 475 | if ((long)regs->regs[insn.i_format.rs] < 0) |
466 | *contpc = regs->cp0_epc + | 476 | *contpc = regs->cp0_epc + |
467 | dec_insn.pc_inc + | 477 | dec_insn.pc_inc + |
@@ -473,12 +483,18 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, | |||
473 | return 1; | 483 | return 1; |
474 | case bgezal_op: | 484 | case bgezal_op: |
475 | case bgezall_op: | 485 | case bgezall_op: |
486 | if (NO_R6EMU && (insn.i_format.rs || | ||
487 | insn.i_format.rt == bgezall_op)) | ||
488 | break; | ||
489 | |||
476 | regs->regs[31] = regs->cp0_epc + | 490 | regs->regs[31] = regs->cp0_epc + |
477 | dec_insn.pc_inc + | 491 | dec_insn.pc_inc + |
478 | dec_insn.next_pc_inc; | 492 | dec_insn.next_pc_inc; |
479 | /* Fall through */ | 493 | /* Fall through */ |
480 | case bgez_op: | ||
481 | case bgezl_op: | 494 | case bgezl_op: |
495 | if (NO_R6EMU) | ||
496 | break; | ||
497 | case bgez_op: | ||
482 | if ((long)regs->regs[insn.i_format.rs] >= 0) | 498 | if ((long)regs->regs[insn.i_format.rs] >= 0) |
483 | *contpc = regs->cp0_epc + | 499 | *contpc = regs->cp0_epc + |
484 | dec_insn.pc_inc + | 500 | dec_insn.pc_inc + |
@@ -505,8 +521,10 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, | |||
505 | /* Set microMIPS mode bit: XOR for jalx. */ | 521 | /* Set microMIPS mode bit: XOR for jalx. */ |
506 | *contpc ^= bit; | 522 | *contpc ^= bit; |
507 | return 1; | 523 | return 1; |
508 | case beq_op: | ||
509 | case beql_op: | 524 | case beql_op: |
525 | if (NO_R6EMU) | ||
526 | break; | ||
527 | case beq_op: | ||
510 | if (regs->regs[insn.i_format.rs] == | 528 | if (regs->regs[insn.i_format.rs] == |
511 | regs->regs[insn.i_format.rt]) | 529 | regs->regs[insn.i_format.rt]) |
512 | *contpc = regs->cp0_epc + | 530 | *contpc = regs->cp0_epc + |
@@ -517,8 +535,10 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, | |||
517 | dec_insn.pc_inc + | 535 | dec_insn.pc_inc + |
518 | dec_insn.next_pc_inc; | 536 | dec_insn.next_pc_inc; |
519 | return 1; | 537 | return 1; |
520 | case bne_op: | ||
521 | case bnel_op: | 538 | case bnel_op: |
539 | if (NO_R6EMU) | ||
540 | break; | ||
541 | case bne_op: | ||
522 | if (regs->regs[insn.i_format.rs] != | 542 | if (regs->regs[insn.i_format.rs] != |
523 | regs->regs[insn.i_format.rt]) | 543 | regs->regs[insn.i_format.rt]) |
524 | *contpc = regs->cp0_epc + | 544 | *contpc = regs->cp0_epc + |
@@ -529,8 +549,34 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, | |||
529 | dec_insn.pc_inc + | 549 | dec_insn.pc_inc + |
530 | dec_insn.next_pc_inc; | 550 | dec_insn.next_pc_inc; |
531 | return 1; | 551 | return 1; |
532 | case blez_op: | ||
533 | case blezl_op: | 552 | case blezl_op: |
553 | if (NO_R6EMU) | ||
554 | break; | ||
555 | case blez_op: | ||
556 | |||
557 | /* | ||
558 | * Compact branches for R6 for the | ||
559 | * blez and blezl opcodes. | ||
560 | * BLEZ | rs = 0 | rt != 0 == BLEZALC | ||
561 | * BLEZ | rs = rt != 0 == BGEZALC | ||
562 | * BLEZ | rs != 0 | rt != 0 == BGEUC | ||
563 | * BLEZL | rs = 0 | rt != 0 == BLEZC | ||
564 | * BLEZL | rs = rt != 0 == BGEZC | ||
565 | * BLEZL | rs != 0 | rt != 0 == BGEC | ||
566 | * | ||
567 | * For real BLEZ{,L}, rt is always 0. | ||
568 | */ | ||
569 | if (cpu_has_mips_r6 && insn.i_format.rt) { | ||
570 | if ((insn.i_format.opcode == blez_op) && | ||
571 | ((!insn.i_format.rs && insn.i_format.rt) || | ||
572 | (insn.i_format.rs == insn.i_format.rt))) | ||
573 | regs->regs[31] = regs->cp0_epc + | ||
574 | dec_insn.pc_inc; | ||
575 | *contpc = regs->cp0_epc + dec_insn.pc_inc + | ||
576 | dec_insn.next_pc_inc; | ||
577 | |||
578 | return 1; | ||
579 | } | ||
534 | if ((long)regs->regs[insn.i_format.rs] <= 0) | 580 | if ((long)regs->regs[insn.i_format.rs] <= 0) |
535 | *contpc = regs->cp0_epc + | 581 | *contpc = regs->cp0_epc + |
536 | dec_insn.pc_inc + | 582 | dec_insn.pc_inc + |
@@ -540,8 +586,35 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, | |||
540 | dec_insn.pc_inc + | 586 | dec_insn.pc_inc + |
541 | dec_insn.next_pc_inc; | 587 | dec_insn.next_pc_inc; |
542 | return 1; | 588 | return 1; |
543 | case bgtz_op: | ||
544 | case bgtzl_op: | 589 | case bgtzl_op: |
590 | if (NO_R6EMU) | ||
591 | break; | ||
592 | case bgtz_op: | ||
593 | /* | ||
594 | * Compact branches for R6 for the | ||
595 | * bgtz and bgtzl opcodes. | ||
596 | * BGTZ | rs = 0 | rt != 0 == BGTZALC | ||
597 | * BGTZ | rs = rt != 0 == BLTZALC | ||
598 | * BGTZ | rs != 0 | rt != 0 == BLTUC | ||
599 | * BGTZL | rs = 0 | rt != 0 == BGTZC | ||
600 | * BGTZL | rs = rt != 0 == BLTZC | ||
601 | * BGTZL | rs != 0 | rt != 0 == BLTC | ||
602 | * | ||
603 | * *ZALC varint for BGTZ &&& rt != 0 | ||
604 | * For real GTZ{,L}, rt is always 0. | ||
605 | */ | ||
606 | if (cpu_has_mips_r6 && insn.i_format.rt) { | ||
607 | if ((insn.i_format.opcode == blez_op) && | ||
608 | ((!insn.i_format.rs && insn.i_format.rt) || | ||
609 | (insn.i_format.rs == insn.i_format.rt))) | ||
610 | regs->regs[31] = regs->cp0_epc + | ||
611 | dec_insn.pc_inc; | ||
612 | *contpc = regs->cp0_epc + dec_insn.pc_inc + | ||
613 | dec_insn.next_pc_inc; | ||
614 | |||
615 | return 1; | ||
616 | } | ||
617 | |||
545 | if ((long)regs->regs[insn.i_format.rs] > 0) | 618 | if ((long)regs->regs[insn.i_format.rs] > 0) |
546 | *contpc = regs->cp0_epc + | 619 | *contpc = regs->cp0_epc + |
547 | dec_insn.pc_inc + | 620 | dec_insn.pc_inc + |
@@ -551,6 +624,16 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, | |||
551 | dec_insn.pc_inc + | 624 | dec_insn.pc_inc + |
552 | dec_insn.next_pc_inc; | 625 | dec_insn.next_pc_inc; |
553 | return 1; | 626 | return 1; |
627 | case cbcond0_op: | ||
628 | case cbcond1_op: | ||
629 | if (!cpu_has_mips_r6) | ||
630 | break; | ||
631 | if (insn.i_format.rt && !insn.i_format.rs) | ||
632 | regs->regs[31] = regs->cp0_epc + 4; | ||
633 | *contpc = regs->cp0_epc + dec_insn.pc_inc + | ||
634 | dec_insn.next_pc_inc; | ||
635 | |||
636 | return 1; | ||
554 | #ifdef CONFIG_CPU_CAVIUM_OCTEON | 637 | #ifdef CONFIG_CPU_CAVIUM_OCTEON |
555 | case lwc2_op: /* This is bbit0 on Octeon */ | 638 | case lwc2_op: /* This is bbit0 on Octeon */ |
556 | if ((regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt)) == 0) | 639 | if ((regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt)) == 0) |
@@ -576,9 +659,73 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, | |||
576 | else | 659 | else |
577 | *contpc = regs->cp0_epc + 8; | 660 | *contpc = regs->cp0_epc + 8; |
578 | return 1; | 661 | return 1; |
662 | #else | ||
663 | case bc6_op: | ||
664 | /* | ||
665 | * Only valid for MIPS R6 but we can still end up | ||
666 | * here from a broken userland so just tell emulator | ||
667 | * this is not a branch and let it break later on. | ||
668 | */ | ||
669 | if (!cpu_has_mips_r6) | ||
670 | break; | ||
671 | *contpc = regs->cp0_epc + dec_insn.pc_inc + | ||
672 | dec_insn.next_pc_inc; | ||
673 | |||
674 | return 1; | ||
675 | case balc6_op: | ||
676 | if (!cpu_has_mips_r6) | ||
677 | break; | ||
678 | regs->regs[31] = regs->cp0_epc + 4; | ||
679 | *contpc = regs->cp0_epc + dec_insn.pc_inc + | ||
680 | dec_insn.next_pc_inc; | ||
681 | |||
682 | return 1; | ||
683 | case beqzcjic_op: | ||
684 | if (!cpu_has_mips_r6) | ||
685 | break; | ||
686 | *contpc = regs->cp0_epc + dec_insn.pc_inc + | ||
687 | dec_insn.next_pc_inc; | ||
688 | |||
689 | return 1; | ||
690 | case bnezcjialc_op: | ||
691 | if (!cpu_has_mips_r6) | ||
692 | break; | ||
693 | if (!insn.i_format.rs) | ||
694 | regs->regs[31] = regs->cp0_epc + 4; | ||
695 | *contpc = regs->cp0_epc + dec_insn.pc_inc + | ||
696 | dec_insn.next_pc_inc; | ||
697 | |||
698 | return 1; | ||
579 | #endif | 699 | #endif |
580 | case cop0_op: | 700 | case cop0_op: |
581 | case cop1_op: | 701 | case cop1_op: |
702 | /* Need to check for R6 bc1nez and bc1eqz branches */ | ||
703 | if (cpu_has_mips_r6 && | ||
704 | ((insn.i_format.rs == bc1eqz_op) || | ||
705 | (insn.i_format.rs == bc1nez_op))) { | ||
706 | bit = 0; | ||
707 | switch (insn.i_format.rs) { | ||
708 | case bc1eqz_op: | ||
709 | if (get_fpr32(¤t->thread.fpu.fpr[insn.i_format.rt], 0) & 0x1) | ||
710 | bit = 1; | ||
711 | break; | ||
712 | case bc1nez_op: | ||
713 | if (!(get_fpr32(¤t->thread.fpu.fpr[insn.i_format.rt], 0) & 0x1)) | ||
714 | bit = 1; | ||
715 | break; | ||
716 | } | ||
717 | if (bit) | ||
718 | *contpc = regs->cp0_epc + | ||
719 | dec_insn.pc_inc + | ||
720 | (insn.i_format.simmediate << 2); | ||
721 | else | ||
722 | *contpc = regs->cp0_epc + | ||
723 | dec_insn.pc_inc + | ||
724 | dec_insn.next_pc_inc; | ||
725 | |||
726 | return 1; | ||
727 | } | ||
728 | /* R2/R6 compatible cop1 instruction. Fall through */ | ||
582 | case cop2_op: | 729 | case cop2_op: |
583 | case cop1x_op: | 730 | case cop1x_op: |
584 | if (insn.i_format.rs == bc_op) { | 731 | if (insn.i_format.rs == bc_op) { |
@@ -1414,14 +1561,14 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1414 | * achieve full IEEE-754 accuracy - however this emulator does. | 1561 | * achieve full IEEE-754 accuracy - however this emulator does. |
1415 | */ | 1562 | */ |
1416 | case frsqrt_op: | 1563 | case frsqrt_op: |
1417 | if (!cpu_has_mips_4_5_r2) | 1564 | if (!cpu_has_mips_4_5_r2_r6) |
1418 | return SIGILL; | 1565 | return SIGILL; |
1419 | 1566 | ||
1420 | handler.u = fpemu_sp_rsqrt; | 1567 | handler.u = fpemu_sp_rsqrt; |
1421 | goto scopuop; | 1568 | goto scopuop; |
1422 | 1569 | ||
1423 | case frecip_op: | 1570 | case frecip_op: |
1424 | if (!cpu_has_mips_4_5_r2) | 1571 | if (!cpu_has_mips_4_5_r2_r6) |
1425 | return SIGILL; | 1572 | return SIGILL; |
1426 | 1573 | ||
1427 | handler.u = fpemu_sp_recip; | 1574 | handler.u = fpemu_sp_recip; |
@@ -1616,13 +1763,13 @@ copcsr: | |||
1616 | * achieve full IEEE-754 accuracy - however this emulator does. | 1763 | * achieve full IEEE-754 accuracy - however this emulator does. |
1617 | */ | 1764 | */ |
1618 | case frsqrt_op: | 1765 | case frsqrt_op: |
1619 | if (!cpu_has_mips_4_5_r2) | 1766 | if (!cpu_has_mips_4_5_r2_r6) |
1620 | return SIGILL; | 1767 | return SIGILL; |
1621 | 1768 | ||
1622 | handler.u = fpemu_dp_rsqrt; | 1769 | handler.u = fpemu_dp_rsqrt; |
1623 | goto dcopuop; | 1770 | goto dcopuop; |
1624 | case frecip_op: | 1771 | case frecip_op: |
1625 | if (!cpu_has_mips_4_5_r2) | 1772 | if (!cpu_has_mips_4_5_r2_r6) |
1626 | return SIGILL; | 1773 | return SIGILL; |
1627 | 1774 | ||
1628 | handler.u = fpemu_dp_recip; | 1775 | handler.u = fpemu_dp_recip; |