Loading target/m68k/cpu.c +1 −1 Original line number Diff line number Diff line Loading @@ -62,7 +62,7 @@ static void m68k_cpu_reset(CPUState *s) for (i = 0; i < 8; i++) { env->fregs[i].d = nan; } env->fpcr = 0; cpu_m68k_set_fpcr(env, 0); env->fpsr = 0; cpu_m68k_set_ccr(env, 0); Loading target/m68k/cpu.h +39 −4 Original line number Diff line number Diff line Loading @@ -171,6 +171,7 @@ int cpu_m68k_signal_handler(int host_signum, void *pinfo, void *puc); uint32_t cpu_m68k_get_ccr(CPUM68KState *env); void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t); void cpu_m68k_set_fpcr(CPUM68KState *env, uint32_t val); /* Instead of computing the condition codes after each m68k instruction, Loading Loading @@ -215,6 +216,43 @@ typedef enum { #define M68K_SSP 0 #define M68K_USP 1 #define M68K_FPIAR_SHIFT 0 #define M68K_FPIAR (1 << M68K_FPIAR_SHIFT) #define M68K_FPSR_SHIFT 1 #define M68K_FPSR (1 << M68K_FPSR_SHIFT) #define M68K_FPCR_SHIFT 2 #define M68K_FPCR (1 << M68K_FPCR_SHIFT) /* Floating-Point Status Register */ /* Condition Code */ #define FPSR_CC_MASK 0x0f000000 #define FPSR_CC_A 0x01000000 /* Not-A-Number */ #define FPSR_CC_I 0x02000000 /* Infinity */ #define FPSR_CC_Z 0x04000000 /* Zero */ #define FPSR_CC_N 0x08000000 /* Negative */ /* Quotient */ #define FPSR_QT_MASK 0x00ff0000 /* Floating-Point Control Register */ /* Rounding mode */ #define FPCR_RND_MASK 0x0030 #define FPCR_RND_N 0x0000 #define FPCR_RND_Z 0x0010 #define FPCR_RND_M 0x0020 #define FPCR_RND_P 0x0030 /* Rounding precision */ #define FPCR_PREC_MASK 0x00c0 #define FPCR_PREC_X 0x0000 #define FPCR_PREC_S 0x0040 #define FPCR_PREC_D 0x0080 #define FPCR_PREC_U 0x00c0 #define FPCR_EXCP_MASK 0xff00 /* CACR fields are implementation defined, but some bits are common. */ #define M68K_CACR_EUSP 0x10 Loading @@ -231,8 +269,6 @@ typedef enum { void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector); void m68k_switch_sp(CPUM68KState *env); #define M68K_FPCR_PREC (1 << 6) void do_m68k_semihosting(CPUM68KState *env, int nr); /* There are 4 ColdFire core ISA revisions: A, A+, B and C. Loading Loading @@ -310,8 +346,7 @@ static inline void cpu_get_tb_cpu_state(CPUM68KState *env, target_ulong *pc, { *pc = env->pc; *cs_base = 0; *flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */ | (env->sr & SR_S) /* Bit 13 */ *flags = (env->sr & SR_S) /* Bit 13 */ | ((env->macsr >> 4) & 0xf); /* Bits 0-3 */ } Loading target/m68k/fpu_helper.c +101 −16 Original line number Diff line number Diff line Loading @@ -58,9 +58,74 @@ void HELPER(firound)(CPUM68KState *env, FPReg *res, FPReg *val) res->d = floatx80_round_to_int(val->d, &env->fp_status); } static void m68k_restore_precision_mode(CPUM68KState *env) { switch (env->fpcr & FPCR_PREC_MASK) { case FPCR_PREC_X: /* extended */ set_floatx80_rounding_precision(80, &env->fp_status); break; case FPCR_PREC_S: /* single */ set_floatx80_rounding_precision(32, &env->fp_status); break; case FPCR_PREC_D: /* double */ set_floatx80_rounding_precision(64, &env->fp_status); break; case FPCR_PREC_U: /* undefined */ default: break; } } static void cf_restore_precision_mode(CPUM68KState *env) { if (env->fpcr & FPCR_PREC_S) { /* single */ set_floatx80_rounding_precision(32, &env->fp_status); } else { /* double */ set_floatx80_rounding_precision(64, &env->fp_status); } } static void restore_rounding_mode(CPUM68KState *env) { switch (env->fpcr & FPCR_RND_MASK) { case FPCR_RND_N: /* round to nearest */ set_float_rounding_mode(float_round_nearest_even, &env->fp_status); break; case FPCR_RND_Z: /* round to zero */ set_float_rounding_mode(float_round_to_zero, &env->fp_status); break; case FPCR_RND_M: /* round toward minus infinity */ set_float_rounding_mode(float_round_down, &env->fp_status); break; case FPCR_RND_P: /* round toward positive infinity */ set_float_rounding_mode(float_round_up, &env->fp_status); break; } } void cpu_m68k_set_fpcr(CPUM68KState *env, uint32_t val) { env->fpcr = val & 0xffff; if (m68k_feature(env, M68K_FEATURE_CF_FPU)) { cf_restore_precision_mode(env); } else { m68k_restore_precision_mode(env); } restore_rounding_mode(env); } void HELPER(fitrunc)(CPUM68KState *env, FPReg *res, FPReg *val) { int rounding_mode = get_float_rounding_mode(&env->fp_status); set_float_rounding_mode(float_round_to_zero, &env->fp_status); res->d = floatx80_round_to_int(val->d, &env->fp_status); set_float_rounding_mode(rounding_mode, &env->fp_status); } void HELPER(set_fpcr)(CPUM68KState *env, uint32_t val) { cpu_m68k_set_fpcr(env, val); } void HELPER(fsqrt)(CPUM68KState *env, FPReg *res, FPReg *val) Loading Loading @@ -98,24 +163,44 @@ void HELPER(fdiv)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) res->d = floatx80_div(val1->d, val0->d, &env->fp_status); } void HELPER(fsub_cmp)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) static int float_comp_to_cc(int float_compare) { /* ??? This may incorrectly raise exceptions. */ /* ??? Should flush denormals to zero. */ res->d = floatx80_sub(val0->d, val1->d, &env->fp_status); if (floatx80_is_quiet_nan(res->d, &env->fp_status)) { /* +/-inf compares equal against itself, but sub returns nan. */ if (!floatx80_is_quiet_nan(val0->d, &env->fp_status) && !floatx80_is_quiet_nan(val1->d, &env->fp_status)) { res->d = floatx80_zero; if (floatx80_lt_quiet(val0->d, res->d, &env->fp_status)) { res->d = floatx80_chs(res->d); } switch (float_compare) { case float_relation_equal: return FPSR_CC_Z; case float_relation_less: return FPSR_CC_N; case float_relation_unordered: return FPSR_CC_A; case float_relation_greater: return 0; default: g_assert_not_reached(); } } void HELPER(fcmp)(CPUM68KState *env, FPReg *val0, FPReg *val1) { int float_compare; float_compare = floatx80_compare(val1->d, val0->d, &env->fp_status); env->fpsr = (env->fpsr & ~FPSR_CC_MASK) | float_comp_to_cc(float_compare); } uint32_t HELPER(fcompare)(CPUM68KState *env, FPReg *val) void HELPER(ftst)(CPUM68KState *env, FPReg *val) { return floatx80_compare_quiet(val->d, floatx80_zero, &env->fp_status); uint32_t cc = 0; if (floatx80_is_neg(val->d)) { cc |= FPSR_CC_N; } if (floatx80_is_any_nan(val->d)) { cc |= FPSR_CC_A; } else if (floatx80_is_infinity(val->d)) { cc |= FPSR_CC_I; } else if (floatx80_is_zero(val->d)) { cc |= FPSR_CC_Z; } env->fpsr = (env->fpsr & ~FPSR_CC_MASK) | cc; } target/m68k/helper.c +17 −5 Original line number Diff line number Diff line Loading @@ -80,8 +80,14 @@ static int cf_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n) stfq_p(mem_buf, floatx80_to_float64(env->fregs[n].d, &s)); return 8; } if (n < 11) { /* FP control registers (not implemented) */ switch (n) { case 8: /* fpcontrol */ stl_be_p(mem_buf, env->fpcr); return 4; case 9: /* fpstatus */ stl_be_p(mem_buf, env->fpsr); return 4; case 10: /* fpiar, not implemented */ memset(mem_buf, 0, 4); return 4; } Loading @@ -95,8 +101,14 @@ static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n) env->fregs[n].d = float64_to_floatx80(ldfq_p(mem_buf), &s); return 8; } if (n < 11) { /* FP control registers (not implemented) */ switch (n) { case 8: /* fpcontrol */ cpu_m68k_set_fpcr(env, ldl_p(mem_buf)); return 4; case 9: /* fpstatus */ env->fpsr = ldl_p(mem_buf); return 4; case 10: /* fpiar, not implemented */ return 4; } return 0; Loading Loading @@ -133,7 +145,7 @@ static int m68k_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n) } switch (n) { case 8: /* fpcontrol */ env->fpcr = ldl_p(mem_buf); cpu_m68k_set_fpcr(env, ldl_p(mem_buf)); return 4; case 9: /* fpstatus */ env->fpsr = ldl_p(mem_buf); Loading target/m68k/helper.h +3 −2 Original line number Diff line number Diff line Loading @@ -32,8 +32,9 @@ DEF_HELPER_4(fadd, void, env, fp, fp, fp) DEF_HELPER_4(fsub, void, env, fp, fp, fp) DEF_HELPER_4(fmul, void, env, fp, fp, fp) DEF_HELPER_4(fdiv, void, env, fp, fp, fp) DEF_HELPER_4(fsub_cmp, void, env, fp, fp, fp) DEF_HELPER_2(fcompare, i32, env, fp) DEF_HELPER_FLAGS_3(fcmp, TCG_CALL_NO_RWG, void, env, fp, fp) DEF_HELPER_FLAGS_2(set_fpcr, TCG_CALL_NO_RWG, void, env, i32) DEF_HELPER_FLAGS_2(ftst, TCG_CALL_NO_RWG, void, env, fp) DEF_HELPER_3(mac_move, void, env, i32, i32) DEF_HELPER_3(macmulf, i64, env, i32, i32) Loading Loading
target/m68k/cpu.c +1 −1 Original line number Diff line number Diff line Loading @@ -62,7 +62,7 @@ static void m68k_cpu_reset(CPUState *s) for (i = 0; i < 8; i++) { env->fregs[i].d = nan; } env->fpcr = 0; cpu_m68k_set_fpcr(env, 0); env->fpsr = 0; cpu_m68k_set_ccr(env, 0); Loading
target/m68k/cpu.h +39 −4 Original line number Diff line number Diff line Loading @@ -171,6 +171,7 @@ int cpu_m68k_signal_handler(int host_signum, void *pinfo, void *puc); uint32_t cpu_m68k_get_ccr(CPUM68KState *env); void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t); void cpu_m68k_set_fpcr(CPUM68KState *env, uint32_t val); /* Instead of computing the condition codes after each m68k instruction, Loading Loading @@ -215,6 +216,43 @@ typedef enum { #define M68K_SSP 0 #define M68K_USP 1 #define M68K_FPIAR_SHIFT 0 #define M68K_FPIAR (1 << M68K_FPIAR_SHIFT) #define M68K_FPSR_SHIFT 1 #define M68K_FPSR (1 << M68K_FPSR_SHIFT) #define M68K_FPCR_SHIFT 2 #define M68K_FPCR (1 << M68K_FPCR_SHIFT) /* Floating-Point Status Register */ /* Condition Code */ #define FPSR_CC_MASK 0x0f000000 #define FPSR_CC_A 0x01000000 /* Not-A-Number */ #define FPSR_CC_I 0x02000000 /* Infinity */ #define FPSR_CC_Z 0x04000000 /* Zero */ #define FPSR_CC_N 0x08000000 /* Negative */ /* Quotient */ #define FPSR_QT_MASK 0x00ff0000 /* Floating-Point Control Register */ /* Rounding mode */ #define FPCR_RND_MASK 0x0030 #define FPCR_RND_N 0x0000 #define FPCR_RND_Z 0x0010 #define FPCR_RND_M 0x0020 #define FPCR_RND_P 0x0030 /* Rounding precision */ #define FPCR_PREC_MASK 0x00c0 #define FPCR_PREC_X 0x0000 #define FPCR_PREC_S 0x0040 #define FPCR_PREC_D 0x0080 #define FPCR_PREC_U 0x00c0 #define FPCR_EXCP_MASK 0xff00 /* CACR fields are implementation defined, but some bits are common. */ #define M68K_CACR_EUSP 0x10 Loading @@ -231,8 +269,6 @@ typedef enum { void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector); void m68k_switch_sp(CPUM68KState *env); #define M68K_FPCR_PREC (1 << 6) void do_m68k_semihosting(CPUM68KState *env, int nr); /* There are 4 ColdFire core ISA revisions: A, A+, B and C. Loading Loading @@ -310,8 +346,7 @@ static inline void cpu_get_tb_cpu_state(CPUM68KState *env, target_ulong *pc, { *pc = env->pc; *cs_base = 0; *flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */ | (env->sr & SR_S) /* Bit 13 */ *flags = (env->sr & SR_S) /* Bit 13 */ | ((env->macsr >> 4) & 0xf); /* Bits 0-3 */ } Loading
target/m68k/fpu_helper.c +101 −16 Original line number Diff line number Diff line Loading @@ -58,9 +58,74 @@ void HELPER(firound)(CPUM68KState *env, FPReg *res, FPReg *val) res->d = floatx80_round_to_int(val->d, &env->fp_status); } static void m68k_restore_precision_mode(CPUM68KState *env) { switch (env->fpcr & FPCR_PREC_MASK) { case FPCR_PREC_X: /* extended */ set_floatx80_rounding_precision(80, &env->fp_status); break; case FPCR_PREC_S: /* single */ set_floatx80_rounding_precision(32, &env->fp_status); break; case FPCR_PREC_D: /* double */ set_floatx80_rounding_precision(64, &env->fp_status); break; case FPCR_PREC_U: /* undefined */ default: break; } } static void cf_restore_precision_mode(CPUM68KState *env) { if (env->fpcr & FPCR_PREC_S) { /* single */ set_floatx80_rounding_precision(32, &env->fp_status); } else { /* double */ set_floatx80_rounding_precision(64, &env->fp_status); } } static void restore_rounding_mode(CPUM68KState *env) { switch (env->fpcr & FPCR_RND_MASK) { case FPCR_RND_N: /* round to nearest */ set_float_rounding_mode(float_round_nearest_even, &env->fp_status); break; case FPCR_RND_Z: /* round to zero */ set_float_rounding_mode(float_round_to_zero, &env->fp_status); break; case FPCR_RND_M: /* round toward minus infinity */ set_float_rounding_mode(float_round_down, &env->fp_status); break; case FPCR_RND_P: /* round toward positive infinity */ set_float_rounding_mode(float_round_up, &env->fp_status); break; } } void cpu_m68k_set_fpcr(CPUM68KState *env, uint32_t val) { env->fpcr = val & 0xffff; if (m68k_feature(env, M68K_FEATURE_CF_FPU)) { cf_restore_precision_mode(env); } else { m68k_restore_precision_mode(env); } restore_rounding_mode(env); } void HELPER(fitrunc)(CPUM68KState *env, FPReg *res, FPReg *val) { int rounding_mode = get_float_rounding_mode(&env->fp_status); set_float_rounding_mode(float_round_to_zero, &env->fp_status); res->d = floatx80_round_to_int(val->d, &env->fp_status); set_float_rounding_mode(rounding_mode, &env->fp_status); } void HELPER(set_fpcr)(CPUM68KState *env, uint32_t val) { cpu_m68k_set_fpcr(env, val); } void HELPER(fsqrt)(CPUM68KState *env, FPReg *res, FPReg *val) Loading Loading @@ -98,24 +163,44 @@ void HELPER(fdiv)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) res->d = floatx80_div(val1->d, val0->d, &env->fp_status); } void HELPER(fsub_cmp)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) static int float_comp_to_cc(int float_compare) { /* ??? This may incorrectly raise exceptions. */ /* ??? Should flush denormals to zero. */ res->d = floatx80_sub(val0->d, val1->d, &env->fp_status); if (floatx80_is_quiet_nan(res->d, &env->fp_status)) { /* +/-inf compares equal against itself, but sub returns nan. */ if (!floatx80_is_quiet_nan(val0->d, &env->fp_status) && !floatx80_is_quiet_nan(val1->d, &env->fp_status)) { res->d = floatx80_zero; if (floatx80_lt_quiet(val0->d, res->d, &env->fp_status)) { res->d = floatx80_chs(res->d); } switch (float_compare) { case float_relation_equal: return FPSR_CC_Z; case float_relation_less: return FPSR_CC_N; case float_relation_unordered: return FPSR_CC_A; case float_relation_greater: return 0; default: g_assert_not_reached(); } } void HELPER(fcmp)(CPUM68KState *env, FPReg *val0, FPReg *val1) { int float_compare; float_compare = floatx80_compare(val1->d, val0->d, &env->fp_status); env->fpsr = (env->fpsr & ~FPSR_CC_MASK) | float_comp_to_cc(float_compare); } uint32_t HELPER(fcompare)(CPUM68KState *env, FPReg *val) void HELPER(ftst)(CPUM68KState *env, FPReg *val) { return floatx80_compare_quiet(val->d, floatx80_zero, &env->fp_status); uint32_t cc = 0; if (floatx80_is_neg(val->d)) { cc |= FPSR_CC_N; } if (floatx80_is_any_nan(val->d)) { cc |= FPSR_CC_A; } else if (floatx80_is_infinity(val->d)) { cc |= FPSR_CC_I; } else if (floatx80_is_zero(val->d)) { cc |= FPSR_CC_Z; } env->fpsr = (env->fpsr & ~FPSR_CC_MASK) | cc; }
target/m68k/helper.c +17 −5 Original line number Diff line number Diff line Loading @@ -80,8 +80,14 @@ static int cf_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n) stfq_p(mem_buf, floatx80_to_float64(env->fregs[n].d, &s)); return 8; } if (n < 11) { /* FP control registers (not implemented) */ switch (n) { case 8: /* fpcontrol */ stl_be_p(mem_buf, env->fpcr); return 4; case 9: /* fpstatus */ stl_be_p(mem_buf, env->fpsr); return 4; case 10: /* fpiar, not implemented */ memset(mem_buf, 0, 4); return 4; } Loading @@ -95,8 +101,14 @@ static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n) env->fregs[n].d = float64_to_floatx80(ldfq_p(mem_buf), &s); return 8; } if (n < 11) { /* FP control registers (not implemented) */ switch (n) { case 8: /* fpcontrol */ cpu_m68k_set_fpcr(env, ldl_p(mem_buf)); return 4; case 9: /* fpstatus */ env->fpsr = ldl_p(mem_buf); return 4; case 10: /* fpiar, not implemented */ return 4; } return 0; Loading Loading @@ -133,7 +145,7 @@ static int m68k_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n) } switch (n) { case 8: /* fpcontrol */ env->fpcr = ldl_p(mem_buf); cpu_m68k_set_fpcr(env, ldl_p(mem_buf)); return 4; case 9: /* fpstatus */ env->fpsr = ldl_p(mem_buf); Loading
target/m68k/helper.h +3 −2 Original line number Diff line number Diff line Loading @@ -32,8 +32,9 @@ DEF_HELPER_4(fadd, void, env, fp, fp, fp) DEF_HELPER_4(fsub, void, env, fp, fp, fp) DEF_HELPER_4(fmul, void, env, fp, fp, fp) DEF_HELPER_4(fdiv, void, env, fp, fp, fp) DEF_HELPER_4(fsub_cmp, void, env, fp, fp, fp) DEF_HELPER_2(fcompare, i32, env, fp) DEF_HELPER_FLAGS_3(fcmp, TCG_CALL_NO_RWG, void, env, fp, fp) DEF_HELPER_FLAGS_2(set_fpcr, TCG_CALL_NO_RWG, void, env, i32) DEF_HELPER_FLAGS_2(ftst, TCG_CALL_NO_RWG, void, env, fp) DEF_HELPER_3(mac_move, void, env, i32, i32) DEF_HELPER_3(macmulf, i64, env, i32, i32) Loading