target/arm: Convert MSR (immediate) to decodetree

Convert the MSR (immediate) insn to decodetree. Our implementation
has basically no commonality between the different destinations,
so we decode the destination register in a64.decode.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20230602155223.2040685-6-peter.maydell@linaro.org
This commit is contained in:
Peter Maydell 2023-06-19 11:20:20 +01:00
parent d78b662f28
commit 45d063d163
2 changed files with 136 additions and 128 deletions

View File

@ -194,3 +194,16 @@ SB 1101 0101 0000 0011 0011 0000 111 11111
CFINV 1101 0101 0000 0 000 0100 0000 000 11111
XAFLAG 1101 0101 0000 0 000 0100 0000 001 11111
AXFLAG 1101 0101 0000 0 000 0100 0000 010 11111
# These are architecturally all "MSR (immediate)"; we decode the destination
# register too because there is no commonality in our implementation.
@msr_i .... .... .... . ... .... imm:4 ... .....
MSR_i_UAO 1101 0101 0000 0 000 0100 .... 011 11111 @msr_i
MSR_i_PAN 1101 0101 0000 0 000 0100 .... 100 11111 @msr_i
MSR_i_SPSEL 1101 0101 0000 0 000 0100 .... 101 11111 @msr_i
MSR_i_SBSS 1101 0101 0000 0 011 0100 .... 001 11111 @msr_i
MSR_i_DIT 1101 0101 0000 0 011 0100 .... 010 11111 @msr_i
MSR_i_TCO 1101 0101 0000 0 011 0100 .... 100 11111 @msr_i
MSR_i_DAIFSET 1101 0101 0000 0 011 0100 .... 110 11111 @msr_i
MSR_i_DAIFCLEAR 1101 0101 0000 0 011 0100 .... 111 11111 @msr_i
MSR_i_SVCR 1101 0101 0000 0 011 0100 0 mask:2 imm:1 011 11111

View File

@ -1927,124 +1927,130 @@ static bool trans_AXFLAG(DisasContext *s, arg_AXFLAG *a)
return true;
}
/* MSR (immediate) - move immediate to processor state field */
static void handle_msr_i(DisasContext *s, uint32_t insn,
unsigned int op1, unsigned int op2, unsigned int crm)
static bool trans_MSR_i_UAO(DisasContext *s, arg_i *a)
{
int op = op1 << 3 | op2;
/* End the TB by default, chaining is ok. */
s->base.is_jmp = DISAS_TOO_MANY;
switch (op) {
case 0x03: /* UAO */
if (!dc_isar_feature(aa64_uao, s) || s->current_el == 0) {
goto do_unallocated;
}
if (crm & 1) {
set_pstate_bits(PSTATE_UAO);
} else {
clear_pstate_bits(PSTATE_UAO);
}
gen_rebuild_hflags(s);
break;
case 0x04: /* PAN */
if (!dc_isar_feature(aa64_pan, s) || s->current_el == 0) {
goto do_unallocated;
}
if (crm & 1) {
set_pstate_bits(PSTATE_PAN);
} else {
clear_pstate_bits(PSTATE_PAN);
}
gen_rebuild_hflags(s);
break;
case 0x05: /* SPSel */
if (s->current_el == 0) {
goto do_unallocated;
}
gen_helper_msr_i_spsel(cpu_env, tcg_constant_i32(crm & PSTATE_SP));
break;
case 0x19: /* SSBS */
if (!dc_isar_feature(aa64_ssbs, s)) {
goto do_unallocated;
}
if (crm & 1) {
set_pstate_bits(PSTATE_SSBS);
} else {
clear_pstate_bits(PSTATE_SSBS);
}
/* Don't need to rebuild hflags since SSBS is a nop */
break;
case 0x1a: /* DIT */
if (!dc_isar_feature(aa64_dit, s)) {
goto do_unallocated;
}
if (crm & 1) {
set_pstate_bits(PSTATE_DIT);
} else {
clear_pstate_bits(PSTATE_DIT);
}
/* There's no need to rebuild hflags because DIT is a nop */
break;
case 0x1e: /* DAIFSet */
gen_helper_msr_i_daifset(cpu_env, tcg_constant_i32(crm));
break;
case 0x1f: /* DAIFClear */
gen_helper_msr_i_daifclear(cpu_env, tcg_constant_i32(crm));
/* For DAIFClear, exit the cpu loop to re-evaluate pending IRQs. */
s->base.is_jmp = DISAS_UPDATE_EXIT;
break;
case 0x1c: /* TCO */
if (dc_isar_feature(aa64_mte, s)) {
/* Full MTE is enabled -- set the TCO bit as directed. */
if (crm & 1) {
set_pstate_bits(PSTATE_TCO);
} else {
clear_pstate_bits(PSTATE_TCO);
}
gen_rebuild_hflags(s);
/* Many factors, including TCO, go into MTE_ACTIVE. */
s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
} else if (dc_isar_feature(aa64_mte_insn_reg, s)) {
/* Only "instructions accessible at EL0" -- PSTATE.TCO is WI. */
s->base.is_jmp = DISAS_NEXT;
} else {
goto do_unallocated;
}
break;
case 0x1b: /* SVCR* */
if (!dc_isar_feature(aa64_sme, s) || crm < 2 || crm > 7) {
goto do_unallocated;
}
if (sme_access_check(s)) {
int old = s->pstate_sm | (s->pstate_za << 1);
int new = (crm & 1) * 3;
int msk = (crm >> 1) & 3;
if ((old ^ new) & msk) {
/* At least one bit changes. */
gen_helper_set_svcr(cpu_env, tcg_constant_i32(new),
tcg_constant_i32(msk));
} else {
s->base.is_jmp = DISAS_NEXT;
}
}
break;
default:
do_unallocated:
unallocated_encoding(s);
return;
if (!dc_isar_feature(aa64_uao, s) || s->current_el == 0) {
return false;
}
if (a->imm & 1) {
set_pstate_bits(PSTATE_UAO);
} else {
clear_pstate_bits(PSTATE_UAO);
}
gen_rebuild_hflags(s);
s->base.is_jmp = DISAS_TOO_MANY;
return true;
}
static bool trans_MSR_i_PAN(DisasContext *s, arg_i *a)
{
if (!dc_isar_feature(aa64_pan, s) || s->current_el == 0) {
return false;
}
if (a->imm & 1) {
set_pstate_bits(PSTATE_PAN);
} else {
clear_pstate_bits(PSTATE_PAN);
}
gen_rebuild_hflags(s);
s->base.is_jmp = DISAS_TOO_MANY;
return true;
}
static bool trans_MSR_i_SPSEL(DisasContext *s, arg_i *a)
{
if (s->current_el == 0) {
return false;
}
gen_helper_msr_i_spsel(cpu_env, tcg_constant_i32(a->imm & PSTATE_SP));
s->base.is_jmp = DISAS_TOO_MANY;
return true;
}
static bool trans_MSR_i_SBSS(DisasContext *s, arg_i *a)
{
if (!dc_isar_feature(aa64_ssbs, s)) {
return false;
}
if (a->imm & 1) {
set_pstate_bits(PSTATE_SSBS);
} else {
clear_pstate_bits(PSTATE_SSBS);
}
/* Don't need to rebuild hflags since SSBS is a nop */
s->base.is_jmp = DISAS_TOO_MANY;
return true;
}
static bool trans_MSR_i_DIT(DisasContext *s, arg_i *a)
{
if (!dc_isar_feature(aa64_dit, s)) {
return false;
}
if (a->imm & 1) {
set_pstate_bits(PSTATE_DIT);
} else {
clear_pstate_bits(PSTATE_DIT);
}
/* There's no need to rebuild hflags because DIT is a nop */
s->base.is_jmp = DISAS_TOO_MANY;
return true;
}
static bool trans_MSR_i_TCO(DisasContext *s, arg_i *a)
{
if (dc_isar_feature(aa64_mte, s)) {
/* Full MTE is enabled -- set the TCO bit as directed. */
if (a->imm & 1) {
set_pstate_bits(PSTATE_TCO);
} else {
clear_pstate_bits(PSTATE_TCO);
}
gen_rebuild_hflags(s);
/* Many factors, including TCO, go into MTE_ACTIVE. */
s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
return true;
} else if (dc_isar_feature(aa64_mte_insn_reg, s)) {
/* Only "instructions accessible at EL0" -- PSTATE.TCO is WI. */
return true;
} else {
/* Insn not present */
return false;
}
}
static bool trans_MSR_i_DAIFSET(DisasContext *s, arg_i *a)
{
gen_helper_msr_i_daifset(cpu_env, tcg_constant_i32(a->imm));
s->base.is_jmp = DISAS_TOO_MANY;
return true;
}
static bool trans_MSR_i_DAIFCLEAR(DisasContext *s, arg_i *a)
{
gen_helper_msr_i_daifclear(cpu_env, tcg_constant_i32(a->imm));
/* Exit the cpu loop to re-evaluate pending IRQs. */
s->base.is_jmp = DISAS_UPDATE_EXIT;
return true;
}
static bool trans_MSR_i_SVCR(DisasContext *s, arg_MSR_i_SVCR *a)
{
if (!dc_isar_feature(aa64_sme, s) || a->mask == 0) {
return false;
}
if (sme_access_check(s)) {
int old = s->pstate_sm | (s->pstate_za << 1);
int new = a->imm * 3;
if ((old ^ new) & a->mask) {
/* At least one bit changes. */
gen_helper_set_svcr(cpu_env, tcg_constant_i32(new),
tcg_constant_i32(a->mask));
s->base.is_jmp = DISAS_TOO_MANY;
}
}
return true;
}
static void gen_get_nzcv(TCGv_i64 tcg_rt)
@ -2319,18 +2325,7 @@ static void disas_system(DisasContext *s, uint32_t insn)
rt = extract32(insn, 0, 5);
if (op0 == 0) {
if (l || rt != 31) {
unallocated_encoding(s);
return;
}
switch (crn) {
case 4: /* MSR (immediate) */
handle_msr_i(s, insn, op1, op2, crm);
break;
default:
unallocated_encoding(s);
break;
}
unallocated_encoding(s);
return;
}
handle_sys(s, insn, l, op0, op1, op2, crn, crm, rt);