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:
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:
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);
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:
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)
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;
if (id == 0)
return NULL;
env = qemu_mallocz(sizeof(CPUARMState));
- if (!env)
- return NULL;
cpu_exec_init(env);
if (!inited) {
inited = 1;
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;
}
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;
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;
}
pointer. */
}
-void do_interrupt_v7m(CPUARMState *env)
+static void do_interrupt_v7m(CPUARMState *env)
{
uint32_t xpsr = xpsr_read(env);
uint32_t lr;
/* ??? 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. */
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)
{
/* 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;
/* 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) {
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. */
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;
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))
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;
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;
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;
}
case ARM_CPUID_ARM11MPCORE:
return 1;
case ARM_CPUID_CORTEXA8:
- return 0;
+ return 2;
default:
goto bad_reg;
}
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;
}
#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;
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;
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)
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 { \
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
}
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))
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) \
{ \
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);
+ }
+}