[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH] target-arm: ARMv4 emulation
From: |
Laurent Desnogues |
Subject: |
Re: [Qemu-devel] [PATCH] target-arm: ARMv4 emulation |
Date: |
Thu, 14 Jan 2010 11:11:24 +0100 |
Since you wanted a "no, because..." there's at least
one :-)
On Tue, Dec 1, 2009 at 9:41 PM, Filip Navara <address@hidden> wrote:
> While most of the ARMv5 instructions are backward compatible with ARMv4, there
> are few important differences. Most notably the stack pop and load
> instructions
> ignore the lowest bit, which is used by ARMv5 to switch to Thumb mode. A
> base-updated data-abort model is used on ARM7TDMI, CP15 coprocessor is not
> present and several instructions of later architectures are not implemented.
>
> This patch introduces flags for the V5, CP15 and ABORT_BU (base-updated abort
> model) features. When V5 feature is not set the bit 0 on POP, LD and LDM of PC
> register is ignored and doesn't swith to/from Thumb mode and several
> instructions are treated as unimplemented (BLX, PLD, BKPT, LDRD, STRD).
>
> Added are processor definitions for ARM7TDMI and ARM920T.
>
> Based on patches by Ulrich Hecht <address@hidden> and Vincent Sanders
> <address@hidden>.
>
> Signed-off-by: Filip Navara <address@hidden>
> ---
> target-arm/cpu.h | 7 ++-
> target-arm/helper.c | 31 ++++++++++++
> target-arm/translate.c | 119 ++++++++++++++++++++++++++++++++++-------------
> 3 files changed, 123 insertions(+), 34 deletions(-)
>
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index 4a1c53f..b8e1e4b 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -334,6 +334,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,
> @@ -345,7 +346,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)
> @@ -371,6 +374,8 @@ 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_ARM920T 0x41129200
> #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 b3aec99..b82959f 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -44,19 +44,34 @@ 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_ARM920T:
> + set_feature(env, ARM_FEATURE_ABORT_BU);
ARM920T is using an ARM9TDMI which uses the Base Restored
Data Abort Model and not the Updated one.
Ref:
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0180a/ch02s01s01.html
Laurent
> + set_feature(env, ARM_FEATURE_CP15);
> + env->cp15.c0_cachetype = 0x0d172172;
> + env->cp15.c1_sys = 0x00000078;
> + 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;
> @@ -64,8 +79,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;
> @@ -75,9 +92,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;
> @@ -87,9 +106,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);
> @@ -129,6 +150,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t
> id)
> env->cp15.c0_ccsid[1] = 0x200fe015; /* 16k L1 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);
> @@ -136,6 +158,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);
> @@ -149,6 +172,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;
> @@ -161,6 +186,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;
> @@ -172,6 +199,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);
> @@ -306,6 +335,8 @@ struct arm_cpu_t {
> };
>
> static const struct arm_cpu_t arm_cpu_names[] = {
> + { ARM_CPUID_ARM7TDMI, "arm7tdmi"},
> + { ARM_CPUID_ARM920T, "arm920t"},
> { 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 45bf772..48602bb 100644
> --- a/target-arm/translate.c
> +++ b/target-arm/translate.c
> @@ -34,9 +34,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)
>
> @@ -2463,8 +2464,10 @@ static int disas_cp15_insn(CPUState *env, DisasContext
> *s, uint32_t insn)
> TCGv tmp, tmp2;
>
> /* 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)) {
> @@ -6000,9 +6003,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)) {
> @@ -6119,7 +6123,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);
> @@ -6141,8 +6145,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;
> @@ -6245,6 +6251,7 @@ static void disas_arm_insn(CPUState * env, DisasContext
> *s)
> gen_bx(s, tmp);
> } else if (op1 == 3) {
> /* clz */
> + ARCH(5);
> rd = (insn >> 12) & 0xf;
> tmp = load_reg(s, rm);
> gen_helper_clz(tmp, tmp);
> @@ -6266,8 +6273,8 @@ static void disas_arm_insn(CPUState * env, DisasContext
> *s)
> case 0x3:
> if (op1 != 1)
> goto illegal_op;
> -
> /* branch link/exchange thumb (blx) */
> + ARCH(5);
> tmp = load_reg(s, rm);
> tmp2 = new_tmp();
> tcg_gen_movi_i32(tmp2, s->pc);
> @@ -6275,6 +6282,7 @@ static void disas_arm_insn(CPUState * env, DisasContext
> *s)
> gen_bx(s, tmp);
> break;
> case 0x5: /* saturating add/subtract */
> + ARCH(5);
> rd = (insn >> 12) & 0xf;
> rn = (insn >> 16) & 0xf;
> tmp = load_reg(s, rm);
> @@ -6289,6 +6297,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);
> @@ -6298,6 +6307,7 @@ static void disas_arm_insn(CPUState * env, DisasContext
> *s)
> case 0xa:
> case 0xc:
> case 0xe:
> + ARCH(5);
> rs = (insn >> 8) & 0xf;
> rn = (insn >> 12) & 0xf;
> rd = (insn >> 16) & 0xf;
> @@ -7019,7 +7029,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);
> @@ -7029,6 +7039,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 */
> @@ -7069,6 +7080,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)) {
> @@ -7076,7 +7119,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) {
> tmp2 = tcg_const_i32(i);
> gen_helper_set_user_reg(tmp2, tmp);
> @@ -7111,25 +7158,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);
> @@ -7290,6 +7320,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);
> @@ -7346,6 +7377,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);
> @@ -7516,7 +7548,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);
> @@ -7863,6 +7895,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);
> }
> @@ -8227,7 +8260,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);
> @@ -8270,6 +8303,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;
> @@ -8402,6 +8436,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);
> @@ -8766,8 +8801,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 */
> @@ -8856,6 +8896,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)) {
> @@ -8872,7 +8925,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.5.1.1367.gcd48
>
>
>
>
>