18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
38c2ecf20Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
48c2ecf20Sopenharmony_ci * for more details.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 1996, 1997, 1998, 2001 by Ralf Baechle
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci#ifndef _ASM_BRANCH_H
98c2ecf20Sopenharmony_ci#define _ASM_BRANCH_H
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <asm/cpu-features.h>
128c2ecf20Sopenharmony_ci#include <asm/mipsregs.h>
138c2ecf20Sopenharmony_ci#include <asm/ptrace.h>
148c2ecf20Sopenharmony_ci#include <asm/inst.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ciextern int __isa_exception_epc(struct pt_regs *regs);
178c2ecf20Sopenharmony_ciextern int __compute_return_epc(struct pt_regs *regs);
188c2ecf20Sopenharmony_ciextern int __compute_return_epc_for_insn(struct pt_regs *regs,
198c2ecf20Sopenharmony_ci					 union mips_instruction insn);
208c2ecf20Sopenharmony_ciextern int __microMIPS_compute_return_epc(struct pt_regs *regs);
218c2ecf20Sopenharmony_ciextern int __MIPS16e_compute_return_epc(struct pt_regs *regs);
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/*
248c2ecf20Sopenharmony_ci * microMIPS bitfields
258c2ecf20Sopenharmony_ci */
268c2ecf20Sopenharmony_ci#define MM_POOL32A_MINOR_MASK	0x3f
278c2ecf20Sopenharmony_ci#define MM_POOL32A_MINOR_SHIFT	0x6
288c2ecf20Sopenharmony_ci#define MM_MIPS32_COND_FC	0x30
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ciint isBranchInstr(struct pt_regs *regs,
318c2ecf20Sopenharmony_ci	struct mm_decoded_insn dec_insn, unsigned long *contpc);
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ciextern int __mm_isBranchInstr(struct pt_regs *regs,
348c2ecf20Sopenharmony_ci	struct mm_decoded_insn dec_insn, unsigned long *contpc);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic inline int mm_isBranchInstr(struct pt_regs *regs,
378c2ecf20Sopenharmony_ci	struct mm_decoded_insn dec_insn, unsigned long *contpc)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	if (!cpu_has_mmips)
408c2ecf20Sopenharmony_ci		return 0;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	return __mm_isBranchInstr(regs, dec_insn, contpc);
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic inline int delay_slot(struct pt_regs *regs)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	return regs->cp0_cause & CAUSEF_BD;
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic inline void clear_delay_slot(struct pt_regs *regs)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	regs->cp0_cause &= ~CAUSEF_BD;
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic inline void set_delay_slot(struct pt_regs *regs)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	regs->cp0_cause |= CAUSEF_BD;
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic inline unsigned long exception_epc(struct pt_regs *regs)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	if (likely(!delay_slot(regs)))
638c2ecf20Sopenharmony_ci		return regs->cp0_epc;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	if (get_isa16_mode(regs->cp0_epc))
668c2ecf20Sopenharmony_ci		return __isa_exception_epc(regs);
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	return regs->cp0_epc + 4;
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci#define BRANCH_LIKELY_TAKEN 0x0001
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic inline int compute_return_epc(struct pt_regs *regs)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	if (get_isa16_mode(regs->cp0_epc)) {
768c2ecf20Sopenharmony_ci		if (cpu_has_mmips)
778c2ecf20Sopenharmony_ci			return __microMIPS_compute_return_epc(regs);
788c2ecf20Sopenharmony_ci		if (cpu_has_mips16)
798c2ecf20Sopenharmony_ci			return __MIPS16e_compute_return_epc(regs);
808c2ecf20Sopenharmony_ci	} else if (!delay_slot(regs)) {
818c2ecf20Sopenharmony_ci		regs->cp0_epc += 4;
828c2ecf20Sopenharmony_ci		return 0;
838c2ecf20Sopenharmony_ci	}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	return __compute_return_epc(regs);
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic inline int MIPS16e_compute_return_epc(struct pt_regs *regs,
898c2ecf20Sopenharmony_ci					     union mips16e_instruction *inst)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	if (likely(!delay_slot(regs))) {
928c2ecf20Sopenharmony_ci		if (inst->ri.opcode == MIPS16e_extend_op) {
938c2ecf20Sopenharmony_ci			regs->cp0_epc += 4;
948c2ecf20Sopenharmony_ci			return 0;
958c2ecf20Sopenharmony_ci		}
968c2ecf20Sopenharmony_ci		regs->cp0_epc += 2;
978c2ecf20Sopenharmony_ci		return 0;
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	return __MIPS16e_compute_return_epc(regs);
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci#endif /* _ASM_BRANCH_H */
104