Since you wanted a "no, because..." there's at least one :-) On Tue, Dec 1, 2009 at 9:41 PM, Filip Navara <filip.nav...@gmail.com> 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 <u...@suse.de> and Vincent Sanders > <vi...@kyllikki.org>. > > Signed-off-by: Filip Navara <filip.nav...@gmail.com> > --- > 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 > > > > >