Commit c04e1692 authored by Max Filippov's avatar Max Filippov
Browse files

target/xtensa: extract FPU2000 opcode translators



FPU2000 implements basic single-precision floating point operations and
can be replaced with a different implementation, like DFPU or HiFi. Move
FPU2000 opcode translators into separate functions and list them in a
separate array.

Signed-off-by: default avatarMax Filippov <jcmvbkbc@gmail.com>
parent 168c12b0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -349,6 +349,7 @@ typedef struct XtensaOpcodeTranslators {
} XtensaOpcodeTranslators;

extern const XtensaOpcodeTranslators xtensa_core_opcodes;
extern const XtensaOpcodeTranslators xtensa_fpu2000_opcodes;

struct XtensaConfig {
    const char *name;
+374 −0
Original line number Diff line number Diff line
@@ -6433,3 +6433,377 @@ const XtensaOpcodeTranslators xtensa_core_opcodes = {
    .num_opcodes = ARRAY_SIZE(core_ops),
    .opcode = core_ops,
};


static void translate_abs_s(DisasContext *dc, const uint32_t arg[],
                            const uint32_t par[])
{
    if (gen_check_cpenable(dc, 0)) {
        gen_helper_abs_s(cpu_FR[arg[0]], cpu_FR[arg[1]]);
    }
}

static void translate_add_s(DisasContext *dc, const uint32_t arg[],
                            const uint32_t par[])
{
    if (gen_check_cpenable(dc, 0)) {
        gen_helper_add_s(cpu_FR[arg[0]], cpu_env,
                         cpu_FR[arg[1]], cpu_FR[arg[2]]);
    }
}

enum {
    COMPARE_UN,
    COMPARE_OEQ,
    COMPARE_UEQ,
    COMPARE_OLT,
    COMPARE_ULT,
    COMPARE_OLE,
    COMPARE_ULE,
};

static void translate_compare_s(DisasContext *dc, const uint32_t arg[],
                                const uint32_t par[])
{
    static void (* const helper[])(TCGv_env env, TCGv_i32 bit,
                                   TCGv_i32 s, TCGv_i32 t) = {
        [COMPARE_UN] = gen_helper_un_s,
        [COMPARE_OEQ] = gen_helper_oeq_s,
        [COMPARE_UEQ] = gen_helper_ueq_s,
        [COMPARE_OLT] = gen_helper_olt_s,
        [COMPARE_ULT] = gen_helper_ult_s,
        [COMPARE_OLE] = gen_helper_ole_s,
        [COMPARE_ULE] = gen_helper_ule_s,
    };

    if (gen_check_cpenable(dc, 0)) {
        TCGv_i32 bit = tcg_const_i32(1 << arg[0]);

        helper[par[0]](cpu_env, bit, cpu_FR[arg[1]], cpu_FR[arg[2]]);
        tcg_temp_free(bit);
    }
}

static void translate_float_s(DisasContext *dc, const uint32_t arg[],
                              const uint32_t par[])
{
    if (gen_window_check1(dc, arg[1]) && gen_check_cpenable(dc, 0)) {
        TCGv_i32 scale = tcg_const_i32(-arg[2]);

        if (par[0]) {
            gen_helper_uitof(cpu_FR[arg[0]], cpu_env, cpu_R[arg[1]], scale);
        } else {
            gen_helper_itof(cpu_FR[arg[0]], cpu_env, cpu_R[arg[1]], scale);
        }
        tcg_temp_free(scale);
    }
}

static void translate_ftoi_s(DisasContext *dc, const uint32_t arg[],
                             const uint32_t par[])
{
    if (gen_window_check1(dc, arg[0]) && gen_check_cpenable(dc, 0)) {
        TCGv_i32 rounding_mode = tcg_const_i32(par[0]);
        TCGv_i32 scale = tcg_const_i32(arg[2]);

        if (par[1]) {
            gen_helper_ftoui(cpu_R[arg[0]], cpu_FR[arg[1]],
                             rounding_mode, scale);
        } else {
            gen_helper_ftoi(cpu_R[arg[0]], cpu_FR[arg[1]],
                            rounding_mode, scale);
        }
        tcg_temp_free(rounding_mode);
        tcg_temp_free(scale);
    }
}

static void translate_ldsti(DisasContext *dc, const uint32_t arg[],
                            const uint32_t par[])
{
    if (gen_window_check1(dc, arg[1]) && gen_check_cpenable(dc, 0)) {
        TCGv_i32 addr = tcg_temp_new_i32();

        tcg_gen_addi_i32(addr, cpu_R[arg[1]], arg[2]);
        gen_load_store_alignment(dc, 2, addr, false);
        if (par[0]) {
            tcg_gen_qemu_st32(cpu_FR[arg[0]], addr, dc->cring);
        } else {
            tcg_gen_qemu_ld32u(cpu_FR[arg[0]], addr, dc->cring);
        }
        if (par[1]) {
            tcg_gen_mov_i32(cpu_R[arg[1]], addr);
        }
        tcg_temp_free(addr);
    }
}

static void translate_ldstx(DisasContext *dc, const uint32_t arg[],
                            const uint32_t par[])
{
    if (gen_window_check2(dc, arg[1], arg[2]) && gen_check_cpenable(dc, 0)) {
        TCGv_i32 addr = tcg_temp_new_i32();

        tcg_gen_add_i32(addr, cpu_R[arg[1]], cpu_R[arg[2]]);
        gen_load_store_alignment(dc, 2, addr, false);
        if (par[0]) {
            tcg_gen_qemu_st32(cpu_FR[arg[0]], addr, dc->cring);
        } else {
            tcg_gen_qemu_ld32u(cpu_FR[arg[0]], addr, dc->cring);
        }
        if (par[1]) {
            tcg_gen_mov_i32(cpu_R[arg[1]], addr);
        }
        tcg_temp_free(addr);
    }
}

static void translate_madd_s(DisasContext *dc, const uint32_t arg[],
                             const uint32_t par[])
{
    if (gen_check_cpenable(dc, 0)) {
        gen_helper_madd_s(cpu_FR[arg[0]], cpu_env,
                          cpu_FR[arg[0]], cpu_FR[arg[1]], cpu_FR[arg[2]]);
    }
}

static void translate_mov_s(DisasContext *dc, const uint32_t arg[],
                            const uint32_t par[])
{
    if (gen_check_cpenable(dc, 0)) {
        tcg_gen_mov_i32(cpu_FR[arg[0]], cpu_FR[arg[1]]);
    }
}

static void translate_movcond_s(DisasContext *dc, const uint32_t arg[],
                                const uint32_t par[])
{
    if (gen_window_check1(dc, arg[2]) && gen_check_cpenable(dc, 0)) {
        TCGv_i32 zero = tcg_const_i32(0);

        tcg_gen_movcond_i32(par[0], cpu_FR[arg[0]],
                            cpu_R[arg[2]], zero,
                            cpu_FR[arg[1]], cpu_FR[arg[2]]);
        tcg_temp_free(zero);
    }
}

static void translate_movp_s(DisasContext *dc, const uint32_t arg[],
                             const uint32_t par[])
{
    if (gen_check_cpenable(dc, 0)) {
        TCGv_i32 zero = tcg_const_i32(0);
        TCGv_i32 tmp = tcg_temp_new_i32();

        tcg_gen_andi_i32(tmp, cpu_SR[BR], 1 << arg[2]);
        tcg_gen_movcond_i32(par[0],
                            cpu_FR[arg[0]], tmp, zero,
                            cpu_FR[arg[1]], cpu_FR[arg[0]]);
        tcg_temp_free(tmp);
        tcg_temp_free(zero);
    }
}

static void translate_mul_s(DisasContext *dc, const uint32_t arg[],
                            const uint32_t par[])
{
    if (gen_check_cpenable(dc, 0)) {
        gen_helper_mul_s(cpu_FR[arg[0]], cpu_env,
                         cpu_FR[arg[1]], cpu_FR[arg[2]]);
    }
}

static void translate_msub_s(DisasContext *dc, const uint32_t arg[],
                             const uint32_t par[])
{
    if (gen_check_cpenable(dc, 0)) {
        gen_helper_msub_s(cpu_FR[arg[0]], cpu_env,
                          cpu_FR[arg[0]], cpu_FR[arg[1]], cpu_FR[arg[2]]);
    }
}

static void translate_neg_s(DisasContext *dc, const uint32_t arg[],
                            const uint32_t par[])
{
    if (gen_check_cpenable(dc, 0)) {
        gen_helper_neg_s(cpu_FR[arg[0]], cpu_FR[arg[1]]);
    }
}

static void translate_rfr_s(DisasContext *dc, const uint32_t arg[],
                            const uint32_t par[])
{
    if (gen_window_check1(dc, arg[0]) &&
        gen_check_cpenable(dc, 0)) {
        tcg_gen_mov_i32(cpu_R[arg[0]], cpu_FR[arg[1]]);
    }
}

static void translate_sub_s(DisasContext *dc, const uint32_t arg[],
                            const uint32_t par[])
{
    if (gen_check_cpenable(dc, 0)) {
        gen_helper_sub_s(cpu_FR[arg[0]], cpu_env,
                         cpu_FR[arg[1]], cpu_FR[arg[2]]);
    }
}

static void translate_wfr_s(DisasContext *dc, const uint32_t arg[],
                            const uint32_t par[])
{
    if (gen_window_check1(dc, arg[1]) &&
        gen_check_cpenable(dc, 0)) {
        tcg_gen_mov_i32(cpu_FR[arg[0]], cpu_R[arg[1]]);
    }
}

static const XtensaOpcodeOps fpu2000_ops[] = {
    {
        .name = "abs.s",
        .translate = translate_abs_s,
    }, {
        .name = "add.s",
        .translate = translate_add_s,
    }, {
        .name = "ceil.s",
        .translate = translate_ftoi_s,
        .par = (const uint32_t[]){float_round_up, false},
    }, {
        .name = "float.s",
        .translate = translate_float_s,
        .par = (const uint32_t[]){false},
    }, {
        .name = "floor.s",
        .translate = translate_ftoi_s,
        .par = (const uint32_t[]){float_round_down, false},
    }, {
        .name = "lsi",
        .translate = translate_ldsti,
        .par = (const uint32_t[]){false, false},
    }, {
        .name = "lsiu",
        .translate = translate_ldsti,
        .par = (const uint32_t[]){false, true},
    }, {
        .name = "lsx",
        .translate = translate_ldstx,
        .par = (const uint32_t[]){false, false},
    }, {
        .name = "lsxu",
        .translate = translate_ldstx,
        .par = (const uint32_t[]){false, true},
    }, {
        .name = "madd.s",
        .translate = translate_madd_s,
    }, {
        .name = "mov.s",
        .translate = translate_mov_s,
    }, {
        .name = "moveqz.s",
        .translate = translate_movcond_s,
        .par = (const uint32_t[]){TCG_COND_EQ},
    }, {
        .name = "movf.s",
        .translate = translate_movp_s,
        .par = (const uint32_t[]){TCG_COND_EQ},
    }, {
        .name = "movgez.s",
        .translate = translate_movcond_s,
        .par = (const uint32_t[]){TCG_COND_GE},
    }, {
        .name = "movltz.s",
        .translate = translate_movcond_s,
        .par = (const uint32_t[]){TCG_COND_LT},
    }, {
        .name = "movnez.s",
        .translate = translate_movcond_s,
        .par = (const uint32_t[]){TCG_COND_NE},
    }, {
        .name = "movt.s",
        .translate = translate_movp_s,
        .par = (const uint32_t[]){TCG_COND_NE},
    }, {
        .name = "msub.s",
        .translate = translate_msub_s,
    }, {
        .name = "mul.s",
        .translate = translate_mul_s,
    }, {
        .name = "neg.s",
        .translate = translate_neg_s,
    }, {
        .name = "oeq.s",
        .translate = translate_compare_s,
        .par = (const uint32_t[]){COMPARE_OEQ},
    }, {
        .name = "ole.s",
        .translate = translate_compare_s,
        .par = (const uint32_t[]){COMPARE_OLE},
    }, {
        .name = "olt.s",
        .translate = translate_compare_s,
        .par = (const uint32_t[]){COMPARE_OLT},
    }, {
        .name = "rfr.s",
        .translate = translate_rfr_s,
    }, {
        .name = "round.s",
        .translate = translate_ftoi_s,
        .par = (const uint32_t[]){float_round_nearest_even, false},
    }, {
        .name = "ssi",
        .translate = translate_ldsti,
        .par = (const uint32_t[]){true, false},
    }, {
        .name = "ssiu",
        .translate = translate_ldsti,
        .par = (const uint32_t[]){true, true},
    }, {
        .name = "ssx",
        .translate = translate_ldstx,
        .par = (const uint32_t[]){true, false},
    }, {
        .name = "ssxu",
        .translate = translate_ldstx,
        .par = (const uint32_t[]){true, true},
    }, {
        .name = "sub.s",
        .translate = translate_sub_s,
    }, {
        .name = "trunc.s",
        .translate = translate_ftoi_s,
        .par = (const uint32_t[]){float_round_to_zero, false},
    }, {
        .name = "ueq.s",
        .translate = translate_compare_s,
        .par = (const uint32_t[]){COMPARE_UEQ},
    }, {
        .name = "ufloat.s",
        .translate = translate_float_s,
        .par = (const uint32_t[]){true},
    }, {
        .name = "ule.s",
        .translate = translate_compare_s,
        .par = (const uint32_t[]){COMPARE_ULE},
    }, {
        .name = "ult.s",
        .translate = translate_compare_s,
        .par = (const uint32_t[]){COMPARE_ULT},
    }, {
        .name = "un.s",
        .translate = translate_compare_s,
        .par = (const uint32_t[]){COMPARE_UN},
    }, {
        .name = "utrunc.s",
        .translate = translate_ftoi_s,
        .par = (const uint32_t[]){float_round_to_zero, true},
    }, {
        .name = "wfr.s",
        .translate = translate_wfr_s,
    },
};

const XtensaOpcodeTranslators xtensa_fpu2000_opcodes = {
    .num_opcodes = ARRAY_SIZE(fpu2000_ops),
    .opcode = fpu2000_ops,
};