diff options
author | Markos Chandras <markos.chandras@imgtec.com> | 2014-11-26 14:05:09 +0100 |
---|---|---|
committer | Markos Chandras <markos.chandras@imgtec.com> | 2015-02-17 16:37:33 +0100 |
commit | f1b44067c19258b7614e3cd09dfe8d8e12ff5895 (patch) | |
tree | eb23ac6695fecc5d565e3c21106ead25d9e672ea /arch/mips/kernel/branch.c | |
parent | MIPS: Emulate the new MIPS R6 B{L,G}Ε{Z,}{AL,}C instructions (diff) | |
download | linux-f1b44067c19258b7614e3cd09dfe8d8e12ff5895.tar.xz linux-f1b44067c19258b7614e3cd09dfe8d8e12ff5895.zip |
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/mips/kernel/branch.c')
-rw-r--r-- | arch/mips/kernel/branch.c | 22 |
1 files changed, 22 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, if (NO_R6EMU) goto sigill_r6; case bgtz_op: + /* + * Compact branches for R6 for the + * bgtz and bgtzl opcodes. + * BGTZ | rs = 0 | rt != 0 == BGTZALC + * BGTZ | rs = rt != 0 == BLTZALC + * BGTZ | rs != 0 | rt != 0 == BLTUC + * BGTZL | rs = 0 | rt != 0 == BGTZC + * BGTZL | rs = rt != 0 == BLTZC + * BGTZL | rs != 0 | rt != 0 == BLTC + * + * *ZALC varint for BGTZ &&& rt != 0 + * For real GTZ{,L}, rt is always 0. + */ + if (cpu_has_mips_r6 && insn.i_format.rt) { + if ((insn.i_format.opcode == blez_op) && + ((!insn.i_format.rs && insn.i_format.rt) || + (insn.i_format.rs == insn.i_format.rt))) + regs->regs[31] = epc + 4; + regs->cp0_epc += 8; + break; + } + /* rt field assumed to be zero */ if ((long)regs->regs[insn.i_format.rs] > 0) { epc = epc + 4 + (insn.i_format.simmediate << 2); |