typo
[qemu] / target-arm / translate.c
index 77c8957..e6e8c68 100644 (file)
@@ -526,6 +526,17 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
     uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask;
     int dp, veclen;
 
+    if (!arm_feature(env, ARM_FEATURE_VFP))
+        return 1;
+
+    if ((env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) == 0) {
+        /* VFP disabled.  Only allow fmxr/fmrx to/from fpexc and fpsid.  */
+        if ((insn & 0x0fe00fff) != 0x0ee00a10)
+            return 1;
+        rn = (insn >> 16) & 0xf;
+        if (rn != 0 && rn != 8)
+            return 1;
+    }
     dp = ((insn & 0xf00) == 0xb00);
     switch ((insn >> 24) & 0xf) {
     case 0xe:
@@ -563,11 +574,15 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     /* vfp->arm */
                     if (insn & (1 << 21)) {
                         /* system register */
+                        rn >>= 1;
                         switch (rn) {
-                        case 0: /* fpsid */
-                            n = 0x0091A0000;
+                        case ARM_VFP_FPSID:
+                        case ARM_VFP_FPEXC:
+                        case ARM_VFP_FPINST:
+                        case ARM_VFP_FPINST2:
+                            gen_op_vfp_movl_T0_xreg(rn);
                             break;
-                        case 2: /* fpscr */
+                        case ARM_VFP_FPSCR:
                            if (rd == 15)
                                gen_op_vfp_movl_T0_fpscr_flags();
                            else
@@ -589,17 +604,24 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     /* arm->vfp */
                     gen_movl_T0_reg(s, rd);
                     if (insn & (1 << 21)) {
+                        rn >>= 1;
                         /* system register */
                         switch (rn) {
-                        case 0: /* fpsid */
+                        case ARM_VFP_FPSID:
                             /* Writes are ignored.  */
                             break;
-                        case 2: /* fpscr */
+                        case ARM_VFP_FPSCR:
                             gen_op_vfp_movl_fpscr_T0();
-                            /* This could change vector settings, so jump to
-                               the next instuction.  */
                             gen_lookup_tb(s);
                             break;
+                        case ARM_VFP_FPEXC:
+                            gen_op_vfp_movl_xreg_T0(rn);
+                            gen_lookup_tb(s);
+                            break;
+                        case ARM_VFP_FPINST:
+                        case ARM_VFP_FPINST2:
+                            gen_op_vfp_movl_xreg_T0(rn);
+                            break;
                         default:
                             return 1;
                         }
@@ -1033,7 +1055,7 @@ static inline void gen_mulxy(int x, int y)
 }
 
 /* Return the mask of PSR bits set by a MSR instruction.  */
-static uint32_t msr_mask(DisasContext *s, int flags) {
+static uint32_t msr_mask(DisasContext *s, int flags, int spsr) {
     uint32_t mask;
 
     mask = 0;
@@ -1045,8 +1067,11 @@ static uint32_t msr_mask(DisasContext *s, int flags) {
         mask |= 0xff0000;
     if (flags & (1 << 3))
         mask |= 0xff000000;
-    /* Mask out undefined bits and state bits.  */
-    mask &= 0xf89f03df;
+    /* Mask out undefined bits.  */
+    mask &= 0xf90f03ff;
+    /* Mask out state bits.  */
+    if (!spsr)
+        mask &= ~0x01000020;
     /* Mask out privileged bits.  */
     if (IS_USER(s))
         mask &= 0xf80f0200;
@@ -1138,8 +1163,8 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
         if (shift)
             val = (val >> shift) | (val << (32 - shift));
         gen_op_movl_T0_im(val);
-        if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf),
-                           (insn & (1 << 22)) != 0))
+        i = ((insn & (1 << 22)) != 0);
+        if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf, i), i))
             goto illegal_op;
     } else if ((insn & 0x0f900000) == 0x01000000
                && (insn & 0x00000090) != 0x00000090) {
@@ -1152,11 +1177,11 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             if (op1 & 1) {
                 /* PSR = reg */
                 gen_movl_T0_reg(s, rm);
-                if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf),
-                                   (op1 & 2) != 0))
+                i = ((op1 & 2) != 0);
+                if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf, i), i))
                     goto illegal_op;
             } else {
-                /* reg = CPSR */
+                /* reg = PSR */
                 rd = (insn >> 12) & 0xf;
                 if (op1 & 2) {
                     if (IS_USER(s))
@@ -2270,8 +2295,21 @@ static void disas_thumb_insn(DisasContext *s)
 
     case 14:
         /* unconditional branch */
-        if (insn & (1 << 11))
-            goto undef; /* Second half of a blx */
+        if (insn & (1 << 11)) {
+            /* Second half of blx.  */
+            offset = ((insn & 0x7ff) << 1);
+            gen_movl_T0_reg(s, 14);
+            gen_op_movl_T1_im(offset);
+            gen_op_addl_T0_T1();
+            gen_op_movl_T1_im(0xfffffffc);
+            gen_op_andl_T0_T1();
+
+            val = (uint32_t)s->pc;
+            gen_op_movl_T1_im(val | 1);
+            gen_movl_reg_T1(s, 14);
+            gen_bx(s);
+            break;
+        }
         val = (uint32_t)s->pc;
         offset = ((int32_t)insn << 21) >> 21;
         val += (offset << 1) + 2;
@@ -2280,6 +2318,29 @@ static void disas_thumb_insn(DisasContext *s)
 
     case 15:
         /* branch and link [and switch to arm] */
+        if ((s->pc & ~TARGET_PAGE_MASK) == 0) {
+            /* Instruction spans a page boundary.  Implement it as two
+               16-bit instructions in case the second half causes an
+               prefetch abort.  */
+            offset = ((int32_t)insn << 21) >> 9;
+            val = s->pc + 2 + offset;
+            gen_op_movl_T0_im(val);
+            gen_movl_reg_T0(s, 14);
+            break;
+        }
+        if (insn & (1 << 11)) {
+            /* Second half of bl.  */
+            offset = ((insn & 0x7ff) << 1) | 1;
+            gen_movl_T0_reg(s, 14);
+            gen_op_movl_T1_im(offset);
+            gen_op_addl_T0_T1();
+
+            val = (uint32_t)s->pc;
+            gen_op_movl_T1_im(val | 1);
+            gen_movl_reg_T1(s, 14);
+            gen_bx(s);
+            break;
+        }
         offset = ((int32_t)insn << 21) >> 10;
         insn = lduw_code(s->pc);
         offset |= insn & 0x7ff;
@@ -2453,35 +2514,6 @@ int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
     return gen_intermediate_code_internal(env, tb, 1);
 }
 
-void cpu_reset(CPUARMState *env)
-{
-#if defined (CONFIG_USER_ONLY)
-    env->uncached_cpsr = ARM_CPU_MODE_USR;
-#else
-    /* SVC mode with interrupts disabled.  */
-    env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
-#endif
-    env->regs[15] = 0;
-}
-
-CPUARMState *cpu_arm_init(void)
-{
-    CPUARMState *env;
-
-    env = qemu_mallocz(sizeof(CPUARMState));
-    if (!env)
-        return NULL;
-    cpu_exec_init(env);
-    cpu_reset(env);
-    tlb_flush(env, 1);
-    return env;
-}
-
-void cpu_arm_close(CPUARMState *env)
-{
-    free(env);
-}
-
 static const char *cpu_mode_names[16] = {
   "usr", "fiq", "irq", "svc", "???", "???", "???", "abt",
   "???", "???", "???", "und", "???", "???", "???", "sys"
@@ -2525,6 +2557,6 @@ void cpu_dump_state(CPUState *env, FILE *f,
                     i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower,
                     d.d);
     }
-    cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.fpscr);
+    cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]);
 }