]> git.proxmox.com Git - mirror_qemu.git/blob - target-cris/helper.c
1bdb7e26b7969a88aca7be9a6af7291b60d8b450
[mirror_qemu.git] / target-cris / helper.c
1 /*
2 * CRIS helper routines.
3 *
4 * Copyright (c) 2007 AXIS Communications AB
5 * Written by Edgar E. Iglesias.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "cpu.h"
22 #include "mmu.h"
23 #include "host-utils.h"
24
25
26 //#define CRIS_HELPER_DEBUG
27
28
29 #ifdef CRIS_HELPER_DEBUG
30 #define D(x) x
31 #define D_LOG(...) qemu_log(__VA__ARGS__)
32 #else
33 #define D(x)
34 #define D_LOG(...) do { } while (0)
35 #endif
36
37 #if defined(CONFIG_USER_ONLY)
38
39 void do_interrupt (CPUCRISState *env)
40 {
41 env->exception_index = -1;
42 env->pregs[PR_ERP] = env->pc;
43 }
44
45 int cpu_cris_handle_mmu_fault(CPUCRISState * env, target_ulong address, int rw,
46 int mmu_idx)
47 {
48 env->exception_index = 0xaa;
49 env->pregs[PR_EDA] = address;
50 cpu_dump_state(env, stderr, fprintf, 0);
51 return 1;
52 }
53
54 #else /* !CONFIG_USER_ONLY */
55
56
57 static void cris_shift_ccs(CPUCRISState *env)
58 {
59 uint32_t ccs;
60 /* Apply the ccs shift. */
61 ccs = env->pregs[PR_CCS];
62 ccs = ((ccs & 0xc0000000) | ((ccs << 12) >> 2)) & ~0x3ff;
63 env->pregs[PR_CCS] = ccs;
64 }
65
66 int cpu_cris_handle_mmu_fault (CPUCRISState *env, target_ulong address, int rw,
67 int mmu_idx)
68 {
69 struct cris_mmu_result res;
70 int prot, miss;
71 int r = -1;
72 target_ulong phy;
73
74 D(printf ("%s addr=%x pc=%x rw=%x\n", __func__, address, env->pc, rw));
75 miss = cris_mmu_translate(&res, env, address & TARGET_PAGE_MASK,
76 rw, mmu_idx, 0);
77 if (miss)
78 {
79 if (env->exception_index == EXCP_BUSFAULT)
80 cpu_abort(env,
81 "CRIS: Illegal recursive bus fault."
82 "addr=%x rw=%d\n",
83 address, rw);
84
85 env->pregs[PR_EDA] = address;
86 env->exception_index = EXCP_BUSFAULT;
87 env->fault_vector = res.bf_vec;
88 r = 1;
89 }
90 else
91 {
92 /*
93 * Mask off the cache selection bit. The ETRAX busses do not
94 * see the top bit.
95 */
96 phy = res.phy & ~0x80000000;
97 prot = res.prot;
98 tlb_set_page(env, address & TARGET_PAGE_MASK, phy,
99 prot, mmu_idx, TARGET_PAGE_SIZE);
100 r = 0;
101 }
102 if (r > 0)
103 D_LOG("%s returns %d irqreq=%x addr=%x phy=%x vec=%x pc=%x\n",
104 __func__, r, env->interrupt_request, address, res.phy,
105 res.bf_vec, env->pc);
106 return r;
107 }
108
109 static void do_interruptv10(CPUCRISState *env)
110 {
111 int ex_vec = -1;
112
113 D_LOG( "exception index=%d interrupt_req=%d\n",
114 env->exception_index,
115 env->interrupt_request);
116
117 assert(!(env->pregs[PR_CCS] & PFIX_FLAG));
118 switch (env->exception_index)
119 {
120 case EXCP_BREAK:
121 /* These exceptions are genereated by the core itself.
122 ERP should point to the insn following the brk. */
123 ex_vec = env->trap_vector;
124 env->pregs[PRV10_BRP] = env->pc;
125 break;
126
127 case EXCP_NMI:
128 /* NMI is hardwired to vector zero. */
129 ex_vec = 0;
130 env->pregs[PR_CCS] &= ~M_FLAG_V10;
131 env->pregs[PRV10_BRP] = env->pc;
132 break;
133
134 case EXCP_BUSFAULT:
135 cpu_abort(env, "Unhandled busfault");
136 break;
137
138 default:
139 /* The interrupt controller gives us the vector. */
140 ex_vec = env->interrupt_vector;
141 /* Normal interrupts are taken between
142 TB's. env->pc is valid here. */
143 env->pregs[PR_ERP] = env->pc;
144 break;
145 }
146
147 if (env->pregs[PR_CCS] & U_FLAG) {
148 /* Swap stack pointers. */
149 env->pregs[PR_USP] = env->regs[R_SP];
150 env->regs[R_SP] = env->ksp;
151 }
152
153 /* Now that we are in kernel mode, load the handlers address. */
154 env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4);
155 env->locked_irq = 1;
156 env->pregs[PR_CCS] |= F_FLAG_V10; /* set F. */
157
158 qemu_log_mask(CPU_LOG_INT, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n",
159 __func__, env->pc, ex_vec,
160 env->pregs[PR_CCS],
161 env->pregs[PR_PID],
162 env->pregs[PR_ERP]);
163 }
164
165 void do_interrupt(CPUCRISState *env)
166 {
167 int ex_vec = -1;
168
169 if (env->pregs[PR_VR] < 32)
170 return do_interruptv10(env);
171
172 D_LOG( "exception index=%d interrupt_req=%d\n",
173 env->exception_index,
174 env->interrupt_request);
175
176 switch (env->exception_index)
177 {
178 case EXCP_BREAK:
179 /* These exceptions are genereated by the core itself.
180 ERP should point to the insn following the brk. */
181 ex_vec = env->trap_vector;
182 env->pregs[PR_ERP] = env->pc;
183 break;
184
185 case EXCP_NMI:
186 /* NMI is hardwired to vector zero. */
187 ex_vec = 0;
188 env->pregs[PR_CCS] &= ~M_FLAG_V32;
189 env->pregs[PR_NRP] = env->pc;
190 break;
191
192 case EXCP_BUSFAULT:
193 ex_vec = env->fault_vector;
194 env->pregs[PR_ERP] = env->pc;
195 break;
196
197 default:
198 /* The interrupt controller gives us the vector. */
199 ex_vec = env->interrupt_vector;
200 /* Normal interrupts are taken between
201 TB's. env->pc is valid here. */
202 env->pregs[PR_ERP] = env->pc;
203 break;
204 }
205
206 /* Fill in the IDX field. */
207 env->pregs[PR_EXS] = (ex_vec & 0xff) << 8;
208
209 if (env->dslot) {
210 D_LOG("excp isr=%x PC=%x ds=%d SP=%x"
211 " ERP=%x pid=%x ccs=%x cc=%d %x\n",
212 ex_vec, env->pc, env->dslot,
213 env->regs[R_SP],
214 env->pregs[PR_ERP], env->pregs[PR_PID],
215 env->pregs[PR_CCS],
216 env->cc_op, env->cc_mask);
217 /* We loose the btarget, btaken state here so rexec the
218 branch. */
219 env->pregs[PR_ERP] -= env->dslot;
220 /* Exception starts with dslot cleared. */
221 env->dslot = 0;
222 }
223
224 if (env->pregs[PR_CCS] & U_FLAG) {
225 /* Swap stack pointers. */
226 env->pregs[PR_USP] = env->regs[R_SP];
227 env->regs[R_SP] = env->ksp;
228 }
229
230 /* Apply the CRIS CCS shift. Clears U if set. */
231 cris_shift_ccs(env);
232
233 /* Now that we are in kernel mode, load the handlers address.
234 This load may not fault, real hw leaves that behaviour as
235 undefined. */
236 env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4);
237
238 /* Clear the excption_index to avoid spurios hw_aborts for recursive
239 bus faults. */
240 env->exception_index = -1;
241
242 D_LOG("%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n",
243 __func__, env->pc, ex_vec,
244 env->pregs[PR_CCS],
245 env->pregs[PR_PID],
246 env->pregs[PR_ERP]);
247 }
248
249 target_phys_addr_t cpu_get_phys_page_debug(CPUCRISState * env, target_ulong addr)
250 {
251 uint32_t phy = addr;
252 struct cris_mmu_result res;
253 int miss;
254
255 miss = cris_mmu_translate(&res, env, addr, 0, 0, 1);
256 /* If D TLB misses, try I TLB. */
257 if (miss) {
258 miss = cris_mmu_translate(&res, env, addr, 2, 0, 1);
259 }
260
261 if (!miss)
262 phy = res.phy;
263 D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy));
264 return phy;
265 }
266 #endif