diff --git a/target/e2k/helper.h b/target/e2k/helper.h index 19e67b0de0..1125496e62 100644 --- a/target/e2k/helper.h +++ b/target/e2k/helper.h @@ -91,3 +91,10 @@ DEF_HELPER_3(fxsubxx, void, env, f80, f80) DEF_HELPER_3(fxrsubxx, void, env, f80, f80) DEF_HELPER_3(fxmulxx, void, env, f80, f80) DEF_HELPER_3(fxdivxx, void, env, f80, f80) + +DEF_HELPER_3(fcmpodsf, i32, env, i32, i32) +DEF_HELPER_3(fcmpudsf, i32, env, i32, i32) +DEF_HELPER_3(fcmpoddf, i32, env, i64, i64) +DEF_HELPER_3(fcmpuddf, i32, env, i64, i64) +DEF_HELPER_3(fxcmpodxf, i32, env, f80, f80) +DEF_HELPER_3(fxcmpudxf, i32, env, f80, f80) diff --git a/target/e2k/helper_fpu.c b/target/e2k/helper_fpu.c index d68cebf871..e4b9ebf030 100644 --- a/target/e2k/helper_fpu.c +++ b/target/e2k/helper_fpu.c @@ -75,7 +75,6 @@ void e2k_update_fp_status(CPUE2KState *env) } set_floatx80_rounding_precision(x, &env->fp_status); - } #define GENERATE_SIMPLE_FLOAT2_OP(name, function, size) \ @@ -183,3 +182,84 @@ void HELPER(fxrsubxx)(CPUE2KState *env, floatx80 *x, floatx80 *y) *x = floatx80_sub(*y, *x, &env->fp_status); merge_exception_flags(env, old_flags); } + +#define GENERATE_FCMPODF(op, IN, F, cvt_macro) \ + uint32_t HELPER(op)(CPUE2KState *env, IN _x, IN _y) \ + { \ + int old_flags = save_exception_flags(env); \ + uint32_t ret; \ + F x = cvt_macro(_x); \ + F y = cvt_macro(_y); \ + if (glue(F, _is_any_nan)(x) || glue(F, _is_any_nan)(y)) { \ + ret = 0x45; \ + } else { \ + FloatRelation relation = glue(F, _compare_quiet)(x, y, &env->fp_status); \ + switch(relation) \ + { \ + case float_relation_less: \ + ret = 0x01; \ + break; \ + case float_relation_greater: \ + ret = 0x00; \ + break; \ + case float_relation_equal: \ + ret = 0x40; \ + break; \ + case float_relation_unordered: \ + default: \ + ret = 0x45; \ + break; \ + } \ + } \ + merge_exception_flags(env, old_flags); \ + return ret; \ + } +GENERATE_FCMPODF(fcmpodsf, uint32_t, float32, make_float32) +GENERATE_FCMPODF(fcmpoddf, uint64_t, float64, make_float64) +GENERATE_FCMPODF(fxcmpodxf, floatx80 *, floatx80, deref) + +/* didn't found any difference between these instruction + so keep it that way for now */ +uint32_t HELPER(fcmpudsf)(CPUE2KState *env, float32 x, float32 y) +{ + return HELPER(fcmpodsf)(env, x, y); +} + +uint32_t HELPER(fcmpuddf)(CPUE2KState *env, float64 x, float64 y) +{ + return HELPER(fcmpoddf)(env, x, y); +} + +uint32_t HELPER(fxcmpudxf)(CPUE2KState *env, floatx80 *x, floatx80 *y) +{ + return HELPER(fxcmpodxf)(env, x, y); +} + +/* TODO: test if valid, test exception flags */ +#if 0 +uint32_t HELPER(frcps)(CPUE2KState *env, uint32_t x) +{ + int old_flags = save_exception_flags(env); + uint32_t y = float32_div(float32_one, make_float32(x), &env->fp_status); + merge_exception_flags(env, old_flags); + return float32_val(y); +} + +uint32_t HELPER(fsqrts)(CPUE2KState *env, uint32_t x) +{ + int old_flags = save_exception_flags(env); + uint32_t y = float32_sqrt(make_float32(x), &env->fp_status); + merge_exception_flags(env, old_flags); + return float32_val(y); +} + +uint32_t HELPER(frsqrts)(CPUE2KState *env, uint32_t x) +{ + int old_flags = save_exception_flags(env); + uint32_t y = float32_div(float32_one, + float32_sqrt(make_float32(x), &env->fp_status), + &env->fp_status); + merge_exception_flags(env, old_flags); + return float32_val(z); +} +#endif diff --git a/target/e2k/translate/alc.c b/target/e2k/translate/alc.c index d271109a52..5c8b1d446f 100644 --- a/target/e2k/translate/alc.c +++ b/target/e2k/translate/alc.c @@ -2134,6 +2134,84 @@ static void gen_alopf1_sess(DisasContext *ctx, int chan, gen_al_result_i32(ctx, chan, dst, tag); } +static void gen_alopf1_sedd(DisasContext *ctx, int chan, + void (*op)(TCGv_i32, TCGv_env, TCGv_i64, TCGv_i64)) +{ + Src64 s1 = get_src1_i64(ctx, chan); + Src64 s2 = get_src2_i64(ctx, chan); + TCGv_i32 tag = e2k_get_temp_i32(ctx); + TCGv_i32 dst = e2k_get_temp_i32(ctx); + + gen_tag2_i64(tag, s1.tag, s2.tag); + (*op)(dst, cpu_env, s1.value, s2.value); + gen_al_result_i32(ctx, chan, dst, tag); +} + +static inline void gen_alopf1_sf80(TCGv_i32 dst, Src80 src1, Src80 src2, + void (*op)(TCGv_i32, TCGv_env, TCGv_ptr, TCGv_ptr)) +{ + TCGv_ptr t0 = tcg_temp_new_ptr(); + TCGv_ptr t1 = tcg_temp_new_ptr(); + + tcg_gen_addi_ptr(t0, cpu_env, offsetof(CPUE2KState, t0.f80)); + tcg_gen_addi_ptr(t1, cpu_env, offsetof(CPUE2KState, t1.f80)); + + gen_temp_reg_write_i64_i32(src1.lo, src1.hi, t0); + gen_temp_reg_write_i64_i32(src2.lo, src2.hi, t1); + + (*op)(dst, cpu_env, t0, t1); + + tcg_temp_free_ptr(t1); + tcg_temp_free_ptr(t0); +} + +static void gen_alopf1_sexs(DisasContext *ctx, int chan, + void (*op)(TCGv_i32, TCGv_env, TCGv_ptr, TCGv_ptr)) +{ + Src80 s1 = get_src1_i80(ctx, chan); + Src32 s2 = get_src2_i32(ctx, chan); + TCGv_i32 tag = e2k_get_temp_i32(ctx); + TCGv_i32 dst = e2k_get_temp_i32(ctx); + Src80 t0 = temp_new_src80(); + + gen_tag2_i64(tag, s1.tag, s2.tag); + gen_fstofx(&t0, s2.value); + gen_alopf1_sf80(dst, s1, t0, op); + gen_al_result_i32(ctx, chan, dst, tag); + + temp_free_src80(&t0); +} + +static void gen_alopf1_sexd(DisasContext *ctx, int chan, + void (*op)(TCGv_i32, TCGv_env, TCGv_ptr, TCGv_ptr)) +{ + Src80 s1 = get_src1_i80(ctx, chan); + Src64 s2 = get_src2_i64(ctx, chan); + TCGv_i32 tag = e2k_get_temp_i32(ctx); + TCGv_i32 dst = e2k_get_temp_i32(ctx); + Src80 t0 = temp_new_src80(); + + gen_tag2_i64(tag, s1.tag, s2.tag); + gen_fdtofx(&t0, s2.value); + gen_alopf1_sf80(dst, s1, t0, op); + gen_al_result_i32(ctx, chan, dst, tag); + + temp_free_src80(&t0); +} + +static void gen_alopf1_sexx(DisasContext *ctx, int chan, + void (*op)(TCGv_i32, TCGv_env, TCGv_ptr, TCGv_ptr)) +{ + Src80 s1 = get_src1_i80(ctx, chan); + Src80 s2 = get_src2_i80(ctx, chan); + TCGv_i32 tag = e2k_get_temp_i32(ctx); + TCGv_i32 dst = e2k_get_temp_i32(ctx); + + gen_tag2_i64(tag, s1.tag, s2.tag); + gen_alopf1_sf80(dst, s1, s2, op); + gen_al_result_i32(ctx, chan, dst, tag); +} + static void gen_alopf1_dss(DisasContext *ctx, int chan, void (*op)(TCGv_i64, TCGv_i32, TCGv_i32)) { @@ -3092,16 +3170,16 @@ static void gen_op(DisasContext *ctx, Instr *instr) case OP_PFCMPNLTD: case OP_PFCMPNLED: case OP_PFCMPODD: - case OP_FCMPODSF: - case OP_FCMPUDSF: - case OP_FCMPODDF: - case OP_FCMPUDDF: - case OP_FXCMPODSF: - case OP_FXCMPUDSF: - case OP_FXCMPODDF: - case OP_FXCMPUDDF: - case OP_FXCMPODXF: - case OP_FXCMPUDXF: + case OP_FCMPODSF: gen_alopf1_sess(ctx, chan, gen_helper_fcmpodsf); break; + case OP_FCMPUDSF: gen_alopf1_sess(ctx, chan, gen_helper_fcmpudsf); break; + case OP_FCMPODDF: gen_alopf1_sedd(ctx, chan, gen_helper_fcmpoddf); break; + case OP_FCMPUDDF: gen_alopf1_sedd(ctx, chan, gen_helper_fcmpoddf); break; + case OP_FXCMPODSF: gen_alopf1_sexs(ctx, chan, gen_helper_fxcmpodxf); break; + case OP_FXCMPUDSF: gen_alopf1_sexs(ctx, chan, gen_helper_fxcmpudxf); break; + case OP_FXCMPODDF: gen_alopf1_sexd(ctx, chan, gen_helper_fxcmpodxf); break; + case OP_FXCMPUDDF: gen_alopf1_sexd(ctx, chan, gen_helper_fxcmpudxf); break; + case OP_FXCMPODXF: gen_alopf1_sexx(ctx, chan, gen_helper_fxcmpodxf); break; + case OP_FXCMPUDXF: gen_alopf1_sexx(ctx, chan, gen_helper_fxcmpudxf); break; case OP_PCMPEQH: case OP_PCMPEQW: case OP_PCMPGTB: