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>
This commit is contained in:
Richard Henderson 2019-05-06 14:49:25 -07:00
parent fe636d3722
commit 62f2b0389f
7 changed files with 333 additions and 4 deletions

View file

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