diff --git a/target-mips/cpu.h b/target-mips/cpu.h index d127d00e8f..e0f03eda73 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -81,9 +81,9 @@ struct CPUMIPSState { #define FCR0_REV 0 /* fcsr */ uint32_t fcr31; -#define SET_FP_COND(num,env) do { (env->fcr31) |= ((num) ? (1 << ((num) + 24)) : (1 << ((num) + 23))); } while(0) -#define CLEAR_FP_COND(num,env) do { (env->fcr31) &= ~((num) ? (1 << ((num) + 24)) : (1 << ((num) + 23))); } while(0) -#define IS_FP_COND_SET(num,env) (((env->fcr31) & ((num) ? (1 << ((num) + 24)) : (1 << ((num) + 23)))) != 0) +#define SET_FP_COND(num,env) do { ((env)->fcr31) |= ((num) ? (1 << ((num) + 24)) : (1 << 23)); } while(0) +#define CLEAR_FP_COND(num,env) do { ((env)->fcr31) &= ~((num) ? (1 << ((num) + 24)) : (1 << 23)); } while(0) +#define GET_FP_COND(env) ((((env)->fcr31 >> 24) & 0xfe) | (((env)->fcr31 >> 23) & 0x1)) #define GET_FP_CAUSE(reg) (((reg) >> 12) & 0x3f) #define GET_FP_ENABLE(reg) (((reg) >> 7) & 0x1f) #define GET_FP_FLAGS(reg) (((reg) >> 2) & 0x1f) diff --git a/target-mips/exec.h b/target-mips/exec.h index e82b71651b..7ebfd78e71 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -165,4 +165,75 @@ void cpu_mips_update_irq (CPUState *env); void cpu_mips_clock_init (CPUState *env); void cpu_mips_tlb_flush (CPUState *env, int flush_global); +void do_ctc1 (void); +void do_float_cvtd_s(void); +void do_float_cvtd_w(void); +void do_float_cvtd_l(void); +void do_float_cvtl_d(void); +void do_float_cvtl_s(void); +void do_float_cvtps_pw(void); +void do_float_cvtpw_ps(void); +void do_float_cvts_d(void); +void do_float_cvts_w(void); +void do_float_cvts_l(void); +void do_float_cvts_pl(void); +void do_float_cvts_pu(void); +void do_float_cvtw_s(void); +void do_float_cvtw_d(void); +void do_float_roundl_d(void); +void do_float_roundl_s(void); +void do_float_roundw_d(void); +void do_float_roundw_s(void); +void do_float_truncl_d(void); +void do_float_truncl_s(void); +void do_float_truncw_d(void); +void do_float_truncw_s(void); +void do_float_ceill_d(void); +void do_float_ceill_s(void); +void do_float_ceilw_d(void); +void do_float_ceilw_s(void); +void do_float_floorl_d(void); +void do_float_floorl_s(void); +void do_float_floorw_d(void); +void do_float_floorw_s(void); +void do_float_add_d(void); +void do_float_add_s(void); +void do_float_add_ps(void); +void do_float_sub_d(void); +void do_float_sub_s(void); +void do_float_sub_ps(void); +void do_float_mul_d(void); +void do_float_mul_s(void); +void do_float_mul_ps(void); +void do_float_div_d(void); +void do_float_div_s(void); +void do_float_div_ps(void); +void do_float_addr_ps(void); + +#define CMP_OPS(op) \ +void do_cmp_d_ ## op(long cc); \ +void do_cmpabs_d_ ## op(long cc); \ +void do_cmp_s_ ## op(long cc); \ +void do_cmpabs_s_ ## op(long cc); \ +void do_cmp_ps_ ## op(long cc); \ +void do_cmpabs_ps_ ## op(long cc); + +CMP_OPS(f) +CMP_OPS(un) +CMP_OPS(eq) +CMP_OPS(ueq) +CMP_OPS(olt) +CMP_OPS(ult) +CMP_OPS(ole) +CMP_OPS(ule) +CMP_OPS(sf) +CMP_OPS(ngle) +CMP_OPS(seq) +CMP_OPS(ngl) +CMP_OPS(lt) +CMP_OPS(nge) +CMP_OPS(le) +CMP_OPS(ngt) +#undef CMP_OPS + #endif /* !defined(__QEMU_MIPS_EXEC_H__) */ diff --git a/target-mips/op.c b/target-mips/op.c index e119765b3c..5e3c797323 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -1609,47 +1609,25 @@ void op_cp1_enabled(void) RETURN(); } -/* convert MIPS rounding mode in FCR31 to IEEE library */ -unsigned int ieee_rm[] = { - float_round_nearest_even, - float_round_to_zero, - float_round_up, - float_round_down -}; - -#define RESTORE_ROUNDING_MODE \ - set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status) - -inline char ieee_ex_to_mips(char xcpt) +/* + * Verify if floating point register is valid; an operation is not defined + * if bit 0 of any register specification is set and the FR bit in the + * Status register equals zero, since the register numbers specify an + * even-odd pair of adjacent coprocessor general registers. When the FR bit + * in the Status register equals one, both even and odd register numbers + * are valid. This limitation exists only for 64 bit wide (d,l,ps) registers. + * + * Multiple 64 bit wide registers can be checked by calling + * gen_op_cp1_registers(freg1 | freg2 | ... | fregN); + */ +void op_cp1_registers(void) { - return (xcpt & float_flag_inexact) >> 5 | - (xcpt & float_flag_underflow) >> 3 | - (xcpt & float_flag_overflow) >> 1 | - (xcpt & float_flag_divbyzero) << 1 | - (xcpt & float_flag_invalid) << 4; + if (!(env->CP0_Status & (1 << CP0St_FR)) && (PARAM1 & 1)) { + CALL_FROM_TB1(do_raise_exception, EXCP_RI); + } + RETURN(); } -inline char mips_ex_to_ieee(char xcpt) -{ - return (xcpt & FP_INEXACT) << 5 | - (xcpt & FP_UNDERFLOW) << 3 | - (xcpt & FP_OVERFLOW) << 1 | - (xcpt & FP_DIV0) >> 1 | - (xcpt & FP_INVALID) >> 4; -} - -inline void update_fcr31(void) -{ - int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fp_status)); - - SET_FP_CAUSE(env->fcr31, tmp); - if (GET_FP_ENABLE(env->fcr31) & tmp) - CALL_FROM_TB1(do_raise_exception, EXCP_FPE); - else - UPDATE_FP_FLAGS(env->fcr31, tmp); -} - - void op_cfc1 (void) { switch (T1) { @@ -1675,38 +1653,7 @@ void op_cfc1 (void) void op_ctc1 (void) { - switch(T1) { - case 25: - if (T0 & 0xffffff00) - goto leave; - env->fcr31 = (env->fcr31 & 0x017fffff) | ((T0 & 0xfe) << 24) | - ((T0 & 0x1) << 23); - break; - case 26: - if (T0 & 0x007c0000) - goto leave; - env->fcr31 = (env->fcr31 & 0xfffc0f83) | (T0 & 0x0003f07c); - break; - case 28: - if (T0 & 0x007c0000) - goto leave; - env->fcr31 = (env->fcr31 & 0xfefff07c) | (T0 & 0x00000f83) | - ((T0 & 0x4) << 22); - break; - case 31: - if (T0 & 0x007c0000) - goto leave; - env->fcr31 = T0; - break; - default: - goto leave; - } - /* set rounding mode */ - RESTORE_ROUNDING_MODE; - set_float_exception_flags(0, &env->fp_status); - if ((GET_FP_ENABLE(env->fcr31) | 0x20) & GET_FP_CAUSE(env->fcr31)) - CALL_FROM_TB1(do_raise_exception, EXCP_FPE); - leave: + CALL_FROM_TB0(do_ctc1); DEBUG_FPU_STATE(); RETURN(); } @@ -1762,45 +1709,31 @@ void op_mthc1 (void) FLOAT_OP(cvtd, s) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = float32_to_float64(FST0, &env->fp_status); - update_fcr31(); + CALL_FROM_TB0(do_float_cvtd_s); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvtd, w) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = int32_to_float64(WT0, &env->fp_status); - update_fcr31(); + CALL_FROM_TB0(do_float_cvtd_w); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvtd, l) { - set_float_exception_flags(0, &env->fp_status); - FDT2 = int64_to_float64(DT0, &env->fp_status); - update_fcr31(); + CALL_FROM_TB0(do_float_cvtd_l); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvtl, d) { - set_float_exception_flags(0, &env->fp_status); - DT2 = float64_to_int64(FDT0, &env->fp_status); - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; + CALL_FROM_TB0(do_float_cvtl_d); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvtl, s) { - set_float_exception_flags(0, &env->fp_status); - DT2 = float32_to_int64(FST0, &env->fp_status); - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; + CALL_FROM_TB0(do_float_cvtl_s); DEBUG_FPU_STATE(); RETURN(); } @@ -1813,81 +1746,55 @@ FLOAT_OP(cvtps, s) } FLOAT_OP(cvtps, pw) { - set_float_exception_flags(0, &env->fp_status); - FST2 = int32_to_float32(WT0, &env->fp_status); - FSTH2 = int32_to_float32(WTH0, &env->fp_status); - update_fcr31(); + CALL_FROM_TB0(do_float_cvtps_pw); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvtpw, ps) { - set_float_exception_flags(0, &env->fp_status); - WT2 = float32_to_int32(FST0, &env->fp_status); - WTH2 = float32_to_int32(FSTH0, &env->fp_status); - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; + CALL_FROM_TB0(do_float_cvtpw_ps); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvts, d) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float64_to_float32(FDT0, &env->fp_status); - update_fcr31(); + CALL_FROM_TB0(do_float_cvts_d); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvts, w) { - set_float_exception_flags(0, &env->fp_status); - FST2 = int32_to_float32(WT0, &env->fp_status); - update_fcr31(); + CALL_FROM_TB0(do_float_cvts_w); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvts, l) { - set_float_exception_flags(0, &env->fp_status); - FST2 = int64_to_float32(DT0, &env->fp_status); - update_fcr31(); + CALL_FROM_TB0(do_float_cvts_l); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvts, pl) { - set_float_exception_flags(0, &env->fp_status); - WT2 = WT0; - update_fcr31(); + CALL_FROM_TB0(do_float_cvts_pl); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvts, pu) { - set_float_exception_flags(0, &env->fp_status); - WT2 = WTH0; - update_fcr31(); + CALL_FROM_TB0(do_float_cvts_pu); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvtw, s) { - set_float_exception_flags(0, &env->fp_status); - WT2 = float32_to_int32(FST0, &env->fp_status); - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; + CALL_FROM_TB0(do_float_cvtw_s); DEBUG_FPU_STATE(); RETURN(); } FLOAT_OP(cvtw, d) { - set_float_exception_flags(0, &env->fp_status); - WT2 = float64_to_int32(FDT0, &env->fp_status); - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; + CALL_FROM_TB0(do_float_cvtw_d); DEBUG_FPU_STATE(); RETURN(); } @@ -1917,177 +1824,34 @@ FLOAT_OP(puu, ps) RETURN(); } -FLOAT_OP(roundl, d) -{ - set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - DT2 = float64_round_to_int(FDT0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(roundl, s) -{ - set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - DT2 = float32_round_to_int(FST0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(roundw, d) -{ - set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - WT2 = float64_round_to_int(FDT0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(roundw, s) -{ - set_float_rounding_mode(float_round_nearest_even, &env->fp_status); - WT2 = float32_round_to_int(FST0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; - DEBUG_FPU_STATE(); - RETURN(); +#define FLOAT_ROUNDOP(op, ttype, stype) \ +FLOAT_OP(op ## ttype, stype) \ +{ \ + CALL_FROM_TB0(do_float_ ## op ## ttype ## _ ## stype); \ + DEBUG_FPU_STATE(); \ + RETURN(); \ } -FLOAT_OP(truncl, d) -{ - DT2 = float64_to_int64_round_to_zero(FDT0, &env->fp_status); - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(truncl, s) -{ - DT2 = float32_to_int64_round_to_zero(FST0, &env->fp_status); - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(truncw, d) -{ - WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status); - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(truncw, s) -{ - WT2 = float32_to_int32_round_to_zero(FST0, &env->fp_status); - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; - DEBUG_FPU_STATE(); - RETURN(); -} +FLOAT_ROUNDOP(round, l, d) +FLOAT_ROUNDOP(round, l, s) +FLOAT_ROUNDOP(round, w, d) +FLOAT_ROUNDOP(round, w, s) -FLOAT_OP(ceill, d) -{ - set_float_rounding_mode(float_round_up, &env->fp_status); - DT2 = float64_round_to_int(FDT0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(ceill, s) -{ - set_float_rounding_mode(float_round_up, &env->fp_status); - DT2 = float32_round_to_int(FST0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(ceilw, d) -{ - set_float_rounding_mode(float_round_up, &env->fp_status); - WT2 = float64_round_to_int(FDT0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(ceilw, s) -{ - set_float_rounding_mode(float_round_up, &env->fp_status); - WT2 = float32_round_to_int(FST0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; - DEBUG_FPU_STATE(); - RETURN(); -} +FLOAT_ROUNDOP(trunc, l, d) +FLOAT_ROUNDOP(trunc, l, s) +FLOAT_ROUNDOP(trunc, w, d) +FLOAT_ROUNDOP(trunc, w, s) -FLOAT_OP(floorl, d) -{ - set_float_rounding_mode(float_round_down, &env->fp_status); - DT2 = float64_round_to_int(FDT0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(floorl, s) -{ - set_float_rounding_mode(float_round_down, &env->fp_status); - DT2 = float32_round_to_int(FST0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - DT2 = 0x7fffffffffffffffULL; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(floorw, d) -{ - set_float_rounding_mode(float_round_down, &env->fp_status); - WT2 = float64_round_to_int(FDT0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; - DEBUG_FPU_STATE(); - RETURN(); -} -FLOAT_OP(floorw, s) -{ - set_float_rounding_mode(float_round_down, &env->fp_status); - WT2 = float32_round_to_int(FST0, &env->fp_status); - RESTORE_ROUNDING_MODE; - update_fcr31(); - if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) - WT2 = 0x7fffffff; - DEBUG_FPU_STATE(); - RETURN(); -} +FLOAT_ROUNDOP(ceil, l, d) +FLOAT_ROUNDOP(ceil, l, s) +FLOAT_ROUNDOP(ceil, w, d) +FLOAT_ROUNDOP(ceil, w, s) + +FLOAT_ROUNDOP(floor, l, d) +FLOAT_ROUNDOP(floor, l, s) +FLOAT_ROUNDOP(floor, w, d) +FLOAT_ROUNDOP(floor, w, s) +#undef FLOAR_ROUNDOP FLOAT_OP(movf, d) { @@ -2186,26 +1950,19 @@ FLOAT_OP(movn, ps) #define FLOAT_BINOP(name) \ FLOAT_OP(name, d) \ { \ - set_float_exception_flags(0, &env->fp_status); \ - FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status); \ - update_fcr31(); \ + CALL_FROM_TB0(do_float_ ## name ## _d); \ DEBUG_FPU_STATE(); \ RETURN(); \ } \ FLOAT_OP(name, s) \ { \ - set_float_exception_flags(0, &env->fp_status); \ - FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \ - update_fcr31(); \ + CALL_FROM_TB0(do_float_ ## name ## _s); \ DEBUG_FPU_STATE(); \ RETURN(); \ } \ FLOAT_OP(name, ps) \ { \ - set_float_exception_flags(0, &env->fp_status); \ - FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \ - FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status); \ - update_fcr31(); \ + CALL_FROM_TB0(do_float_ ## name ## _ps); \ DEBUG_FPU_STATE(); \ RETURN(); \ } @@ -2217,10 +1974,7 @@ FLOAT_BINOP(div) FLOAT_OP(addr, ps) { - set_float_exception_flags(0, &env->fp_status); - FST2 = float32_add (FST0, FSTH0, &env->fp_status); - FSTH2 = float32_add (FST1, FSTH1, &env->fp_status); - update_fcr31(); + CALL_FROM_TB0(do_float_addr_ps); DEBUG_FPU_STATE(); RETURN(); } @@ -2390,249 +2144,77 @@ FLOAT_OP(alnv, ps) extern void dump_fpu_s(CPUState *env); -#define FOP_COND_D(op, cond) \ -void op_cmp_d_ ## op (void) \ -{ \ - int c = cond; \ - update_fcr31(); \ - if (c) \ - SET_FP_COND(PARAM1, env); \ - else \ - CLEAR_FP_COND(PARAM1, env); \ - DEBUG_FPU_STATE(); \ - RETURN(); \ -} \ -void op_cmpabs_d_ ## op (void) \ -{ \ - int c; \ - FDT0 &= ~(1ULL << 63); \ - FDT1 &= ~(1ULL << 63); \ - c = cond; \ - update_fcr31(); \ - if (c) \ - SET_FP_COND(PARAM1, env); \ - else \ - CLEAR_FP_COND(PARAM1, env); \ - DEBUG_FPU_STATE(); \ - RETURN(); \ +#define CMP_OP(fmt, op) \ +void OPPROTO op_cmp ## _ ## fmt ## _ ## op(void) \ +{ \ + CALL_FROM_TB1(do_cmp ## _ ## fmt ## _ ## op, PARAM1); \ + DEBUG_FPU_STATE(); \ + RETURN(); \ +} \ +void OPPROTO op_cmpabs ## _ ## fmt ## _ ## op(void) \ +{ \ + CALL_FROM_TB1(do_cmpabs ## _ ## fmt ## _ ## op, PARAM1); \ + DEBUG_FPU_STATE(); \ + RETURN(); \ } +#define CMP_OPS(op) \ +CMP_OP(d, op) \ +CMP_OP(s, op) \ +CMP_OP(ps, op) -int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM) -{ - if (float64_is_signaling_nan(a) || - float64_is_signaling_nan(b) || - (sig && (float64_is_nan(a) || float64_is_nan(b)))) { - float_raise(float_flag_invalid, status); - return 1; - } else if (float64_is_nan(a) || float64_is_nan(b)) { - return 1; - } else { - return 0; - } -} - -/* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_D(f, (float64_is_unordered(0, FDT1, FDT0, &env->fp_status), 0)) -FOP_COND_D(un, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)) -FOP_COND_D(eq, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) -/* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_D(sf, (float64_is_unordered(1, FDT1, FDT0, &env->fp_status), 0)) -FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fp_status)) -FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(lt, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(le, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status)) -FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) - -#define FOP_COND_S(op, cond) \ -void op_cmp_s_ ## op (void) \ -{ \ - int c = cond; \ - update_fcr31(); \ - if (c) \ - SET_FP_COND(PARAM1, env); \ - else \ - CLEAR_FP_COND(PARAM1, env); \ - DEBUG_FPU_STATE(); \ - RETURN(); \ -} \ -void op_cmpabs_s_ ## op (void) \ -{ \ - int c; \ - FST0 &= ~(1 << 31); \ - FST1 &= ~(1 << 31); \ - c = cond; \ - update_fcr31(); \ - if (c) \ - SET_FP_COND(PARAM1, env); \ - else \ - CLEAR_FP_COND(PARAM1, env); \ - DEBUG_FPU_STATE(); \ - RETURN(); \ -} - -flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM) -{ - extern flag float32_is_nan(float32 a); - if (float32_is_signaling_nan(a) || - float32_is_signaling_nan(b) || - (sig && (float32_is_nan(a) || float32_is_nan(b)))) { - float_raise(float_flag_invalid, status); - return 1; - } else if (float32_is_nan(a) || float32_is_nan(b)) { - return 1; - } else { - return 0; - } -} - -/* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_S(f, (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0)) -FOP_COND_S(un, float32_is_unordered(0, FST1, FST0, &env->fp_status)) -FOP_COND_S(eq, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status)) -FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) -FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status)) -FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) -FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status)) -FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) -/* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_S(sf, (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0)) -FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status)) -FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status)) -FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) -FOP_COND_S(lt, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status)) -FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) -FOP_COND_S(le, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status)) -FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) - -#define FOP_COND_PS(op, condl, condh) \ -void op_cmp_ps_ ## op (void) \ -{ \ - int cl = condl; \ - int ch = condh; \ - update_fcr31(); \ - if (cl) \ - SET_FP_COND(PARAM1, env); \ - else \ - CLEAR_FP_COND(PARAM1, env); \ - if (ch) \ - SET_FP_COND(PARAM1 + 1, env); \ - else \ - CLEAR_FP_COND(PARAM1 + 1, env); \ - DEBUG_FPU_STATE(); \ - RETURN(); \ -} \ -void op_cmpabs_ps_ ## op (void) \ -{ \ - int cl, ch; \ - FST0 &= ~(1 << 31); \ - FSTH0 &= ~(1 << 31); \ - FST1 &= ~(1 << 31); \ - FSTH1 &= ~(1 << 31); \ - cl = condl; \ - ch = condh; \ - update_fcr31(); \ - if (cl) \ - SET_FP_COND(PARAM1, env); \ - else \ - CLEAR_FP_COND(PARAM1, env); \ - if (ch) \ - SET_FP_COND(PARAM1 + 1, env); \ - else \ - CLEAR_FP_COND(PARAM1 + 1, env); \ - DEBUG_FPU_STATE(); \ - RETURN(); \ -} - -/* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_PS(f, (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0), - (float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status), 0)) -FOP_COND_PS(un, float32_is_unordered(0, FST1, FST0, &env->fp_status), - float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)) -FOP_COND_PS(eq, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status), - !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status), - float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_eq(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status), - !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status), - float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_lt(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status), - !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status), - float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_le(FSTH0, FSTH1, &env->fp_status)) -/* NOTE: the comma operator will make "cond" to eval to false, - * but float*_is_unordered() is still called. */ -FOP_COND_PS(sf, (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0), - (float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status), 0)) -FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status), - float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)) -FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status), - !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status), - float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_eq(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(lt, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status), - !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status), - float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_lt(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(le, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status), - !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status)) -FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status), - float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_le(FSTH0, FSTH1, &env->fp_status)) +CMP_OPS(f) +CMP_OPS(un) +CMP_OPS(eq) +CMP_OPS(ueq) +CMP_OPS(olt) +CMP_OPS(ult) +CMP_OPS(ole) +CMP_OPS(ule) +CMP_OPS(sf) +CMP_OPS(ngle) +CMP_OPS(seq) +CMP_OPS(ngl) +CMP_OPS(lt) +CMP_OPS(nge) +CMP_OPS(le) +CMP_OPS(ngt) +#undef CMP_OPS +#undef CMP_OP void op_bc1f (void) { - T0 = !IS_FP_COND_SET(PARAM1, env); + T0 = !!(~GET_FP_COND(env) & (0x1 << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } -void op_bc1fany2 (void) +void op_bc1any2f (void) { - T0 = (!IS_FP_COND_SET(PARAM1, env) || - !IS_FP_COND_SET(PARAM1 + 1, env)); + T0 = !!(~GET_FP_COND(env) & (0x3 << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } -void op_bc1fany4 (void) +void op_bc1any4f (void) { - T0 = (!IS_FP_COND_SET(PARAM1, env) || - !IS_FP_COND_SET(PARAM1 + 1, env) || - !IS_FP_COND_SET(PARAM1 + 2, env) || - !IS_FP_COND_SET(PARAM1 + 3, env)); + T0 = !!(~GET_FP_COND(env) & (0xf << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } void op_bc1t (void) { - T0 = IS_FP_COND_SET(PARAM1, env); + T0 = !!(GET_FP_COND(env) & (0x1 << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } -void op_bc1tany2 (void) +void op_bc1any2t (void) { - T0 = (IS_FP_COND_SET(PARAM1, env) || - IS_FP_COND_SET(PARAM1 + 1, env)); + T0 = !!(GET_FP_COND(env) & (0x3 << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } -void op_bc1tany4 (void) +void op_bc1any4t (void) { - T0 = (IS_FP_COND_SET(PARAM1, env) || - IS_FP_COND_SET(PARAM1 + 1, env) || - IS_FP_COND_SET(PARAM1 + 2, env) || - IS_FP_COND_SET(PARAM1 + 3, env)); + T0 = !!(GET_FP_COND(env) & (0xf << PARAM1)); DEBUG_FPU_STATE(); RETURN(); } @@ -2808,17 +2390,6 @@ void op_save_pc (void) RETURN(); } -void op_save_fp_status (void) -{ - union fps { - uint32_t i; - float_status f; - } fps; - fps.i = PARAM1; - env->fp_status = fps.f; - RETURN(); -} - void op_interrupt_restart (void) { if (!(env->CP0_Status & (1 << CP0St_EXL)) && diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 9cc55dcef8..85ad33355a 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -598,3 +598,544 @@ void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) } #endif + +/* Complex FPU operations which may need stack space. */ + +/* convert MIPS rounding mode in FCR31 to IEEE library */ +unsigned int ieee_rm[] = { + float_round_nearest_even, + float_round_to_zero, + float_round_up, + float_round_down +}; + +#define RESTORE_ROUNDING_MODE \ + set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status) + +void do_ctc1 (void) +{ + switch(T1) { + case 25: + if (T0 & 0xffffff00) + return; + env->fcr31 = (env->fcr31 & 0x017fffff) | ((T0 & 0xfe) << 24) | + ((T0 & 0x1) << 23); + break; + case 26: + if (T0 & 0x007c0000) + return; + env->fcr31 = (env->fcr31 & 0xfffc0f83) | (T0 & 0x0003f07c); + break; + case 28: + if (T0 & 0x007c0000) + return; + env->fcr31 = (env->fcr31 & 0xfefff07c) | (T0 & 0x00000f83) | + ((T0 & 0x4) << 22); + break; + case 31: + if (T0 & 0x007c0000) + return; + env->fcr31 = T0; + break; + default: + return; + } + /* set rounding mode */ + RESTORE_ROUNDING_MODE; + set_float_exception_flags(0, &env->fp_status); + if ((GET_FP_ENABLE(env->fcr31) | 0x20) & GET_FP_CAUSE(env->fcr31)) + do_raise_exception(EXCP_FPE); +} + +inline char ieee_ex_to_mips(char xcpt) +{ + return (xcpt & float_flag_inexact) >> 5 | + (xcpt & float_flag_underflow) >> 3 | + (xcpt & float_flag_overflow) >> 1 | + (xcpt & float_flag_divbyzero) << 1 | + (xcpt & float_flag_invalid) << 4; +} + +inline char mips_ex_to_ieee(char xcpt) +{ + return (xcpt & FP_INEXACT) << 5 | + (xcpt & FP_UNDERFLOW) << 3 | + (xcpt & FP_OVERFLOW) << 1 | + (xcpt & FP_DIV0) >> 1 | + (xcpt & FP_INVALID) >> 4; +} + +inline void update_fcr31(void) +{ + int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fp_status)); + + SET_FP_CAUSE(env->fcr31, tmp); + if (GET_FP_ENABLE(env->fcr31) & tmp) + do_raise_exception(EXCP_FPE); + else + UPDATE_FP_FLAGS(env->fcr31, tmp); +} + +#define FLOAT_OP(name, p) void do_float_##name##_##p(void) + +FLOAT_OP(cvtd, s) +{ + set_float_exception_flags(0, &env->fp_status); + FDT2 = float32_to_float64(FST0, &env->fp_status); + update_fcr31(); +} +FLOAT_OP(cvtd, w) +{ + set_float_exception_flags(0, &env->fp_status); + FDT2 = int32_to_float64(WT0, &env->fp_status); + update_fcr31(); +} +FLOAT_OP(cvtd, l) +{ + set_float_exception_flags(0, &env->fp_status); + FDT2 = int64_to_float64(DT0, &env->fp_status); + update_fcr31(); +} +FLOAT_OP(cvtl, d) +{ + set_float_exception_flags(0, &env->fp_status); + DT2 = float64_to_int64(FDT0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; +} +FLOAT_OP(cvtl, s) +{ + set_float_exception_flags(0, &env->fp_status); + DT2 = float32_to_int64(FST0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; +} + +FLOAT_OP(cvtps, pw) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = int32_to_float32(WT0, &env->fp_status); + FSTH2 = int32_to_float32(WTH0, &env->fp_status); + update_fcr31(); +} +FLOAT_OP(cvtpw, ps) +{ + set_float_exception_flags(0, &env->fp_status); + WT2 = float32_to_int32(FST0, &env->fp_status); + WTH2 = float32_to_int32(FSTH0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; +} +FLOAT_OP(cvts, d) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = float64_to_float32(FDT0, &env->fp_status); + update_fcr31(); +} +FLOAT_OP(cvts, w) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = int32_to_float32(WT0, &env->fp_status); + update_fcr31(); +} +FLOAT_OP(cvts, l) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = int64_to_float32(DT0, &env->fp_status); + update_fcr31(); +} +FLOAT_OP(cvts, pl) +{ + set_float_exception_flags(0, &env->fp_status); + WT2 = WT0; + update_fcr31(); +} +FLOAT_OP(cvts, pu) +{ + set_float_exception_flags(0, &env->fp_status); + WT2 = WTH0; + update_fcr31(); +} +FLOAT_OP(cvtw, s) +{ + set_float_exception_flags(0, &env->fp_status); + WT2 = float32_to_int32(FST0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; +} +FLOAT_OP(cvtw, d) +{ + set_float_exception_flags(0, &env->fp_status); + WT2 = float64_to_int32(FDT0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; +} + +FLOAT_OP(roundl, d) +{ + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + DT2 = float64_round_to_int(FDT0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; +} +FLOAT_OP(roundl, s) +{ + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + DT2 = float32_round_to_int(FST0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; +} +FLOAT_OP(roundw, d) +{ + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + WT2 = float64_round_to_int(FDT0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; +} +FLOAT_OP(roundw, s) +{ + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + WT2 = float32_round_to_int(FST0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; +} + +FLOAT_OP(truncl, d) +{ + DT2 = float64_to_int64_round_to_zero(FDT0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; +} +FLOAT_OP(truncl, s) +{ + DT2 = float32_to_int64_round_to_zero(FST0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; +} +FLOAT_OP(truncw, d) +{ + WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; +} +FLOAT_OP(truncw, s) +{ + WT2 = float32_to_int32_round_to_zero(FST0, &env->fp_status); + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; +} + +FLOAT_OP(ceill, d) +{ + set_float_rounding_mode(float_round_up, &env->fp_status); + DT2 = float64_round_to_int(FDT0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; +} +FLOAT_OP(ceill, s) +{ + set_float_rounding_mode(float_round_up, &env->fp_status); + DT2 = float32_round_to_int(FST0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; +} +FLOAT_OP(ceilw, d) +{ + set_float_rounding_mode(float_round_up, &env->fp_status); + WT2 = float64_round_to_int(FDT0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; +} +FLOAT_OP(ceilw, s) +{ + set_float_rounding_mode(float_round_up, &env->fp_status); + WT2 = float32_round_to_int(FST0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; +} + +FLOAT_OP(floorl, d) +{ + set_float_rounding_mode(float_round_down, &env->fp_status); + DT2 = float64_round_to_int(FDT0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; +} +FLOAT_OP(floorl, s) +{ + set_float_rounding_mode(float_round_down, &env->fp_status); + DT2 = float32_round_to_int(FST0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + DT2 = 0x7fffffffffffffffULL; +} +FLOAT_OP(floorw, d) +{ + set_float_rounding_mode(float_round_down, &env->fp_status); + WT2 = float64_round_to_int(FDT0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; +} +FLOAT_OP(floorw, s) +{ + set_float_rounding_mode(float_round_down, &env->fp_status); + WT2 = float32_round_to_int(FST0, &env->fp_status); + RESTORE_ROUNDING_MODE; + update_fcr31(); + if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID)) + WT2 = 0x7fffffff; +} + +/* binary operations */ +#define FLOAT_BINOP(name) \ +FLOAT_OP(name, d) \ +{ \ + set_float_exception_flags(0, &env->fp_status); \ + FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status); \ + update_fcr31(); \ +} \ +FLOAT_OP(name, s) \ +{ \ + set_float_exception_flags(0, &env->fp_status); \ + FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \ + update_fcr31(); \ +} \ +FLOAT_OP(name, ps) \ +{ \ + set_float_exception_flags(0, &env->fp_status); \ + FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \ + FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status); \ + update_fcr31(); \ +} +FLOAT_BINOP(add) +FLOAT_BINOP(sub) +FLOAT_BINOP(mul) +FLOAT_BINOP(div) +#undef FLOAT_BINOP + +FLOAT_OP(addr, ps) +{ + set_float_exception_flags(0, &env->fp_status); + FST2 = float32_add (FST0, FSTH0, &env->fp_status); + FSTH2 = float32_add (FST1, FSTH1, &env->fp_status); + update_fcr31(); +} + +#define FOP_COND_D(op, cond) \ +void do_cmp_d_ ## op (long cc) \ +{ \ + int c = cond; \ + update_fcr31(); \ + if (c) \ + SET_FP_COND(cc, env); \ + else \ + CLEAR_FP_COND(cc, env); \ +} \ +void do_cmpabs_d_ ## op (long cc) \ +{ \ + int c; \ + FDT0 &= ~(1ULL << 63); \ + FDT1 &= ~(1ULL << 63); \ + c = cond; \ + update_fcr31(); \ + if (c) \ + SET_FP_COND(cc, env); \ + else \ + CLEAR_FP_COND(cc, env); \ +} + +int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM) +{ + if (float64_is_signaling_nan(a) || + float64_is_signaling_nan(b) || + (sig && (float64_is_nan(a) || float64_is_nan(b)))) { + float_raise(float_flag_invalid, status); + return 1; + } else if (float64_is_nan(a) || float64_is_nan(b)) { + return 1; + } else { + return 0; + } +} + +/* NOTE: the comma operator will make "cond" to eval to false, + * but float*_is_unordered() is still called. */ +FOP_COND_D(f, (float64_is_unordered(0, FDT1, FDT0, &env->fp_status), 0)) +FOP_COND_D(un, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)) +FOP_COND_D(eq, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) +/* NOTE: the comma operator will make "cond" to eval to false, + * but float*_is_unordered() is still called. */ +FOP_COND_D(sf, (float64_is_unordered(1, FDT1, FDT0, &env->fp_status), 0)) +FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fp_status)) +FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(lt, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(le, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status)) +FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status)) + +#define FOP_COND_S(op, cond) \ +void do_cmp_s_ ## op (long cc) \ +{ \ + int c = cond; \ + update_fcr31(); \ + if (c) \ + SET_FP_COND(cc, env); \ + else \ + CLEAR_FP_COND(cc, env); \ +} \ +void do_cmpabs_s_ ## op (long cc) \ +{ \ + int c; \ + FST0 &= ~(1 << 31); \ + FST1 &= ~(1 << 31); \ + c = cond; \ + update_fcr31(); \ + if (c) \ + SET_FP_COND(cc, env); \ + else \ + CLEAR_FP_COND(cc, env); \ +} + +flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM) +{ + extern flag float32_is_nan(float32 a); + if (float32_is_signaling_nan(a) || + float32_is_signaling_nan(b) || + (sig && (float32_is_nan(a) || float32_is_nan(b)))) { + float_raise(float_flag_invalid, status); + return 1; + } else if (float32_is_nan(a) || float32_is_nan(b)) { + return 1; + } else { + return 0; + } +} + +/* NOTE: the comma operator will make "cond" to eval to false, + * but float*_is_unordered() is still called. */ +FOP_COND_S(f, (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0)) +FOP_COND_S(un, float32_is_unordered(0, FST1, FST0, &env->fp_status)) +FOP_COND_S(eq, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status)) +FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) +FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status)) +FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) +FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status)) +FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) +/* NOTE: the comma operator will make "cond" to eval to false, + * but float*_is_unordered() is still called. */ +FOP_COND_S(sf, (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0)) +FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status)) +FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status)) +FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status)) +FOP_COND_S(lt, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status)) +FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status)) +FOP_COND_S(le, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status)) +FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status)) + +#define FOP_COND_PS(op, condl, condh) \ +void do_cmp_ps_ ## op (long cc) \ +{ \ + int cl = condl; \ + int ch = condh; \ + update_fcr31(); \ + if (cl) \ + SET_FP_COND(cc, env); \ + else \ + CLEAR_FP_COND(cc, env); \ + if (ch) \ + SET_FP_COND(cc + 1, env); \ + else \ + CLEAR_FP_COND(cc + 1, env); \ +} \ +void do_cmpabs_ps_ ## op (long cc) \ +{ \ + int cl, ch; \ + FST0 &= ~(1 << 31); \ + FSTH0 &= ~(1 << 31); \ + FST1 &= ~(1 << 31); \ + FSTH1 &= ~(1 << 31); \ + cl = condl; \ + ch = condh; \ + update_fcr31(); \ + if (cl) \ + SET_FP_COND(cc, env); \ + else \ + CLEAR_FP_COND(cc, env); \ + if (ch) \ + SET_FP_COND(cc + 1, env); \ + else \ + CLEAR_FP_COND(cc + 1, env); \ +} + +/* NOTE: the comma operator will make "cond" to eval to false, + * but float*_is_unordered() is still called. */ +FOP_COND_PS(f, (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0), + (float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status), 0)) +FOP_COND_PS(un, float32_is_unordered(0, FST1, FST0, &env->fp_status), + float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)) +FOP_COND_PS(eq, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status), + !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status), + float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_eq(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status), + !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status), + float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_lt(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status), + !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status), + float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_le(FSTH0, FSTH1, &env->fp_status)) +/* NOTE: the comma operator will make "cond" to eval to false, + * but float*_is_unordered() is still called. */ +FOP_COND_PS(sf, (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0), + (float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status), 0)) +FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status), + float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)) +FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status), + !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status), + float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_eq(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(lt, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status), + !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status), + float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_lt(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(le, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status), + !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status)) +FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status), + float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_le(FSTH0, FSTH1, &env->fp_status)) diff --git a/target-mips/translate.c b/target-mips/translate.c index 66e9def854..57e5777ccb 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -491,7 +491,7 @@ FGEN32(gen_op_load_fpr_WTH2, gen_op_load_fpr_WTH2_fpr); FGEN32(gen_op_store_fpr_WTH2, gen_op_store_fpr_WTH2_fpr); #define FOP_CONDS(type, fmt) \ -static GenOpFunc1 * cond ## type ## _ ## fmt ## _table[16] = { \ +static GenOpFunc1 * gen_op_cmp ## type ## _ ## fmt ## _table[16] = { \ gen_op_cmp ## type ## _ ## fmt ## _f, \ gen_op_cmp ## type ## _ ## fmt ## _un, \ gen_op_cmp ## type ## _ ## fmt ## _eq, \ @@ -511,7 +511,7 @@ static GenOpFunc1 * cond ## type ## _ ## fmt ## _table[16] = { \ }; \ static inline void gen_cmp ## type ## _ ## fmt(int n, long cc) \ { \ - cond ## type ## _ ## fmt ## _table[n](cc); \ + gen_op_cmp ## type ## _ ## fmt ## _table[n](cc); \ } FOP_CONDS(, d) @@ -525,11 +525,10 @@ typedef struct DisasContext { struct TranslationBlock *tb; target_ulong pc, saved_pc; uint32_t opcode; - uint32_t fp_status, saved_fp_status; + uint32_t fp_status; /* Routine used to access memory */ int mem_idx; uint32_t hflags, saved_hflags; - uint32_t CP0_Status; int bstate; target_ulong btarget; } DisasContext; @@ -628,11 +627,21 @@ static inline void save_cpu_state (DisasContext *ctx, int do_save_pc) } } -static inline void save_fpu_state (DisasContext *ctx) +static inline void restore_cpu_state (CPUState *env, DisasContext *ctx) { - if (ctx->fp_status != ctx->saved_fp_status) { - gen_op_save_fp_status(ctx->fp_status); - ctx->saved_fp_status = ctx->fp_status; + ctx->saved_hflags = ctx->hflags; + switch (ctx->hflags & MIPS_HFLAG_BMASK) { + case MIPS_HFLAG_BR: + gen_op_restore_breg_target(); + break; + case MIPS_HFLAG_B: + ctx->btarget = env->btarget; + break; + case MIPS_HFLAG_BC: + case MIPS_HFLAG_BL: + ctx->btarget = env->btarget; + gen_op_restore_bcond(); + break; } } @@ -4293,20 +4302,20 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, gen_op_save_bcond(); break; case OPC_BC1FANY2: - gen_op_bc1fany2(cc); - opn = "bc1fany2"; + gen_op_bc1any2f(cc); + opn = "bc1any2f"; goto not_likely; case OPC_BC1TANY2: - gen_op_bc1tany2(cc); - opn = "bc1tany2"; + gen_op_bc1any2t(cc); + opn = "bc1any2t"; goto not_likely; case OPC_BC1FANY4: - gen_op_bc1fany4(cc); - opn = "bc1fany4"; + gen_op_bc1any4f(cc); + opn = "bc1any4f"; goto not_likely; case OPC_BC1TANY4: - gen_op_bc1tany4(cc); - opn = "bc1tany4"; + gen_op_bc1any4t(cc); + opn = "bc1any4t"; not_likely: ctx->hflags |= MIPS_HFLAG_BC; gen_op_set_bcond(); @@ -4323,27 +4332,6 @@ static void gen_compute_branch1 (DisasContext *ctx, uint32_t op, /* Coprocessor 1 (FPU) */ -/* verify if floating point register is valid; an operation is not defined - * if bit 0 of any register specification is set and the FR bit in the - * Status register equals zero, since the register numbers specify an - * even-odd pair of adjacent coprocessor general registers. When the FR bit - * in the Status register equals one, both even and odd register numbers - * are valid. This limitation exists only for 64 bit wide (d,l,ps) registers. - * - * Multiple 64 bit wide registers can be checked by calling - * CHECK_FR(ctx, freg1 | freg2 | ... | fregN); - * - * FIXME: This is broken for R2, it needs to be checked at runtime, not - * at translation time. - */ -#define CHECK_FR(ctx, freg) do { \ - if (!((ctx)->CP0_Status & (1 << CP0St_FR)) && ((freg) & 1)) { \ - MIPS_INVAL("FPU mode"); \ - generate_exception (ctx, EXCP_RI); \ - return; \ - } \ - } while(0) - #define FOP(func, fmt) (((fmt) << 21) | (func)) static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) @@ -4388,14 +4376,14 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) opn = "dmtc1"; break; case OPC_MFHC1: - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_mfhc1(); GEN_STORE_TN_REG(rt, T0); opn = "mfhc1"; break; case OPC_MTHC1: - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_REG_TN(T0, rt); gen_op_mthc1(); GEN_STORE_FTN_FREG(fs, WTH0); @@ -4546,28 +4534,28 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "neg.s"; break; case FOP(8, 16): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_roundl_s(); GEN_STORE_FTN_FREG(fd, DT2); opn = "round.l.s"; break; case FOP(9, 16): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_truncl_s(); GEN_STORE_FTN_FREG(fd, DT2); opn = "trunc.l.s"; break; case FOP(10, 16): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_ceill_s(); GEN_STORE_FTN_FREG(fd, DT2); opn = "ceil.l.s"; break; case FOP(11, 16): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_floorl_s(); GEN_STORE_FTN_FREG(fd, DT2); @@ -4622,7 +4610,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "movn.s"; break; case FOP(33, 16): - CHECK_FR(ctx, fd); + gen_op_cp1_registers(fd); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_cvtd_s(); GEN_STORE_FTN_FREG(fd, DT2); @@ -4635,14 +4623,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "cvt.w.s"; break; case FOP(37, 16): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_cvtl_s(); GEN_STORE_FTN_FREG(fd, DT2); opn = "cvt.l.s"; break; case FOP(38, 16): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WT1, fs); GEN_LOAD_FREG_FTN(WT0, ft); gen_op_float_cvtps_s(); @@ -4676,7 +4664,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, } break; case FOP(0, 17): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); gen_op_float_add_d(); @@ -4685,7 +4673,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, optype = BINOP; break; case FOP(1, 17): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); gen_op_float_sub_d(); @@ -4694,7 +4682,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, optype = BINOP; break; case FOP(2, 17): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); gen_op_float_mul_d(); @@ -4703,7 +4691,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, optype = BINOP; break; case FOP(3, 17): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); gen_op_float_div_d(); @@ -4712,84 +4700,84 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, optype = BINOP; break; case FOP(4, 17): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_sqrt_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "sqrt.d"; break; case FOP(5, 17): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_abs_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "abs.d"; break; case FOP(6, 17): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_mov_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "mov.d"; break; case FOP(7, 17): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_chs_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "neg.d"; break; case FOP(8, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_roundl_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "round.l.d"; break; case FOP(9, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_truncl_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "trunc.l.d"; break; case FOP(10, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_ceill_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "ceil.l.d"; break; case FOP(11, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_floorl_d(); GEN_STORE_FTN_FREG(fd, DT2); opn = "floor.l.d"; break; case FOP(12, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_roundw_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "round.w.d"; break; case FOP(13, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_truncw_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "trunc.w.d"; break; case FOP(14, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_ceilw_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "ceil.w.d"; break; case FOP(15, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_floorw_d(); GEN_STORE_FTN_FREG(fd, WT2); @@ -4835,7 +4823,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, case FOP(61, 17): case FOP(62, 17): case FOP(63, 17): - CHECK_FR(ctx, fs | ft); + gen_op_cp1_registers(fs | ft); GEN_LOAD_FREG_FTN(DT0, fs); GEN_LOAD_FREG_FTN(DT1, ft); if (ctx->opcode & (1 << 6)) { @@ -4847,21 +4835,21 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, } break; case FOP(32, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvts_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.s.d"; break; case FOP(36, 17): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvtw_d(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.w.d"; break; case FOP(37, 17): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvtl_d(); GEN_STORE_FTN_FREG(fd, DT2); @@ -4874,21 +4862,21 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "cvt.s.w"; break; case FOP(33, 20): - CHECK_FR(ctx, fd); + gen_op_cp1_registers(fd); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_cvtd_w(); GEN_STORE_FTN_FREG(fd, DT2); opn = "cvt.d.w"; break; case FOP(32, 21): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvts_l(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.s.l"; break; case FOP(33, 21): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(DT0, fs); gen_op_float_cvtd_l(); GEN_STORE_FTN_FREG(fd, DT2); @@ -4896,7 +4884,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, break; case FOP(38, 20): case FOP(38, 21): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_cvtps_pw(); @@ -4905,7 +4893,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "cvt.ps.pw"; break; case FOP(0, 22): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -4916,7 +4904,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "add.ps"; break; case FOP(1, 22): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -4927,7 +4915,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "sub.ps"; break; case FOP(2, 22): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -4938,7 +4926,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "mul.ps"; break; case FOP(5, 22): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_abs_ps(); @@ -4947,7 +4935,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "abs.ps"; break; case FOP(6, 22): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_mov_ps(); @@ -4956,7 +4944,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "mov.ps"; break; case FOP(7, 22): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_chs_ps(); @@ -4998,7 +4986,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "movn.ps"; break; case FOP(24, 22): - CHECK_FR(ctx, fs | fd | ft); + gen_op_cp1_registers(fs | fd | ft); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -5009,14 +4997,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "addr.ps"; break; case FOP(32, 22): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_cvts_pu(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.s.pu"; break; case FOP(36, 22): - CHECK_FR(ctx, fs | fd); + gen_op_cp1_registers(fs | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); gen_op_float_cvtpw_ps(); @@ -5025,14 +5013,14 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "cvt.pw.ps"; break; case FOP(40, 22): - CHECK_FR(ctx, fs); + gen_op_cp1_registers(fs); GEN_LOAD_FREG_FTN(WT0, fs); gen_op_float_cvts_pl(); GEN_STORE_FTN_FREG(fd, WT2); opn = "cvt.s.pl"; break; case FOP(44, 22): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WT1, ft); gen_op_float_pll_ps(); @@ -5040,7 +5028,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "pll.ps"; break; case FOP(45, 22): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH1, ft); gen_op_float_plu_ps(); @@ -5048,7 +5036,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "plu.ps"; break; case FOP(46, 22): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); gen_op_float_pul_ps(); @@ -5056,7 +5044,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, opn = "pul.ps"; break; case FOP(47, 22): - CHECK_FR(ctx, fs | ft | fd); + gen_op_cp1_registers(fs | ft | fd); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WTH1, ft); gen_op_float_puu_ps(); @@ -5079,7 +5067,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, case FOP(61, 22): case FOP(62, 22): case FOP(63, 22): - CHECK_FR(ctx, fs | ft); + gen_op_cp1_registers(fs | ft); GEN_LOAD_FREG_FTN(WT0, fs); GEN_LOAD_FREG_FTN(WTH0, fs); GEN_LOAD_FREG_FTN(WT1, ft); @@ -5166,7 +5154,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, int fd, const char *opn = "flt3_arith"; /* All of those work only on 64bit FPUs. */ - CHECK_FR(ctx, fd | fr | fs | ft); + gen_op_cp1_registers(fd | fr | fs | ft); switch (opc) { case OPC_ALNV_PS: GEN_LOAD_REG_TN(T0, fr); @@ -5874,26 +5862,12 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, ctx.bstate = BS_NONE; /* Restore delay slot state from the tb context. */ ctx.hflags = tb->flags; - ctx.saved_hflags = ctx.hflags; - switch (ctx.hflags & MIPS_HFLAG_BMASK) { - case MIPS_HFLAG_BR: - gen_op_restore_breg_target(); - break; - case MIPS_HFLAG_B: - ctx.btarget = env->btarget; - break; - case MIPS_HFLAG_BC: - case MIPS_HFLAG_BL: - ctx.btarget = env->btarget; - gen_op_restore_bcond(); - break; - } + restore_cpu_state(env, &ctx); #if defined(CONFIG_USER_ONLY) ctx.mem_idx = 0; #else ctx.mem_idx = !((ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM); #endif - ctx.CP0_Status = env->CP0_Status; #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_CPU) { fprintf(logfile, "------------------------------------------------\n");