--- qemu/target-microblaze/op_helper.c 2018/04/24 17:23:14 1.1.1.1 +++ qemu/target-microblaze/op_helper.c 2018/04/24 18:36:13 1.1.1.4 @@ -80,6 +80,15 @@ void helper_debug(void) int i; qemu_log("PC=%8.8x\n", env->sregs[SR_PC]); + qemu_log("rmsr=%x resr=%x rear=%x debug[%x] imm=%x iflags=%x\n", + env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR], + env->debug, env->imm, env->iflags); + qemu_log("btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n", + env->btaken, env->btarget, + (env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel", + (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel", + (env->sregs[SR_MSR] & MSR_EIP), + (env->sregs[SR_MSR] & MSR_IE)); for (i = 0; i < 32; i++) { qemu_log("r%2.2d=%8.8x ", i, env->regs[i]); if ((i + 1) % 4 == 0) @@ -119,55 +128,23 @@ uint32_t helper_cmpu(uint32_t a, uint32_ return t; } -uint32_t helper_addkc(uint32_t a, uint32_t b, uint32_t k, uint32_t c) +uint32_t helper_carry(uint32_t a, uint32_t b, uint32_t cf) { - uint32_t d, cf = 0, ncf; - - if (c) - cf = env->sregs[SR_MSR] >> 31; - assert(cf == 0 || cf == 1); - d = a + b + cf; - - if (!k) { - ncf = compute_carry(a, b, cf); - assert(ncf == 0 || ncf == 1); - if (ncf) - env->sregs[SR_MSR] |= MSR_C | MSR_CC; - else - env->sregs[SR_MSR] &= ~(MSR_C | MSR_CC); - } - D(qemu_log("%x = %x + %x cf=%d ncf=%d k=%d c=%d\n", - d, a, b, cf, ncf, k, c)); - return d; -} - -uint32_t helper_subkc(uint32_t a, uint32_t b, uint32_t k, uint32_t c) -{ - uint32_t d, cf = 1, ncf; - - if (c) - cf = env->sregs[SR_MSR] >> 31; - assert(cf == 0 || cf == 1); - d = b + ~a + cf; - - if (!k) { - ncf = compute_carry(b, ~a, cf); - assert(ncf == 0 || ncf == 1); - if (ncf) - env->sregs[SR_MSR] |= MSR_C | MSR_CC; - else - env->sregs[SR_MSR] &= ~(MSR_C | MSR_CC); - } - D(qemu_log("%x = %x + %x cf=%d ncf=%d k=%d c=%d\n", - d, a, b, cf, ncf, k, c)); - return d; + uint32_t ncf; + ncf = compute_carry(a, b, cf); + return ncf; } static inline int div_prepare(uint32_t a, uint32_t b) { if (b == 0) { env->sregs[SR_MSR] |= MSR_DZ; - /* FIXME: Raise the div by zero exception. */ + + if ((env->sregs[SR_MSR] & MSR_EE) + && !(env->pvr.regs[2] & PVR2_DIV_ZERO_EXC_MASK)) { + env->sregs[SR_ESR] = ESR_EC_DIVZERO; + helper_raise_exception(EXCP_HW_EXCP); + } return 0; } env->sregs[SR_MSR] &= ~MSR_DZ; @@ -188,6 +165,250 @@ uint32_t helper_divu(uint32_t a, uint32_ return a / b; } +/* raise FPU exception. */ +static void raise_fpu_exception(void) +{ + env->sregs[SR_ESR] = ESR_EC_FPU; + helper_raise_exception(EXCP_HW_EXCP); +} + +static void update_fpu_flags(int flags) +{ + int raise = 0; + + if (flags & float_flag_invalid) { + env->sregs[SR_FSR] |= FSR_IO; + raise = 1; + } + if (flags & float_flag_divbyzero) { + env->sregs[SR_FSR] |= FSR_DZ; + raise = 1; + } + if (flags & float_flag_overflow) { + env->sregs[SR_FSR] |= FSR_OF; + raise = 1; + } + if (flags & float_flag_underflow) { + env->sregs[SR_FSR] |= FSR_UF; + raise = 1; + } + if (raise + && (env->pvr.regs[2] & PVR2_FPU_EXC_MASK) + && (env->sregs[SR_MSR] & MSR_EE)) { + raise_fpu_exception(); + } +} + +uint32_t helper_fadd(uint32_t a, uint32_t b) +{ + CPU_FloatU fd, fa, fb; + int flags; + + set_float_exception_flags(0, &env->fp_status); + fa.l = a; + fb.l = b; + fd.f = float32_add(fa.f, fb.f, &env->fp_status); + + flags = get_float_exception_flags(&env->fp_status); + update_fpu_flags(flags); + return fd.l; +} + +uint32_t helper_frsub(uint32_t a, uint32_t b) +{ + CPU_FloatU fd, fa, fb; + int flags; + + set_float_exception_flags(0, &env->fp_status); + fa.l = a; + fb.l = b; + fd.f = float32_sub(fb.f, fa.f, &env->fp_status); + flags = get_float_exception_flags(&env->fp_status); + update_fpu_flags(flags); + return fd.l; +} + +uint32_t helper_fmul(uint32_t a, uint32_t b) +{ + CPU_FloatU fd, fa, fb; + int flags; + + set_float_exception_flags(0, &env->fp_status); + fa.l = a; + fb.l = b; + fd.f = float32_mul(fa.f, fb.f, &env->fp_status); + flags = get_float_exception_flags(&env->fp_status); + update_fpu_flags(flags); + + return fd.l; +} + +uint32_t helper_fdiv(uint32_t a, uint32_t b) +{ + CPU_FloatU fd, fa, fb; + int flags; + + set_float_exception_flags(0, &env->fp_status); + fa.l = a; + fb.l = b; + fd.f = float32_div(fb.f, fa.f, &env->fp_status); + flags = get_float_exception_flags(&env->fp_status); + update_fpu_flags(flags); + + return fd.l; +} + +uint32_t helper_fcmp_un(uint32_t a, uint32_t b) +{ + CPU_FloatU fa, fb; + uint32_t r = 0; + + fa.l = a; + fb.l = b; + + if (float32_is_signaling_nan(fa.f) || float32_is_signaling_nan(fb.f)) { + update_fpu_flags(float_flag_invalid); + r = 1; + } + + if (float32_is_quiet_nan(fa.f) || float32_is_quiet_nan(fb.f)) { + r = 1; + } + + return r; +} + +uint32_t helper_fcmp_lt(uint32_t a, uint32_t b) +{ + CPU_FloatU fa, fb; + int r; + int flags; + + set_float_exception_flags(0, &env->fp_status); + fa.l = a; + fb.l = b; + r = float32_lt(fb.f, fa.f, &env->fp_status); + flags = get_float_exception_flags(&env->fp_status); + update_fpu_flags(flags & float_flag_invalid); + + return r; +} + +uint32_t helper_fcmp_eq(uint32_t a, uint32_t b) +{ + CPU_FloatU fa, fb; + int flags; + int r; + + set_float_exception_flags(0, &env->fp_status); + fa.l = a; + fb.l = b; + r = float32_eq(fa.f, fb.f, &env->fp_status); + flags = get_float_exception_flags(&env->fp_status); + update_fpu_flags(flags & float_flag_invalid); + + return r; +} + +uint32_t helper_fcmp_le(uint32_t a, uint32_t b) +{ + CPU_FloatU fa, fb; + int flags; + int r; + + fa.l = a; + fb.l = b; + set_float_exception_flags(0, &env->fp_status); + r = float32_le(fa.f, fb.f, &env->fp_status); + flags = get_float_exception_flags(&env->fp_status); + update_fpu_flags(flags & float_flag_invalid); + + + return r; +} + +uint32_t helper_fcmp_gt(uint32_t a, uint32_t b) +{ + CPU_FloatU fa, fb; + int flags, r; + + fa.l = a; + fb.l = b; + set_float_exception_flags(0, &env->fp_status); + r = float32_lt(fa.f, fb.f, &env->fp_status); + flags = get_float_exception_flags(&env->fp_status); + update_fpu_flags(flags & float_flag_invalid); + return r; +} + +uint32_t helper_fcmp_ne(uint32_t a, uint32_t b) +{ + CPU_FloatU fa, fb; + int flags, r; + + fa.l = a; + fb.l = b; + set_float_exception_flags(0, &env->fp_status); + r = !float32_eq(fa.f, fb.f, &env->fp_status); + flags = get_float_exception_flags(&env->fp_status); + update_fpu_flags(flags & float_flag_invalid); + + return r; +} + +uint32_t helper_fcmp_ge(uint32_t a, uint32_t b) +{ + CPU_FloatU fa, fb; + int flags, r; + + fa.l = a; + fb.l = b; + set_float_exception_flags(0, &env->fp_status); + r = !float32_lt(fa.f, fb.f, &env->fp_status); + flags = get_float_exception_flags(&env->fp_status); + update_fpu_flags(flags & float_flag_invalid); + + return r; +} + +uint32_t helper_flt(uint32_t a) +{ + CPU_FloatU fd, fa; + + fa.l = a; + fd.f = int32_to_float32(fa.l, &env->fp_status); + return fd.l; +} + +uint32_t helper_fint(uint32_t a) +{ + CPU_FloatU fa; + uint32_t r; + int flags; + + set_float_exception_flags(0, &env->fp_status); + fa.l = a; + r = float32_to_int32(fa.f, &env->fp_status); + flags = get_float_exception_flags(&env->fp_status); + update_fpu_flags(flags); + + return r; +} + +uint32_t helper_fsqrt(uint32_t a) +{ + CPU_FloatU fd, fa; + int flags; + + set_float_exception_flags(0, &env->fp_status); + fa.l = a; + fd.l = float32_sqrt(fa.f, &env->fp_status); + flags = get_float_exception_flags(&env->fp_status); + update_fpu_flags(flags); + + return fd.l; +} + uint32_t helper_pcmpbf(uint32_t a, uint32_t b) { unsigned int i; @@ -201,6 +422,25 @@ uint32_t helper_pcmpbf(uint32_t a, uint3 return 0; } +void helper_memalign(uint32_t addr, uint32_t dr, uint32_t wr, uint32_t mask) +{ + if (addr & mask) { + qemu_log_mask(CPU_LOG_INT, + "unaligned access addr=%x mask=%x, wr=%d dr=r%d\n", + addr, mask, wr, dr); + env->sregs[SR_EAR] = addr; + env->sregs[SR_ESR] = ESR_EC_UNALIGNED_DATA | (wr << 10) \ + | (dr & 31) << 5; + if (mask == 3) { + env->sregs[SR_ESR] |= 1 << 11; + } + if (!(env->sregs[SR_MSR] & MSR_EE)) { + return; + } + helper_raise_exception(EXCP_HW_EXCP); + } +} + #if !defined(CONFIG_USER_ONLY) /* Writes/reads to the MMU's special regs end up here. */ uint32_t helper_mmu_read(uint32_t rn) @@ -212,4 +452,40 @@ void helper_mmu_write(uint32_t rn, uint3 { mmu_write(env, rn, v); } + +void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, + int is_asi, int size) +{ + CPUState *saved_env; + + if (!cpu_single_env) { + /* XXX: ??? */ + return; + } + + /* XXX: hack to restore env in all cases, even if not called from + generated code */ + saved_env = env; + env = cpu_single_env; + qemu_log_mask(CPU_LOG_INT, "Unassigned " TARGET_FMT_plx " wr=%d exe=%d\n", + addr, is_write, is_exec); + if (!(env->sregs[SR_MSR] & MSR_EE)) { + env = saved_env; + return; + } + + env->sregs[SR_EAR] = addr; + if (is_exec) { + if ((env->pvr.regs[2] & PVR2_IOPB_BUS_EXC_MASK)) { + env->sregs[SR_ESR] = ESR_EC_INSN_BUS; + helper_raise_exception(EXCP_HW_EXCP); + } + } else { + if ((env->pvr.regs[2] & PVR2_DOPB_BUS_EXC_MASK)) { + env->sregs[SR_ESR] = ESR_EC_DATA_BUS; + helper_raise_exception(EXCP_HW_EXCP); + } + } + env = saved_env; +} #endif