OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [mips/] [kernel/] [branch.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
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.
5
 *
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>
19
 
20
/*
21
 * Compute the return address and do emulate branch simulation, if required.
22
 */
23
int __compute_return_epc(struct pt_regs *regs)
24
{
25
        unsigned int __user *addr;
26
        unsigned int bit, fcr31, dspcontrol;
27
        long epc;
28
        union mips_instruction insn;
29
 
30
        epc = regs->cp0_epc;
31
        if (epc & 3)
32
                goto unaligned;
33
 
34
        /*
35
         * Read the instruction
36
         */
37
        addr = (unsigned int __user *) epc;
38
        if (__get_user(insn.word, addr)) {
39
                force_sig(SIGSEGV, current);
40
                return -EFAULT;
41
        }
42
 
43
        regs->regs[0] = 0;
44
        switch (insn.i_format.opcode) {
45
        /*
46
         * jr and jalr are in r_format format.
47
         */
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;
56
                }
57
                break;
58
 
59
        /*
60
         * This group contains:
61
         * bltz_op, bgez_op, bltzl_op, bgezl_op,
62
         * bltzal_op, bgezal_op, bltzall_op, bgezall_op.
63
         */
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;
74
 
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;
83
 
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;
93
 
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;
106
 
107
                        dspcontrol = rddsp(0x01);
108
 
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;
115
                }
116
                break;
117
 
118
        /*
119
         * These are unconditional and in j_format.
120
         */
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;
130
 
131
        /*
132
         * These are conditional and in i_format.
133
         */
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;
143
 
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;
153
 
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;
163
 
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;
173
 
174
        /*
175
         * And now the FPA/cp1 branch instructions.
176
         */
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();
184
 
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;
197
 
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;
206
                }
207
                break;
208
        }
209
 
210
        return 0;
211
 
212
unaligned:
213
        printk("%s: unaligned epc - sending SIGBUS.\n", current->comm);
214
        force_sig(SIGBUS, current);
215
        return -EFAULT;
216
 
217
sigill:
218
        printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm);
219
        force_sig(SIGBUS, current);
220
        return -EFAULT;
221
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.