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