From: Filip Navara <filip.navara@gmail.com>
To: Jamie Lokier <jamie@shareable.org>
Cc: Paul Brook <paul@codesourcery.com>, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH] ARM7TDMI emulation
Date: Wed, 17 Jun 2009 12:24:25 +0200 [thread overview]
Message-ID: <5b31733c0906170324s663cd361q8c27098be17021a2@mail.gmail.com> (raw)
In-Reply-To: <5b31733c0906170255p65c995a3r6e3f5ab060440fde@mail.gmail.com>
[-- Attachment #1.1: Type: text/plain, Size: 1166 bytes --]
On Wed, Jun 17, 2009 at 11:55 AM, Filip Navara <filip.navara@gmail.com>wrote:
> On Tue, Jun 16, 2009 at 10:49 PM, Filip Navara <filip.navara@gmail.com>wrote:
>
>> Do you know of a good summary reference which lists which instructions
>>> are available in each ARM architecture level from ARMv4 up to ARMv7
>>> and it's variants?
>>>
>>
>> My main reference are the technical reference manuals for ARM processors
>> downloaded from Atmel site. I'm not sure about the license, but it states
>> "This document is Open Access. This document has no restriction on
>> distribution." Other reference sources are Skyeye emulation (has to be taken
>> with grain of salt and checked against the manuals, but it makes distinction
>> between v4, v5 and v5e) and Paul Brook.
>>
>> I've certainly missed handling BLX (at least on three places) in the patch
>> and possibly more. I'll post an updated patch soon.
>>
>
> ... and here's the updated patch. Comments welcome.
>
> I've added more checks for V5+ instructions and fixed about every LDR/LDM
> place I found to not call gen_bx to set r15.
>
> Best regards,
> Filip Navara
>
Damn it, forgot to attach it. Thanks Laurent!
[-- Attachment #1.2: Type: text/html, Size: 2018 bytes --]
[-- Attachment #2: 0001-ARM7TDMI-emulation-ignore-bit-0-on-POP-PC-no-BLX-no-.patch --]
[-- Type: application/octet-stream, Size: 18442 bytes --]
From e4ad4939178a464d50edcbdf7f1faa98e3e9cc3a Mon Sep 17 00:00:00 2001
From: Filip Navara <filip.navara@gmail.com>
Date: Mon, 15 Jun 2009 21:05:19 +0200
Subject: [PATCH] ARM7TDMI emulation (ignore bit 0 on POP PC, no BLX, no CP15, base-updated data aborts). Based on patch by Ulrich Hecht <uli@suse.de>.
---
target-arm/cpu.h | 6 ++-
target-arm/helper.c | 24 ++++++++++
target-arm/translate.c | 116 ++++++++++++++++++++++++++++++++++--------------
3 files changed, 112 insertions(+), 34 deletions(-)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index f98655f..d004777 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -331,6 +331,7 @@ enum arm_features {
ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */
ARM_FEATURE_XSCALE, /* Intel XScale extensions. */
ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension. */
+ ARM_FEATURE_V5,
ARM_FEATURE_V6,
ARM_FEATURE_V6K,
ARM_FEATURE_V7,
@@ -341,7 +342,9 @@ enum arm_features {
ARM_FEATURE_DIV,
ARM_FEATURE_M, /* Microcontroller profile. */
ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling. */
- ARM_FEATURE_THUMB2EE
+ ARM_FEATURE_THUMB2EE,
+ ARM_FEATURE_CP15, /* ARM7TDMI, ARM7TDMI-S, ARM7EJ-S, and ARM9TDMI cores do not have a CP15 */
+ ARM_FEATURE_ABORT_BU /* base updated abort model, e.g. ARMxTDMI */
};
static inline int arm_feature(CPUARMState *env, int feature)
@@ -367,6 +370,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
#define IS_M(env) arm_feature(env, ARM_FEATURE_M)
#define ARM_CPUID(env) (env->cp15.c0_cpuid)
+#define ARM_CPUID_ARM7TDMI 0x41807000 /* guess; no CP15 on ARM7TDMI */
#define ARM_CPUID_ARM1026 0x4106a262
#define ARM_CPUID_ARM926 0x41069265
#define ARM_CPUID_ARM946 0x41059461
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 701629a..38875d4 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -37,19 +37,28 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
{
env->cp15.c0_cpuid = id;
switch (id) {
+ case ARM_CPUID_ARM7TDMI:
+ set_feature(env, ARM_FEATURE_ABORT_BU);
+ break;
case ARM_CPUID_ARM926:
+ set_feature(env, ARM_FEATURE_V5);
set_feature(env, ARM_FEATURE_VFP);
+ set_feature(env, ARM_FEATURE_CP15);
env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
env->cp15.c0_cachetype = 0x1dd20d2;
env->cp15.c1_sys = 0x00090078;
break;
case ARM_CPUID_ARM946:
+ set_feature(env, ARM_FEATURE_V5);
+ set_feature(env, ARM_FEATURE_CP15);
set_feature(env, ARM_FEATURE_MPU);
env->cp15.c0_cachetype = 0x0f004006;
env->cp15.c1_sys = 0x00000078;
break;
case ARM_CPUID_ARM1026:
+ set_feature(env, ARM_FEATURE_V5);
set_feature(env, ARM_FEATURE_VFP);
+ set_feature(env, ARM_FEATURE_CP15);
set_feature(env, ARM_FEATURE_AUXCR);
env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
env->cp15.c0_cachetype = 0x1dd20d2;
@@ -57,8 +66,10 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
break;
case ARM_CPUID_ARM1136_R2:
case ARM_CPUID_ARM1136:
+ set_feature(env, ARM_FEATURE_V5);
set_feature(env, ARM_FEATURE_V6);
set_feature(env, ARM_FEATURE_VFP);
+ set_feature(env, ARM_FEATURE_CP15);
set_feature(env, ARM_FEATURE_AUXCR);
env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
@@ -68,9 +79,11 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c0_cachetype = 0x1dd20d2;
break;
case ARM_CPUID_ARM11MPCORE:
+ set_feature(env, ARM_FEATURE_V5);
set_feature(env, ARM_FEATURE_V6);
set_feature(env, ARM_FEATURE_V6K);
set_feature(env, ARM_FEATURE_VFP);
+ set_feature(env, ARM_FEATURE_CP15);
set_feature(env, ARM_FEATURE_AUXCR);
env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
@@ -80,9 +93,11 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c0_cachetype = 0x1dd20d2;
break;
case ARM_CPUID_CORTEXA8:
+ set_feature(env, ARM_FEATURE_V5);
set_feature(env, ARM_FEATURE_V6);
set_feature(env, ARM_FEATURE_V6K);
set_feature(env, ARM_FEATURE_V7);
+ set_feature(env, ARM_FEATURE_CP15);
set_feature(env, ARM_FEATURE_AUXCR);
set_feature(env, ARM_FEATURE_THUMB2);
set_feature(env, ARM_FEATURE_VFP);
@@ -101,6 +116,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */
break;
case ARM_CPUID_CORTEXM3:
+ set_feature(env, ARM_FEATURE_V5);
set_feature(env, ARM_FEATURE_V6);
set_feature(env, ARM_FEATURE_THUMB2);
set_feature(env, ARM_FEATURE_V7);
@@ -108,6 +124,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
set_feature(env, ARM_FEATURE_DIV);
break;
case ARM_CPUID_ANY: /* For userspace emulation. */
+ set_feature(env, ARM_FEATURE_V5);
set_feature(env, ARM_FEATURE_V6);
set_feature(env, ARM_FEATURE_V6K);
set_feature(env, ARM_FEATURE_V7);
@@ -120,6 +137,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
break;
case ARM_CPUID_TI915T:
case ARM_CPUID_TI925T:
+ set_feature(env, ARM_FEATURE_V5);
+ set_feature(env, ARM_FEATURE_CP15);
set_feature(env, ARM_FEATURE_OMAPCP);
env->cp15.c0_cpuid = ARM_CPUID_TI925T; /* Depends on wiring. */
env->cp15.c0_cachetype = 0x5109149;
@@ -132,6 +151,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
case ARM_CPUID_PXA260:
case ARM_CPUID_PXA261:
case ARM_CPUID_PXA262:
+ set_feature(env, ARM_FEATURE_V5);
+ set_feature(env, ARM_FEATURE_CP15);
set_feature(env, ARM_FEATURE_XSCALE);
/* JTAG_ID is ((id << 28) | 0x09265013) */
env->cp15.c0_cachetype = 0xd172172;
@@ -143,6 +164,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
case ARM_CPUID_PXA270_B1:
case ARM_CPUID_PXA270_C0:
case ARM_CPUID_PXA270_C5:
+ set_feature(env, ARM_FEATURE_V5);
+ set_feature(env, ARM_FEATURE_CP15);
set_feature(env, ARM_FEATURE_XSCALE);
/* JTAG_ID is ((id << 28) | 0x09265013) */
set_feature(env, ARM_FEATURE_IWMMXT);
@@ -277,6 +300,7 @@ struct arm_cpu_t {
};
static const struct arm_cpu_t arm_cpu_names[] = {
+ { ARM_CPUID_ARM7TDMI, "arm7tdmi"},
{ ARM_CPUID_ARM926, "arm926"},
{ ARM_CPUID_ARM946, "arm946"},
{ ARM_CPUID_ARM1026, "arm1026"},
diff --git a/target-arm/translate.c b/target-arm/translate.c
index adac19a..8c601b1 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -35,9 +35,10 @@
#define GEN_HELPER 1
#include "helpers.h"
+#define ENABLE_ARCH_5 arm_feature(env, ARM_FEATURE_V5)
#define ENABLE_ARCH_5J 0
#define ENABLE_ARCH_6 arm_feature(env, ARM_FEATURE_V6)
-#define ENABLE_ARCH_6K arm_feature(env, ARM_FEATURE_V6K)
+#define ENABLE_ARCH_6K arm_feature(env, ARM_FEATURE_V6K)
#define ENABLE_ARCH_6T2 arm_feature(env, ARM_FEATURE_THUMB2)
#define ENABLE_ARCH_7 arm_feature(env, ARM_FEATURE_V7)
@@ -2596,8 +2597,10 @@ static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
TCGv tmp;
/* M profile cores use memory mapped registers instead of cp15. */
- if (arm_feature(env, ARM_FEATURE_M))
- return 1;
+ if (arm_feature(env, ARM_FEATURE_M) ||
+ !arm_feature(env, ARM_FEATURE_CP15)) {
+ return 1;
+ }
if ((insn & (1 << 25)) == 0) {
if (insn & (1 << 20)) {
@@ -5754,9 +5757,10 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
goto illegal_op;
return;
}
- if ((insn & 0x0d70f000) == 0x0550f000)
+ if ((insn & 0x0d70f000) == 0x0550f000) {
+ ARCH(5);
return; /* PLD */
- else if ((insn & 0x0ffffdff) == 0x01010000) {
+ } else if ((insn & 0x0ffffdff) == 0x01010000) {
ARCH(6);
/* setend */
if (insn & (1 << 9)) {
@@ -5868,7 +5872,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
} else if ((insn & 0x0e000000) == 0x0a000000) {
/* branch link and change to thumb (blx <offset>) */
int32_t offset;
-
+ ARCH(5);
val = (uint32_t)s->pc;
tmp = new_tmp();
tcg_gen_movi_i32(tmp, val);
@@ -5890,8 +5894,10 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
}
} else if ((insn & 0x0fe00000) == 0x0c400000) {
/* Coprocessor double register transfer. */
+ ARCH(5);
} else if ((insn & 0x0f000010) == 0x0e000010) {
/* Additional coprocessor register transfer. */
+ ARCH(5);
} else if ((insn & 0x0ff10020) == 0x01000000) {
uint32_t mask;
uint32_t val;
@@ -6017,7 +6023,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
case 0x3:
if (op1 != 1)
goto illegal_op;
-
+ ARCH(5);
/* branch link/exchange thumb (blx) */
tmp = load_reg(s, rm);
tmp2 = new_tmp();
@@ -6040,6 +6046,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
store_reg(s, rd, tmp);
break;
case 7: /* bkpt */
+ ARCH(5);
gen_set_condexec(s);
gen_set_pc_im(s->pc - 4);
gen_exception(EXCP_BKPT);
@@ -6776,7 +6783,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
}
if (insn & (1 << 20)) {
/* Complete the load. */
- if (rd == 15)
+ if (rd == 15 && ENABLE_ARCH_5)
gen_bx(s, tmp);
else
store_reg(s, rd, tmp);
@@ -6786,6 +6793,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
case 0x09:
{
int j, n, user, loaded_base;
+ int crement = 0;
TCGv loaded_var;
/* load/store multiple words */
/* XXX: store correct base if write back */
@@ -6826,6 +6834,38 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
}
}
+
+ if (insn & (1 << 21)) {
+ /* write back */
+ if (insn & (1 << 23)) {
+ if (insn & (1 << 24)) {
+ /* pre increment */
+ } else {
+ /* post increment */
+ crement = 4;
+ }
+ } else {
+ if (insn & (1 << 24)) {
+ /* pre decrement */
+ if (n != 1) {
+ crement = -((n - 1) * 4);
+ }
+ } else {
+ /* post decrement */
+ crement = -(n * 4);
+ }
+ }
+ if (arm_feature(env, ARM_FEATURE_ABORT_BU)) {
+ /* base-updated abort model: update base register
+ before an abort can happen */
+ crement += (n - 1) * 4;
+ tmp = new_tmp();
+ tcg_gen_addi_i32(tmp, addr, crement);
+ store_reg(s, rn, tmp);
+ }
+
+ }
+
j = 0;
for(i=0;i<16;i++) {
if (insn & (1 << i)) {
@@ -6833,7 +6873,11 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
/* load */
tmp = gen_ld32(addr, IS_USER(s));
if (i == 15) {
- gen_bx(s, tmp);
+ if (ENABLE_ARCH_5) {
+ gen_bx(s, tmp);
+ } else {
+ store_reg(s, i, tmp);
+ }
} else if (user) {
gen_helper_set_user_reg(tcg_const_i32(i), tmp);
dead_tmp(tmp);
@@ -6864,25 +6908,8 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
tcg_gen_addi_i32(addr, addr, 4);
}
}
- if (insn & (1 << 21)) {
- /* write back */
- if (insn & (1 << 23)) {
- if (insn & (1 << 24)) {
- /* pre increment */
- } else {
- /* post increment */
- tcg_gen_addi_i32(addr, addr, 4);
- }
- } else {
- if (insn & (1 << 24)) {
- /* pre decrement */
- if (n != 1)
- tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
- } else {
- /* post decrement */
- tcg_gen_addi_i32(addr, addr, -(n * 4));
- }
- }
+ if (!arm_feature(env, ARM_FEATURE_ABORT_BU) && (insn & (1 << 21))) {
+ tcg_gen_addi_i32(addr, addr, crement);
store_reg(s, rn, addr);
} else {
dead_tmp(addr);
@@ -7043,6 +7070,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
16-bit instructions to get correct prefetch abort behavior. */
insn = insn_hw1;
if ((insn & (1 << 12)) == 0) {
+ ARCH(5);
/* Second half of blx. */
offset = ((insn & 0x7ff) << 1);
tmp = load_reg(s, 14);
@@ -7100,6 +7128,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
/* Other load/store, table branch. */
if (insn & 0x01200000) {
/* Load/store doubleword. */
+ ARCH(5);
if (rn == 15) {
addr = new_tmp();
tcg_gen_movi_i32(addr, s->pc & ~3);
@@ -7313,7 +7342,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
if (insn & (1 << 20)) {
/* Load. */
tmp = gen_ld32(addr, IS_USER(s));
- if (i == 15) {
+ if (i == 15 && ENABLE_ARCH_5) {
gen_bx(s, tmp);
} else {
store_reg(s, i, tmp);
@@ -7652,6 +7681,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
gen_jmp(s, offset);
} else {
/* blx */
+ ARCH(5);
offset &= ~(uint32_t)2;
gen_bx_im(s, offset);
}
@@ -8007,7 +8037,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
case 2: tmp = gen_ld32(addr, user); break;
default: goto illegal_op;
}
- if (rs == 15) {
+ if (rs == 15 && ENABLE_ARCH_5) {
gen_bx(s, tmp);
} else {
store_reg(s, rs, tmp);
@@ -8050,6 +8080,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
TCGv tmp;
TCGv tmp2;
TCGv addr;
+ int crement;
if (s->condexec_mask) {
cond = s->condexec_cond;
@@ -8171,6 +8202,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
case 3:/* branch [and link] exchange thumb register */
tmp = load_reg(s, rm);
if (insn & (1 << 7)) {
+ ARCH(5);
val = (uint32_t)s->pc | 1;
tmp2 = new_tmp();
tcg_gen_movi_i32(tmp2, val);
@@ -8523,8 +8555,13 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
/* write back the new stack pointer */
store_reg(s, 13, addr);
/* set the new PC value */
- if ((insn & 0x0900) == 0x0900)
- gen_bx(s, tmp);
+ if ((insn & 0x0900) == 0x0900) {
+ if (ENABLE_ARCH_5) {
+ gen_bx(s, tmp);
+ } else {
+ store_reg(s, 15, tmp);
+ }
+ }
break;
case 1: case 3: case 9: case 11: /* czb */
@@ -8613,6 +8650,19 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
/* load/store multiple */
rn = (insn >> 8) & 0x7;
addr = load_reg(s, rn);
+ if (arm_feature(env, ARM_FEATURE_ABORT_BU) && (insn & (1 << rn)) == 0) {
+ /* base-updated abort model: update base register
+ before an abort can happen */
+ crement = 0;
+ for (i = 0; i < 8; i++) {
+ if (insn & (1 << i)) {
+ crement += 4;
+ }
+ }
+ tmp = new_tmp();
+ tcg_gen_addi_i32(tmp, addr, crement);
+ store_reg(s, rn, tmp);
+ }
for (i = 0; i < 8; i++) {
if (insn & (1 << i)) {
if (insn & (1 << 11)) {
@@ -8629,7 +8679,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
}
}
/* Base register writeback. */
- if ((insn & (1 << rn)) == 0) {
+ if (!arm_feature(env, ARM_FEATURE_ABORT_BU) && (insn & (1 << rn)) == 0) {
store_reg(s, rn, addr);
} else {
dead_tmp(addr);
--
1.6.3.msysgit.0
next prev parent reply other threads:[~2009-06-17 10:24 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-07-02 13:27 [Qemu-devel] [PATCH] ARM7TDMI emulation Ulrich Hecht
2007-07-02 13:40 ` Paul Brook
2007-07-02 16:14 ` Ulrich Hecht
2007-07-03 14:45 ` Ulrich Hecht
2009-06-15 19:11 ` Filip Navara
2009-06-16 17:25 ` Paul Brook
2009-06-16 19:02 ` Jamie Lokier
2009-06-16 19:05 ` Paul Brook
2009-06-16 20:49 ` Filip Navara
2009-06-16 21:47 ` Filip Navara
2009-06-17 9:55 ` Filip Navara
2009-06-17 10:24 ` Filip Navara [this message]
-- strict thread matches above, loose matches on Subject: below --
2009-07-15 12:08 Filip Navara
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5b31733c0906170324s663cd361q8c27098be17021a2@mail.gmail.com \
--to=filip.navara@gmail.com \
--cc=jamie@shareable.org \
--cc=paul@codesourcery.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).