aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/math-emu/cp1emu.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/math-emu/cp1emu.c')
-rw-r--r--arch/mips/math-emu/cp1emu.c169
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 */
71static const unsigned int fpucondbit[8] = { 72const 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(&current->thread.fpu.fpr[insn.i_format.rt], 0) & 0x1)
710 bit = 1;
711 break;
712 case bc1nez_op:
713 if (!(get_fpr32(&current->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;