Commit e695238182aa391f5f91343c7484d9818bc66369

Authored by Filip Navara
1 parent 660f11be

ARM7TDMI emulation

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).

Based on patch by Ulrich Hecht <uli@suse.de>.

Signed-off-by: Filip Navara <filip.navara@gmail.com>
target-arm/cpu.h
... ... @@ -330,6 +330,7 @@ enum arm_features {
330 330 ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */
331 331 ARM_FEATURE_XSCALE, /* Intel XScale extensions. */
332 332 ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension. */
  333 + ARM_FEATURE_V5,
333 334 ARM_FEATURE_V6,
334 335 ARM_FEATURE_V6K,
335 336 ARM_FEATURE_V7,
... ... @@ -340,7 +341,9 @@ enum arm_features {
340 341 ARM_FEATURE_DIV,
341 342 ARM_FEATURE_M, /* Microcontroller profile. */
342 343 ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling. */
343   - ARM_FEATURE_THUMB2EE
  344 + ARM_FEATURE_THUMB2EE,
  345 + ARM_FEATURE_CP15, /* ARM7TDMI, ARM7TDMI-S, ARM7EJ-S, and ARM9TDMI cores do not have a CP15 */
  346 + ARM_FEATURE_ABORT_BU /* base updated abort model, e.g. ARMxTDMI */
344 347 };
345 348  
346 349 static inline int arm_feature(CPUARMState *env, int feature)
... ... @@ -366,6 +369,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
366 369 #define IS_M(env) arm_feature(env, ARM_FEATURE_M)
367 370 #define ARM_CPUID(env) (env->cp15.c0_cpuid)
368 371  
  372 +#define ARM_CPUID_ARM7TDMI 0x41807000 /* guess; no CP15 on ARM7TDMI */
369 373 #define ARM_CPUID_ARM1026 0x4106a262
370 374 #define ARM_CPUID_ARM926 0x41069265
371 375 #define ARM_CPUID_ARM946 0x41059461
... ...
target-arm/helper.c
... ... @@ -37,19 +37,28 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
37 37 {
38 38 env->cp15.c0_cpuid = id;
39 39 switch (id) {
  40 + case ARM_CPUID_ARM7TDMI:
  41 + set_feature(env, ARM_FEATURE_ABORT_BU);
  42 + break;
40 43 case ARM_CPUID_ARM926:
  44 + set_feature(env, ARM_FEATURE_V5);
41 45 set_feature(env, ARM_FEATURE_VFP);
  46 + set_feature(env, ARM_FEATURE_CP15);
42 47 env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
43 48 env->cp15.c0_cachetype = 0x1dd20d2;
44 49 env->cp15.c1_sys = 0x00090078;
45 50 break;
46 51 case ARM_CPUID_ARM946:
  52 + set_feature(env, ARM_FEATURE_V5);
  53 + set_feature(env, ARM_FEATURE_CP15);
47 54 set_feature(env, ARM_FEATURE_MPU);
48 55 env->cp15.c0_cachetype = 0x0f004006;
49 56 env->cp15.c1_sys = 0x00000078;
50 57 break;
51 58 case ARM_CPUID_ARM1026:
  59 + set_feature(env, ARM_FEATURE_V5);
52 60 set_feature(env, ARM_FEATURE_VFP);
  61 + set_feature(env, ARM_FEATURE_CP15);
53 62 set_feature(env, ARM_FEATURE_AUXCR);
54 63 env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
55 64 env->cp15.c0_cachetype = 0x1dd20d2;
... ... @@ -57,8 +66,10 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
57 66 break;
58 67 case ARM_CPUID_ARM1136_R2:
59 68 case ARM_CPUID_ARM1136:
  69 + set_feature(env, ARM_FEATURE_V5);
60 70 set_feature(env, ARM_FEATURE_V6);
61 71 set_feature(env, ARM_FEATURE_VFP);
  72 + set_feature(env, ARM_FEATURE_CP15);
62 73 set_feature(env, ARM_FEATURE_AUXCR);
63 74 env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
64 75 env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
... ... @@ -68,9 +79,11 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
68 79 env->cp15.c0_cachetype = 0x1dd20d2;
69 80 break;
70 81 case ARM_CPUID_ARM11MPCORE:
  82 + set_feature(env, ARM_FEATURE_V5);
71 83 set_feature(env, ARM_FEATURE_V6);
72 84 set_feature(env, ARM_FEATURE_V6K);
73 85 set_feature(env, ARM_FEATURE_VFP);
  86 + set_feature(env, ARM_FEATURE_CP15);
74 87 set_feature(env, ARM_FEATURE_AUXCR);
75 88 env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
76 89 env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
... ... @@ -80,9 +93,11 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
80 93 env->cp15.c0_cachetype = 0x1dd20d2;
81 94 break;
82 95 case ARM_CPUID_CORTEXA8:
  96 + set_feature(env, ARM_FEATURE_V5);
83 97 set_feature(env, ARM_FEATURE_V6);
84 98 set_feature(env, ARM_FEATURE_V6K);
85 99 set_feature(env, ARM_FEATURE_V7);
  100 + set_feature(env, ARM_FEATURE_CP15);
86 101 set_feature(env, ARM_FEATURE_AUXCR);
87 102 set_feature(env, ARM_FEATURE_THUMB2);
88 103 set_feature(env, ARM_FEATURE_VFP);
... ... @@ -101,6 +116,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
101 116 env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */
102 117 break;
103 118 case ARM_CPUID_CORTEXM3:
  119 + set_feature(env, ARM_FEATURE_V5);
104 120 set_feature(env, ARM_FEATURE_V6);
105 121 set_feature(env, ARM_FEATURE_THUMB2);
106 122 set_feature(env, ARM_FEATURE_V7);
... ... @@ -108,6 +124,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
108 124 set_feature(env, ARM_FEATURE_DIV);
109 125 break;
110 126 case ARM_CPUID_ANY: /* For userspace emulation. */
  127 + set_feature(env, ARM_FEATURE_V5);
111 128 set_feature(env, ARM_FEATURE_V6);
112 129 set_feature(env, ARM_FEATURE_V6K);
113 130 set_feature(env, ARM_FEATURE_V7);
... ... @@ -120,6 +137,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
120 137 break;
121 138 case ARM_CPUID_TI915T:
122 139 case ARM_CPUID_TI925T:
  140 + set_feature(env, ARM_FEATURE_V5);
  141 + set_feature(env, ARM_FEATURE_CP15);
123 142 set_feature(env, ARM_FEATURE_OMAPCP);
124 143 env->cp15.c0_cpuid = ARM_CPUID_TI925T; /* Depends on wiring. */
125 144 env->cp15.c0_cachetype = 0x5109149;
... ... @@ -132,6 +151,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
132 151 case ARM_CPUID_PXA260:
133 152 case ARM_CPUID_PXA261:
134 153 case ARM_CPUID_PXA262:
  154 + set_feature(env, ARM_FEATURE_V5);
  155 + set_feature(env, ARM_FEATURE_CP15);
135 156 set_feature(env, ARM_FEATURE_XSCALE);
136 157 /* JTAG_ID is ((id << 28) | 0x09265013) */
137 158 env->cp15.c0_cachetype = 0xd172172;
... ... @@ -143,6 +164,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
143 164 case ARM_CPUID_PXA270_B1:
144 165 case ARM_CPUID_PXA270_C0:
145 166 case ARM_CPUID_PXA270_C5:
  167 + set_feature(env, ARM_FEATURE_V5);
  168 + set_feature(env, ARM_FEATURE_CP15);
146 169 set_feature(env, ARM_FEATURE_XSCALE);
147 170 /* JTAG_ID is ((id << 28) | 0x09265013) */
148 171 set_feature(env, ARM_FEATURE_IWMMXT);
... ... @@ -277,6 +300,7 @@ struct arm_cpu_t {
277 300 };
278 301  
279 302 static const struct arm_cpu_t arm_cpu_names[] = {
  303 + { ARM_CPUID_ARM7TDMI, "arm7tdmi"},
280 304 { ARM_CPUID_ARM926, "arm926"},
281 305 { ARM_CPUID_ARM946, "arm946"},
282 306 { ARM_CPUID_ARM1026, "arm1026"},
... ...
target-arm/translate.c
... ... @@ -34,9 +34,10 @@
34 34 #define GEN_HELPER 1
35 35 #include "helpers.h"
36 36  
  37 +#define ENABLE_ARCH_5 arm_feature(env, ARM_FEATURE_V5)
37 38 #define ENABLE_ARCH_5J 0
38 39 #define ENABLE_ARCH_6 arm_feature(env, ARM_FEATURE_V6)
39   -#define ENABLE_ARCH_6K arm_feature(env, ARM_FEATURE_V6K)
  40 +#define ENABLE_ARCH_6K arm_feature(env, ARM_FEATURE_V6K)
40 41 #define ENABLE_ARCH_6T2 arm_feature(env, ARM_FEATURE_THUMB2)
41 42 #define ENABLE_ARCH_7 arm_feature(env, ARM_FEATURE_V7)
42 43  
... ... @@ -2587,8 +2588,10 @@ static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
2587 2588 TCGv tmp;
2588 2589  
2589 2590 /* M profile cores use memory mapped registers instead of cp15. */
2590   - if (arm_feature(env, ARM_FEATURE_M))
2591   - return 1;
  2591 + if (arm_feature(env, ARM_FEATURE_M) ||
  2592 + !arm_feature(env, ARM_FEATURE_CP15)) {
  2593 + return 1;
  2594 + }
2592 2595  
2593 2596 if ((insn & (1 << 25)) == 0) {
2594 2597 if (insn & (1 << 20)) {
... ... @@ -5745,9 +5748,10 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
5745 5748 goto illegal_op;
5746 5749 return;
5747 5750 }
5748   - if ((insn & 0x0d70f000) == 0x0550f000)
  5751 + if ((insn & 0x0d70f000) == 0x0550f000) {
  5752 + ARCH(5);
5749 5753 return; /* PLD */
5750   - else if ((insn & 0x0ffffdff) == 0x01010000) {
  5754 + } else if ((insn & 0x0ffffdff) == 0x01010000) {
5751 5755 ARCH(6);
5752 5756 /* setend */
5753 5757 if (insn & (1 << 9)) {
... ... @@ -5859,7 +5863,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
5859 5863 } else if ((insn & 0x0e000000) == 0x0a000000) {
5860 5864 /* branch link and change to thumb (blx <offset>) */
5861 5865 int32_t offset;
5862   -
  5866 + ARCH(5);
5863 5867 val = (uint32_t)s->pc;
5864 5868 tmp = new_tmp();
5865 5869 tcg_gen_movi_i32(tmp, val);
... ... @@ -5881,8 +5885,10 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
5881 5885 }
5882 5886 } else if ((insn & 0x0fe00000) == 0x0c400000) {
5883 5887 /* Coprocessor double register transfer. */
  5888 + ARCH(5);
5884 5889 } else if ((insn & 0x0f000010) == 0x0e000010) {
5885 5890 /* Additional coprocessor register transfer. */
  5891 + ARCH(5);
5886 5892 } else if ((insn & 0x0ff10020) == 0x01000000) {
5887 5893 uint32_t mask;
5888 5894 uint32_t val;
... ... @@ -6008,7 +6014,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6008 6014 case 0x3:
6009 6015 if (op1 != 1)
6010 6016 goto illegal_op;
6011   -
  6017 + ARCH(5);
6012 6018 /* branch link/exchange thumb (blx) */
6013 6019 tmp = load_reg(s, rm);
6014 6020 tmp2 = new_tmp();
... ... @@ -6031,6 +6037,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6031 6037 store_reg(s, rd, tmp);
6032 6038 break;
6033 6039 case 7: /* bkpt */
  6040 + ARCH(5);
6034 6041 gen_set_condexec(s);
6035 6042 gen_set_pc_im(s->pc - 4);
6036 6043 gen_exception(EXCP_BKPT);
... ... @@ -6767,7 +6774,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6767 6774 }
6768 6775 if (insn & (1 << 20)) {
6769 6776 /* Complete the load. */
6770   - if (rd == 15)
  6777 + if (rd == 15 && ENABLE_ARCH_5)
6771 6778 gen_bx(s, tmp);
6772 6779 else
6773 6780 store_reg(s, rd, tmp);
... ... @@ -6777,6 +6784,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6777 6784 case 0x09:
6778 6785 {
6779 6786 int j, n, user, loaded_base;
  6787 + int crement = 0;
6780 6788 TCGv loaded_var;
6781 6789 /* load/store multiple words */
6782 6790 /* XXX: store correct base if write back */
... ... @@ -6817,6 +6825,38 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6817 6825 tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
6818 6826 }
6819 6827 }
  6828 +
  6829 + if (insn & (1 << 21)) {
  6830 + /* write back */
  6831 + if (insn & (1 << 23)) {
  6832 + if (insn & (1 << 24)) {
  6833 + /* pre increment */
  6834 + } else {
  6835 + /* post increment */
  6836 + crement = 4;
  6837 + }
  6838 + } else {
  6839 + if (insn & (1 << 24)) {
  6840 + /* pre decrement */
  6841 + if (n != 1) {
  6842 + crement = -((n - 1) * 4);
  6843 + }
  6844 + } else {
  6845 + /* post decrement */
  6846 + crement = -(n * 4);
  6847 + }
  6848 + }
  6849 + if (arm_feature(env, ARM_FEATURE_ABORT_BU)) {
  6850 + /* base-updated abort model: update base register
  6851 + before an abort can happen */
  6852 + crement += (n - 1) * 4;
  6853 + tmp = new_tmp();
  6854 + tcg_gen_addi_i32(tmp, addr, crement);
  6855 + store_reg(s, rn, tmp);
  6856 + }
  6857 +
  6858 + }
  6859 +
6820 6860 j = 0;
6821 6861 for(i=0;i<16;i++) {
6822 6862 if (insn & (1 << i)) {
... ... @@ -6824,7 +6864,11 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6824 6864 /* load */
6825 6865 tmp = gen_ld32(addr, IS_USER(s));
6826 6866 if (i == 15) {
6827   - gen_bx(s, tmp);
  6867 + if (ENABLE_ARCH_5) {
  6868 + gen_bx(s, tmp);
  6869 + } else {
  6870 + store_reg(s, i, tmp);
  6871 + }
6828 6872 } else if (user) {
6829 6873 gen_helper_set_user_reg(tcg_const_i32(i), tmp);
6830 6874 dead_tmp(tmp);
... ... @@ -6855,25 +6899,8 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
6855 6899 tcg_gen_addi_i32(addr, addr, 4);
6856 6900 }
6857 6901 }
6858   - if (insn & (1 << 21)) {
6859   - /* write back */
6860   - if (insn & (1 << 23)) {
6861   - if (insn & (1 << 24)) {
6862   - /* pre increment */
6863   - } else {
6864   - /* post increment */
6865   - tcg_gen_addi_i32(addr, addr, 4);
6866   - }
6867   - } else {
6868   - if (insn & (1 << 24)) {
6869   - /* pre decrement */
6870   - if (n != 1)
6871   - tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
6872   - } else {
6873   - /* post decrement */
6874   - tcg_gen_addi_i32(addr, addr, -(n * 4));
6875   - }
6876   - }
  6902 + if (!arm_feature(env, ARM_FEATURE_ABORT_BU) && (insn & (1 << 21))) {
  6903 + tcg_gen_addi_i32(addr, addr, crement);
6877 6904 store_reg(s, rn, addr);
6878 6905 } else {
6879 6906 dead_tmp(addr);
... ... @@ -7034,6 +7061,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
7034 7061 16-bit instructions to get correct prefetch abort behavior. */
7035 7062 insn = insn_hw1;
7036 7063 if ((insn & (1 << 12)) == 0) {
  7064 + ARCH(5);
7037 7065 /* Second half of blx. */
7038 7066 offset = ((insn & 0x7ff) << 1);
7039 7067 tmp = load_reg(s, 14);
... ... @@ -7091,6 +7119,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
7091 7119 /* Other load/store, table branch. */
7092 7120 if (insn & 0x01200000) {
7093 7121 /* Load/store doubleword. */
  7122 + ARCH(5);
7094 7123 if (rn == 15) {
7095 7124 addr = new_tmp();
7096 7125 tcg_gen_movi_i32(addr, s->pc & ~3);
... ... @@ -7304,7 +7333,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
7304 7333 if (insn & (1 << 20)) {
7305 7334 /* Load. */
7306 7335 tmp = gen_ld32(addr, IS_USER(s));
7307   - if (i == 15) {
  7336 + if (i == 15 && ENABLE_ARCH_5) {
7308 7337 gen_bx(s, tmp);
7309 7338 } else {
7310 7339 store_reg(s, i, tmp);
... ... @@ -7643,6 +7672,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
7643 7672 gen_jmp(s, offset);
7644 7673 } else {
7645 7674 /* blx */
  7675 + ARCH(5);
7646 7676 offset &= ~(uint32_t)2;
7647 7677 gen_bx_im(s, offset);
7648 7678 }
... ... @@ -7998,7 +8028,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
7998 8028 case 2: tmp = gen_ld32(addr, user); break;
7999 8029 default: goto illegal_op;
8000 8030 }
8001   - if (rs == 15) {
  8031 + if (rs == 15 && ENABLE_ARCH_5) {
8002 8032 gen_bx(s, tmp);
8003 8033 } else {
8004 8034 store_reg(s, rs, tmp);
... ... @@ -8041,6 +8071,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
8041 8071 TCGv tmp;
8042 8072 TCGv tmp2;
8043 8073 TCGv addr;
  8074 + int crement;
8044 8075  
8045 8076 if (s->condexec_mask) {
8046 8077 cond = s->condexec_cond;
... ... @@ -8162,6 +8193,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
8162 8193 case 3:/* branch [and link] exchange thumb register */
8163 8194 tmp = load_reg(s, rm);
8164 8195 if (insn & (1 << 7)) {
  8196 + ARCH(5);
8165 8197 val = (uint32_t)s->pc | 1;
8166 8198 tmp2 = new_tmp();
8167 8199 tcg_gen_movi_i32(tmp2, val);
... ... @@ -8514,8 +8546,13 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
8514 8546 /* write back the new stack pointer */
8515 8547 store_reg(s, 13, addr);
8516 8548 /* set the new PC value */
8517   - if ((insn & 0x0900) == 0x0900)
8518   - gen_bx(s, tmp);
  8549 + if ((insn & 0x0900) == 0x0900) {
  8550 + if (ENABLE_ARCH_5) {
  8551 + gen_bx(s, tmp);
  8552 + } else {
  8553 + store_reg(s, 15, tmp);
  8554 + }
  8555 + }
8519 8556 break;
8520 8557  
8521 8558 case 1: case 3: case 9: case 11: /* czb */
... ... @@ -8604,6 +8641,19 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
8604 8641 /* load/store multiple */
8605 8642 rn = (insn >> 8) & 0x7;
8606 8643 addr = load_reg(s, rn);
  8644 + if (arm_feature(env, ARM_FEATURE_ABORT_BU) && (insn & (1 << rn)) == 0) {
  8645 + /* base-updated abort model: update base register
  8646 + before an abort can happen */
  8647 + crement = 0;
  8648 + for (i = 0; i < 8; i++) {
  8649 + if (insn & (1 << i)) {
  8650 + crement += 4;
  8651 + }
  8652 + }
  8653 + tmp = new_tmp();
  8654 + tcg_gen_addi_i32(tmp, addr, crement);
  8655 + store_reg(s, rn, tmp);
  8656 + }
8607 8657 for (i = 0; i < 8; i++) {
8608 8658 if (insn & (1 << i)) {
8609 8659 if (insn & (1 << 11)) {
... ... @@ -8620,7 +8670,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
8620 8670 }
8621 8671 }
8622 8672 /* Base register writeback. */
8623   - if ((insn & (1 << rn)) == 0) {
  8673 + if (!arm_feature(env, ARM_FEATURE_ABORT_BU) && (insn & (1 << rn)) == 0) {
8624 8674 store_reg(s, rn, addr);
8625 8675 } else {
8626 8676 dead_tmp(addr);
... ...