xref: /openbmc/linux/arch/mips/include/asm/branch.h (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
1384740dcSRalf Baechle /*
2384740dcSRalf Baechle  * This file is subject to the terms and conditions of the GNU General Public
3384740dcSRalf Baechle  * License.  See the file "COPYING" in the main directory of this archive
4384740dcSRalf Baechle  * for more details.
5384740dcSRalf Baechle  *
6384740dcSRalf Baechle  * Copyright (C) 1996, 1997, 1998, 2001 by Ralf Baechle
7384740dcSRalf Baechle  */
8384740dcSRalf Baechle #ifndef _ASM_BRANCH_H
9384740dcSRalf Baechle #define _ASM_BRANCH_H
10384740dcSRalf Baechle 
115160d45dSRalf Baechle #include <asm/cpu-features.h>
125160d45dSRalf Baechle #include <asm/mipsregs.h>
13384740dcSRalf Baechle #include <asm/ptrace.h>
14d8d4e3aeSManeesh Soni #include <asm/inst.h>
15384740dcSRalf Baechle 
16fb6883e5SLeonid Yegoshin extern int __isa_exception_epc(struct pt_regs *regs);
17fb6883e5SLeonid Yegoshin extern int __compute_return_epc(struct pt_regs *regs);
18fb6883e5SLeonid Yegoshin extern int __compute_return_epc_for_insn(struct pt_regs *regs,
19fb6883e5SLeonid Yegoshin 					 union mips_instruction insn);
20fb6883e5SLeonid Yegoshin extern int __microMIPS_compute_return_epc(struct pt_regs *regs);
218508488fSSteven J. Hill extern int __MIPS16e_compute_return_epc(struct pt_regs *regs);
22fb6883e5SLeonid Yegoshin 
2376fbfc31SRalf Baechle /*
2476fbfc31SRalf Baechle  * microMIPS bitfields
2576fbfc31SRalf Baechle  */
2676fbfc31SRalf Baechle #define MM_POOL32A_MINOR_MASK	0x3f
2776fbfc31SRalf Baechle #define MM_POOL32A_MINOR_SHIFT	0x6
2876fbfc31SRalf Baechle #define MM_MIPS32_COND_FC	0x30
2976fbfc31SRalf Baechle 
30*c05b5940SHuacai Chen int isBranchInstr(struct pt_regs *regs,
31*c05b5940SHuacai Chen 	struct mm_decoded_insn dec_insn, unsigned long *contpc);
32*c05b5940SHuacai Chen 
3376fbfc31SRalf Baechle extern int __mm_isBranchInstr(struct pt_regs *regs,
3476fbfc31SRalf Baechle 	struct mm_decoded_insn dec_insn, unsigned long *contpc);
3576fbfc31SRalf Baechle 
mm_isBranchInstr(struct pt_regs * regs,struct mm_decoded_insn dec_insn,unsigned long * contpc)3676fbfc31SRalf Baechle static inline int mm_isBranchInstr(struct pt_regs *regs,
3776fbfc31SRalf Baechle 	struct mm_decoded_insn dec_insn, unsigned long *contpc)
3876fbfc31SRalf Baechle {
3976fbfc31SRalf Baechle 	if (!cpu_has_mmips)
4076fbfc31SRalf Baechle 		return 0;
4176fbfc31SRalf Baechle 
4276fbfc31SRalf Baechle 	return __mm_isBranchInstr(regs, dec_insn, contpc);
4376fbfc31SRalf Baechle }
44fb6883e5SLeonid Yegoshin 
delay_slot(struct pt_regs * regs)45384740dcSRalf Baechle static inline int delay_slot(struct pt_regs *regs)
46384740dcSRalf Baechle {
47384740dcSRalf Baechle 	return regs->cp0_cause & CAUSEF_BD;
48384740dcSRalf Baechle }
49384740dcSRalf Baechle 
clear_delay_slot(struct pt_regs * regs)505a7ebbf8SRalf Baechle static inline void clear_delay_slot(struct pt_regs *regs)
515a7ebbf8SRalf Baechle {
525a7ebbf8SRalf Baechle 	regs->cp0_cause &= ~CAUSEF_BD;
535a7ebbf8SRalf Baechle }
545a7ebbf8SRalf Baechle 
set_delay_slot(struct pt_regs * regs)555a7ebbf8SRalf Baechle static inline void set_delay_slot(struct pt_regs *regs)
565a7ebbf8SRalf Baechle {
575a7ebbf8SRalf Baechle 	regs->cp0_cause |= CAUSEF_BD;
585a7ebbf8SRalf Baechle }
595a7ebbf8SRalf Baechle 
exception_epc(struct pt_regs * regs)60384740dcSRalf Baechle static inline unsigned long exception_epc(struct pt_regs *regs)
61384740dcSRalf Baechle {
62fb6883e5SLeonid Yegoshin 	if (likely(!delay_slot(regs)))
63384740dcSRalf Baechle 		return regs->cp0_epc;
64384740dcSRalf Baechle 
65fb6883e5SLeonid Yegoshin 	if (get_isa16_mode(regs->cp0_epc))
66fb6883e5SLeonid Yegoshin 		return __isa_exception_epc(regs);
67fb6883e5SLeonid Yegoshin 
68384740dcSRalf Baechle 	return regs->cp0_epc + 4;
69384740dcSRalf Baechle }
70384740dcSRalf Baechle 
71d8d4e3aeSManeesh Soni #define BRANCH_LIKELY_TAKEN 0x0001
72d8d4e3aeSManeesh Soni 
compute_return_epc(struct pt_regs * regs)73384740dcSRalf Baechle static inline int compute_return_epc(struct pt_regs *regs)
74384740dcSRalf Baechle {
75fb6883e5SLeonid Yegoshin 	if (get_isa16_mode(regs->cp0_epc)) {
76fb6883e5SLeonid Yegoshin 		if (cpu_has_mmips)
77fb6883e5SLeonid Yegoshin 			return __microMIPS_compute_return_epc(regs);
788508488fSSteven J. Hill 		if (cpu_has_mips16)
798508488fSSteven J. Hill 			return __MIPS16e_compute_return_epc(regs);
8011a3799dSMaciej W. Rozycki 	} else if (!delay_slot(regs)) {
81384740dcSRalf Baechle 		regs->cp0_epc += 4;
82384740dcSRalf Baechle 		return 0;
83384740dcSRalf Baechle 	}
84384740dcSRalf Baechle 
85384740dcSRalf Baechle 	return __compute_return_epc(regs);
86384740dcSRalf Baechle }
87384740dcSRalf Baechle 
MIPS16e_compute_return_epc(struct pt_regs * regs,union mips16e_instruction * inst)888508488fSSteven J. Hill static inline int MIPS16e_compute_return_epc(struct pt_regs *regs,
898508488fSSteven J. Hill 					     union mips16e_instruction *inst)
908508488fSSteven J. Hill {
918508488fSSteven J. Hill 	if (likely(!delay_slot(regs))) {
928508488fSSteven J. Hill 		if (inst->ri.opcode == MIPS16e_extend_op) {
938508488fSSteven J. Hill 			regs->cp0_epc += 4;
948508488fSSteven J. Hill 			return 0;
958508488fSSteven J. Hill 		}
968508488fSSteven J. Hill 		regs->cp0_epc += 2;
978508488fSSteven J. Hill 		return 0;
988508488fSSteven J. Hill 	}
998508488fSSteven J. Hill 
1008508488fSSteven J. Hill 	return __MIPS16e_compute_return_epc(regs);
1018508488fSSteven J. Hill }
1028508488fSSteven J. Hill 
103384740dcSRalf Baechle #endif /* _ASM_BRANCH_H */
104