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