From b888c75194376c4af9e9fe0435837b9205ae4b44 Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Thu, 10 Dec 2020 01:23:46 +0300 Subject: [PATCH] target: e2k: add conversion instructions, handle float comparison with predicate result instrs --- target/e2k/helper.h | 19 ++++ target/e2k/helper_fpu.c | 34 +++++- target/e2k/helper_int.c | 2 +- target/e2k/translate/alc.c | 209 +++++++++++++++++++++++++++++++++++++ 4 files changed, 260 insertions(+), 4 deletions(-) diff --git a/target/e2k/helper.h b/target/e2k/helper.h index c66c4b44e7..f997776b17 100644 --- a/target/e2k/helper.h +++ b/target/e2k/helper.h @@ -45,3 +45,22 @@ DEF_HELPER_3_32_64(fcmplt) DEF_HELPER_3_32_64(fcmpnlt) DEF_HELPER_3_32_64(fcmpuod) DEF_HELPER_3_32_64(fcmpod) +#undef DEF_HELPER_3_32_64 + +DEF_HELPER_2(fstois, i32, env, i32) +DEF_HELPER_2(istofs, i32, env, i32) +DEF_HELPER_2(fstoistr, i32, env, i32) + +DEF_HELPER_2(fdtoid, i64, env, i64) +DEF_HELPER_2(idtofd, i64, env, i64) +DEF_HELPER_2(fdtoidtr, i64, env, i64) + +DEF_HELPER_2(fstofd, i64, env, i32) +DEF_HELPER_2(fstoid, i64, env, i32) +DEF_HELPER_2(istofd, i64, env, i32) +DEF_HELPER_2(fstoidtr, i64, env, i32) + +DEF_HELPER_2(fdtofs, i32, env, i64) +DEF_HELPER_2(fdtois, i32, env, i64) +DEF_HELPER_2(idtofs, i32, env, i64) +DEF_HELPER_2(fdtoistr, i32, env, i64) diff --git a/target/e2k/helper_fpu.c b/target/e2k/helper_fpu.c index 6aeb550e2a..baa4d6c98d 100644 --- a/target/e2k/helper_fpu.c +++ b/target/e2k/helper_fpu.c @@ -90,14 +90,24 @@ void e2k_update_fp_status(CPUE2KState *env) return z; \ } +#define no_cvt(x) (x) // when function already returns in correct type + +#define GENERATE_CVT_FLOAT1_OP(name, from_t, to_t, size_from, size_to, func_from, func_to) \ + uint##size_to##_t HELPER(name)(CPUE2KState *env, uint##size_from##_t x) \ + {\ + uint8_t old_flags = save_exception_flags(env); \ + uint##size_to##_t z = func_to( from_t##_to_##to_t (func_from(x), &env->fp_status) );\ + merge_exception_flags(env, old_flags); \ + return z; \ + } + #define GENERATE_SIMPLE_FLOAT2_OPS_32_64(name, function) \ GENERATE_SIMPLE_FLOAT2_OP(name##s, function, 32) \ GENERATE_SIMPLE_FLOAT2_OP(name##d, function, 64) #define GENERATE_CMP_FLOAT2_OPS_32_64(name, function, expr) \ - GENERATE_CMP_FLOAT2_OP(name##s, function, 32) \ - GENERATE_CMP_FLOAT2_OP(name##d, function, 64) - + GENERATE_CMP_FLOAT2_OP(name##s, function, expr, 32) \ + GENERATE_CMP_FLOAT2_OP(name##d, function, expr, 64) GENERATE_SIMPLE_FLOAT2_OPS_32_64(fadd, add) GENERATE_SIMPLE_FLOAT2_OPS_32_64(fsub, sub) @@ -113,3 +123,21 @@ GENERATE_CMP_FLOAT2_OPS_32_64(fcmplt, lt, ) GENERATE_CMP_FLOAT2_OPS_32_64(fcmpnlt, lt, !) GENERATE_CMP_FLOAT2_OPS_32_64(fcmpuod, unordered, ) GENERATE_CMP_FLOAT2_OPS_32_64(fcmpod, unordered, !) + +GENERATE_CVT_FLOAT1_OP(fstois, float32, int32, 32, 32, make_float32, no_cvt) +GENERATE_CVT_FLOAT1_OP(istofs, int32, float32, 32, 32, no_cvt, float32_val) +GENERATE_CVT_FLOAT1_OP(fstoistr, float32, int32_round_to_zero, 32, 32, make_float32, no_cvt) + +GENERATE_CVT_FLOAT1_OP(fdtoid, float64, int64, 64, 64, make_float64, no_cvt) +GENERATE_CVT_FLOAT1_OP(idtofd, int64, float64, 64, 64, no_cvt, float64_val) +GENERATE_CVT_FLOAT1_OP(fdtoidtr, float64, int64_round_to_zero, 64, 64, make_float64, no_cvt) + +GENERATE_CVT_FLOAT1_OP(fstofd, float32, float64, 32, 64, make_float32, float64_val) +GENERATE_CVT_FLOAT1_OP(fstoid, float32, int64, 32, 64, make_float32, no_cvt) +GENERATE_CVT_FLOAT1_OP(istofd, int32, float64, 32, 64, no_cvt, float64_val) +GENERATE_CVT_FLOAT1_OP(fstoidtr, float32, int64_round_to_zero, 32, 64, make_float32, no_cvt) + +GENERATE_CVT_FLOAT1_OP(fdtofs, float64, float32, 64, 32, make_float64, float32_val) +GENERATE_CVT_FLOAT1_OP(fdtois, float64, int32, 64, 32, make_float64, no_cvt) +GENERATE_CVT_FLOAT1_OP(idtofs, int64, float32, 64, 32, no_cvt, float32_val) +GENERATE_CVT_FLOAT1_OP(fdtoistr, float64, int32_round_to_zero, 64, 32, make_float64, no_cvt) diff --git a/target/e2k/helper_int.c b/target/e2k/helper_int.c index 5a8478a042..dc29568b98 100644 --- a/target/e2k/helper_int.c +++ b/target/e2k/helper_int.c @@ -35,7 +35,7 @@ static uint64_t* state_reg_ptr(CPUE2KState *env, int idx) switch (idx) { case 0x80: return &env->upsr; /* %upsr */ case 0x83: return &env->lsr; /* %lsr */ - case 0x85: return &env->fpcr.raw; /* %fpcr */ + case 0x85: return &env->fpcr.raw; /* %fpcr */ /* TODO: fix invalid conversion! */ case 0x86: return &env->fpsr.raw; /* %fpsr */ default: return NULL; } diff --git a/target/e2k/translate/alc.c b/target/e2k/translate/alc.c index 78b5baf815..50441bf8fc 100644 --- a/target/e2k/translate/alc.c +++ b/target/e2k/translate/alc.c @@ -986,6 +986,88 @@ static inline void gen_cmpand_i32(TCGv_i32 ret, int opc, TCGv_i32 src1, tcg_temp_free_i32(t0); } +static void gen_fcmp_i32(TCGv_i32 ret, int opc, TCGv_i32 src1, TCGv_i32 src2) +{ + void (*f)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32) = 0; + TCGv_i32 dst = tcg_temp_new_i32(); + + switch(opc) { + case 0: /* eq */ + f = gen_helper_fcmpeqs; + break; + case 1: /* lt */ + f = gen_helper_fcmplts; + break; + case 2: /* le */ + f = gen_helper_fcmples; + break; + case 3: /* uod */ + f = gen_helper_fcmpuods; + break; + case 4: /* neq */ + f = gen_helper_fcmpneqs; + break; + case 5: /* nlt */ + f = gen_helper_fcmpnlts; + break; + case 6: /* nle */ + f = gen_helper_fcmpnles; + break; + case 7: /* od */ + f = gen_helper_fcmpods; + break; + default: + e2k_gen_exception(E2K_EXCP_ILLOPC); + break; + } + + (*f)(dst, cpu_env, src1, src2); + tcg_gen_setcondi_i32(TCG_COND_NE, ret, dst, 0); + + tcg_temp_free_i32(dst); +} + +static void gen_fcmp_i64(TCGv_i64 ret, int opc, TCGv_i64 src1, TCGv_i64 src2) +{ + void (*f)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64) = 0; + TCGv_i64 dst = tcg_temp_new_i64(); + + switch(opc) { + case 0: /* eq */ + f = gen_helper_fcmpeqd; + break; + case 1: /* lt */ + f = gen_helper_fcmpltd; + break; + case 2: /* le */ + f = gen_helper_fcmpled; + break; + case 3: /* uod */ + f = gen_helper_fcmpuodd; + break; + case 4: /* neq */ + f = gen_helper_fcmpneqd; + break; + case 5: /* nlt */ + f = gen_helper_fcmpnltd; + break; + case 6: /* nle */ + f = gen_helper_fcmpnled; + break; + case 7: /* od */ + f = gen_helper_fcmpodd; + break; + default: + e2k_gen_exception(E2K_EXCP_ILLOPC); + break; + } + + (*f)(dst, cpu_env, src1, src2); + tcg_gen_setcondi_i64(TCG_COND_NE, ret, dst, 0); + + tcg_temp_free_i64(dst); +} + /* * ret[31:0] = x[31:0] * ret[63:32] = y[63:32] @@ -1956,6 +2038,51 @@ static void gen_alopf2_i64(DisasContext *ctx, int chan, void (*op)(TCGv_i64, TCG gen_al_result_i64(ctx, chan, dst, tag); } +static void gen_alopf2_i32_env(DisasContext *ctx, int chan, void (*op)(TCGv_i32, TCGv_env, TCGv_i32)) +{ + Src32 s2 = get_src2_i32(ctx, chan); + TCGv_i32 dst = e2k_get_temp_i32(ctx); + TCGv_i32 tag = e2k_get_temp_i32(ctx); + + gen_tag1_i32(tag, s2.tag); + (*op)(dst, cpu_env, s2.value); + gen_al_result_i32(ctx, chan, dst, tag); +} + +static void gen_alopf2_i64_env(DisasContext *ctx, int chan, void (*op)(TCGv_i64, TCGv_env, TCGv_i64)) +{ + Src64 s2 = get_src2_i64(ctx, chan); + TCGv_i64 dst = e2k_get_temp_i64(ctx); + TCGv_i32 tag = e2k_get_temp_i32(ctx); + + gen_tag1_i64(tag, s2.tag); + (*op)(dst, cpu_env, s2.value); + gen_al_result_i64(ctx, chan, dst, tag); +} + +static void gen_alopf2_i64_i32_env(DisasContext *ctx, int chan, void (*op)(TCGv_i32, TCGv_env, TCGv_i64)) +{ + Src64 s2 = get_src2_i64(ctx, chan); + TCGv_i32 dst = e2k_get_temp_i32(ctx); + TCGv_i32 tag = e2k_get_temp_i32(ctx); + + gen_tag1_i32(tag, s2.tag); + (*op)(dst, cpu_env, s2.value); + gen_al_result_i32(ctx, chan, dst, tag); +} + +static void gen_alopf2_i32_i64_env(DisasContext *ctx, int chan, void (*op)(TCGv_i64, TCGv_env, TCGv_i32)) +{ + Src32 s2 = get_src2_i32(ctx, chan); + TCGv_i64 dst = e2k_get_temp_i64(ctx); + TCGv_i32 tag = e2k_get_temp_i32(ctx); + + gen_tag1_i64(tag, s2.tag); + (*op)(dst, cpu_env, s2.value); + gen_al_result_i64(ctx, chan, dst, tag); +} + + static void execute_ext_00(DisasContext *ctx, Instr *instr) { int chan = instr->chan; @@ -2060,6 +2187,22 @@ static void execute_ext_00(DisasContext *ctx, Instr *instr) } break; } + case 0x2e: { + if (is_chan_0134(chan)) { + /* fcmp{op}sb */ + gen_alopf1_cmp_i32(ctx, instr, gen_fcmp_i32); + return; + } + break; + } + case 0x2f: { + if (is_chan_0134(chan)) { + /* fcmp{op}db */ + gen_alopf1_cmp_i64(ctx, instr, gen_fcmp_i64); + return; + } + break; + } case 0x30: if (ctx->version >= 4 || is_chan_0134(chan)) { /* faddd */ @@ -2130,6 +2273,72 @@ static void execute_ext_00(DisasContext *ctx, Instr *instr) return; } break; + case 0x3c: + if (is_chan_0134(chan)) { + void (*func)(TCGv_i32, TCGv_env, TCGv_i32) = 0; + + switch(instr->opce1) { + case 0xc0: func = gen_helper_fstois; break; + case 0xc2: func = gen_helper_fstoistr; break; + case 0xc4: func = gen_helper_istofs; break; + } + + if (func) { + gen_alopf2_i32_env(ctx, chan, func); + return; + } + } + break; + case 0x3d: + if (is_chan_0134(chan)) { + void (*func)(TCGv_i64, TCGv_env, TCGv_i64) = 0; + + switch(instr->opce1) { + case 0xc0: func = gen_helper_fdtoid; break; + case 0xc2: func = ctx->version >= 2 ? gen_helper_fdtoidtr : 0; break; + case 0xc4: func = gen_helper_idtofd; break; + } + + if (func) { + gen_alopf2_i64_env(ctx, chan, func); + return; + } + } + break; + case 0x3e: + if (is_chan_0134(chan)) { + void (*func)(TCGv_i64, TCGv_env, TCGv_i32) = 0; + + switch(instr->opce1) { + case 0xc0: func = gen_helper_fstoid; break; + case 0xc2: func = ctx->version >= 2 ? gen_helper_fstoidtr : 0; break; + case 0xc4: func = gen_helper_istofd; break; + case 0xc6: func = gen_helper_fstofd; break; + } + + if (func) { + gen_alopf2_i32_i64_env(ctx, chan, func); + } + return; + } + break; + case 0x3f: + if (is_chan_0134(chan)) { + void (*func)(TCGv_i32, TCGv_env, TCGv_i64) = 0; + + switch(instr->opce1) { + case 0xc0: func = gen_helper_fdtois; break; + case 0xc2: func = gen_helper_fdtoistr; break; + case 0xc4: func = gen_helper_idtofs; break; + case 0xc6: func = gen_helper_fdtofs; break; + } + + if (func) { + gen_alopf2_i64_i32_env(ctx, chan, func); + } + return; + } + break; case 0x40: if (chan == 5) { // FIXME: temp hack