target/arm: Separate decode from handling of coproc insns

As a prelude to making coproc insns use decodetree, split out the
part of disas_coproc_insn() which does instruction decoding from the
part which does the actual work, and make do_coproc_insn() handle the
UNDEF-on-bad-permissions and similar cases itself rather than
returning 1 to eventually percolate up to a callsite that calls
unallocated_encoding() for it.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20200803111849.13368-3-peter.maydell@linaro.org
This commit is contained in:
Peter Maydell 2020-08-03 12:18:44 +01:00
parent 7b4f933db8
commit 19c23a9baa
1 changed files with 44 additions and 32 deletions

View File

@ -4544,34 +4544,12 @@ void gen_gvec_uaba(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]);
}
static int disas_coproc_insn(DisasContext *s, uint32_t insn)
static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
int opc1, int crn, int crm, int opc2,
bool isread, int rt, int rt2)
{
int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2;
const ARMCPRegInfo *ri;
cpnum = (insn >> 8) & 0xf;
is64 = (insn & (1 << 25)) == 0;
if (!is64 && ((insn & (1 << 4)) == 0)) {
/* cdp */
return 1;
}
crm = insn & 0xf;
if (is64) {
crn = 0;
opc1 = (insn >> 4) & 0xf;
opc2 = 0;
rt2 = (insn >> 16) & 0xf;
} else {
crn = (insn >> 16) & 0xf;
opc1 = (insn >> 21) & 7;
opc2 = (insn >> 5) & 7;
rt2 = 0;
}
isread = (insn >> 20) & 1;
rt = (insn >> 12) & 0xf;
ri = get_arm_cp_reginfo(s->cp_regs,
ENCODE_CP_REG(cpnum, is64, s->ns, crn, crm, opc1, opc2));
if (ri) {
@ -4579,7 +4557,8 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
/* Check access permissions */
if (!cp_access_ok(s->current_el, ri, isread)) {
return 1;
unallocated_encoding(s);
return;
}
if (s->hstr_active || ri->accessfn ||
@ -4653,14 +4632,15 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
/* Handle special cases first */
switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
case ARM_CP_NOP:
return 0;
return;
case ARM_CP_WFI:
if (isread) {
return 1;
unallocated_encoding(s);
return;
}
gen_set_pc_im(s, s->base.pc_next);
s->base.is_jmp = DISAS_WFI;
return 0;
return;
default:
break;
}
@ -4720,7 +4700,7 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
/* Write */
if (ri->type & ARM_CP_CONST) {
/* If not forbidden by access permissions, treat as WI */
return 0;
return;
}
if (is64) {
@ -4786,7 +4766,7 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
gen_lookup_tb(s);
}
return 0;
return;
}
/* Unknown register; this might be a guest error or a QEMU
@ -4806,7 +4786,39 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
s->ns ? "non-secure" : "secure");
}
return 1;
unallocated_encoding(s);
return;
}
static int disas_coproc_insn(DisasContext *s, uint32_t insn)
{
int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2;
cpnum = (insn >> 8) & 0xf;
is64 = (insn & (1 << 25)) == 0;
if (!is64 && ((insn & (1 << 4)) == 0)) {
/* cdp */
return 1;
}
crm = insn & 0xf;
if (is64) {
crn = 0;
opc1 = (insn >> 4) & 0xf;
opc2 = 0;
rt2 = (insn >> 16) & 0xf;
} else {
crn = (insn >> 16) & 0xf;
opc1 = (insn >> 21) & 7;
opc2 = (insn >> 5) & 7;
rt2 = 0;
}
isread = (insn >> 20) & 1;
rt = (insn >> 12) & 0xf;
do_coproc_insn(s, cpnum, is64, opc1, crn, crm, opc2, isread, rt, rt2);
return 0;
}
/* Decode XScale DSP or iWMMXt insn (in the copro space, cp=0 or 1) */