162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
362306a36Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
462306a36Sopenharmony_ci * for more details.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 1996, 1997, 1998, 2001 by Ralf Baechle
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci#ifndef _ASM_BRANCH_H
962306a36Sopenharmony_ci#define _ASM_BRANCH_H
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <asm/cpu-features.h>
1262306a36Sopenharmony_ci#include <asm/mipsregs.h>
1362306a36Sopenharmony_ci#include <asm/ptrace.h>
1462306a36Sopenharmony_ci#include <asm/inst.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ciextern int __isa_exception_epc(struct pt_regs *regs);
1762306a36Sopenharmony_ciextern int __compute_return_epc(struct pt_regs *regs);
1862306a36Sopenharmony_ciextern int __compute_return_epc_for_insn(struct pt_regs *regs,
1962306a36Sopenharmony_ci					 union mips_instruction insn);
2062306a36Sopenharmony_ciextern int __microMIPS_compute_return_epc(struct pt_regs *regs);
2162306a36Sopenharmony_ciextern int __MIPS16e_compute_return_epc(struct pt_regs *regs);
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/*
2462306a36Sopenharmony_ci * microMIPS bitfields
2562306a36Sopenharmony_ci */
2662306a36Sopenharmony_ci#define MM_POOL32A_MINOR_MASK	0x3f
2762306a36Sopenharmony_ci#define MM_POOL32A_MINOR_SHIFT	0x6
2862306a36Sopenharmony_ci#define MM_MIPS32_COND_FC	0x30
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ciint isBranchInstr(struct pt_regs *regs,
3162306a36Sopenharmony_ci	struct mm_decoded_insn dec_insn, unsigned long *contpc);
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ciextern int __mm_isBranchInstr(struct pt_regs *regs,
3462306a36Sopenharmony_ci	struct mm_decoded_insn dec_insn, unsigned long *contpc);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic inline int mm_isBranchInstr(struct pt_regs *regs,
3762306a36Sopenharmony_ci	struct mm_decoded_insn dec_insn, unsigned long *contpc)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	if (!cpu_has_mmips)
4062306a36Sopenharmony_ci		return 0;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	return __mm_isBranchInstr(regs, dec_insn, contpc);
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic inline int delay_slot(struct pt_regs *regs)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	return regs->cp0_cause & CAUSEF_BD;
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic inline void clear_delay_slot(struct pt_regs *regs)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	regs->cp0_cause &= ~CAUSEF_BD;
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic inline void set_delay_slot(struct pt_regs *regs)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	regs->cp0_cause |= CAUSEF_BD;
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic inline unsigned long exception_epc(struct pt_regs *regs)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	if (likely(!delay_slot(regs)))
6362306a36Sopenharmony_ci		return regs->cp0_epc;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	if (get_isa16_mode(regs->cp0_epc))
6662306a36Sopenharmony_ci		return __isa_exception_epc(regs);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	return regs->cp0_epc + 4;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#define BRANCH_LIKELY_TAKEN 0x0001
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic inline int compute_return_epc(struct pt_regs *regs)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	if (get_isa16_mode(regs->cp0_epc)) {
7662306a36Sopenharmony_ci		if (cpu_has_mmips)
7762306a36Sopenharmony_ci			return __microMIPS_compute_return_epc(regs);
7862306a36Sopenharmony_ci		if (cpu_has_mips16)
7962306a36Sopenharmony_ci			return __MIPS16e_compute_return_epc(regs);
8062306a36Sopenharmony_ci	} else if (!delay_slot(regs)) {
8162306a36Sopenharmony_ci		regs->cp0_epc += 4;
8262306a36Sopenharmony_ci		return 0;
8362306a36Sopenharmony_ci	}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	return __compute_return_epc(regs);
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic inline int MIPS16e_compute_return_epc(struct pt_regs *regs,
8962306a36Sopenharmony_ci					     union mips16e_instruction *inst)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	if (likely(!delay_slot(regs))) {
9262306a36Sopenharmony_ci		if (inst->ri.opcode == MIPS16e_extend_op) {
9362306a36Sopenharmony_ci			regs->cp0_epc += 4;
9462306a36Sopenharmony_ci			return 0;
9562306a36Sopenharmony_ci		}
9662306a36Sopenharmony_ci		regs->cp0_epc += 2;
9762306a36Sopenharmony_ci		return 0;
9862306a36Sopenharmony_ci	}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	return __MIPS16e_compute_return_epc(regs);
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci#endif /* _ASM_BRANCH_H */
104