wusb: add the Wireless USB include files.
[linux-2.6/mini2440.git] / arch / mips / kernel / branch.c
blob6b5df8bfab85d0a97b503ad2ca441ff37d4c21d0
1 /*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
6 * Copyright (C) 1996, 97, 2000, 2001 by Ralf Baechle
7 * Copyright (C) 2001 MIPS Technologies, Inc.
8 */
9 #include <linux/kernel.h>
10 #include <linux/sched.h>
11 #include <linux/signal.h>
12 #include <asm/branch.h>
13 #include <asm/cpu.h>
14 #include <asm/cpu-features.h>
15 #include <asm/fpu.h>
16 #include <asm/inst.h>
17 #include <asm/ptrace.h>
18 #include <asm/uaccess.h>
21 * Compute the return address and do emulate branch simulation, if required.
23 int __compute_return_epc(struct pt_regs *regs)
25 unsigned int __user *addr;
26 unsigned int bit, fcr31, dspcontrol;
27 long epc;
28 union mips_instruction insn;
30 epc = regs->cp0_epc;
31 if (epc & 3)
32 goto unaligned;
35 * Read the instruction
37 addr = (unsigned int __user *) epc;
38 if (__get_user(insn.word, addr)) {
39 force_sig(SIGSEGV, current);
40 return -EFAULT;
43 regs->regs[0] = 0;
44 switch (insn.i_format.opcode) {
46 * jr and jalr are in r_format format.
48 case spec_op:
49 switch (insn.r_format.func) {
50 case jalr_op:
51 regs->regs[insn.r_format.rd] = epc + 8;
52 /* Fall through */
53 case jr_op:
54 regs->cp0_epc = regs->regs[insn.r_format.rs];
55 break;
57 break;
60 * This group contains:
61 * bltz_op, bgez_op, bltzl_op, bgezl_op,
62 * bltzal_op, bgezal_op, bltzall_op, bgezall_op.
64 case bcond_op:
65 switch (insn.i_format.rt) {
66 case bltz_op:
67 case bltzl_op:
68 if ((long)regs->regs[insn.i_format.rs] < 0)
69 epc = epc + 4 + (insn.i_format.simmediate << 2);
70 else
71 epc += 8;
72 regs->cp0_epc = epc;
73 break;
75 case bgez_op:
76 case bgezl_op:
77 if ((long)regs->regs[insn.i_format.rs] >= 0)
78 epc = epc + 4 + (insn.i_format.simmediate << 2);
79 else
80 epc += 8;
81 regs->cp0_epc = epc;
82 break;
84 case bltzal_op:
85 case bltzall_op:
86 regs->regs[31] = epc + 8;
87 if ((long)regs->regs[insn.i_format.rs] < 0)
88 epc = epc + 4 + (insn.i_format.simmediate << 2);
89 else
90 epc += 8;
91 regs->cp0_epc = epc;
92 break;
94 case bgezal_op:
95 case bgezall_op:
96 regs->regs[31] = epc + 8;
97 if ((long)regs->regs[insn.i_format.rs] >= 0)
98 epc = epc + 4 + (insn.i_format.simmediate << 2);
99 else
100 epc += 8;
101 regs->cp0_epc = epc;
102 break;
103 case bposge32_op:
104 if (!cpu_has_dsp)
105 goto sigill;
107 dspcontrol = rddsp(0x01);
109 if (dspcontrol >= 32) {
110 epc = epc + 4 + (insn.i_format.simmediate << 2);
111 } else
112 epc += 8;
113 regs->cp0_epc = epc;
114 break;
116 break;
119 * These are unconditional and in j_format.
121 case jal_op:
122 regs->regs[31] = regs->cp0_epc + 8;
123 case j_op:
124 epc += 4;
125 epc >>= 28;
126 epc <<= 28;
127 epc |= (insn.j_format.target << 2);
128 regs->cp0_epc = epc;
129 break;
132 * These are conditional and in i_format.
134 case beq_op:
135 case beql_op:
136 if (regs->regs[insn.i_format.rs] ==
137 regs->regs[insn.i_format.rt])
138 epc = epc + 4 + (insn.i_format.simmediate << 2);
139 else
140 epc += 8;
141 regs->cp0_epc = epc;
142 break;
144 case bne_op:
145 case bnel_op:
146 if (regs->regs[insn.i_format.rs] !=
147 regs->regs[insn.i_format.rt])
148 epc = epc + 4 + (insn.i_format.simmediate << 2);
149 else
150 epc += 8;
151 regs->cp0_epc = epc;
152 break;
154 case blez_op: /* not really i_format */
155 case blezl_op:
156 /* rt field assumed to be zero */
157 if ((long)regs->regs[insn.i_format.rs] <= 0)
158 epc = epc + 4 + (insn.i_format.simmediate << 2);
159 else
160 epc += 8;
161 regs->cp0_epc = epc;
162 break;
164 case bgtz_op:
165 case bgtzl_op:
166 /* rt field assumed to be zero */
167 if ((long)regs->regs[insn.i_format.rs] > 0)
168 epc = epc + 4 + (insn.i_format.simmediate << 2);
169 else
170 epc += 8;
171 regs->cp0_epc = epc;
172 break;
175 * And now the FPA/cp1 branch instructions.
177 case cop1_op:
178 preempt_disable();
179 if (is_fpu_owner())
180 asm volatile("cfc1\t%0,$31" : "=r" (fcr31));
181 else
182 fcr31 = current->thread.fpu.fcr31;
183 preempt_enable();
185 bit = (insn.i_format.rt >> 2);
186 bit += (bit != 0);
187 bit += 23;
188 switch (insn.i_format.rt & 3) {
189 case 0: /* bc1f */
190 case 2: /* bc1fl */
191 if (~fcr31 & (1 << bit))
192 epc = epc + 4 + (insn.i_format.simmediate << 2);
193 else
194 epc += 8;
195 regs->cp0_epc = epc;
196 break;
198 case 1: /* bc1t */
199 case 3: /* bc1tl */
200 if (fcr31 & (1 << bit))
201 epc = epc + 4 + (insn.i_format.simmediate << 2);
202 else
203 epc += 8;
204 regs->cp0_epc = epc;
205 break;
207 break;
210 return 0;
212 unaligned:
213 printk("%s: unaligned epc - sending SIGBUS.\n", current->comm);
214 force_sig(SIGBUS, current);
215 return -EFAULT;
217 sigill:
218 printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm);
219 force_sig(SIGBUS, current);
220 return -EFAULT;