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);
+        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);
