aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMarkos Chandras <markos.chandras@imgtec.com>2014-11-26 08:05:09 -0500
committerMarkos Chandras <markos.chandras@imgtec.com>2015-02-17 10:37:33 -0500
commitf1b44067c19258b7614e3cd09dfe8d8e12ff5895 (patch)
treeeb23ac6695fecc5d565e3c21106ead25d9e672ea /arch
parenta8ff66f52d3f17b5ae793955270675c197f73d6c (diff)
MIPS: Emulate the new MIPS R6 B{L,G}T{Z,}{AL,}C instructions
MIPS R6 added the following four instructions which share the BGTZ and BGTZL opcode: BLTZALC: Compact branch-and-link if GPR rt is < to zero BGTZALC: Compact branch-and-link if GPR rt is > to zero BLTZL : Compact branch if GPR rt is < to zero BGTZL : Compact branch if GPR rt is > to zero BLTC : Compact branch if GPR rs is less than GPR rt BLTUC : Similar to BLTC but unsigned Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/mips/kernel/branch.c22
-rw-r--r--arch/mips/math-emu/cp1emu.c25
2 files changed, 47 insertions, 0 deletions
diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c
index a1fd8786d716..cd880b91f092 100644
--- a/arch/mips/kernel/branch.c
+++ b/arch/mips/kernel/branch.c
@@ -635,6 +635,28 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
635 if (NO_R6EMU) 635 if (NO_R6EMU)
636 goto sigill_r6; 636 goto sigill_r6;
637 case bgtz_op: 637 case bgtz_op:
638 /*
639 * Compact branches for R6 for the
640 * bgtz and bgtzl opcodes.
641 * BGTZ | rs = 0 | rt != 0 == BGTZALC
642 * BGTZ | rs = rt != 0 == BLTZALC
643 * BGTZ | rs != 0 | rt != 0 == BLTUC
644 * BGTZL | rs = 0 | rt != 0 == BGTZC
645 * BGTZL | rs = rt != 0 == BLTZC
646 * BGTZL | rs != 0 | rt != 0 == BLTC
647 *
648 * *ZALC varint for BGTZ &&& rt != 0
649 * For real GTZ{,L}, rt is always 0.
650 */
651 if (cpu_has_mips_r6 && insn.i_format.rt) {
652 if ((insn.i_format.opcode == blez_op) &&
653 ((!insn.i_format.rs && insn.i_format.rt) ||
654 (insn.i_format.rs == insn.i_format.rt)))
655 regs->regs[31] = epc + 4;
656 regs->cp0_epc += 8;
657 break;
658 }
659
638 /* rt field assumed to be zero */ 660 /* rt field assumed to be zero */
639 if ((long)regs->regs[insn.i_format.rs] > 0) { 661 if ((long)regs->regs[insn.i_format.rs] > 0) {
640 epc = epc + 4 + (insn.i_format.simmediate << 2); 662 epc = epc + 4 + (insn.i_format.simmediate << 2);
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
index c770617dc340..d6d67e2a0434 100644
--- a/arch/mips/math-emu/cp1emu.c
+++ b/arch/mips/math-emu/cp1emu.c
@@ -589,6 +589,31 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
589 if (NO_R6EMU) 589 if (NO_R6EMU)
590 break; 590 break;
591 case bgtz_op: 591 case bgtz_op:
592 /*
593 * Compact branches for R6 for the
594 * bgtz and bgtzl opcodes.
595 * BGTZ | rs = 0 | rt != 0 == BGTZALC
596 * BGTZ | rs = rt != 0 == BLTZALC
597 * BGTZ | rs != 0 | rt != 0 == BLTUC
598 * BGTZL | rs = 0 | rt != 0 == BGTZC
599 * BGTZL | rs = rt != 0 == BLTZC
600 * BGTZL | rs != 0 | rt != 0 == BLTC
601 *
602 * *ZALC varint for BGTZ &&& rt != 0
603 * For real GTZ{,L}, rt is always 0.
604 */
605 if (cpu_has_mips_r6 && insn.i_format.rt) {
606 if ((insn.i_format.opcode == blez_op) &&
607 ((!insn.i_format.rs && insn.i_format.rt) ||
608 (insn.i_format.rs == insn.i_format.rt)))
609 regs->regs[31] = regs->cp0_epc +
610 dec_insn.pc_inc;
611 *contpc = regs->cp0_epc + dec_insn.pc_inc +
612 dec_insn.next_pc_inc;
613
614 return 1;
615 }
616
592 if ((long)regs->regs[insn.i_format.rs] > 0) 617 if ((long)regs->regs[insn.i_format.rs] > 0)
593 *contpc = regs->cp0_epc + 618 *contpc = regs->cp0_epc +
594 dec_insn.pc_inc + 619 dec_insn.pc_inc +