]>
Commit | Line | Data |
---|---|---|
81fdc5f8 TS |
1 | /* |
2 | * CRIS helper routines | |
3 | * | |
4 | * Copyright (c) 2007 AXIS Communications | |
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, write to the Free Software | |
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
20 | */ | |
21 | ||
22 | #include <assert.h> | |
23 | #include "exec.h" | |
786c02f1 | 24 | #include "mmu.h" |
81fdc5f8 TS |
25 | |
26 | #define MMUSUFFIX _mmu | |
273af660 TS |
27 | #ifdef __s390__ |
28 | # define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL)) | |
29 | #else | |
30 | # define GETPC() (__builtin_return_address(0)) | |
31 | #endif | |
81fdc5f8 TS |
32 | |
33 | #define SHIFT 0 | |
34 | #include "softmmu_template.h" | |
35 | ||
36 | #define SHIFT 1 | |
37 | #include "softmmu_template.h" | |
38 | ||
39 | #define SHIFT 2 | |
40 | #include "softmmu_template.h" | |
41 | ||
42 | #define SHIFT 3 | |
43 | #include "softmmu_template.h" | |
44 | ||
786c02f1 EI |
45 | #define D(x) |
46 | ||
81fdc5f8 TS |
47 | /* Try to fill the TLB and return an exception if error. If retaddr is |
48 | NULL, it means that the function was called in C code (i.e. not | |
49 | from generated code or from helper.c) */ | |
50 | /* XXX: fix it to restore all registers */ | |
6ebbf390 | 51 | void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) |
81fdc5f8 TS |
52 | { |
53 | TranslationBlock *tb; | |
54 | CPUState *saved_env; | |
44f8625d | 55 | unsigned long pc; |
81fdc5f8 TS |
56 | int ret; |
57 | ||
58 | /* XXX: hack to restore env in all cases, even if not called from | |
59 | generated code */ | |
60 | saved_env = env; | |
61 | env = cpu_single_env; | |
b41f7df0 | 62 | |
ef29a70d EI |
63 | D(fprintf(logfile, "%s pc=%x tpc=%x ra=%x\n", __func__, |
64 | env->pc, env->debug1, retaddr)); | |
6ebbf390 | 65 | ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); |
81fdc5f8 TS |
66 | if (__builtin_expect(ret, 0)) { |
67 | if (retaddr) { | |
68 | /* now we have a real cpu fault */ | |
44f8625d | 69 | pc = (unsigned long)retaddr; |
81fdc5f8 TS |
70 | tb = tb_find_pc(pc); |
71 | if (tb) { | |
72 | /* the PC is inside the translated code. It means that we have | |
73 | a virtual CPU fault */ | |
74 | cpu_restore_state(tb, env, pc, NULL); | |
75 | } | |
76 | } | |
77 | cpu_loop_exit(); | |
78 | } | |
79 | env = saved_env; | |
80 | } | |
81 | ||
786c02f1 EI |
82 | void helper_tlb_update(uint32_t T0) |
83 | { | |
84 | #if !defined(CONFIG_USER_ONLY) | |
85 | uint32_t vaddr; | |
b41f7df0 EI |
86 | uint32_t srs = env->pregs[PR_SRS]; |
87 | ||
88 | if (srs != 1 && srs != 2) | |
89 | return; | |
786c02f1 EI |
90 | |
91 | vaddr = cris_mmu_tlb_latest_update(env, T0); | |
ef29a70d | 92 | D(fprintf(logfile, "flush old_vaddr=%x vaddr=%x T0=%x\n", vaddr, |
b41f7df0 | 93 | env->sregs[SFR_R_MM_CAUSE] & TARGET_PAGE_MASK, T0)); |
786c02f1 EI |
94 | tlb_flush_page(env, vaddr); |
95 | #endif | |
96 | } | |
97 | ||
b41f7df0 EI |
98 | void helper_tlb_flush(void) |
99 | { | |
100 | tlb_flush(env, 1); | |
101 | } | |
102 | ||
103 | void helper_dump(uint32_t a0, uint32_t a1) | |
104 | { | |
105 | (fprintf(logfile, "%s: a0=%x a1=%x\n", __func__, a0, a1)); | |
106 | } | |
107 | ||
108 | void helper_dummy(void) | |
109 | { | |
110 | ||
111 | } | |
112 | ||
113 | /* Only used for debugging at the moment. */ | |
114 | void helper_rfe(void) | |
115 | { | |
116 | D(fprintf(logfile, "rfe: erp=%x pid=%x ccs=%x btarget=%x\n", | |
117 | env->pregs[PR_ERP], env->pregs[PR_PID], | |
118 | env->pregs[PR_CCS], | |
119 | env->btarget)); | |
120 | } | |
121 | ||
122 | void helper_store(uint32_t a0) | |
123 | { | |
124 | if (env->pregs[PR_CCS] & P_FLAG ) | |
125 | { | |
126 | cpu_abort(env, "cond_store_failed! pc=%x a0=%x\n", | |
127 | env->pc, a0); | |
128 | } | |
129 | } | |
130 | ||
81fdc5f8 TS |
131 | void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, |
132 | int is_asi) | |
133 | { | |
786c02f1 EI |
134 | D(printf("%s addr=%x w=%d ex=%d asi=%d\n", |
135 | __func__, addr, is_write, is_exec, is_asi)); | |
81fdc5f8 | 136 | } |
b41f7df0 EI |
137 | |
138 | static void evaluate_flags_writeback(uint32_t flags) | |
139 | { | |
140 | int x; | |
141 | ||
142 | /* Extended arithmetics, leave the z flag alone. */ | |
143 | env->debug3 = env->pregs[PR_CCS]; | |
144 | ||
145 | if (env->cc_x_live) | |
146 | x = env->cc_x; | |
147 | else | |
148 | x = env->pregs[PR_CCS] & X_FLAG; | |
149 | ||
150 | if ((x || env->cc_op == CC_OP_ADDC) | |
151 | && flags & Z_FLAG) | |
152 | env->cc_mask &= ~Z_FLAG; | |
153 | ||
154 | /* all insn clear the x-flag except setf or clrf. */ | |
155 | env->pregs[PR_CCS] &= ~(env->cc_mask | X_FLAG); | |
156 | flags &= env->cc_mask; | |
157 | env->pregs[PR_CCS] |= flags; | |
158 | RETURN(); | |
159 | } | |
160 | ||
161 | void helper_evaluate_flags_muls(void) | |
162 | { | |
163 | uint32_t src; | |
164 | uint32_t dst; | |
165 | uint32_t res; | |
166 | uint32_t flags = 0; | |
167 | /* were gonna have to redo the muls. */ | |
168 | int64_t tmp, t0 ,t1; | |
169 | int32_t mof; | |
170 | int dneg; | |
171 | ||
172 | src = env->cc_src; | |
173 | dst = env->cc_dest; | |
174 | res = env->cc_result; | |
175 | ||
176 | ||
177 | /* cast into signed values to make GCC sign extend. */ | |
178 | t0 = (int32_t)src; | |
179 | t1 = (int32_t)dst; | |
180 | dneg = ((int32_t)res) < 0; | |
181 | ||
182 | tmp = t0 * t1; | |
183 | mof = tmp >> 32; | |
184 | if (tmp == 0) | |
185 | flags |= Z_FLAG; | |
186 | else if (tmp < 0) | |
187 | flags |= N_FLAG; | |
188 | if ((dneg && mof != -1) | |
189 | || (!dneg && mof != 0)) | |
190 | flags |= V_FLAG; | |
191 | evaluate_flags_writeback(flags); | |
192 | } | |
193 | ||
194 | void helper_evaluate_flags_mulu(void) | |
195 | { | |
196 | uint32_t src; | |
197 | uint32_t dst; | |
198 | uint32_t res; | |
199 | uint32_t flags = 0; | |
200 | /* were gonna have to redo the muls. */ | |
201 | uint64_t tmp, t0 ,t1; | |
202 | uint32_t mof; | |
203 | ||
204 | src = env->cc_src; | |
205 | dst = env->cc_dest; | |
206 | res = env->cc_result; | |
207 | ||
208 | ||
209 | /* cast into signed values to make GCC sign extend. */ | |
210 | t0 = src; | |
211 | t1 = dst; | |
212 | ||
213 | tmp = t0 * t1; | |
214 | mof = tmp >> 32; | |
215 | if (tmp == 0) | |
216 | flags |= Z_FLAG; | |
217 | else if (tmp >> 63) | |
218 | flags |= N_FLAG; | |
219 | if (mof) | |
220 | flags |= V_FLAG; | |
221 | ||
222 | evaluate_flags_writeback(flags); | |
223 | } | |
224 | ||
225 | void helper_evaluate_flags_mcp(void) | |
226 | { | |
227 | uint32_t src; | |
228 | uint32_t dst; | |
229 | uint32_t res; | |
230 | uint32_t flags = 0; | |
231 | ||
232 | src = env->cc_src; | |
233 | dst = env->cc_dest; | |
234 | res = env->cc_result; | |
235 | ||
236 | if ((res & 0x80000000L) != 0L) | |
237 | { | |
238 | flags |= N_FLAG; | |
239 | if (((src & 0x80000000L) == 0L) | |
240 | && ((dst & 0x80000000L) == 0L)) | |
241 | { | |
242 | flags |= V_FLAG; | |
243 | } | |
244 | else if (((src & 0x80000000L) != 0L) && | |
245 | ((dst & 0x80000000L) != 0L)) | |
246 | { | |
247 | flags |= R_FLAG; | |
248 | } | |
249 | } | |
250 | else | |
251 | { | |
252 | if (res == 0L) | |
253 | flags |= Z_FLAG; | |
254 | if (((src & 0x80000000L) != 0L) | |
255 | && ((dst & 0x80000000L) != 0L)) | |
256 | flags |= V_FLAG; | |
257 | if ((dst & 0x80000000L) != 0L | |
258 | || (src & 0x80000000L) != 0L) | |
259 | flags |= R_FLAG; | |
260 | } | |
261 | ||
262 | evaluate_flags_writeback(flags); | |
263 | } | |
264 | ||
265 | void helper_evaluate_flags_alu_4(void) | |
266 | { | |
267 | uint32_t src; | |
268 | uint32_t dst; | |
269 | uint32_t res; | |
270 | uint32_t flags = 0; | |
271 | ||
272 | src = env->cc_src; | |
273 | dst = env->cc_dest; | |
274 | res = env->cc_result; | |
275 | ||
276 | if ((res & 0x80000000L) != 0L) | |
277 | { | |
278 | flags |= N_FLAG; | |
279 | if (((src & 0x80000000L) == 0L) | |
280 | && ((dst & 0x80000000L) == 0L)) | |
281 | { | |
282 | flags |= V_FLAG; | |
283 | } | |
284 | else if (((src & 0x80000000L) != 0L) && | |
285 | ((dst & 0x80000000L) != 0L)) | |
286 | { | |
287 | flags |= C_FLAG; | |
288 | } | |
289 | } | |
290 | else | |
291 | { | |
292 | if (res == 0L) | |
293 | flags |= Z_FLAG; | |
294 | if (((src & 0x80000000L) != 0L) | |
295 | && ((dst & 0x80000000L) != 0L)) | |
296 | flags |= V_FLAG; | |
297 | if ((dst & 0x80000000L) != 0L | |
298 | || (src & 0x80000000L) != 0L) | |
299 | flags |= C_FLAG; | |
300 | } | |
301 | ||
302 | if (env->cc_op == CC_OP_SUB | |
303 | || env->cc_op == CC_OP_CMP) { | |
304 | flags ^= C_FLAG; | |
305 | } | |
306 | evaluate_flags_writeback(flags); | |
307 | } | |
308 | ||
309 | void helper_evaluate_flags_move_4 (void) | |
310 | { | |
311 | uint32_t src; | |
312 | uint32_t res; | |
313 | uint32_t flags = 0; | |
314 | ||
315 | src = env->cc_src; | |
316 | res = env->cc_result; | |
317 | ||
318 | if ((int32_t)res < 0) | |
319 | flags |= N_FLAG; | |
320 | else if (res == 0L) | |
321 | flags |= Z_FLAG; | |
322 | ||
323 | evaluate_flags_writeback(flags); | |
324 | } | |
325 | void helper_evaluate_flags_move_2 (void) | |
326 | { | |
327 | uint32_t src; | |
328 | uint32_t flags = 0; | |
329 | uint16_t res; | |
330 | ||
331 | src = env->cc_src; | |
332 | res = env->cc_result; | |
333 | ||
334 | if ((int16_t)res < 0L) | |
335 | flags |= N_FLAG; | |
336 | else if (res == 0) | |
337 | flags |= Z_FLAG; | |
338 | ||
339 | evaluate_flags_writeback(flags); | |
340 | } | |
341 | ||
342 | /* TODO: This is expensive. We could split things up and only evaluate part of | |
343 | CCR on a need to know basis. For now, we simply re-evaluate everything. */ | |
344 | void helper_evaluate_flags (void) | |
345 | { | |
346 | uint32_t src; | |
347 | uint32_t dst; | |
348 | uint32_t res; | |
349 | uint32_t flags = 0; | |
350 | ||
351 | src = env->cc_src; | |
352 | dst = env->cc_dest; | |
353 | res = env->cc_result; | |
354 | ||
355 | ||
356 | /* Now, evaluate the flags. This stuff is based on | |
357 | Per Zander's CRISv10 simulator. */ | |
358 | switch (env->cc_size) | |
359 | { | |
360 | case 1: | |
361 | if ((res & 0x80L) != 0L) | |
362 | { | |
363 | flags |= N_FLAG; | |
364 | if (((src & 0x80L) == 0L) | |
365 | && ((dst & 0x80L) == 0L)) | |
366 | { | |
367 | flags |= V_FLAG; | |
368 | } | |
369 | else if (((src & 0x80L) != 0L) | |
370 | && ((dst & 0x80L) != 0L)) | |
371 | { | |
372 | flags |= C_FLAG; | |
373 | } | |
374 | } | |
375 | else | |
376 | { | |
377 | if ((res & 0xFFL) == 0L) | |
378 | { | |
379 | flags |= Z_FLAG; | |
380 | } | |
381 | if (((src & 0x80L) != 0L) | |
382 | && ((dst & 0x80L) != 0L)) | |
383 | { | |
384 | flags |= V_FLAG; | |
385 | } | |
386 | if ((dst & 0x80L) != 0L | |
387 | || (src & 0x80L) != 0L) | |
388 | { | |
389 | flags |= C_FLAG; | |
390 | } | |
391 | } | |
392 | break; | |
393 | case 2: | |
394 | if ((res & 0x8000L) != 0L) | |
395 | { | |
396 | flags |= N_FLAG; | |
397 | if (((src & 0x8000L) == 0L) | |
398 | && ((dst & 0x8000L) == 0L)) | |
399 | { | |
400 | flags |= V_FLAG; | |
401 | } | |
402 | else if (((src & 0x8000L) != 0L) | |
403 | && ((dst & 0x8000L) != 0L)) | |
404 | { | |
405 | flags |= C_FLAG; | |
406 | } | |
407 | } | |
408 | else | |
409 | { | |
410 | if ((res & 0xFFFFL) == 0L) | |
411 | { | |
412 | flags |= Z_FLAG; | |
413 | } | |
414 | if (((src & 0x8000L) != 0L) | |
415 | && ((dst & 0x8000L) != 0L)) | |
416 | { | |
417 | flags |= V_FLAG; | |
418 | } | |
419 | if ((dst & 0x8000L) != 0L | |
420 | || (src & 0x8000L) != 0L) | |
421 | { | |
422 | flags |= C_FLAG; | |
423 | } | |
424 | } | |
425 | break; | |
426 | case 4: | |
427 | if ((res & 0x80000000L) != 0L) | |
428 | { | |
429 | flags |= N_FLAG; | |
430 | if (((src & 0x80000000L) == 0L) | |
431 | && ((dst & 0x80000000L) == 0L)) | |
432 | { | |
433 | flags |= V_FLAG; | |
434 | } | |
435 | else if (((src & 0x80000000L) != 0L) && | |
436 | ((dst & 0x80000000L) != 0L)) | |
437 | { | |
438 | flags |= C_FLAG; | |
439 | } | |
440 | } | |
441 | else | |
442 | { | |
443 | if (res == 0L) | |
444 | flags |= Z_FLAG; | |
445 | if (((src & 0x80000000L) != 0L) | |
446 | && ((dst & 0x80000000L) != 0L)) | |
447 | flags |= V_FLAG; | |
448 | if ((dst & 0x80000000L) != 0L | |
449 | || (src & 0x80000000L) != 0L) | |
450 | flags |= C_FLAG; | |
451 | } | |
452 | break; | |
453 | default: | |
454 | break; | |
455 | } | |
456 | ||
457 | if (env->cc_op == CC_OP_SUB | |
458 | || env->cc_op == CC_OP_CMP) { | |
459 | flags ^= C_FLAG; | |
460 | } | |
461 | evaluate_flags_writeback(flags); | |
462 | } |