cpu: Move halted and interrupt_request fields to CPUState
[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 "qemu/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 D(CPUState *cpu = CPU(cris_env_get_cpu(env)));
70 struct cris_mmu_result res;
71 int prot, miss;
72 int r = -1;
73 target_ulong phy;
74
75 D(printf("%s addr=%x pc=%x rw=%x\n", __func__, address, env->pc, rw));
76 miss = cris_mmu_translate(&res, env, address & TARGET_PAGE_MASK,
77 rw, mmu_idx, 0);
78 if (miss) {
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
86 env->pregs[PR_EDA] = address;
87 env->exception_index = EXCP_BUSFAULT;
88 env->fault_vector = res.bf_vec;
89 r = 1;
90 } else {
91 /*
92 * Mask off the cache selection bit. The ETRAX busses do not
93 * see the top bit.
94 */
95 phy = res.phy & ~0x80000000;
96 prot = res.prot;
97 tlb_set_page(env, address & TARGET_PAGE_MASK, phy,
98 prot, mmu_idx, TARGET_PAGE_SIZE);
99 r = 0;
100 }
101 if (r > 0) {
102 D_LOG("%s returns %d irqreq=%x addr=%x phy=%x vec=%x pc=%x\n",
103 __func__, r, cpu->interrupt_request, address, res.phy,
104 res.bf_vec, env->pc);
105 }
106 return r;
107 }
108
109 static void do_interruptv10(CPUCRISState *env)
110 {
111 D(CPUState *cs = CPU(cris_env_get_cpu(env)));
112 int ex_vec = -1;
113
114 D_LOG("exception index=%d interrupt_req=%d\n",
115 env->exception_index,
116 cs->interrupt_request);
117
118 assert(!(env->pregs[PR_CCS] & PFIX_FLAG));
119 switch (env->exception_index) {
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 D(CPUState *cs = CPU(cris_env_get_cpu(env)));
168 int ex_vec = -1;
169
170 if (env->pregs[PR_VR] < 32) {
171 return do_interruptv10(env);
172 }
173
174 D_LOG("exception index=%d interrupt_req=%d\n",
175 env->exception_index,
176 cs->interrupt_request);
177
178 switch (env->exception_index) {
179 case EXCP_BREAK:
180 /* These exceptions are genereated by the core itself.
181 ERP should point to the insn following the brk. */
182 ex_vec = env->trap_vector;
183 env->pregs[PR_ERP] = env->pc;
184 break;
185
186 case EXCP_NMI:
187 /* NMI is hardwired to vector zero. */
188 ex_vec = 0;
189 env->pregs[PR_CCS] &= ~M_FLAG_V32;
190 env->pregs[PR_NRP] = env->pc;
191 break;
192
193 case EXCP_BUSFAULT:
194 ex_vec = env->fault_vector;
195 env->pregs[PR_ERP] = env->pc;
196 break;
197
198 default:
199 /* The interrupt controller gives us the vector. */
200 ex_vec = env->interrupt_vector;
201 /* Normal interrupts are taken between
202 TB's. env->pc is valid here. */
203 env->pregs[PR_ERP] = env->pc;
204 break;
205 }
206
207 /* Fill in the IDX field. */
208 env->pregs[PR_EXS] = (ex_vec & 0xff) << 8;
209
210 if (env->dslot) {
211 D_LOG("excp isr=%x PC=%x ds=%d SP=%x"
212 " ERP=%x pid=%x ccs=%x cc=%d %x\n",
213 ex_vec, env->pc, env->dslot,
214 env->regs[R_SP],
215 env->pregs[PR_ERP], env->pregs[PR_PID],
216 env->pregs[PR_CCS],
217 env->cc_op, env->cc_mask);
218 /* We loose the btarget, btaken state here so rexec the
219 branch. */
220 env->pregs[PR_ERP] -= env->dslot;
221 /* Exception starts with dslot cleared. */
222 env->dslot = 0;
223 }
224
225 if (env->pregs[PR_CCS] & U_FLAG) {
226 /* Swap stack pointers. */
227 env->pregs[PR_USP] = env->regs[R_SP];
228 env->regs[R_SP] = env->ksp;
229 }
230
231 /* Apply the CRIS CCS shift. Clears U if set. */
232 cris_shift_ccs(env);
233
234 /* Now that we are in kernel mode, load the handlers address.
235 This load may not fault, real hw leaves that behaviour as
236 undefined. */
237 env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4);
238
239 /* Clear the excption_index to avoid spurios hw_aborts for recursive
240 bus faults. */
241 env->exception_index = -1;
242
243 D_LOG("%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n",
244 __func__, env->pc, ex_vec,
245 env->pregs[PR_CCS],
246 env->pregs[PR_PID],
247 env->pregs[PR_ERP]);
248 }
249
250 hwaddr cpu_get_phys_page_debug(CPUCRISState * env, target_ulong addr)
251 {
252 uint32_t phy = addr;
253 struct cris_mmu_result res;
254 int miss;
255
256 miss = cris_mmu_translate(&res, env, addr, 0, 0, 1);
257 /* If D TLB misses, try I TLB. */
258 if (miss) {
259 miss = cris_mmu_translate(&res, env, addr, 2, 0, 1);
260 }
261
262 if (!miss) {
263 phy = res.phy;
264 }
265 D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy));
266 return phy;
267 }
268 #endif