target/xtensa: extract test for cpdisabled exception

- add XtensaOpcodeOps::coprocessor with bitmask of coprocessors used by
  the instruction;
- replace coprocessor id parameter of gen_check_cpenable with the
  bitmask of used coprocessors;
- collect coprocessor IDs used by an instruction in the disassembly
  loop;
- put test for coprocessor disabled exception after the alloca test;

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
This commit is contained in:
Max Filippov 2018-08-31 13:57:08 -07:00
parent 90d6494d13
commit 582fef0f47
2 changed files with 123 additions and 108 deletions

View File

@ -381,6 +381,7 @@ typedef struct XtensaOpcodeOps {
const uint32_t *par;
uint32_t op_flags;
uint32_t windowed_register_op;
uint32_t coprocessor;
} XtensaOpcodeOps;
typedef struct XtensaOpcodeTranslators {

View File

@ -351,11 +351,12 @@ static bool gen_check_privilege(DisasContext *dc)
return false;
}
static bool gen_check_cpenable(DisasContext *dc, unsigned cp)
static bool gen_check_cpenable(DisasContext *dc, uint32_t cp_mask)
{
if (option_enabled(dc, XTENSA_OPTION_COPROCESSOR) &&
!(dc->cpenable & (1 << cp))) {
gen_exception_cause(dc, COPROCESSOR0_DISABLED + cp);
cp_mask &= ~dc->cpenable;
if (option_enabled(dc, XTENSA_OPTION_COPROCESSOR) && cp_mask) {
gen_exception_cause(dc, COPROCESSOR0_DISABLED + ctz32(cp_mask));
dc->base.is_jmp = DISAS_NORETURN;
return false;
}
@ -953,6 +954,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
} slot_prop[MAX_INSN_SLOTS];
uint32_t debug_cause = 0;
uint32_t windowed_register = 0;
uint32_t coprocessor = 0;
if (len == XTENSA_UNDEFINED) {
qemu_log_mask(LOG_GUEST_ERROR,
@ -1050,6 +1052,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
reg_opnd ^= 1 << i;
}
}
coprocessor |= ops->coprocessor;
}
if ((op_flags & XTENSA_OP_PRIVILEGED) &&
@ -1085,6 +1088,10 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
tcg_temp_free(tmp);
}
if (coprocessor && !gen_check_cpenable(dc, coprocessor)) {
return;
}
for (slot = 0; slot < slots; ++slot) {
XtensaOpcodeOps *ops = slot_prop[slot].ops;
@ -4084,11 +4091,13 @@ static const XtensaOpcodeOps core_ops[] = {
.translate = translate_rur,
.par = (const uint32_t[]){FCR},
.windowed_register_op = 0x1,
.coprocessor = 0x1,
}, {
.name = "rur.fsr",
.translate = translate_rur,
.par = (const uint32_t[]){FSR},
.windowed_register_op = 0x1,
.coprocessor = 0x1,
}, {
.name = "rur.threadptr",
.translate = translate_rur,
@ -4805,11 +4814,13 @@ static const XtensaOpcodeOps core_ops[] = {
.translate = translate_wur,
.par = (const uint32_t[]){FCR},
.windowed_register_op = 0x1,
.coprocessor = 0x1,
}, {
.name = "wur.fsr",
.translate = translate_wur,
.par = (const uint32_t[]){FSR},
.windowed_register_op = 0x1,
.coprocessor = 0x1,
}, {
.name = "wur.threadptr",
.translate = translate_wur,
@ -5354,18 +5365,14 @@ const XtensaOpcodeTranslators xtensa_core_opcodes = {
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]]);
}
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]]);
}
gen_helper_add_s(cpu_FR[arg[0]], cpu_env,
cpu_FR[arg[1]], cpu_FR[arg[2]]);
}
enum {
@ -5391,350 +5398,357 @@ static void translate_compare_s(DisasContext *dc, const uint32_t arg[],
[COMPARE_OLE] = gen_helper_ole_s,
[COMPARE_ULE] = gen_helper_ule_s,
};
TCGv_i32 bit = tcg_const_i32(1 << arg[0]);
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);
}
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_check_cpenable(dc, 0)) {
TCGv_i32 scale = tcg_const_i32(-arg[2]);
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);
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_check_cpenable(dc, 0)) {
TCGv_i32 rounding_mode = tcg_const_i32(par[0]);
TCGv_i32 scale = tcg_const_i32(arg[2]);
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);
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_check_cpenable(dc, 0)) {
TCGv_i32 addr = tcg_temp_new_i32();
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);
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_check_cpenable(dc, 0)) {
TCGv_i32 addr = tcg_temp_new_i32();
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);
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]]);
}
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]]);
}
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_check_cpenable(dc, 0)) {
TCGv_i32 zero = tcg_const_i32(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[0]]);
tcg_temp_free(zero);
}
tcg_gen_movcond_i32(par[0], cpu_FR[arg[0]],
cpu_R[arg[2]], zero,
cpu_FR[arg[1]], cpu_FR[arg[0]]);
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();
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);
}
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]]);
}
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]]);
}
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]]);
}
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_check_cpenable(dc, 0)) {
tcg_gen_mov_i32(cpu_R[arg[0]], cpu_FR[arg[1]]);
}
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]]);
}
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_check_cpenable(dc, 0)) {
tcg_gen_mov_i32(cpu_FR[arg[0]], cpu_R[arg[1]]);
}
tcg_gen_mov_i32(cpu_FR[arg[0]], cpu_R[arg[1]]);
}
static const XtensaOpcodeOps fpu2000_ops[] = {
{
.name = "abs.s",
.translate = translate_abs_s,
.coprocessor = 0x1,
}, {
.name = "add.s",
.translate = translate_add_s,
.coprocessor = 0x1,
}, {
.name = "ceil.s",
.translate = translate_ftoi_s,
.par = (const uint32_t[]){float_round_up, false},
.windowed_register_op = 0x1,
.coprocessor = 0x1,
}, {
.name = "float.s",
.translate = translate_float_s,
.par = (const uint32_t[]){false},
.windowed_register_op = 0x2,
.coprocessor = 0x1,
}, {
.name = "floor.s",
.translate = translate_ftoi_s,
.par = (const uint32_t[]){float_round_down, false},
.windowed_register_op = 0x1,
.coprocessor = 0x1,
}, {
.name = "lsi",
.translate = translate_ldsti,
.par = (const uint32_t[]){false, false},
.windowed_register_op = 0x2,
.coprocessor = 0x1,
}, {
.name = "lsiu",
.translate = translate_ldsti,
.par = (const uint32_t[]){false, true},
.windowed_register_op = 0x2,
.coprocessor = 0x1,
}, {
.name = "lsx",
.translate = translate_ldstx,
.par = (const uint32_t[]){false, false},
.windowed_register_op = 0x6,
.coprocessor = 0x1,
}, {
.name = "lsxu",
.translate = translate_ldstx,
.par = (const uint32_t[]){false, true},
.windowed_register_op = 0x6,
.coprocessor = 0x1,
}, {
.name = "madd.s",
.translate = translate_madd_s,
.coprocessor = 0x1,
}, {
.name = "mov.s",
.translate = translate_mov_s,
.coprocessor = 0x1,
}, {
.name = "moveqz.s",
.translate = translate_movcond_s,
.par = (const uint32_t[]){TCG_COND_EQ},
.windowed_register_op = 0x4,
.coprocessor = 0x1,
}, {
.name = "movf.s",
.translate = translate_movp_s,
.par = (const uint32_t[]){TCG_COND_EQ},
.coprocessor = 0x1,
}, {
.name = "movgez.s",
.translate = translate_movcond_s,
.par = (const uint32_t[]){TCG_COND_GE},
.windowed_register_op = 0x4,
.coprocessor = 0x1,
}, {
.name = "movltz.s",
.translate = translate_movcond_s,
.par = (const uint32_t[]){TCG_COND_LT},
.windowed_register_op = 0x4,
.coprocessor = 0x1,
}, {
.name = "movnez.s",
.translate = translate_movcond_s,
.par = (const uint32_t[]){TCG_COND_NE},
.windowed_register_op = 0x4,
.coprocessor = 0x1,
}, {
.name = "movt.s",
.translate = translate_movp_s,
.par = (const uint32_t[]){TCG_COND_NE},
.coprocessor = 0x1,
}, {
.name = "msub.s",
.translate = translate_msub_s,
.coprocessor = 0x1,
}, {
.name = "mul.s",
.translate = translate_mul_s,
.coprocessor = 0x1,
}, {
.name = "neg.s",
.translate = translate_neg_s,
.coprocessor = 0x1,
}, {
.name = "oeq.s",
.translate = translate_compare_s,
.par = (const uint32_t[]){COMPARE_OEQ},
.coprocessor = 0x1,
}, {
.name = "ole.s",
.translate = translate_compare_s,
.par = (const uint32_t[]){COMPARE_OLE},
.coprocessor = 0x1,
}, {
.name = "olt.s",
.translate = translate_compare_s,
.par = (const uint32_t[]){COMPARE_OLT},
.coprocessor = 0x1,
}, {
.name = "rfr",
.translate = translate_rfr_s,
.windowed_register_op = 0x1,
.coprocessor = 0x1,
}, {
.name = "round.s",
.translate = translate_ftoi_s,
.par = (const uint32_t[]){float_round_nearest_even, false},
.windowed_register_op = 0x1,
.coprocessor = 0x1,
}, {
.name = "ssi",
.translate = translate_ldsti,
.par = (const uint32_t[]){true, false},
.windowed_register_op = 0x2,
.coprocessor = 0x1,
}, {
.name = "ssiu",
.translate = translate_ldsti,
.par = (const uint32_t[]){true, true},
.windowed_register_op = 0x2,
.coprocessor = 0x1,
}, {
.name = "ssx",
.translate = translate_ldstx,
.par = (const uint32_t[]){true, false},
.windowed_register_op = 0x6,
.coprocessor = 0x1,
}, {
.name = "ssxu",
.translate = translate_ldstx,
.par = (const uint32_t[]){true, true},
.windowed_register_op = 0x6,
.coprocessor = 0x1,
}, {
.name = "sub.s",
.translate = translate_sub_s,
.coprocessor = 0x1,
}, {
.name = "trunc.s",
.translate = translate_ftoi_s,
.par = (const uint32_t[]){float_round_to_zero, false},
.windowed_register_op = 0x1,
.coprocessor = 0x1,
}, {
.name = "ueq.s",
.translate = translate_compare_s,
.par = (const uint32_t[]){COMPARE_UEQ},
.coprocessor = 0x1,
}, {
.name = "ufloat.s",
.translate = translate_float_s,
.par = (const uint32_t[]){true},
.windowed_register_op = 0x2,
.coprocessor = 0x1,
}, {
.name = "ule.s",
.translate = translate_compare_s,
.par = (const uint32_t[]){COMPARE_ULE},
.coprocessor = 0x1,
}, {
.name = "ult.s",
.translate = translate_compare_s,
.par = (const uint32_t[]){COMPARE_ULT},
.coprocessor = 0x1,
}, {
.name = "un.s",
.translate = translate_compare_s,
.par = (const uint32_t[]){COMPARE_UN},
.coprocessor = 0x1,
}, {
.name = "utrunc.s",
.translate = translate_ftoi_s,
.par = (const uint32_t[]){float_round_to_zero, true},
.windowed_register_op = 0x1,
.coprocessor = 0x1,
}, {
.name = "wfr",
.translate = translate_wfr_s,
.windowed_register_op = 0x2,
.coprocessor = 0x1,
},
};