target: e2k: add conversion instructions, handle float comparison with predicate result instrs

This commit is contained in:
Alibek Omarov 2020-12-10 01:23:46 +03:00 committed by Denis Drakhnia
parent ebb2b2485f
commit b888c75194
4 changed files with 260 additions and 4 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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;
}

View File

@ -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