mirror of https://github.com/xemu-project/xemu.git
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:
parent
d78b662f28
commit
45d063d163
|
@ -194,3 +194,16 @@ SB 1101 0101 0000 0011 0011 0000 111 11111
|
||||||
CFINV 1101 0101 0000 0 000 0100 0000 000 11111
|
CFINV 1101 0101 0000 0 000 0100 0000 000 11111
|
||||||
XAFLAG 1101 0101 0000 0 000 0100 0000 001 11111
|
XAFLAG 1101 0101 0000 0 000 0100 0000 001 11111
|
||||||
AXFLAG 1101 0101 0000 0 000 0100 0000 010 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
|
||||||
|
|
|
@ -1927,85 +1927,81 @@ static bool trans_AXFLAG(DisasContext *s, arg_AXFLAG *a)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MSR (immediate) - move immediate to processor state field */
|
static bool trans_MSR_i_UAO(DisasContext *s, arg_i *a)
|
||||||
static void handle_msr_i(DisasContext *s, uint32_t insn,
|
|
||||||
unsigned int op1, unsigned int op2, unsigned int crm)
|
|
||||||
{
|
{
|
||||||
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) {
|
if (!dc_isar_feature(aa64_uao, s) || s->current_el == 0) {
|
||||||
goto do_unallocated;
|
return false;
|
||||||
}
|
}
|
||||||
if (crm & 1) {
|
if (a->imm & 1) {
|
||||||
set_pstate_bits(PSTATE_UAO);
|
set_pstate_bits(PSTATE_UAO);
|
||||||
} else {
|
} else {
|
||||||
clear_pstate_bits(PSTATE_UAO);
|
clear_pstate_bits(PSTATE_UAO);
|
||||||
}
|
}
|
||||||
gen_rebuild_hflags(s);
|
gen_rebuild_hflags(s);
|
||||||
break;
|
s->base.is_jmp = DISAS_TOO_MANY;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
case 0x04: /* PAN */
|
static bool trans_MSR_i_PAN(DisasContext *s, arg_i *a)
|
||||||
|
{
|
||||||
if (!dc_isar_feature(aa64_pan, s) || s->current_el == 0) {
|
if (!dc_isar_feature(aa64_pan, s) || s->current_el == 0) {
|
||||||
goto do_unallocated;
|
return false;
|
||||||
}
|
}
|
||||||
if (crm & 1) {
|
if (a->imm & 1) {
|
||||||
set_pstate_bits(PSTATE_PAN);
|
set_pstate_bits(PSTATE_PAN);
|
||||||
} else {
|
} else {
|
||||||
clear_pstate_bits(PSTATE_PAN);
|
clear_pstate_bits(PSTATE_PAN);
|
||||||
}
|
}
|
||||||
gen_rebuild_hflags(s);
|
gen_rebuild_hflags(s);
|
||||||
break;
|
s->base.is_jmp = DISAS_TOO_MANY;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
case 0x05: /* SPSel */
|
static bool trans_MSR_i_SPSEL(DisasContext *s, arg_i *a)
|
||||||
|
{
|
||||||
if (s->current_el == 0) {
|
if (s->current_el == 0) {
|
||||||
goto do_unallocated;
|
return false;
|
||||||
}
|
}
|
||||||
gen_helper_msr_i_spsel(cpu_env, tcg_constant_i32(crm & PSTATE_SP));
|
gen_helper_msr_i_spsel(cpu_env, tcg_constant_i32(a->imm & PSTATE_SP));
|
||||||
break;
|
s->base.is_jmp = DISAS_TOO_MANY;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
case 0x19: /* SSBS */
|
static bool trans_MSR_i_SBSS(DisasContext *s, arg_i *a)
|
||||||
|
{
|
||||||
if (!dc_isar_feature(aa64_ssbs, s)) {
|
if (!dc_isar_feature(aa64_ssbs, s)) {
|
||||||
goto do_unallocated;
|
return false;
|
||||||
}
|
}
|
||||||
if (crm & 1) {
|
if (a->imm & 1) {
|
||||||
set_pstate_bits(PSTATE_SSBS);
|
set_pstate_bits(PSTATE_SSBS);
|
||||||
} else {
|
} else {
|
||||||
clear_pstate_bits(PSTATE_SSBS);
|
clear_pstate_bits(PSTATE_SSBS);
|
||||||
}
|
}
|
||||||
/* Don't need to rebuild hflags since SSBS is a nop */
|
/* Don't need to rebuild hflags since SSBS is a nop */
|
||||||
break;
|
s->base.is_jmp = DISAS_TOO_MANY;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
case 0x1a: /* DIT */
|
static bool trans_MSR_i_DIT(DisasContext *s, arg_i *a)
|
||||||
|
{
|
||||||
if (!dc_isar_feature(aa64_dit, s)) {
|
if (!dc_isar_feature(aa64_dit, s)) {
|
||||||
goto do_unallocated;
|
return false;
|
||||||
}
|
}
|
||||||
if (crm & 1) {
|
if (a->imm & 1) {
|
||||||
set_pstate_bits(PSTATE_DIT);
|
set_pstate_bits(PSTATE_DIT);
|
||||||
} else {
|
} else {
|
||||||
clear_pstate_bits(PSTATE_DIT);
|
clear_pstate_bits(PSTATE_DIT);
|
||||||
}
|
}
|
||||||
/* There's no need to rebuild hflags because DIT is a nop */
|
/* There's no need to rebuild hflags because DIT is a nop */
|
||||||
break;
|
s->base.is_jmp = DISAS_TOO_MANY;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
case 0x1e: /* DAIFSet */
|
static bool trans_MSR_i_TCO(DisasContext *s, arg_i *a)
|
||||||
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)) {
|
if (dc_isar_feature(aa64_mte, s)) {
|
||||||
/* Full MTE is enabled -- set the TCO bit as directed. */
|
/* Full MTE is enabled -- set the TCO bit as directed. */
|
||||||
if (crm & 1) {
|
if (a->imm & 1) {
|
||||||
set_pstate_bits(PSTATE_TCO);
|
set_pstate_bits(PSTATE_TCO);
|
||||||
} else {
|
} else {
|
||||||
clear_pstate_bits(PSTATE_TCO);
|
clear_pstate_bits(PSTATE_TCO);
|
||||||
|
@ -2013,38 +2009,48 @@ static void handle_msr_i(DisasContext *s, uint32_t insn,
|
||||||
gen_rebuild_hflags(s);
|
gen_rebuild_hflags(s);
|
||||||
/* Many factors, including TCO, go into MTE_ACTIVE. */
|
/* Many factors, including TCO, go into MTE_ACTIVE. */
|
||||||
s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
|
s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
|
||||||
|
return true;
|
||||||
} else if (dc_isar_feature(aa64_mte_insn_reg, s)) {
|
} else if (dc_isar_feature(aa64_mte_insn_reg, s)) {
|
||||||
/* Only "instructions accessible at EL0" -- PSTATE.TCO is WI. */
|
/* Only "instructions accessible at EL0" -- PSTATE.TCO is WI. */
|
||||||
s->base.is_jmp = DISAS_NEXT;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
goto do_unallocated;
|
/* Insn not present */
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
|
|
||||||
case 0x1b: /* SVCR* */
|
static bool trans_MSR_i_DAIFSET(DisasContext *s, arg_i *a)
|
||||||
if (!dc_isar_feature(aa64_sme, s) || crm < 2 || crm > 7) {
|
{
|
||||||
goto do_unallocated;
|
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)) {
|
if (sme_access_check(s)) {
|
||||||
int old = s->pstate_sm | (s->pstate_za << 1);
|
int old = s->pstate_sm | (s->pstate_za << 1);
|
||||||
int new = (crm & 1) * 3;
|
int new = a->imm * 3;
|
||||||
int msk = (crm >> 1) & 3;
|
|
||||||
|
|
||||||
if ((old ^ new) & msk) {
|
if ((old ^ new) & a->mask) {
|
||||||
/* At least one bit changes. */
|
/* At least one bit changes. */
|
||||||
gen_helper_set_svcr(cpu_env, tcg_constant_i32(new),
|
gen_helper_set_svcr(cpu_env, tcg_constant_i32(new),
|
||||||
tcg_constant_i32(msk));
|
tcg_constant_i32(a->mask));
|
||||||
} else {
|
s->base.is_jmp = DISAS_TOO_MANY;
|
||||||
s->base.is_jmp = DISAS_NEXT;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
return true;
|
||||||
|
|
||||||
default:
|
|
||||||
do_unallocated:
|
|
||||||
unallocated_encoding(s);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gen_get_nzcv(TCGv_i64 tcg_rt)
|
static void gen_get_nzcv(TCGv_i64 tcg_rt)
|
||||||
|
@ -2319,20 +2325,9 @@ static void disas_system(DisasContext *s, uint32_t insn)
|
||||||
rt = extract32(insn, 0, 5);
|
rt = extract32(insn, 0, 5);
|
||||||
|
|
||||||
if (op0 == 0) {
|
if (op0 == 0) {
|
||||||
if (l || rt != 31) {
|
|
||||||
unallocated_encoding(s);
|
unallocated_encoding(s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (crn) {
|
|
||||||
case 4: /* MSR (immediate) */
|
|
||||||
handle_msr_i(s, insn, op1, op2, crm);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
unallocated_encoding(s);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
handle_sys(s, insn, l, op0, op1, op2, crn, crm, rt);
|
handle_sys(s, insn, l, op0, op1, op2, crn, crm, rt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue