diff options
author | Richard Henderson <richard.henderson@linaro.org> | 2019-05-06 14:49:25 -0700 |
---|---|---|
committer | Richard Henderson <richard.henderson@linaro.org> | 2019-09-04 12:53:33 -0700 |
commit | 62f2b0389ff6fc7856b801bb5bee1c2d364d3e6c (patch) | |
tree | 67be040ef1a5bab9ee48aabfcaffdb15432d4409 /target/openrisc/translate.c | |
parent | fe636d3722bf266c7b1bd3ca12fa53fb78ceffa0 (diff) | |
download | qemu-62f2b0389ff6fc7856b801bb5bee1c2d364d3e6c.zip qemu-62f2b0389ff6fc7856b801bb5bee1c2d364d3e6c.tar.gz qemu-62f2b0389ff6fc7856b801bb5bee1c2d364d3e6c.tar.bz2 |
target/openrisc: Add support for ORFPX64A32
This is hardware support for double-precision floating-point using
pairs of 32-bit registers. Fix latent bugs in the heretofore unused
helper_itofd and helper_ftoid. Include the bit for cpu "any".
Change the default cpu for linux-user to "any".
Reviewed-by: Stafford Horne <shorne@gmail.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'target/openrisc/translate.c')
-rw-r--r-- | target/openrisc/translate.c | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 2f5c969..b8ef485 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -146,6 +146,11 @@ static bool check_of32s(DisasContext *dc) return dc->cpucfgr & CPUCFGR_OF32S; } +static bool check_of64a32s(DisasContext *dc) +{ + return dc->cpucfgr & CPUCFGR_OF64A32S; +} + static TCGv cpu_R(DisasContext *dc, int reg) { if (reg == 0) { @@ -1260,6 +1265,231 @@ static bool trans_lf_sfle_s(DisasContext *dc, arg_ab *a) return do_fpcmp(dc, a, gen_helper_float_le_s, false, false); } +static bool check_pair(DisasContext *dc, int r, int p) +{ + return r + 1 + p < 32; +} + +static void load_pair(DisasContext *dc, TCGv_i64 t, int r, int p) +{ + tcg_gen_concat_i32_i64(t, cpu_R(dc, r + 1 + p), cpu_R(dc, r)); +} + +static void save_pair(DisasContext *dc, TCGv_i64 t, int r, int p) +{ + tcg_gen_extr_i64_i32(cpu_R(dc, r + 1 + p), cpu_R(dc, r), t); +} + +static bool do_dp3(DisasContext *dc, arg_dab_pair *a, + void (*fn)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64)) +{ + TCGv_i64 t0, t1; + + if (!check_of64a32s(dc) || + !check_pair(dc, a->a, a->ap) || + !check_pair(dc, a->b, a->bp) || + !check_pair(dc, a->d, a->dp)) { + return false; + } + check_r0_write(dc, a->d); + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + load_pair(dc, t0, a->a, a->ap); + load_pair(dc, t1, a->b, a->bp); + fn(t0, cpu_env, t0, t1); + save_pair(dc, t0, a->d, a->dp); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + + gen_helper_update_fpcsr(cpu_env); + return true; +} + +static bool do_dp2(DisasContext *dc, arg_da_pair *a, + void (*fn)(TCGv_i64, TCGv_env, TCGv_i64)) +{ + TCGv_i64 t0; + + if (!check_of64a32s(dc) || + !check_pair(dc, a->a, a->ap) || + !check_pair(dc, a->d, a->dp)) { + return false; + } + check_r0_write(dc, a->d); + + t0 = tcg_temp_new_i64(); + load_pair(dc, t0, a->a, a->ap); + fn(t0, cpu_env, t0); + save_pair(dc, t0, a->d, a->dp); + tcg_temp_free_i64(t0); + + gen_helper_update_fpcsr(cpu_env); + return true; +} + +static bool do_dpcmp(DisasContext *dc, arg_ab_pair *a, + void (*fn)(TCGv, TCGv_env, TCGv_i64, TCGv_i64), + bool inv, bool swap) +{ + TCGv_i64 t0, t1; + + if (!check_of64a32s(dc) || + !check_pair(dc, a->a, a->ap) || + !check_pair(dc, a->b, a->bp)) { + return false; + } + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + load_pair(dc, t0, a->a, a->ap); + load_pair(dc, t1, a->b, a->bp); + if (swap) { + fn(cpu_sr_f, cpu_env, t1, t0); + } else { + fn(cpu_sr_f, cpu_env, t0, t1); + } + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + + if (inv) { + tcg_gen_xori_tl(cpu_sr_f, cpu_sr_f, 1); + } + gen_helper_update_fpcsr(cpu_env); + return true; +} + +static bool trans_lf_add_d(DisasContext *dc, arg_dab_pair *a) +{ + return do_dp3(dc, a, gen_helper_float_add_d); +} + +static bool trans_lf_sub_d(DisasContext *dc, arg_dab_pair *a) +{ + return do_dp3(dc, a, gen_helper_float_sub_d); +} + +static bool trans_lf_mul_d(DisasContext *dc, arg_dab_pair *a) +{ + return do_dp3(dc, a, gen_helper_float_mul_d); +} + +static bool trans_lf_div_d(DisasContext *dc, arg_dab_pair *a) +{ + return do_dp3(dc, a, gen_helper_float_div_d); +} + +static bool trans_lf_rem_d(DisasContext *dc, arg_dab_pair *a) +{ + return do_dp3(dc, a, gen_helper_float_rem_d); +} + +static bool trans_lf_itof_d(DisasContext *dc, arg_da_pair *a) +{ + return do_dp2(dc, a, gen_helper_itofd); +} + +static bool trans_lf_ftoi_d(DisasContext *dc, arg_da_pair *a) +{ + return do_dp2(dc, a, gen_helper_ftoid); +} + +static bool trans_lf_stod_d(DisasContext *dc, arg_lf_stod_d *a) +{ + TCGv_i64 t0; + + if (!check_of64a32s(dc) || + !check_pair(dc, a->d, a->dp)) { + return false; + } + check_r0_write(dc, a->d); + + t0 = tcg_temp_new_i64(); + gen_helper_stod(t0, cpu_env, cpu_R(dc, a->a)); + save_pair(dc, t0, a->d, a->dp); + tcg_temp_free_i64(t0); + + gen_helper_update_fpcsr(cpu_env); + return true; +} + +static bool trans_lf_dtos_d(DisasContext *dc, arg_lf_dtos_d *a) +{ + TCGv_i64 t0; + + if (!check_of64a32s(dc) || + !check_pair(dc, a->a, a->ap)) { + return false; + } + check_r0_write(dc, a->d); + + t0 = tcg_temp_new_i64(); + load_pair(dc, t0, a->a, a->ap); + gen_helper_dtos(cpu_R(dc, a->d), cpu_env, t0); + tcg_temp_free_i64(t0); + + gen_helper_update_fpcsr(cpu_env); + return true; +} + +static bool trans_lf_madd_d(DisasContext *dc, arg_dab_pair *a) +{ + TCGv_i64 t0, t1, t2; + + if (!check_of64a32s(dc) || + !check_pair(dc, a->a, a->ap) || + !check_pair(dc, a->b, a->bp) || + !check_pair(dc, a->d, a->dp)) { + return false; + } + check_r0_write(dc, a->d); + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + t2 = tcg_temp_new_i64(); + load_pair(dc, t0, a->d, a->dp); + load_pair(dc, t1, a->a, a->ap); + load_pair(dc, t2, a->b, a->bp); + gen_helper_float_madd_d(t0, cpu_env, t0, t1, t2); + save_pair(dc, t0, a->d, a->dp); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + + gen_helper_update_fpcsr(cpu_env); + return true; +} + +static bool trans_lf_sfeq_d(DisasContext *dc, arg_ab_pair *a) +{ + return do_dpcmp(dc, a, gen_helper_float_eq_d, false, false); +} + +static bool trans_lf_sfne_d(DisasContext *dc, arg_ab_pair *a) +{ + return do_dpcmp(dc, a, gen_helper_float_eq_d, true, false); +} + +static bool trans_lf_sfgt_d(DisasContext *dc, arg_ab_pair *a) +{ + return do_dpcmp(dc, a, gen_helper_float_lt_d, false, true); +} + +static bool trans_lf_sfge_d(DisasContext *dc, arg_ab_pair *a) +{ + return do_dpcmp(dc, a, gen_helper_float_le_d, false, true); +} + +static bool trans_lf_sflt_d(DisasContext *dc, arg_ab_pair *a) +{ + return do_dpcmp(dc, a, gen_helper_float_lt_d, false, false); +} + +static bool trans_lf_sfle_d(DisasContext *dc, arg_ab_pair *a) +{ + return do_dpcmp(dc, a, gen_helper_float_le_d, false, false); +} + static void openrisc_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) { DisasContext *dc = container_of(dcb, DisasContext, base); |