]> git.proxmox.com Git - mirror_qemu.git/blobdiff - target-arm/helper.c
Get rid of _t suffix
[mirror_qemu.git] / target-arm / helper.c
index 5d70ef193b01eca304526a4e66a3967541731e4d..7a61c1c0e5aa44cab31b75bf0f65de41245736eb 100644 (file)
@@ -64,7 +64,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
         memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c1, 8 * sizeof(uint32_t));
-        memcpy(env->cp15.c0_c1, arm1136_cp15_c0_c2, 8 * sizeof(uint32_t));
+        memcpy(env->cp15.c0_c2, arm1136_cp15_c0_c2, 8 * sizeof(uint32_t));
         env->cp15.c0_cachetype = 0x1dd20d2;
         break;
     case ARM_CPUID_ARM11MPCORE:
@@ -76,7 +76,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
         memcpy(env->cp15.c0_c1, mpcore_cp15_c0_c1, 8 * sizeof(uint32_t));
-        memcpy(env->cp15.c0_c1, mpcore_cp15_c0_c2, 8 * sizeof(uint32_t));
+        memcpy(env->cp15.c0_c2, mpcore_cp15_c0_c2, 8 * sizeof(uint32_t));
         env->cp15.c0_cachetype = 0x1dd20d2;
         break;
     case ARM_CPUID_CORTEXA8:
@@ -88,12 +88,17 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         set_feature(env, ARM_FEATURE_VFP);
         set_feature(env, ARM_FEATURE_VFP3);
         set_feature(env, ARM_FEATURE_NEON);
+        set_feature(env, ARM_FEATURE_THUMB2EE);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410330c0;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100;
         memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c1, 8 * sizeof(uint32_t));
-        memcpy(env->cp15.c0_c1, cortexa8_cp15_c0_c2, 8 * sizeof(uint32_t));
-        env->cp15.c0_cachetype = 0x1dd20d2;
+        memcpy(env->cp15.c0_c2, cortexa8_cp15_c0_c2, 8 * sizeof(uint32_t));
+        env->cp15.c0_cachetype = 0x82048004;
+        env->cp15.c0_clid = (1 << 27) | (2 << 24) | 3;
+        env->cp15.c0_ccsid[0] = 0xe007e01a; /* 16k L1 dcache. */
+        env->cp15.c0_ccsid[1] = 0x2007e01a; /* 16k L1 icache. */
+        env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */
         break;
     case ARM_CPUID_CORTEXM3:
         set_feature(env, ARM_FEATURE_V6);
@@ -110,6 +115,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         set_feature(env, ARM_FEATURE_VFP);
         set_feature(env, ARM_FEATURE_VFP3);
         set_feature(env, ARM_FEATURE_NEON);
+        set_feature(env, ARM_FEATURE_THUMB2EE);
         set_feature(env, ARM_FEATURE_DIV);
         break;
     case ARM_CPUID_TI915T:
@@ -153,6 +159,12 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
 void cpu_reset(CPUARMState *env)
 {
     uint32_t id;
+
+    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+        log_cpu_state(env, 0);
+    }
+
     id = env->cp15.c0_cpuid;
     memset(env, 0, offsetof(CPUARMState, breakpoints));
     if (id)
@@ -168,11 +180,64 @@ void cpu_reset(CPUARMState *env)
     if (IS_M(env))
         env->uncached_cpsr &= ~CPSR_I;
     env->vfp.xregs[ARM_VFP_FPEXC] = 0;
+    env->cp15.c2_base_mask = 0xffffc000u;
 #endif
     env->regs[15] = 0;
     tlb_flush(env, 1);
 }
 
+static int vfp_gdb_get_reg(CPUState *env, uint8_t *buf, int reg)
+{
+    int nregs;
+
+    /* VFP data registers are always little-endian.  */
+    nregs = arm_feature(env, ARM_FEATURE_VFP3) ? 32 : 16;
+    if (reg < nregs) {
+        stfq_le_p(buf, env->vfp.regs[reg]);
+        return 8;
+    }
+    if (arm_feature(env, ARM_FEATURE_NEON)) {
+        /* Aliases for Q regs.  */
+        nregs += 16;
+        if (reg < nregs) {
+            stfq_le_p(buf, env->vfp.regs[(reg - 32) * 2]);
+            stfq_le_p(buf + 8, env->vfp.regs[(reg - 32) * 2 + 1]);
+            return 16;
+        }
+    }
+    switch (reg - nregs) {
+    case 0: stl_p(buf, env->vfp.xregs[ARM_VFP_FPSID]); return 4;
+    case 1: stl_p(buf, env->vfp.xregs[ARM_VFP_FPSCR]); return 4;
+    case 2: stl_p(buf, env->vfp.xregs[ARM_VFP_FPEXC]); return 4;
+    }
+    return 0;
+}
+
+static int vfp_gdb_set_reg(CPUState *env, uint8_t *buf, int reg)
+{
+    int nregs;
+
+    nregs = arm_feature(env, ARM_FEATURE_VFP3) ? 32 : 16;
+    if (reg < nregs) {
+        env->vfp.regs[reg] = ldfq_le_p(buf);
+        return 8;
+    }
+    if (arm_feature(env, ARM_FEATURE_NEON)) {
+        nregs += 16;
+        if (reg < nregs) {
+            env->vfp.regs[(reg - 32) * 2] = ldfq_le_p(buf);
+            env->vfp.regs[(reg - 32) * 2 + 1] = ldfq_le_p(buf + 8);
+            return 16;
+        }
+    }
+    switch (reg - nregs) {
+    case 0: env->vfp.xregs[ARM_VFP_FPSID] = ldl_p(buf); return 4;
+    case 1: env->vfp.xregs[ARM_VFP_FPSCR] = ldl_p(buf); return 4;
+    case 2: env->vfp.xregs[ARM_VFP_FPEXC] = ldl_p(buf); return 4;
+    }
+    return 0;
+}
+
 CPUARMState *cpu_arm_init(const char *cpu_model)
 {
     CPUARMState *env;
@@ -183,8 +248,6 @@ CPUARMState *cpu_arm_init(const char *cpu_model)
     if (id == 0)
         return NULL;
     env = qemu_mallocz(sizeof(CPUARMState));
-    if (!env)
-        return NULL;
     cpu_exec_init(env);
     if (!inited) {
         inited = 1;
@@ -194,6 +257,17 @@ CPUARMState *cpu_arm_init(const char *cpu_model)
     env->cpu_model_str = cpu_model;
     env->cp15.c0_cpuid = id;
     cpu_reset(env);
+    if (arm_feature(env, ARM_FEATURE_NEON)) {
+        gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg,
+                                 51, "arm-neon.xml", 0);
+    } else if (arm_feature(env, ARM_FEATURE_VFP3)) {
+        gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg,
+                                 35, "arm-vfp3.xml", 0);
+    } else if (arm_feature(env, ARM_FEATURE_VFP)) {
+        gdb_register_coprocessor(env, vfp_gdb_get_reg, vfp_gdb_set_reg,
+                                 19, "arm-vfp.xml", 0);
+    }
+    qemu_init_vcpu(env);
     return env;
 }
 
@@ -393,8 +467,6 @@ int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
 static void allocate_mmon_state(CPUState *env)
 {
     env->mmon_entry = malloc(sizeof (mmon_state));
-    if (!env->mmon_entry)
-        abort();
     memset (env->mmon_entry, 0, sizeof (mmon_state));
     env->mmon_entry->cpu_env = env;
     mmon_head = env->mmon_entry;
@@ -448,7 +520,7 @@ void HELPER(clrex)(CPUState *env)
     flush_mmon(env->mmon_entry->addr);
 }
 
-target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+a_target_phys_addr cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 {
     return addr;
 }
@@ -619,7 +691,7 @@ static void do_v7m_exception_exit(CPUARMState *env)
        pointer.  */
 }
 
-void do_interrupt_v7m(CPUARMState *env)
+static void do_interrupt_v7m(CPUARMState *env)
 {
     uint32_t xpsr = xpsr_read(env);
     uint32_t lr;
@@ -674,7 +746,7 @@ void do_interrupt_v7m(CPUARMState *env)
     /* ??? Should only do this if Configuration Control Register
        STACKALIGN bit is set.  */
     if (env->regs[13] & 4) {
-        env->regs[13] += 4;
+        env->regs[13] -= 4;
         xpsr |= 0x200;
     }
     /* Switch to the handler mode.  */
@@ -837,17 +909,34 @@ static inline int check_ap(CPUState *env, int ap, int domain, int access_type,
           return PAGE_READ | PAGE_WRITE;
   case 3:
       return PAGE_READ | PAGE_WRITE;
-  case 4: case 7: /* Reserved.  */
+  case 4: /* Reserved.  */
       return 0;
   case 5:
       return is_user ? 0 : prot_ro;
   case 6:
       return prot_ro;
+  case 7:
+      if (!arm_feature (env, ARM_FEATURE_V7))
+          return 0;
+      return prot_ro;
   default:
       abort();
   }
 }
 
+static uint32_t get_level1_table_address(CPUState *env, uint32_t address)
+{
+    uint32_t table;
+
+    if (address & env->cp15.c2_mask)
+        table = env->cp15.c2_base1 & 0xffffc000;
+    else
+        table = env->cp15.c2_base0 & env->cp15.c2_base_mask;
+
+    table |= (address >> 18) & 0x3ffc;
+    return table;
+}
+
 static int get_phys_addr_v5(CPUState *env, uint32_t address, int access_type,
                            int is_user, uint32_t *phys_ptr, int *prot)
 {
@@ -861,11 +950,7 @@ static int get_phys_addr_v5(CPUState *env, uint32_t address, int access_type,
 
     /* Pagetable walk.  */
     /* Lookup l1 descriptor.  */
-    if (address & env->cp15.c2_mask)
-        table = env->cp15.c2_base1;
-    else
-        table = env->cp15.c2_base0;
-    table = (table & 0xffffc000) | ((address >> 18) & 0x3ffc);
+    table = get_level1_table_address(env, address);
     desc = ldl_phys(table);
     type = (desc & 3);
     domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3;
@@ -953,11 +1038,7 @@ static int get_phys_addr_v6(CPUState *env, uint32_t address, int access_type,
 
     /* Pagetable walk.  */
     /* Lookup l1 descriptor.  */
-    if (address & env->cp15.c2_mask)
-        table = env->cp15.c2_base1;
-    else
-        table = env->cp15.c2_base0;
-    table = (table & 0xffffc000) | ((address >> 18) & 0x3ffc);
+    table = get_level1_table_address(env, address);
     desc = ldl_phys(table);
     type = (desc & 3);
     if (type == 0) {
@@ -1017,6 +1098,12 @@ static int get_phys_addr_v6(CPUState *env, uint32_t address, int access_type,
     if (xn && access_type == 2)
         goto do_fault;
 
+    /* The simplified model uses AP[0] as an access control bit.  */
+    if ((env->cp15.c1_sys & (1 << 29)) && (ap & 1) == 0) {
+        /* Access flag fault.  */
+        code = (code == 15) ? 6 : 3;
+        goto do_fault;
+    }
     *prot = check_ap(env, ap, domain, access_type, is_user);
     if (!*prot) {
         /* Access permission fault.  */
@@ -1143,7 +1230,7 @@ int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address,
     return 1;
 }
 
-target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+a_target_phys_addr cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 {
     uint32_t phys_addr;
     int prot;
@@ -1241,15 +1328,16 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
     crm = insn & 0xf;
     switch ((insn >> 16) & 0xf) {
     case 0:
-        if (((insn >> 21) & 7) == 2) {
-            /* ??? Select cache level.  Ignore.  */
-            return;
-        }
         /* ID codes.  */
         if (arm_feature(env, ARM_FEATURE_XSCALE))
             break;
         if (arm_feature(env, ARM_FEATURE_OMAPCP))
             break;
+        if (arm_feature(env, ARM_FEATURE_V7)
+                && op1 == 2 && crm == 0 && op2 == 0) {
+            env->cp15.c0_cssel = val & 0xf;
+            break;
+        }
         goto bad_reg;
     case 1: /* System configuration.  */
         if (arm_feature(env, ARM_FEATURE_OMAPCP))
@@ -1272,9 +1360,11 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
         case 2:
             if (arm_feature(env, ARM_FEATURE_XSCALE))
                 goto bad_reg;
-            env->cp15.c1_coproc = val;
-            /* ??? Is this safe when called from within a TB?  */
-            tb_flush(env);
+            if (env->cp15.c1_coproc != val) {
+                env->cp15.c1_coproc = val;
+                /* ??? Is this safe when called from within a TB?  */
+                tb_flush(env);
+            }
             break;
         default:
             goto bad_reg;
@@ -1301,7 +1391,10 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
                env->cp15.c2_base1 = val;
                break;
            case 2:
+                val &= 7;
+                env->cp15.c2_control = val;
                env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> val);
+                env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> val);
                break;
            default:
                goto bad_reg;
@@ -1563,9 +1656,22 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
                 goto bad_reg;
             if (crm != 0)
                 goto bad_reg;
-            if (arm_feature(env, ARM_FEATURE_XSCALE))
+            if (!arm_feature(env, ARM_FEATURE_V7))
+                return 0;
+
+            switch (op2) {
+            case 0:
+                return env->cp15.c0_ccsid[env->cp15.c0_cssel];
+            case 1:
+                return env->cp15.c0_clid;
+            case 7:
+                return 0;
+            }
+            goto bad_reg;
+        case 2:
+            if (op2 != 0 || crm != 0)
                 goto bad_reg;
-            return 0;
+            return env->cp15.c0_cssel;
         default:
             goto bad_reg;
         }
@@ -1589,7 +1695,7 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
             case ARM_CPUID_ARM11MPCORE:
                 return 1;
             case ARM_CPUID_CORTEXA8:
-                return 0;
+                return 2;
             default:
                 goto bad_reg;
             }
@@ -1619,17 +1725,7 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
            case 1:
                return env->cp15.c2_base1;
            case 2:
-               {
-                   int n;
-                   uint32_t mask;
-                   n = 0;
-                   mask = env->cp15.c2_mask;
-                   while (mask) {
-                       n++;
-                       mask <<= 1;
-                   }
-                   return n;
-               }
+                return env->cp15.c2_control;
            default:
                goto bad_reg;
            }
@@ -1985,7 +2081,7 @@ static inline uint8_t sub8_sat(uint8_t a, uint8_t b)
 #include "op_addsub.h"
 
 /* Unsigned saturating arithmetic.  */
-static inline uint16_t add16_usat(uint16_t a, uint8_t b)
+static inline uint16_t add16_usat(uint16_t a, uint16_t b)
 {
     uint16_t res;
     res = a + b;
@@ -1994,7 +2090,7 @@ static inline uint16_t add16_usat(uint16_t a, uint8_t b)
     return res;
 }
 
-static inline uint16_t sub16_usat(uint16_t a, uint8_t b)
+static inline uint16_t sub16_usat(uint16_t a, uint16_t b)
 {
     if (a < b)
         return a - b;
@@ -2059,7 +2155,7 @@ static inline uint8_t sub8_usat(uint8_t a, uint8_t b)
     uint32_t sum; \
     sum = (uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b); \
     RESULT(sum, n, 16); \
-    if ((sum >> 16) == 0) \
+    if ((sum >> 16) == 1) \
         ge |= 3 << (n * 2); \
     } while(0)
 
@@ -2067,8 +2163,8 @@ static inline uint8_t sub8_usat(uint8_t a, uint8_t b)
     uint32_t sum; \
     sum = (uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b); \
     RESULT(sum, n, 8); \
-    if ((sum >> 8) == 0) \
-        ge |= 3 << (n * 2); \
+    if ((sum >> 8) == 1) \
+        ge |= 1 << n; \
     } while(0)
 
 #define SUB16(a, b, n) do { \
@@ -2084,7 +2180,7 @@ static inline uint8_t sub8_usat(uint8_t a, uint8_t b)
     sum = (uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b); \
     RESULT(sum, n, 8); \
     if ((sum >> 8) == 0) \
-        ge |= 3 << (n * 2); \
+        ge |= 1 << n; \
     } while(0)
 
 #define PFX u
@@ -2241,10 +2337,13 @@ void HELPER(vfp_set_fpscr)(CPUState *env, uint32_t val)
         }
         set_float_rounding_mode(i, &env->vfp.fp_status);
     }
+    if (changed & (1 << 24))
+        set_flush_to_zero((val & (1 << 24)) != 0, &env->vfp.fp_status);
+    if (changed & (1 << 25))
+        set_default_nan_mode((val & (1 << 25)) != 0, &env->vfp.fp_status);
 
     i = vfp_exceptbits_to_host((val >> 8) & 0x1f);
     set_float_exception_flags(i, &env->vfp.fp_status);
-    /* XXX: FZ and DN are not implemented.  */
 }
 
 #define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p))
@@ -2449,7 +2548,7 @@ ftype VFP_HELPER(name##to, p)(ftype x, uint32_t shift, CPUState *env) \
     ftype tmp; \
     tmp = sign##int32_to_##ftype ((itype)vfp_##p##toi(x), \
                                   &env->vfp.fp_status); \
-    return ftype##_scalbn(tmp, shift, &env->vfp.fp_status); \
+    return ftype##_scalbn(tmp, -(int)shift, &env->vfp.fp_status); \
 } \
 ftype VFP_HELPER(to##name, p)(ftype x, uint32_t shift, CPUState *env) \
 { \
@@ -2522,3 +2621,12 @@ uint32_t HELPER(rsqrte_u32)(uint32_t a, CPUState *env)
     tmp = float32_scalbn(tmp, 31, s);
     return float32_to_int32(tmp, s);
 }
+
+void HELPER(set_teecr)(CPUState *env, uint32_t val)
+{
+    val &= 1;
+    if (env->teecr != val) {
+        env->teecr = val;
+        tb_flush(env);
+    }
+}