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: Max Filippov <jcmvbkbc@gmail.com>
stable-2.12
Max Filippov 2017-11-03 19:37:13 -07:00
parent 168c12b024
commit c04e1692e3
2 changed files with 375 additions and 0 deletions

View File

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

View File

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