summaryrefslogtreecommitdiffstats
path: root/target/arm/translate.c
diff options
context:
space:
mode:
authorRichard Henderson2019-09-04 21:30:24 +0200
committerPeter Maydell2019-09-05 14:23:03 +0200
commit885782a78c6d05932c5d8f463dc50fc8312e3eb9 (patch)
treef546e3bc16fd49465f69e8707099bfeb0482c751 /target/arm/translate.c
parenttarget/arm: Convert SVC (diff)
downloadqemu-885782a78c6d05932c5d8f463dc50fc8312e3eb9.tar.gz
qemu-885782a78c6d05932c5d8f463dc50fc8312e3eb9.tar.xz
qemu-885782a78c6d05932c5d8f463dc50fc8312e3eb9.zip
target/arm: Convert RFE and SRS
Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20190904193059.26202-35-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target/arm/translate.c')
-rw-r--r--target/arm/translate.c144
1 files changed, 55 insertions, 89 deletions
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 208021181f..ca4873e514 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -10094,15 +10094,64 @@ static bool trans_SVC(DisasContext *s, arg_SVC *a)
}
/*
+ * Unconditional system instructions
+ */
+
+static bool trans_RFE(DisasContext *s, arg_RFE *a)
+{
+ static const int8_t pre_offset[4] = {
+ /* DA */ -4, /* IA */ 0, /* DB */ -8, /* IB */ 4
+ };
+ static const int8_t post_offset[4] = {
+ /* DA */ -8, /* IA */ 4, /* DB */ -4, /* IB */ 0
+ };
+ TCGv_i32 addr, t1, t2;
+
+ if (!ENABLE_ARCH_6 || arm_dc_feature(s, ARM_FEATURE_M)) {
+ return false;
+ }
+ if (IS_USER(s)) {
+ unallocated_encoding(s);
+ return true;
+ }
+
+ addr = load_reg(s, a->rn);
+ tcg_gen_addi_i32(addr, addr, pre_offset[a->pu]);
+
+ /* Load PC into tmp and CPSR into tmp2. */
+ t1 = tcg_temp_new_i32();
+ gen_aa32_ld32u(s, t1, addr, get_mem_index(s));
+ tcg_gen_addi_i32(addr, addr, 4);
+ t2 = tcg_temp_new_i32();
+ gen_aa32_ld32u(s, t2, addr, get_mem_index(s));
+
+ if (a->w) {
+ /* Base writeback. */
+ tcg_gen_addi_i32(addr, addr, post_offset[a->pu]);
+ store_reg(s, a->rn, addr);
+ } else {
+ tcg_temp_free_i32(addr);
+ }
+ gen_rfe(s, t1, t2);
+ return true;
+}
+
+static bool trans_SRS(DisasContext *s, arg_SRS *a)
+{
+ if (!ENABLE_ARCH_6 || arm_dc_feature(s, ARM_FEATURE_M)) {
+ return false;
+ }
+ gen_srs(s, a->mode, a->pu, a->w);
+ return true;
+}
+
+/*
* Legacy decoder.
*/
static void disas_arm_insn(DisasContext *s, unsigned int insn)
{
- unsigned int cond, op1, i, rn;
- TCGv_i32 tmp;
- TCGv_i32 tmp2;
- TCGv_i32 addr;
+ unsigned int cond, op1;
/* M variants do not implement ARM mode; this must raise the INVSTATE
* UsageFault exception.
@@ -10221,52 +10270,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
default:
goto illegal_op;
}
- } else if ((insn & 0x0e5fffe0) == 0x084d0500) {
- /* srs */
- ARCH(6);
- gen_srs(s, (insn & 0x1f), (insn >> 23) & 3, insn & (1 << 21));
- return;
- } else if ((insn & 0x0e50ffe0) == 0x08100a00) {
- /* rfe */
- int32_t offset;
- if (IS_USER(s))
- goto illegal_op;
- ARCH(6);
- rn = (insn >> 16) & 0xf;
- addr = load_reg(s, rn);
- i = (insn >> 23) & 3;
- switch (i) {
- case 0: offset = -4; break; /* DA */
- case 1: offset = 0; break; /* IA */
- case 2: offset = -8; break; /* DB */
- case 3: offset = 4; break; /* IB */
- default: abort();
- }
- if (offset)
- tcg_gen_addi_i32(addr, addr, offset);
- /* Load PC into tmp and CPSR into tmp2. */
- tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
- tcg_gen_addi_i32(addr, addr, 4);
- tmp2 = tcg_temp_new_i32();
- gen_aa32_ld32u(s, tmp2, addr, get_mem_index(s));
- if (insn & (1 << 21)) {
- /* Base writeback. */
- switch (i) {
- case 0: offset = -8; break;
- case 1: offset = 4; break;
- case 2: offset = -4; break;
- case 3: offset = 0; break;
- default: abort();
- }
- if (offset)
- tcg_gen_addi_i32(addr, addr, offset);
- store_reg(s, rn, addr);
- } else {
- tcg_temp_free_i32(addr);
- }
- gen_rfe(s, tmp, tmp2);
- return;
} else if ((insn & 0x0e000f00) == 0x0c000100) {
if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) {
/* iWMMXt register transfer. */
@@ -10429,7 +10432,6 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
uint32_t imm, offset;
uint32_t rd, rn, rm, rs;
TCGv_i32 tmp;
- TCGv_i32 tmp2;
TCGv_i32 addr;
int op;
@@ -10573,44 +10575,8 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
goto illegal_op;
}
} else {
- /* Load/store multiple, RFE, SRS. */
- if (((insn >> 23) & 1) == ((insn >> 24) & 1)) {
- /* RFE, SRS: not available in user mode or on M profile */
- if (IS_USER(s) || arm_dc_feature(s, ARM_FEATURE_M)) {
- goto illegal_op;
- }
- if (insn & (1 << 20)) {
- /* rfe */
- addr = load_reg(s, rn);
- if ((insn & (1 << 24)) == 0)
- tcg_gen_addi_i32(addr, addr, -8);
- /* Load PC into tmp and CPSR into tmp2. */
- tmp = tcg_temp_new_i32();
- gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
- tcg_gen_addi_i32(addr, addr, 4);
- tmp2 = tcg_temp_new_i32();
- gen_aa32_ld32u(s, tmp2, addr, get_mem_index(s));
- if (insn & (1 << 21)) {
- /* Base writeback. */
- if (insn & (1 << 24)) {
- tcg_gen_addi_i32(addr, addr, 4);
- } else {
- tcg_gen_addi_i32(addr, addr, -4);
- }
- store_reg(s, rn, addr);
- } else {
- tcg_temp_free_i32(addr);
- }
- gen_rfe(s, tmp, tmp2);
- } else {
- /* srs */
- gen_srs(s, (insn & 0x1f), (insn & (1 << 24)) ? 1 : 2,
- insn & (1 << 21));
- }
- } else {
- /* Load/store multiple, in decodetree */
- goto illegal_op;
- }
+ /* Load/store multiple, RFE, SRS, in decodetree */
+ goto illegal_op;
}
break;
case 5: