*/
#include <stdlib.h>
#include "cpu.h"
-#include "host-utils.h"
+#include "qemu/host-utils.h"
#include "helper.h"
#if !defined(CONFIG_USER_ONLY)
-#include "softmmu_exec.h"
+#include "exec/softmmu_exec.h"
#endif /* !defined(CONFIG_USER_ONLY) */
#ifndef CONFIG_USER_ONLY
/*****************************************************************************/
/* Exceptions processing helpers */
-void helper_raise_exception_err(CPUMIPSState *env, uint32_t exception,
- int error_code)
+static inline void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env,
+ uint32_t exception,
+ int error_code,
+ uintptr_t pc)
{
-#if 1
- if (exception < 0x100)
+ if (exception < EXCP_SC) {
qemu_log("%s: %d %d\n", __func__, exception, error_code);
-#endif
+ }
env->exception_index = exception;
env->error_code = error_code;
+
+ if (pc) {
+ /* now we have a real cpu fault */
+ cpu_restore_state(env, pc);
+ }
+
cpu_loop_exit(env);
}
-void helper_raise_exception(CPUMIPSState *env, uint32_t exception)
+static inline void QEMU_NORETURN do_raise_exception(CPUMIPSState *env,
+ uint32_t exception,
+ uintptr_t pc)
{
- helper_raise_exception_err(env, exception, 0);
+ do_raise_exception_err(env, exception, 0, pc);
}
-#if !defined(CONFIG_USER_ONLY)
-static void do_restore_state(CPUMIPSState *env, uintptr_t pc)
+void helper_raise_exception_err(CPUMIPSState *env, uint32_t exception,
+ int error_code)
{
- TranslationBlock *tb;
+ do_raise_exception_err(env, exception, error_code, 0);
+}
- tb = tb_find_pc (pc);
- if (tb) {
- cpu_restore_state(tb, env, pc);
- }
+void helper_raise_exception(CPUMIPSState *env, uint32_t exception)
+{
+ do_raise_exception(env, exception, 0);
}
-#endif
#if defined(CONFIG_USER_ONLY)
#define HELPER_LD(name, insn, type) \
(uint64_t)(uint32_t)arg2);
}
-#ifdef TARGET_MIPS64
-void helper_dmult(CPUMIPSState *env, target_ulong arg1, target_ulong arg2)
-{
- muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
-}
-
-void helper_dmultu(CPUMIPSState *env, target_ulong arg1, target_ulong arg2)
-{
- mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
-}
-#endif
-
#ifndef CONFIG_USER_ONLY
static inline hwaddr do_translate_address(CPUMIPSState *env,
#define GET_OFFSET(addr, offset) (addr - (offset))
#endif
-target_ulong helper_lwl(CPUMIPSState *env, target_ulong arg1,
- target_ulong arg2, int mem_idx)
-{
- target_ulong tmp;
-
- tmp = do_lbu(env, arg2, mem_idx);
- arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
-
- if (GET_LMASK(arg2) <= 2) {
- tmp = do_lbu(env, GET_OFFSET(arg2, 1), mem_idx);
- arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
- }
-
- if (GET_LMASK(arg2) <= 1) {
- tmp = do_lbu(env, GET_OFFSET(arg2, 2), mem_idx);
- arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
- }
-
- if (GET_LMASK(arg2) == 0) {
- tmp = do_lbu(env, GET_OFFSET(arg2, 3), mem_idx);
- arg1 = (arg1 & 0xFFFFFF00) | tmp;
- }
- return (int32_t)arg1;
-}
-
-target_ulong helper_lwr(CPUMIPSState *env, target_ulong arg1,
- target_ulong arg2, int mem_idx)
-{
- target_ulong tmp;
-
- tmp = do_lbu(env, arg2, mem_idx);
- arg1 = (arg1 & 0xFFFFFF00) | tmp;
-
- if (GET_LMASK(arg2) >= 1) {
- tmp = do_lbu(env, GET_OFFSET(arg2, -1), mem_idx);
- arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
- }
-
- if (GET_LMASK(arg2) >= 2) {
- tmp = do_lbu(env, GET_OFFSET(arg2, -2), mem_idx);
- arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
- }
-
- if (GET_LMASK(arg2) == 3) {
- tmp = do_lbu(env, GET_OFFSET(arg2, -3), mem_idx);
- arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
- }
- return (int32_t)arg1;
-}
-
void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
int mem_idx)
{
#define GET_LMASK64(v) (((v) & 7) ^ 7)
#endif
-target_ulong helper_ldl(CPUMIPSState *env, target_ulong arg1,
- target_ulong arg2, int mem_idx)
-{
- uint64_t tmp;
-
- tmp = do_lbu(env, arg2, mem_idx);
- arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
-
- if (GET_LMASK64(arg2) <= 6) {
- tmp = do_lbu(env, GET_OFFSET(arg2, 1), mem_idx);
- arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
- }
-
- if (GET_LMASK64(arg2) <= 5) {
- tmp = do_lbu(env, GET_OFFSET(arg2, 2), mem_idx);
- arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
- }
-
- if (GET_LMASK64(arg2) <= 4) {
- tmp = do_lbu(env, GET_OFFSET(arg2, 3), mem_idx);
- arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
- }
-
- if (GET_LMASK64(arg2) <= 3) {
- tmp = do_lbu(env, GET_OFFSET(arg2, 4), mem_idx);
- arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
- }
-
- if (GET_LMASK64(arg2) <= 2) {
- tmp = do_lbu(env, GET_OFFSET(arg2, 5), mem_idx);
- arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
- }
-
- if (GET_LMASK64(arg2) <= 1) {
- tmp = do_lbu(env, GET_OFFSET(arg2, 6), mem_idx);
- arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8);
- }
-
- if (GET_LMASK64(arg2) == 0) {
- tmp = do_lbu(env, GET_OFFSET(arg2, 7), mem_idx);
- arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
- }
-
- return arg1;
-}
-
-target_ulong helper_ldr(CPUMIPSState *env, target_ulong arg1,
- target_ulong arg2, int mem_idx)
-{
- uint64_t tmp;
-
- tmp = do_lbu(env, arg2, mem_idx);
- arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
-
- if (GET_LMASK64(arg2) >= 1) {
- tmp = do_lbu(env, GET_OFFSET(arg2, -1), mem_idx);
- arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8);
- }
-
- if (GET_LMASK64(arg2) >= 2) {
- tmp = do_lbu(env, GET_OFFSET(arg2, -2), mem_idx);
- arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
- }
-
- if (GET_LMASK64(arg2) >= 3) {
- tmp = do_lbu(env, GET_OFFSET(arg2, -3), mem_idx);
- arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
- }
-
- if (GET_LMASK64(arg2) >= 4) {
- tmp = do_lbu(env, GET_OFFSET(arg2, -4), mem_idx);
- arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
- }
-
- if (GET_LMASK64(arg2) >= 5) {
- tmp = do_lbu(env, GET_OFFSET(arg2, -5), mem_idx);
- arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
- }
-
- if (GET_LMASK64(arg2) >= 6) {
- tmp = do_lbu(env, GET_OFFSET(arg2, -6), mem_idx);
- arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
- }
-
- if (GET_LMASK64(arg2) == 7) {
- tmp = do_lbu(env, GET_OFFSET(arg2, -7), mem_idx);
- arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
- }
-
- return arg1;
-}
-
void helper_sdl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
int mem_idx)
{
{
target_ulong base_reglist = reglist & 0xf;
target_ulong do_r31 = reglist & 0x10;
-#ifdef CONFIG_USER_ONLY
-#undef ldfun
-#define ldfun(env, addr) ldl_raw(addr)
-#else
- uint32_t (*ldfun)(CPUMIPSState *env, target_ulong);
-
- switch (mem_idx)
- {
- case 0: ldfun = cpu_ldl_kernel; break;
- case 1: ldfun = cpu_ldl_super; break;
- default:
- case 2: ldfun = cpu_ldl_user; break;
- }
-#endif
if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
target_ulong i;
for (i = 0; i < base_reglist; i++) {
- env->active_tc.gpr[multiple_regs[i]] = (target_long)ldfun(env, addr);
+ env->active_tc.gpr[multiple_regs[i]] =
+ (target_long)do_lw(env, addr, mem_idx);
addr += 4;
}
}
if (do_r31) {
- env->active_tc.gpr[31] = (target_long)ldfun(env, addr);
+ env->active_tc.gpr[31] = (target_long)do_lw(env, addr, mem_idx);
}
}
{
target_ulong base_reglist = reglist & 0xf;
target_ulong do_r31 = reglist & 0x10;
-#ifdef CONFIG_USER_ONLY
-#undef stfun
-#define stfun(env, addr, val) stl_raw(addr, val)
-#else
- void (*stfun)(CPUMIPSState *env, target_ulong, uint32_t);
-
- switch (mem_idx)
- {
- case 0: stfun = cpu_stl_kernel; break;
- case 1: stfun = cpu_stl_super; break;
- default:
- case 2: stfun = cpu_stl_user; break;
- }
-#endif
if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
target_ulong i;
for (i = 0; i < base_reglist; i++) {
- stfun(env, addr, env->active_tc.gpr[multiple_regs[i]]);
+ do_sw(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx);
addr += 4;
}
}
if (do_r31) {
- stfun(env, addr, env->active_tc.gpr[31]);
+ do_sw(env, addr, env->active_tc.gpr[31], mem_idx);
}
}
{
target_ulong base_reglist = reglist & 0xf;
target_ulong do_r31 = reglist & 0x10;
-#ifdef CONFIG_USER_ONLY
-#undef ldfun
-#define ldfun(env, addr) ldq_raw(addr)
-#else
- uint64_t (*ldfun)(CPUMIPSState *env, target_ulong);
-
- switch (mem_idx)
- {
- case 0: ldfun = cpu_ldq_kernel; break;
- case 1: ldfun = cpu_ldq_super; break;
- default:
- case 2: ldfun = cpu_ldq_user; break;
- }
-#endif
if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
target_ulong i;
for (i = 0; i < base_reglist; i++) {
- env->active_tc.gpr[multiple_regs[i]] = ldfun(env, addr);
+ env->active_tc.gpr[multiple_regs[i]] = do_ld(env, addr, mem_idx);
addr += 8;
}
}
if (do_r31) {
- env->active_tc.gpr[31] = ldfun(env, addr);
+ env->active_tc.gpr[31] = do_ld(env, addr, mem_idx);
}
}
{
target_ulong base_reglist = reglist & 0xf;
target_ulong do_r31 = reglist & 0x10;
-#ifdef CONFIG_USER_ONLY
-#undef stfun
-#define stfun(env, addr, val) stq_raw(addr, val)
-#else
- void (*stfun)(CPUMIPSState *env, target_ulong, uint64_t);
-
- switch (mem_idx)
- {
- case 0: stfun = cpu_stq_kernel; break;
- case 1: stfun = cpu_stq_super; break;
- default:
- case 2: stfun = cpu_stq_user; break;
- }
-#endif
if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
target_ulong i;
for (i = 0; i < base_reglist; i++) {
- stfun(env, addr, env->active_tc.gpr[multiple_regs[i]]);
+ do_sd(env, addr, env->active_tc.gpr[multiple_regs[i]], mem_idx);
addr += 8;
}
}
if (do_r31) {
- stfun(env, addr, env->active_tc.gpr[31]);
+ do_sd(env, addr, env->active_tc.gpr[31], mem_idx);
}
}
#endif
/* SMP helpers. */
static bool mips_vpe_is_wfi(MIPSCPU *c)
{
+ CPUState *cpu = CPU(c);
CPUMIPSState *env = &c->env;
/* If the VPE is halted but otherwise active, it means it's waiting for
an interrupt. */
- return env->halted && mips_vpe_active(env);
+ return cpu->halted && mips_vpe_active(env);
}
-static inline void mips_vpe_wake(CPUMIPSState *c)
+static inline void mips_vpe_wake(MIPSCPU *c)
{
/* Dont set ->halted = 0 directly, let it be done via cpu_has_work
because there might be other conditions that state that c should
be sleeping. */
- cpu_interrupt(c, CPU_INTERRUPT_WAKE);
+ cpu_interrupt(CPU(c), CPU_INTERRUPT_WAKE);
}
static inline void mips_vpe_sleep(MIPSCPU *cpu)
{
- CPUMIPSState *c = &cpu->env;
+ CPUState *cs = CPU(cpu);
/* The VPE was shut off, really go to bed.
Reset any old _WAKE requests. */
- c->halted = 1;
- cpu_reset_interrupt(c, CPU_INTERRUPT_WAKE);
+ cs->halted = 1;
+ cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
}
static inline void mips_tc_wake(MIPSCPU *cpu, int tc)
/* FIXME: TC reschedule. */
if (mips_vpe_active(c) && !mips_vpe_is_wfi(cpu)) {
- mips_vpe_wake(c);
+ mips_vpe_wake(cpu);
}
}
}
}
-/* tc should point to an int with the value of the global TC index.
- This function will transform it into a local index within the
- returned CPUMIPSState.
-
- FIXME: This code assumes that all VPEs have the same number of TCs,
+/**
+ * mips_cpu_map_tc:
+ * @env: CPU from which mapping is performed.
+ * @tc: Should point to an int with the value of the global TC index.
+ *
+ * This function will transform @tc into a local index within the
+ * returned #CPUMIPSState.
+ */
+/* FIXME: This code assumes that all VPEs have the same number of TCs,
which depends on runtime setup. Can probably be fixed by
walking the list of CPUMIPSStates. */
static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc)
{
- CPUMIPSState *other;
- int vpe_idx, nr_threads = env->nr_threads;
+ MIPSCPU *cpu;
+ CPUState *cs;
+ CPUState *other_cs;
+ int vpe_idx;
int tc_idx = *tc;
if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))) {
return env;
}
- vpe_idx = tc_idx / nr_threads;
- *tc = tc_idx % nr_threads;
- other = qemu_get_cpu(vpe_idx);
- return other ? other : env;
+ cs = CPU(mips_env_get_cpu(env));
+ vpe_idx = tc_idx / cs->nr_threads;
+ *tc = tc_idx % cs->nr_threads;
+ other_cs = qemu_get_cpu(vpe_idx);
+ if (other_cs == NULL) {
+ return env;
+ }
+ cpu = MIPS_CPU(other_cs);
+ return &cpu->env;
}
/* The per VPE CP0_Status register shares some fields with the per TC
&& !mips_vpe_is_wfi(other_cpu)) {
/* Enable the VPE. */
other_cpu_env->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
- mips_vpe_wake(other_cpu_env); /* And wake it up. */
+ mips_vpe_wake(other_cpu); /* And wake it up. */
}
other_cpu_env = other_cpu_env->next_cpu;
} while (other_cpu_env);
void r4k_helper_tlbwi(CPUMIPSState *env)
{
+ r4k_tlb_t *tlb;
int idx;
+ target_ulong VPN;
+ uint8_t ASID;
+ bool G, V0, D0, V1, D1;
idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
+ tlb = &env->tlb->mmu.r4k.tlb[idx];
+ VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
+#if defined(TARGET_MIPS64)
+ VPN &= env->SEGMask;
+#endif
+ ASID = env->CP0_EntryHi & 0xff;
+ G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
+ V0 = (env->CP0_EntryLo0 & 2) != 0;
+ D0 = (env->CP0_EntryLo0 & 4) != 0;
+ V1 = (env->CP0_EntryLo1 & 2) != 0;
+ D1 = (env->CP0_EntryLo1 & 4) != 0;
- /* Discard cached TLB entries. We could avoid doing this if the
- tlbwi is just upgrading access permissions on the current entry;
- that might be a further win. */
- r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb);
+ /* Discard cached TLB entries, unless tlbwi is just upgrading access
+ permissions on the current entry. */
+ if (tlb->VPN != VPN || tlb->ASID != ASID || tlb->G != G ||
+ (tlb->V0 && !V0) || (tlb->D0 && !D0) ||
+ (tlb->V1 && !V1) || (tlb->D1 && !D1)) {
+ r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
+ }
r4k_invalidate_tlb(env, idx, 0);
r4k_fill_tlb(env, idx);
mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
tag = env->CP0_EntryHi & ~mask;
VPN = tlb->VPN & ~mask;
+#if defined(TARGET_MIPS64)
+ tag &= env->SEGMask;
+#endif
/* Check ASID, virtual page number & size */
if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
/* TLB match */
mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
tag = env->CP0_EntryHi & ~mask;
VPN = tlb->VPN & ~mask;
+#if defined(TARGET_MIPS64)
+ tag &= env->SEGMask;
+#endif
/* Check ASID, virtual page number & size */
if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
r4k_mips_tlb_flush_extra (env, i);
void helper_wait(CPUMIPSState *env)
{
- env->halted = 1;
- cpu_reset_interrupt(env, CPU_INTERRUPT_WAKE);
+ CPUState *cs = CPU(mips_env_get_cpu(env));
+
+ cs->halted = 1;
+ cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
helper_raise_exception(env, EXCP_HLT);
}
#define ALIGNED_ONLY
#define SHIFT 0
-#include "softmmu_template.h"
+#include "exec/softmmu_template.h"
#define SHIFT 1
-#include "softmmu_template.h"
+#include "exec/softmmu_template.h"
#define SHIFT 2
-#include "softmmu_template.h"
+#include "exec/softmmu_template.h"
#define SHIFT 3
-#include "softmmu_template.h"
+#include "exec/softmmu_template.h"
static void do_unaligned_access(CPUMIPSState *env, target_ulong addr,
int is_write, int is_user, uintptr_t retaddr)
{
env->CP0_BadVAddr = addr;
- do_restore_state(env, retaddr);
- helper_raise_exception(env, (is_write == 1) ? EXCP_AdES : EXCP_AdEL);
+ do_raise_exception(env, (is_write == 1) ? EXCP_AdES : EXCP_AdEL, retaddr);
}
void tlb_fill(CPUMIPSState *env, target_ulong addr, int is_write, int mmu_idx,
uintptr_t retaddr)
{
- TranslationBlock *tb;
int ret;
ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx);
if (ret) {
- if (retaddr) {
- /* now we have a real cpu fault */
- tb = tb_find_pc(retaddr);
- if (tb) {
- /* the PC is inside the translated code. It means that we have
- a virtual CPU fault */
- cpu_restore_state(tb, env, retaddr);
- }
- }
- helper_raise_exception_err(env, env->exception_index, env->error_code);
+ do_raise_exception_err(env, env->exception_index,
+ env->error_code, retaddr);
}
}
/* Complex FPU operations which may need stack space. */
-#define FLOAT_ONE32 make_float32(0x3f8 << 20)
-#define FLOAT_ONE64 make_float64(0x3ffULL << 52)
#define FLOAT_TWO32 make_float32(1 << 30)
#define FLOAT_TWO64 make_float64(1ULL << 62)
-#define FLOAT_QNAN32 0x7fbfffff
-#define FLOAT_QNAN64 0x7ff7ffffffffffffULL
-#define FLOAT_SNAN32 0x7fffffff
-#define FLOAT_SNAN64 0x7fffffffffffffffULL
+#define FP_TO_INT32_OVERFLOW 0x7fffffff
+#define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL
/* convert MIPS rounding mode in FCR31 to IEEE library */
static unsigned int ieee_rm[] = {
float_round_down
};
-#define RESTORE_ROUNDING_MODE \
- set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], &env->active_fpu.fp_status)
+static inline void restore_rounding_mode(CPUMIPSState *env)
+{
+ set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3],
+ &env->active_fpu.fp_status);
+}
-#define RESTORE_FLUSH_MODE \
- set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, &env->active_fpu.fp_status);
+static inline void restore_flush_mode(CPUMIPSState *env)
+{
+ set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0,
+ &env->active_fpu.fp_status);
+}
target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg)
{
return;
}
/* set rounding mode */
- RESTORE_ROUNDING_MODE;
+ restore_rounding_mode(env);
/* set flush-to-zero mode */
- RESTORE_FLUSH_MODE;
+ restore_flush_mode(env);
set_float_exception_flags(0, &env->active_fpu.fp_status);
if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31))
- helper_raise_exception(env, EXCP_FPE);
+ do_raise_exception(env, EXCP_FPE, GETPC());
}
static inline int ieee_ex_to_mips(int xcpt)
return ret;
}
-static inline void update_fcr31(CPUMIPSState *env)
+static inline void update_fcr31(CPUMIPSState *env, uintptr_t pc)
{
int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
- if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp)
- helper_raise_exception(env, EXCP_FPE);
- else
- UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
+
+ if (tmp) {
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
+
+ if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp) {
+ do_raise_exception(env, EXCP_FPE, pc);
+ } else {
+ UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
+ }
+ }
}
/* Float support.
/* unary operations, modifying fp status */
uint64_t helper_float_sqrt_d(CPUMIPSState *env, uint64_t fdt0)
{
- return float64_sqrt(fdt0, &env->active_fpu.fp_status);
+ fdt0 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
+ return fdt0;
}
uint32_t helper_float_sqrt_s(CPUMIPSState *env, uint32_t fst0)
{
- return float32_sqrt(fst0, &env->active_fpu.fp_status);
+ fst0 = float32_sqrt(fst0, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
+ return fst0;
}
uint64_t helper_float_cvtd_s(CPUMIPSState *env, uint32_t fst0)
{
uint64_t fdt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
- update_fcr31(env);
+ update_fcr31(env, GETPC());
return fdt2;
}
{
uint64_t fdt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
- update_fcr31(env);
+ update_fcr31(env, GETPC());
return fdt2;
}
{
uint64_t fdt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
- update_fcr31(env);
+ update_fcr31(env, GETPC());
return fdt2;
}
{
uint64_t dt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
- update_fcr31(env);
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
- dt2 = FLOAT_SNAN64;
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ dt2 = FP_TO_INT64_OVERFLOW;
+ }
+ update_fcr31(env, GETPC());
return dt2;
}
{
uint64_t dt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
- update_fcr31(env);
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
- dt2 = FLOAT_SNAN64;
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ dt2 = FP_TO_INT64_OVERFLOW;
+ }
+ update_fcr31(env, GETPC());
return dt2;
}
uint32_t fst2;
uint32_t fsth2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
- update_fcr31(env);
+ update_fcr31(env, GETPC());
return ((uint64_t)fsth2 << 32) | fst2;
}
{
uint32_t wt2;
uint32_t wth2;
+ int excp, excph;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
+ excp = get_float_exception_flags(&env->active_fpu.fp_status);
+ if (excp & (float_flag_overflow | float_flag_invalid)) {
+ wt2 = FP_TO_INT32_OVERFLOW;
+ }
+
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
- update_fcr31(env);
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) {
- wt2 = FLOAT_SNAN32;
- wth2 = FLOAT_SNAN32;
+ excph = get_float_exception_flags(&env->active_fpu.fp_status);
+ if (excph & (float_flag_overflow | float_flag_invalid)) {
+ wth2 = FP_TO_INT32_OVERFLOW;
}
+
+ set_float_exception_flags(excp | excph, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
+
return ((uint64_t)wth2 << 32) | wt2;
}
{
uint32_t fst2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
- update_fcr31(env);
+ update_fcr31(env, GETPC());
return fst2;
}
{
uint32_t fst2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
- update_fcr31(env);
+ update_fcr31(env, GETPC());
return fst2;
}
{
uint32_t fst2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
- update_fcr31(env);
+ update_fcr31(env, GETPC());
return fst2;
}
{
uint32_t wt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
wt2 = wt0;
- update_fcr31(env);
+ update_fcr31(env, GETPC());
return wt2;
}
{
uint32_t wt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
wt2 = wth0;
- update_fcr31(env);
+ update_fcr31(env, GETPC());
return wt2;
}
{
uint32_t wt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
- update_fcr31(env);
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
- wt2 = FLOAT_SNAN32;
+ update_fcr31(env, GETPC());
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ wt2 = FP_TO_INT32_OVERFLOW;
+ }
return wt2;
}
{
uint32_t wt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
- update_fcr31(env);
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
- wt2 = FLOAT_SNAN32;
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ wt2 = FP_TO_INT32_OVERFLOW;
+ }
+ update_fcr31(env, GETPC());
return wt2;
}
{
uint64_t dt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
- RESTORE_ROUNDING_MODE;
- update_fcr31(env);
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
- dt2 = FLOAT_SNAN64;
+ restore_rounding_mode(env);
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ dt2 = FP_TO_INT64_OVERFLOW;
+ }
+ update_fcr31(env, GETPC());
return dt2;
}
{
uint64_t dt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
- RESTORE_ROUNDING_MODE;
- update_fcr31(env);
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
- dt2 = FLOAT_SNAN64;
+ restore_rounding_mode(env);
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ dt2 = FP_TO_INT64_OVERFLOW;
+ }
+ update_fcr31(env, GETPC());
return dt2;
}
{
uint32_t wt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
- RESTORE_ROUNDING_MODE;
- update_fcr31(env);
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
- wt2 = FLOAT_SNAN32;
+ restore_rounding_mode(env);
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ wt2 = FP_TO_INT32_OVERFLOW;
+ }
+ update_fcr31(env, GETPC());
return wt2;
}
{
uint32_t wt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
- RESTORE_ROUNDING_MODE;
- update_fcr31(env);
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
- wt2 = FLOAT_SNAN32;
+ restore_rounding_mode(env);
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ wt2 = FP_TO_INT32_OVERFLOW;
+ }
+ update_fcr31(env, GETPC());
return wt2;
}
{
uint64_t dt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
- update_fcr31(env);
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
- dt2 = FLOAT_SNAN64;
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ dt2 = FP_TO_INT64_OVERFLOW;
+ }
+ update_fcr31(env, GETPC());
return dt2;
}
{
uint64_t dt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
- update_fcr31(env);
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
- dt2 = FLOAT_SNAN64;
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ dt2 = FP_TO_INT64_OVERFLOW;
+ }
+ update_fcr31(env, GETPC());
return dt2;
}
{
uint32_t wt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
- update_fcr31(env);
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
- wt2 = FLOAT_SNAN32;
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ wt2 = FP_TO_INT32_OVERFLOW;
+ }
+ update_fcr31(env, GETPC());
return wt2;
}
{
uint32_t wt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
- update_fcr31(env);
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
- wt2 = FLOAT_SNAN32;
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ wt2 = FP_TO_INT32_OVERFLOW;
+ }
+ update_fcr31(env, GETPC());
return wt2;
}
{
uint64_t dt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
- RESTORE_ROUNDING_MODE;
- update_fcr31(env);
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
- dt2 = FLOAT_SNAN64;
+ restore_rounding_mode(env);
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ dt2 = FP_TO_INT64_OVERFLOW;
+ }
+ update_fcr31(env, GETPC());
return dt2;
}
{
uint64_t dt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
- RESTORE_ROUNDING_MODE;
- update_fcr31(env);
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
- dt2 = FLOAT_SNAN64;
+ restore_rounding_mode(env);
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ dt2 = FP_TO_INT64_OVERFLOW;
+ }
+ update_fcr31(env, GETPC());
return dt2;
}
{
uint32_t wt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
- RESTORE_ROUNDING_MODE;
- update_fcr31(env);
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
- wt2 = FLOAT_SNAN32;
+ restore_rounding_mode(env);
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ wt2 = FP_TO_INT32_OVERFLOW;
+ }
+ update_fcr31(env, GETPC());
return wt2;
}
{
uint32_t wt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
- RESTORE_ROUNDING_MODE;
- update_fcr31(env);
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
- wt2 = FLOAT_SNAN32;
+ restore_rounding_mode(env);
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ wt2 = FP_TO_INT32_OVERFLOW;
+ }
+ update_fcr31(env, GETPC());
return wt2;
}
{
uint64_t dt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
- RESTORE_ROUNDING_MODE;
- update_fcr31(env);
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
- dt2 = FLOAT_SNAN64;
+ restore_rounding_mode(env);
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ dt2 = FP_TO_INT64_OVERFLOW;
+ }
+ update_fcr31(env, GETPC());
return dt2;
}
{
uint64_t dt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
- RESTORE_ROUNDING_MODE;
- update_fcr31(env);
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
- dt2 = FLOAT_SNAN64;
+ restore_rounding_mode(env);
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ dt2 = FP_TO_INT64_OVERFLOW;
+ }
+ update_fcr31(env, GETPC());
return dt2;
}
{
uint32_t wt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
- RESTORE_ROUNDING_MODE;
- update_fcr31(env);
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
- wt2 = FLOAT_SNAN32;
+ restore_rounding_mode(env);
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ wt2 = FP_TO_INT32_OVERFLOW;
+ }
+ update_fcr31(env, GETPC());
return wt2;
}
{
uint32_t wt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
- RESTORE_ROUNDING_MODE;
- update_fcr31(env);
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
- wt2 = FLOAT_SNAN32;
+ restore_rounding_mode(env);
+ if (get_float_exception_flags(&env->active_fpu.fp_status)
+ & (float_flag_invalid | float_flag_overflow)) {
+ wt2 = FP_TO_INT32_OVERFLOW;
+ }
+ update_fcr31(env, GETPC());
return wt2;
}
{
uint64_t fdt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
- fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
- update_fcr31(env);
+ fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
return fdt2;
}
{
uint32_t fst2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
- fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
- update_fcr31(env);
+ fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
return fst2;
}
{
uint64_t fdt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
- fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
- update_fcr31(env);
+ fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
return fdt2;
}
{
uint32_t fst2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
- fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
- update_fcr31(env);
+ fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
return fst2;
}
{
uint64_t fdt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
- fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
- update_fcr31(env);
+ fdt2 = float64_div(float64_one, fdt0, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
return fdt2;
}
{
uint32_t fst2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
- fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
- update_fcr31(env);
+ fst2 = float32_div(float32_one, fst0, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
return fst2;
}
uint32_t fst2;
uint32_t fsth2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
- fst2 = float32_div(FLOAT_ONE32, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
- fsth2 = float32_div(FLOAT_ONE32, fdt0 >> 32, &env->active_fpu.fp_status);
- update_fcr31(env);
+ fst2 = float32_div(float32_one, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
+ fsth2 = float32_div(float32_one, fdt0 >> 32, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
return ((uint64_t)fsth2 << 32) | fst2;
}
{
uint64_t fdt2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
- fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
- update_fcr31(env);
+ fdt2 = float64_div(float64_one, fdt2, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
return fdt2;
}
{
uint32_t fst2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
- fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
- update_fcr31(env);
+ fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
return fst2;
}
uint32_t fst2;
uint32_t fsth2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
- fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
- fsth2 = float32_div(FLOAT_ONE32, fsth2, &env->active_fpu.fp_status);
- update_fcr31(env);
+ fst2 = float32_div(float32_one, fst2, &env->active_fpu.fp_status);
+ fsth2 = float32_div(float32_one, fsth2, &env->active_fpu.fp_status);
+ update_fcr31(env, GETPC());
return ((uint64_t)fsth2 << 32) | fst2;
}
{ \
uint64_t dt2; \
\
- set_float_exception_flags(0, &env->active_fpu.fp_status); \
dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status); \
- update_fcr31(env); \
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) \
- dt2 = FLOAT_QNAN64; \
+ update_fcr31(env, GETPC()); \
return dt2; \
} \
\
{ \
uint32_t wt2; \
\
- set_float_exception_flags(0, &env->active_fpu.fp_status); \
wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \
- update_fcr31(env); \
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) \
- wt2 = FLOAT_QNAN32; \
+ update_fcr31(env, GETPC()); \
return wt2; \
} \
\
uint32_t wt2; \
uint32_t wth2; \
\
- set_float_exception_flags(0, &env->active_fpu.fp_status); \
wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \
wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status); \
- update_fcr31(env); \
- if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) { \
- wt2 = FLOAT_QNAN32; \
- wth2 = FLOAT_QNAN32; \
- } \
+ update_fcr31(env, GETPC()); \
return ((uint64_t)wth2 << 32) | wt2; \
}
FLOAT_BINOP(div)
#undef FLOAT_BINOP
+#define UNFUSED_FMA(prefix, a, b, c, flags) \
+{ \
+ a = prefix##_mul(a, b, &env->active_fpu.fp_status); \
+ if ((flags) & float_muladd_negate_c) { \
+ a = prefix##_sub(a, c, &env->active_fpu.fp_status); \
+ } else { \
+ a = prefix##_add(a, c, &env->active_fpu.fp_status); \
+ } \
+ if ((flags) & float_muladd_negate_result) { \
+ a = prefix##_chs(a); \
+ } \
+}
+
/* FMA based operations */
#define FLOAT_FMA(name, type) \
uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \
uint64_t fdt0, uint64_t fdt1, \
uint64_t fdt2) \
{ \
- set_float_exception_flags(0, &env->active_fpu.fp_status); \
- fdt0 = float64_muladd(fdt0, fdt1, fdt2, type, \
- &env->active_fpu.fp_status); \
- update_fcr31(env); \
+ UNFUSED_FMA(float64, fdt0, fdt1, fdt2, type); \
+ update_fcr31(env, GETPC()); \
return fdt0; \
} \
\
uint32_t fst0, uint32_t fst1, \
uint32_t fst2) \
{ \
- set_float_exception_flags(0, &env->active_fpu.fp_status); \
- fst0 = float32_muladd(fst0, fst1, fst2, type, \
- &env->active_fpu.fp_status); \
- update_fcr31(env); \
+ UNFUSED_FMA(float32, fst0, fst1, fst2, type); \
+ update_fcr31(env, GETPC()); \
return fst0; \
} \
\
uint32_t fst2 = fdt2 & 0XFFFFFFFF; \
uint32_t fsth2 = fdt2 >> 32; \
\
- set_float_exception_flags(0, &env->active_fpu.fp_status); \
- fst0 = float32_muladd(fst0, fst1, fst2, type, \
- &env->active_fpu.fp_status); \
- fsth0 = float32_muladd(fsth0, fsth1, fsth2, type, \
- &env->active_fpu.fp_status); \
- update_fcr31(env); \
+ UNFUSED_FMA(float32, fst0, fst1, fst2, type); \
+ UNFUSED_FMA(float32, fsth0, fsth1, fsth2, type); \
+ update_fcr31(env, GETPC()); \
return ((uint64_t)fsth0 << 32) | fst0; \
}
FLOAT_FMA(madd, 0)
/* MIPS specific binary operations */
uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
{
- set_float_exception_flags(0, &env->active_fpu.fp_status);
fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
- fdt2 = float64_chs(float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status));
- update_fcr31(env);
+ fdt2 = float64_chs(float64_sub(fdt2, float64_one, &env->active_fpu.fp_status));
+ update_fcr31(env, GETPC());
return fdt2;
}
uint32_t helper_float_recip2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
{
- set_float_exception_flags(0, &env->active_fpu.fp_status);
fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
- fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status));
- update_fcr31(env);
+ fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
+ update_fcr31(env, GETPC());
return fst2;
}
uint32_t fst2 = fdt2 & 0XFFFFFFFF;
uint32_t fsth2 = fdt2 >> 32;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
- fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status));
- fsth2 = float32_chs(float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status));
- update_fcr31(env);
+ fst2 = float32_chs(float32_sub(fst2, float32_one, &env->active_fpu.fp_status));
+ fsth2 = float32_chs(float32_sub(fsth2, float32_one, &env->active_fpu.fp_status));
+ update_fcr31(env, GETPC());
return ((uint64_t)fsth2 << 32) | fst2;
}
uint64_t helper_float_rsqrt2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2)
{
- set_float_exception_flags(0, &env->active_fpu.fp_status);
fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
- fdt2 = float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status);
+ fdt2 = float64_sub(fdt2, float64_one, &env->active_fpu.fp_status);
fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
- update_fcr31(env);
+ update_fcr31(env, GETPC());
return fdt2;
}
uint32_t helper_float_rsqrt2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2)
{
- set_float_exception_flags(0, &env->active_fpu.fp_status);
fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
- fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status);
+ fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
- update_fcr31(env);
+ update_fcr31(env, GETPC());
return fst2;
}
uint32_t fst2 = fdt2 & 0XFFFFFFFF;
uint32_t fsth2 = fdt2 >> 32;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
- fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status);
- fsth2 = float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status);
+ fst2 = float32_sub(fst2, float32_one, &env->active_fpu.fp_status);
+ fsth2 = float32_sub(fsth2, float32_one, &env->active_fpu.fp_status);
fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status));
- update_fcr31(env);
+ update_fcr31(env, GETPC());
return ((uint64_t)fsth2 << 32) | fst2;
}
uint32_t fst2;
uint32_t fsth2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
- update_fcr31(env);
+ update_fcr31(env, GETPC());
return ((uint64_t)fsth2 << 32) | fst2;
}
uint32_t fst2;
uint32_t fsth2;
- set_float_exception_flags(0, &env->active_fpu.fp_status);
fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
- update_fcr31(env);
+ update_fcr31(env, GETPC());
return ((uint64_t)fsth2 << 32) | fst2;
}
uint64_t fdt1, int cc) \
{ \
int c; \
- set_float_exception_flags(0, &env->active_fpu.fp_status); \
c = cond; \
- update_fcr31(env); \
+ update_fcr31(env, GETPC()); \
if (c) \
SET_FP_COND(cc, env->active_fpu); \
else \
uint64_t fdt1, int cc) \
{ \
int c; \
- set_float_exception_flags(0, &env->active_fpu.fp_status); \
fdt0 = float64_abs(fdt0); \
fdt1 = float64_abs(fdt1); \
c = cond; \
- update_fcr31(env); \
+ update_fcr31(env, GETPC()); \
if (c) \
SET_FP_COND(cc, env->active_fpu); \
else \
uint32_t fst1, int cc) \
{ \
int c; \
- set_float_exception_flags(0, &env->active_fpu.fp_status); \
c = cond; \
- update_fcr31(env); \
+ update_fcr31(env, GETPC()); \
if (c) \
SET_FP_COND(cc, env->active_fpu); \
else \
uint32_t fst1, int cc) \
{ \
int c; \
- set_float_exception_flags(0, &env->active_fpu.fp_status); \
fst0 = float32_abs(fst0); \
fst1 = float32_abs(fst1); \
c = cond; \
- update_fcr31(env); \
+ update_fcr31(env, GETPC()); \
if (c) \
SET_FP_COND(cc, env->active_fpu); \
else \
{ \
uint32_t fst0, fsth0, fst1, fsth1; \
int ch, cl; \
- set_float_exception_flags(0, &env->active_fpu.fp_status); \
fst0 = fdt0 & 0XFFFFFFFF; \
fsth0 = fdt0 >> 32; \
fst1 = fdt1 & 0XFFFFFFFF; \
fsth1 = fdt1 >> 32; \
cl = condl; \
ch = condh; \
- update_fcr31(env); \
+ update_fcr31(env, GETPC()); \
if (cl) \
SET_FP_COND(cc, env->active_fpu); \
else \
fsth1 = float32_abs(fdt1 >> 32); \
cl = condl; \
ch = condh; \
- update_fcr31(env); \
+ update_fcr31(env, GETPC()); \
if (cl) \
SET_FP_COND(cc, env->active_fpu); \
else \