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