]>
Commit | Line | Data |
---|---|---|
81fdc5f8 TS |
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 | |
8167ee88 | 18 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
81fdc5f8 TS |
19 | */ |
20 | ||
23b0d7df | 21 | #include "qemu/osdep.h" |
81fdc5f8 TS |
22 | #include "cpu.h" |
23 | #include "mmu.h" | |
1de7afc9 | 24 | #include "qemu/host-utils.h" |
f08b6170 | 25 | #include "exec/cpu_ldst.h" |
81fdc5f8 | 26 | |
d12d51d5 AL |
27 | |
28 | //#define CRIS_HELPER_DEBUG | |
29 | ||
30 | ||
31 | #ifdef CRIS_HELPER_DEBUG | |
32 | #define D(x) x | |
3f668b6c | 33 | #define D_LOG(...) qemu_log(__VA_ARGS__) |
d12d51d5 | 34 | #else |
e62b5b13 | 35 | #define D(x) |
d12d51d5 AL |
36 | #define D_LOG(...) do { } while (0) |
37 | #endif | |
e62b5b13 | 38 | |
81fdc5f8 TS |
39 | #if defined(CONFIG_USER_ONLY) |
40 | ||
97a8ea5a | 41 | void cris_cpu_do_interrupt(CPUState *cs) |
81fdc5f8 | 42 | { |
97a8ea5a AF |
43 | CRISCPU *cpu = CRIS_CPU(cs); |
44 | CPUCRISState *env = &cpu->env; | |
45 | ||
27103424 | 46 | cs->exception_index = -1; |
21317bc2 | 47 | env->pregs[PR_ERP] = env->pc; |
81fdc5f8 TS |
48 | } |
49 | ||
b21bfeea AF |
50 | void crisv10_cpu_do_interrupt(CPUState *cs) |
51 | { | |
52 | cris_cpu_do_interrupt(cs); | |
53 | } | |
54 | ||
7510454e | 55 | int cris_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, |
97b348e7 | 56 | int mmu_idx) |
81fdc5f8 | 57 | { |
7510454e | 58 | CRISCPU *cpu = CRIS_CPU(cs); |
878096ee | 59 | |
27103424 | 60 | cs->exception_index = 0xaa; |
7510454e AF |
61 | cpu->env.pregs[PR_EDA] = address; |
62 | cpu_dump_state(cs, stderr, fprintf, 0); | |
21317bc2 | 63 | return 1; |
81fdc5f8 TS |
64 | } |
65 | ||
81fdc5f8 TS |
66 | #else /* !CONFIG_USER_ONLY */ |
67 | ||
e62b5b13 | 68 | |
a1170bfd | 69 | static void cris_shift_ccs(CPUCRISState *env) |
e62b5b13 | 70 | { |
21317bc2 AF |
71 | uint32_t ccs; |
72 | /* Apply the ccs shift. */ | |
73 | ccs = env->pregs[PR_CCS]; | |
74 | ccs = ((ccs & 0xc0000000) | ((ccs << 12) >> 2)) & ~0x3ff; | |
75 | env->pregs[PR_CCS] = ccs; | |
e62b5b13 EI |
76 | } |
77 | ||
7510454e | 78 | int cris_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, |
21317bc2 | 79 | int mmu_idx) |
81fdc5f8 | 80 | { |
7510454e AF |
81 | CRISCPU *cpu = CRIS_CPU(cs); |
82 | CPUCRISState *env = &cpu->env; | |
21317bc2 AF |
83 | struct cris_mmu_result res; |
84 | int prot, miss; | |
85 | int r = -1; | |
86 | target_ulong phy; | |
87 | ||
339aaf5b AP |
88 | qemu_log_mask(CPU_LOG_MMU, "%s addr=%" VADDR_PRIx " pc=%x rw=%x\n", |
89 | __func__, address, env->pc, rw); | |
21317bc2 AF |
90 | miss = cris_mmu_translate(&res, env, address & TARGET_PAGE_MASK, |
91 | rw, mmu_idx, 0); | |
92 | if (miss) { | |
27103424 | 93 | if (cs->exception_index == EXCP_BUSFAULT) { |
a47dddd7 | 94 | cpu_abort(cs, |
21317bc2 | 95 | "CRIS: Illegal recursive bus fault." |
7510454e | 96 | "addr=%" VADDR_PRIx " rw=%d\n", |
21317bc2 AF |
97 | address, rw); |
98 | } | |
99 | ||
100 | env->pregs[PR_EDA] = address; | |
27103424 | 101 | cs->exception_index = EXCP_BUSFAULT; |
21317bc2 AF |
102 | env->fault_vector = res.bf_vec; |
103 | r = 1; | |
104 | } else { | |
105 | /* | |
106 | * Mask off the cache selection bit. The ETRAX busses do not | |
107 | * see the top bit. | |
108 | */ | |
109 | phy = res.phy & ~0x80000000; | |
110 | prot = res.prot; | |
0c591eb0 | 111 | tlb_set_page(cs, address & TARGET_PAGE_MASK, phy, |
21317bc2 AF |
112 | prot, mmu_idx, TARGET_PAGE_SIZE); |
113 | r = 0; | |
114 | } | |
115 | if (r > 0) { | |
339aaf5b AP |
116 | qemu_log_mask(CPU_LOG_MMU, |
117 | "%s returns %d irqreq=%x addr=%" VADDR_PRIx " phy=%x vec=%x" | |
118 | " pc=%x\n", __func__, r, cs->interrupt_request, address, | |
119 | res.phy, res.bf_vec, env->pc); | |
21317bc2 AF |
120 | } |
121 | return r; | |
81fdc5f8 TS |
122 | } |
123 | ||
b21bfeea | 124 | void crisv10_cpu_do_interrupt(CPUState *cs) |
7a977356 | 125 | { |
b21bfeea AF |
126 | CRISCPU *cpu = CRIS_CPU(cs); |
127 | CPUCRISState *env = &cpu->env; | |
21317bc2 AF |
128 | int ex_vec = -1; |
129 | ||
130 | D_LOG("exception index=%d interrupt_req=%d\n", | |
27103424 | 131 | cs->exception_index, |
259186a7 | 132 | cs->interrupt_request); |
21317bc2 | 133 | |
d66433ff EI |
134 | if (env->dslot) { |
135 | /* CRISv10 never takes interrupts while in a delay-slot. */ | |
a47dddd7 | 136 | cpu_abort(cs, "CRIS: Interrupt on delay-slot\n"); |
d66433ff EI |
137 | } |
138 | ||
21317bc2 | 139 | assert(!(env->pregs[PR_CCS] & PFIX_FLAG)); |
27103424 | 140 | switch (cs->exception_index) { |
21317bc2 AF |
141 | case EXCP_BREAK: |
142 | /* These exceptions are genereated by the core itself. | |
143 | ERP should point to the insn following the brk. */ | |
144 | ex_vec = env->trap_vector; | |
145 | env->pregs[PRV10_BRP] = env->pc; | |
146 | break; | |
147 | ||
148 | case EXCP_NMI: | |
149 | /* NMI is hardwired to vector zero. */ | |
150 | ex_vec = 0; | |
151 | env->pregs[PR_CCS] &= ~M_FLAG_V10; | |
152 | env->pregs[PRV10_BRP] = env->pc; | |
153 | break; | |
154 | ||
155 | case EXCP_BUSFAULT: | |
a47dddd7 | 156 | cpu_abort(cs, "Unhandled busfault"); |
21317bc2 AF |
157 | break; |
158 | ||
159 | default: | |
160 | /* The interrupt controller gives us the vector. */ | |
161 | ex_vec = env->interrupt_vector; | |
162 | /* Normal interrupts are taken between | |
163 | TB's. env->pc is valid here. */ | |
164 | env->pregs[PR_ERP] = env->pc; | |
165 | break; | |
166 | } | |
167 | ||
168 | if (env->pregs[PR_CCS] & U_FLAG) { | |
169 | /* Swap stack pointers. */ | |
170 | env->pregs[PR_USP] = env->regs[R_SP]; | |
171 | env->regs[R_SP] = env->ksp; | |
172 | } | |
173 | ||
174 | /* Now that we are in kernel mode, load the handlers address. */ | |
175 | env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4); | |
176 | env->locked_irq = 1; | |
177 | env->pregs[PR_CCS] |= F_FLAG_V10; /* set F. */ | |
178 | ||
179 | qemu_log_mask(CPU_LOG_INT, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n", | |
180 | __func__, env->pc, ex_vec, | |
181 | env->pregs[PR_CCS], | |
182 | env->pregs[PR_PID], | |
183 | env->pregs[PR_ERP]); | |
7a977356 EI |
184 | } |
185 | ||
97a8ea5a | 186 | void cris_cpu_do_interrupt(CPUState *cs) |
81fdc5f8 | 187 | { |
97a8ea5a AF |
188 | CRISCPU *cpu = CRIS_CPU(cs); |
189 | CPUCRISState *env = &cpu->env; | |
21317bc2 AF |
190 | int ex_vec = -1; |
191 | ||
21317bc2 | 192 | D_LOG("exception index=%d interrupt_req=%d\n", |
27103424 | 193 | cs->exception_index, |
259186a7 | 194 | cs->interrupt_request); |
21317bc2 | 195 | |
27103424 | 196 | switch (cs->exception_index) { |
21317bc2 AF |
197 | case EXCP_BREAK: |
198 | /* These exceptions are genereated by the core itself. | |
199 | ERP should point to the insn following the brk. */ | |
200 | ex_vec = env->trap_vector; | |
201 | env->pregs[PR_ERP] = env->pc; | |
202 | break; | |
203 | ||
204 | case EXCP_NMI: | |
205 | /* NMI is hardwired to vector zero. */ | |
206 | ex_vec = 0; | |
207 | env->pregs[PR_CCS] &= ~M_FLAG_V32; | |
208 | env->pregs[PR_NRP] = env->pc; | |
209 | break; | |
210 | ||
211 | case EXCP_BUSFAULT: | |
212 | ex_vec = env->fault_vector; | |
213 | env->pregs[PR_ERP] = env->pc; | |
214 | break; | |
215 | ||
216 | default: | |
217 | /* The interrupt controller gives us the vector. */ | |
218 | ex_vec = env->interrupt_vector; | |
219 | /* Normal interrupts are taken between | |
220 | TB's. env->pc is valid here. */ | |
221 | env->pregs[PR_ERP] = env->pc; | |
222 | break; | |
223 | } | |
224 | ||
225 | /* Fill in the IDX field. */ | |
226 | env->pregs[PR_EXS] = (ex_vec & 0xff) << 8; | |
227 | ||
228 | if (env->dslot) { | |
229 | D_LOG("excp isr=%x PC=%x ds=%d SP=%x" | |
230 | " ERP=%x pid=%x ccs=%x cc=%d %x\n", | |
231 | ex_vec, env->pc, env->dslot, | |
232 | env->regs[R_SP], | |
233 | env->pregs[PR_ERP], env->pregs[PR_PID], | |
234 | env->pregs[PR_CCS], | |
235 | env->cc_op, env->cc_mask); | |
236 | /* We loose the btarget, btaken state here so rexec the | |
237 | branch. */ | |
238 | env->pregs[PR_ERP] -= env->dslot; | |
239 | /* Exception starts with dslot cleared. */ | |
240 | env->dslot = 0; | |
241 | } | |
b41f7df0 | 242 | |
21317bc2 AF |
243 | if (env->pregs[PR_CCS] & U_FLAG) { |
244 | /* Swap stack pointers. */ | |
245 | env->pregs[PR_USP] = env->regs[R_SP]; | |
246 | env->regs[R_SP] = env->ksp; | |
247 | } | |
248 | ||
249 | /* Apply the CRIS CCS shift. Clears U if set. */ | |
250 | cris_shift_ccs(env); | |
251 | ||
252 | /* Now that we are in kernel mode, load the handlers address. | |
253 | This load may not fault, real hw leaves that behaviour as | |
254 | undefined. */ | |
255 | env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4); | |
256 | ||
257 | /* Clear the excption_index to avoid spurios hw_aborts for recursive | |
258 | bus faults. */ | |
27103424 | 259 | cs->exception_index = -1; |
21317bc2 AF |
260 | |
261 | D_LOG("%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n", | |
262 | __func__, env->pc, ex_vec, | |
263 | env->pregs[PR_CCS], | |
264 | env->pregs[PR_PID], | |
265 | env->pregs[PR_ERP]); | |
81fdc5f8 TS |
266 | } |
267 | ||
00b941e5 | 268 | hwaddr cris_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) |
81fdc5f8 | 269 | { |
00b941e5 | 270 | CRISCPU *cpu = CRIS_CPU(cs); |
21317bc2 AF |
271 | uint32_t phy = addr; |
272 | struct cris_mmu_result res; | |
273 | int miss; | |
274 | ||
00b941e5 | 275 | miss = cris_mmu_translate(&res, &cpu->env, addr, 0, 0, 1); |
21317bc2 AF |
276 | /* If D TLB misses, try I TLB. */ |
277 | if (miss) { | |
00b941e5 | 278 | miss = cris_mmu_translate(&res, &cpu->env, addr, 2, 0, 1); |
21317bc2 AF |
279 | } |
280 | ||
281 | if (!miss) { | |
282 | phy = res.phy; | |
283 | } | |
284 | D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy)); | |
285 | return phy; | |
81fdc5f8 TS |
286 | } |
287 | #endif | |
5a1f7f44 RH |
288 | |
289 | bool cris_cpu_exec_interrupt(CPUState *cs, int interrupt_request) | |
290 | { | |
291 | CPUClass *cc = CPU_GET_CLASS(cs); | |
292 | CRISCPU *cpu = CRIS_CPU(cs); | |
293 | CPUCRISState *env = &cpu->env; | |
294 | bool ret = false; | |
295 | ||
296 | if (interrupt_request & CPU_INTERRUPT_HARD | |
297 | && (env->pregs[PR_CCS] & I_FLAG) | |
298 | && !env->locked_irq) { | |
299 | cs->exception_index = EXCP_IRQ; | |
300 | cc->do_interrupt(cs); | |
301 | ret = true; | |
302 | } | |
303 | if (interrupt_request & CPU_INTERRUPT_NMI) { | |
304 | unsigned int m_flag_archval; | |
305 | if (env->pregs[PR_VR] < 32) { | |
306 | m_flag_archval = M_FLAG_V10; | |
307 | } else { | |
308 | m_flag_archval = M_FLAG_V32; | |
309 | } | |
310 | if ((env->pregs[PR_CCS] & m_flag_archval)) { | |
311 | cs->exception_index = EXCP_NMI; | |
312 | cc->do_interrupt(cs); | |
313 | ret = true; | |
314 | } | |
315 | } | |
316 | ||
317 | return ret; | |
318 | } |