]> rtime.felk.cvut.cz Git - lisovros/qemu_apohw.git/blob - target-microblaze/op_helper.c
cpu-exec: Change cpu_loop_exit() argument to CPUState
[lisovros/qemu_apohw.git] / target-microblaze / op_helper.c
1 /*
2  *  Microblaze helper routines.
3  *
4  *  Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias@gmail.com>.
5  *  Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
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 <assert.h>
22 #include "cpu.h"
23 #include "helper.h"
24 #include "qemu/host-utils.h"
25
26 #define D(x)
27
28 #if !defined(CONFIG_USER_ONLY)
29 #include "exec/softmmu_exec.h"
30
31 #define MMUSUFFIX _mmu
32 #define SHIFT 0
33 #include "exec/softmmu_template.h"
34 #define SHIFT 1
35 #include "exec/softmmu_template.h"
36 #define SHIFT 2
37 #include "exec/softmmu_template.h"
38 #define SHIFT 3
39 #include "exec/softmmu_template.h"
40
41 /* Try to fill the TLB and return an exception if error. If retaddr is
42  * NULL, it means that the function was called in C code (i.e. not
43  * from generated code or from helper.c)
44  */
45 void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
46               uintptr_t retaddr)
47 {
48     int ret;
49
50     ret = mb_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
51     if (unlikely(ret)) {
52         MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
53         CPUMBState *env = &cpu->env;
54
55         if (retaddr) {
56             /* now we have a real cpu fault */
57             cpu_restore_state(env, retaddr);
58         }
59         cpu_loop_exit(cs);
60     }
61 }
62 #endif
63
64 void helper_put(uint32_t id, uint32_t ctrl, uint32_t data)
65 {
66     int test = ctrl & STREAM_TEST;
67     int atomic = ctrl & STREAM_ATOMIC;
68     int control = ctrl & STREAM_CONTROL;
69     int nonblock = ctrl & STREAM_NONBLOCK;
70     int exception = ctrl & STREAM_EXCEPTION;
71
72     qemu_log("Unhandled stream put to stream-id=%d data=%x %s%s%s%s%s\n",
73              id, data,
74              test ? "t" : "",
75              nonblock ? "n" : "",
76              exception ? "e" : "",
77              control ? "c" : "",
78              atomic ? "a" : "");
79 }
80
81 uint32_t helper_get(uint32_t id, uint32_t ctrl)
82 {
83     int test = ctrl & STREAM_TEST;
84     int atomic = ctrl & STREAM_ATOMIC;
85     int control = ctrl & STREAM_CONTROL;
86     int nonblock = ctrl & STREAM_NONBLOCK;
87     int exception = ctrl & STREAM_EXCEPTION;
88
89     qemu_log("Unhandled stream get from stream-id=%d %s%s%s%s%s\n",
90              id,
91              test ? "t" : "",
92              nonblock ? "n" : "",
93              exception ? "e" : "",
94              control ? "c" : "",
95              atomic ? "a" : "");
96     return 0xdead0000 | id;
97 }
98
99 void helper_raise_exception(CPUMBState *env, uint32_t index)
100 {
101     CPUState *cs = CPU(mb_env_get_cpu(env));
102
103     cs->exception_index = index;
104     cpu_loop_exit(cs);
105 }
106
107 void helper_debug(CPUMBState *env)
108 {
109     int i;
110
111     qemu_log("PC=%8.8x\n", env->sregs[SR_PC]);
112     qemu_log("rmsr=%x resr=%x rear=%x debug[%x] imm=%x iflags=%x\n",
113              env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR],
114              env->debug, env->imm, env->iflags);
115     qemu_log("btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n",
116              env->btaken, env->btarget,
117              (env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel",
118              (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel",
119              (env->sregs[SR_MSR] & MSR_EIP),
120              (env->sregs[SR_MSR] & MSR_IE));
121     for (i = 0; i < 32; i++) {
122         qemu_log("r%2.2d=%8.8x ", i, env->regs[i]);
123         if ((i + 1) % 4 == 0)
124             qemu_log("\n");
125     }
126     qemu_log("\n\n");
127 }
128
129 static inline uint32_t compute_carry(uint32_t a, uint32_t b, uint32_t cin)
130 {
131     uint32_t cout = 0;
132
133     if ((b == ~0) && cin)
134         cout = 1;
135     else if ((~0 - a) < (b + cin))
136         cout = 1;
137     return cout;
138 }
139
140 uint32_t helper_cmp(uint32_t a, uint32_t b)
141 {
142     uint32_t t;
143
144     t = b + ~a + 1;
145     if ((b & 0x80000000) ^ (a & 0x80000000))
146         t = (t & 0x7fffffff) | (b & 0x80000000);
147     return t;
148 }
149
150 uint32_t helper_cmpu(uint32_t a, uint32_t b)
151 {
152     uint32_t t;
153
154     t = b + ~a + 1;
155     if ((b & 0x80000000) ^ (a & 0x80000000))
156         t = (t & 0x7fffffff) | (a & 0x80000000);
157     return t;
158 }
159
160 uint32_t helper_clz(uint32_t t0)
161 {
162     return clz32(t0);
163 }
164
165 uint32_t helper_carry(uint32_t a, uint32_t b, uint32_t cf)
166 {
167     uint32_t ncf;
168     ncf = compute_carry(a, b, cf);
169     return ncf;
170 }
171
172 static inline int div_prepare(CPUMBState *env, uint32_t a, uint32_t b)
173 {
174     if (b == 0) {
175         env->sregs[SR_MSR] |= MSR_DZ;
176
177         if ((env->sregs[SR_MSR] & MSR_EE)
178             && !(env->pvr.regs[2] & PVR2_DIV_ZERO_EXC_MASK)) {
179             env->sregs[SR_ESR] = ESR_EC_DIVZERO;
180             helper_raise_exception(env, EXCP_HW_EXCP);
181         }
182         return 0;
183     }
184     env->sregs[SR_MSR] &= ~MSR_DZ;
185     return 1;
186 }
187
188 uint32_t helper_divs(CPUMBState *env, uint32_t a, uint32_t b)
189 {
190     if (!div_prepare(env, a, b)) {
191         return 0;
192     }
193     return (int32_t)a / (int32_t)b;
194 }
195
196 uint32_t helper_divu(CPUMBState *env, uint32_t a, uint32_t b)
197 {
198     if (!div_prepare(env, a, b)) {
199         return 0;
200     }
201     return a / b;
202 }
203
204 /* raise FPU exception.  */
205 static void raise_fpu_exception(CPUMBState *env)
206 {
207     env->sregs[SR_ESR] = ESR_EC_FPU;
208     helper_raise_exception(env, EXCP_HW_EXCP);
209 }
210
211 static void update_fpu_flags(CPUMBState *env, int flags)
212 {
213     int raise = 0;
214
215     if (flags & float_flag_invalid) {
216         env->sregs[SR_FSR] |= FSR_IO;
217         raise = 1;
218     }
219     if (flags & float_flag_divbyzero) {
220         env->sregs[SR_FSR] |= FSR_DZ;
221         raise = 1;
222     }
223     if (flags & float_flag_overflow) {
224         env->sregs[SR_FSR] |= FSR_OF;
225         raise = 1;
226     }
227     if (flags & float_flag_underflow) {
228         env->sregs[SR_FSR] |= FSR_UF;
229         raise = 1;
230     }
231     if (raise
232         && (env->pvr.regs[2] & PVR2_FPU_EXC_MASK)
233         && (env->sregs[SR_MSR] & MSR_EE)) {
234         raise_fpu_exception(env);
235     }
236 }
237
238 uint32_t helper_fadd(CPUMBState *env, uint32_t a, uint32_t b)
239 {
240     CPU_FloatU fd, fa, fb;
241     int flags;
242
243     set_float_exception_flags(0, &env->fp_status);
244     fa.l = a;
245     fb.l = b;
246     fd.f = float32_add(fa.f, fb.f, &env->fp_status);
247
248     flags = get_float_exception_flags(&env->fp_status);
249     update_fpu_flags(env, flags);
250     return fd.l;
251 }
252
253 uint32_t helper_frsub(CPUMBState *env, uint32_t a, uint32_t b)
254 {
255     CPU_FloatU fd, fa, fb;
256     int flags;
257
258     set_float_exception_flags(0, &env->fp_status);
259     fa.l = a;
260     fb.l = b;
261     fd.f = float32_sub(fb.f, fa.f, &env->fp_status);
262     flags = get_float_exception_flags(&env->fp_status);
263     update_fpu_flags(env, flags);
264     return fd.l;
265 }
266
267 uint32_t helper_fmul(CPUMBState *env, uint32_t a, uint32_t b)
268 {
269     CPU_FloatU fd, fa, fb;
270     int flags;
271
272     set_float_exception_flags(0, &env->fp_status);
273     fa.l = a;
274     fb.l = b;
275     fd.f = float32_mul(fa.f, fb.f, &env->fp_status);
276     flags = get_float_exception_flags(&env->fp_status);
277     update_fpu_flags(env, flags);
278
279     return fd.l;
280 }
281
282 uint32_t helper_fdiv(CPUMBState *env, uint32_t a, uint32_t b)
283 {
284     CPU_FloatU fd, fa, fb;
285     int flags;
286
287     set_float_exception_flags(0, &env->fp_status);
288     fa.l = a;
289     fb.l = b;
290     fd.f = float32_div(fb.f, fa.f, &env->fp_status);
291     flags = get_float_exception_flags(&env->fp_status);
292     update_fpu_flags(env, flags);
293
294     return fd.l;
295 }
296
297 uint32_t helper_fcmp_un(CPUMBState *env, uint32_t a, uint32_t b)
298 {
299     CPU_FloatU fa, fb;
300     uint32_t r = 0;
301
302     fa.l = a;
303     fb.l = b;
304
305     if (float32_is_signaling_nan(fa.f) || float32_is_signaling_nan(fb.f)) {
306         update_fpu_flags(env, float_flag_invalid);
307         r = 1;
308     }
309
310     if (float32_is_quiet_nan(fa.f) || float32_is_quiet_nan(fb.f)) {
311         r = 1;
312     }
313
314     return r;
315 }
316
317 uint32_t helper_fcmp_lt(CPUMBState *env, uint32_t a, uint32_t b)
318 {
319     CPU_FloatU fa, fb;
320     int r;
321     int flags;
322
323     set_float_exception_flags(0, &env->fp_status);
324     fa.l = a;
325     fb.l = b;
326     r = float32_lt(fb.f, fa.f, &env->fp_status);
327     flags = get_float_exception_flags(&env->fp_status);
328     update_fpu_flags(env, flags & float_flag_invalid);
329
330     return r;
331 }
332
333 uint32_t helper_fcmp_eq(CPUMBState *env, uint32_t a, uint32_t b)
334 {
335     CPU_FloatU fa, fb;
336     int flags;
337     int r;
338
339     set_float_exception_flags(0, &env->fp_status);
340     fa.l = a;
341     fb.l = b;
342     r = float32_eq_quiet(fa.f, fb.f, &env->fp_status);
343     flags = get_float_exception_flags(&env->fp_status);
344     update_fpu_flags(env, flags & float_flag_invalid);
345
346     return r;
347 }
348
349 uint32_t helper_fcmp_le(CPUMBState *env, uint32_t a, uint32_t b)
350 {
351     CPU_FloatU fa, fb;
352     int flags;
353     int r;
354
355     fa.l = a;
356     fb.l = b;
357     set_float_exception_flags(0, &env->fp_status);
358     r = float32_le(fa.f, fb.f, &env->fp_status);
359     flags = get_float_exception_flags(&env->fp_status);
360     update_fpu_flags(env, flags & float_flag_invalid);
361
362
363     return r;
364 }
365
366 uint32_t helper_fcmp_gt(CPUMBState *env, uint32_t a, uint32_t b)
367 {
368     CPU_FloatU fa, fb;
369     int flags, r;
370
371     fa.l = a;
372     fb.l = b;
373     set_float_exception_flags(0, &env->fp_status);
374     r = float32_lt(fa.f, fb.f, &env->fp_status);
375     flags = get_float_exception_flags(&env->fp_status);
376     update_fpu_flags(env, flags & float_flag_invalid);
377     return r;
378 }
379
380 uint32_t helper_fcmp_ne(CPUMBState *env, uint32_t a, uint32_t b)
381 {
382     CPU_FloatU fa, fb;
383     int flags, r;
384
385     fa.l = a;
386     fb.l = b;
387     set_float_exception_flags(0, &env->fp_status);
388     r = !float32_eq_quiet(fa.f, fb.f, &env->fp_status);
389     flags = get_float_exception_flags(&env->fp_status);
390     update_fpu_flags(env, flags & float_flag_invalid);
391
392     return r;
393 }
394
395 uint32_t helper_fcmp_ge(CPUMBState *env, uint32_t a, uint32_t b)
396 {
397     CPU_FloatU fa, fb;
398     int flags, r;
399
400     fa.l = a;
401     fb.l = b;
402     set_float_exception_flags(0, &env->fp_status);
403     r = !float32_lt(fa.f, fb.f, &env->fp_status);
404     flags = get_float_exception_flags(&env->fp_status);
405     update_fpu_flags(env, flags & float_flag_invalid);
406
407     return r;
408 }
409
410 uint32_t helper_flt(CPUMBState *env, uint32_t a)
411 {
412     CPU_FloatU fd, fa;
413
414     fa.l = a;
415     fd.f = int32_to_float32(fa.l, &env->fp_status);
416     return fd.l;
417 }
418
419 uint32_t helper_fint(CPUMBState *env, uint32_t a)
420 {
421     CPU_FloatU fa;
422     uint32_t r;
423     int flags;
424
425     set_float_exception_flags(0, &env->fp_status);
426     fa.l = a;
427     r = float32_to_int32(fa.f, &env->fp_status);
428     flags = get_float_exception_flags(&env->fp_status);
429     update_fpu_flags(env, flags);
430
431     return r;
432 }
433
434 uint32_t helper_fsqrt(CPUMBState *env, uint32_t a)
435 {
436     CPU_FloatU fd, fa;
437     int flags;
438
439     set_float_exception_flags(0, &env->fp_status);
440     fa.l = a;
441     fd.l = float32_sqrt(fa.f, &env->fp_status);
442     flags = get_float_exception_flags(&env->fp_status);
443     update_fpu_flags(env, flags);
444
445     return fd.l;
446 }
447
448 uint32_t helper_pcmpbf(uint32_t a, uint32_t b)
449 {
450     unsigned int i;
451     uint32_t mask = 0xff000000;
452
453     for (i = 0; i < 4; i++) {
454         if ((a & mask) == (b & mask))
455             return i + 1;
456         mask >>= 8;
457     }
458     return 0;
459 }
460
461 void helper_memalign(CPUMBState *env, uint32_t addr, uint32_t dr, uint32_t wr,
462                      uint32_t mask)
463 {
464     if (addr & mask) {
465             qemu_log_mask(CPU_LOG_INT,
466                           "unaligned access addr=%x mask=%x, wr=%d dr=r%d\n",
467                           addr, mask, wr, dr);
468             env->sregs[SR_EAR] = addr;
469             env->sregs[SR_ESR] = ESR_EC_UNALIGNED_DATA | (wr << 10) \
470                                  | (dr & 31) << 5;
471             if (mask == 3) {
472                 env->sregs[SR_ESR] |= 1 << 11;
473             }
474             if (!(env->sregs[SR_MSR] & MSR_EE)) {
475                 return;
476             }
477             helper_raise_exception(env, EXCP_HW_EXCP);
478     }
479 }
480
481 void helper_stackprot(CPUMBState *env, uint32_t addr)
482 {
483     if (addr < env->slr || addr > env->shr) {
484             qemu_log("Stack protector violation at %x %x %x\n",
485                      addr, env->slr, env->shr);
486             env->sregs[SR_EAR] = addr;
487             env->sregs[SR_ESR] = ESR_EC_STACKPROT;
488             helper_raise_exception(env, EXCP_HW_EXCP);
489     }
490 }
491
492 #if !defined(CONFIG_USER_ONLY)
493 /* Writes/reads to the MMU's special regs end up here.  */
494 uint32_t helper_mmu_read(CPUMBState *env, uint32_t rn)
495 {
496     return mmu_read(env, rn);
497 }
498
499 void helper_mmu_write(CPUMBState *env, uint32_t rn, uint32_t v)
500 {
501     mmu_write(env, rn, v);
502 }
503
504 void mb_cpu_unassigned_access(CPUState *cs, hwaddr addr,
505                               bool is_write, bool is_exec, int is_asi,
506                               unsigned size)
507 {
508     MicroBlazeCPU *cpu;
509     CPUMBState *env;
510
511     qemu_log_mask(CPU_LOG_INT, "Unassigned " TARGET_FMT_plx " wr=%d exe=%d\n",
512              addr, is_write ? 1 : 0, is_exec ? 1 : 0);
513     if (cs == NULL) {
514         return;
515     }
516     cpu = MICROBLAZE_CPU(cs);
517     env = &cpu->env;
518     if (!(env->sregs[SR_MSR] & MSR_EE)) {
519         return;
520     }
521
522     env->sregs[SR_EAR] = addr;
523     if (is_exec) {
524         if ((env->pvr.regs[2] & PVR2_IOPB_BUS_EXC_MASK)) {
525             env->sregs[SR_ESR] = ESR_EC_INSN_BUS;
526             helper_raise_exception(env, EXCP_HW_EXCP);
527         }
528     } else {
529         if ((env->pvr.regs[2] & PVR2_DOPB_BUS_EXC_MASK)) {
530             env->sregs[SR_ESR] = ESR_EC_DATA_BUS;
531             helper_raise_exception(env, EXCP_HW_EXCP);
532         }
533     }
534 }
535 #endif