#include "cpu.h"
#include "exec-all.h"
+void cpu_reset(CPUARMState *env)
+{
+#if defined (CONFIG_USER_ONLY)
+ env->uncached_cpsr = ARM_CPU_MODE_USR;
+ env->vfp.xregs[ARM_VFP_FPEXC] = 1 << 30;
+#else
+ /* SVC mode with interrupts disabled. */
+ env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
+ env->vfp.xregs[ARM_VFP_FPEXC] = 0;
+#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;
+}
+
+static inline void set_feature(CPUARMState *env, int feature)
+{
+ env->features |= 1u << feature;
+}
+
+void cpu_arm_set_model(CPUARMState *env, uint32_t id)
+{
+ env->cp15.c0_cpuid = id;
+ switch (id) {
+ case ARM_CPUID_ARM926:
+ set_feature(env, ARM_FEATURE_VFP);
+ env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
+ break;
+ case ARM_CPUID_ARM1026:
+ set_feature(env, ARM_FEATURE_VFP);
+ set_feature(env, ARM_FEATURE_AUXCR);
+ env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
+ break;
+ default:
+ cpu_abort(env, "Bad CPU ID: %x\n", id);
+ break;
+ }
+}
+
+void cpu_arm_close(CPUARMState *env)
+{
+ free(env);
+}
+
#if defined(CONFIG_USER_ONLY)
void do_interrupt (CPUState *env)
if (old_mode == ARM_CPU_MODE_FIQ) {
memcpy (env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t));
- memcpy (env->regs, env->usr_regs + 8, 5 * sizeof(uint32_t));
+ memcpy (env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t));
} else if (mode == ARM_CPU_MODE_FIQ) {
memcpy (env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t));
- memcpy (env->regs, env->fiq_regs + 8, 5 * sizeof(uint32_t));
+ memcpy (env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t));
}
i = bank_number(old_mode);
switch (ap) {
case 0:
- if (access_type != 1)
+ if (access_type == 1)
return 0;
switch ((env->cp15.c1_sys >> 8) & 3) {
case 1:
case 13: /* Process ID. */
switch (op2) {
case 0:
- env->cp15.c9_data = val;
+ /* Unlike real hardware the qemu TLB uses virtual addresses,
+ not modified virtual addresses, so this causes a TLB flush.
+ */
+ if (env->cp15.c13_fcse != val)
+ tlb_flush(env, 1);
+ env->cp15.c13_fcse = val;
break;
case 1:
- env->cp15.c9_insn = val;
+ /* This changes the ASID, so do a TLB flush. */
+ if (env->cp15.c13_context != val)
+ tlb_flush(env, 0);
+ env->cp15.c13_context = val;
break;
default:
goto bad_reg;
case 0: /* ID codes. */
switch (op2) {
default: /* Device ID. */
- return 0x4106a262;
+ return env->cp15.c0_cpuid;
case 1: /* Cache Type. */
return 0x1dd20d2;
case 2: /* TCM status. */
case 0: /* Control register. */
return env->cp15.c1_sys;
case 1: /* Auxiliary control register. */
- return 1;
+ if (arm_feature(env, ARM_FEATURE_AUXCR))
+ return 1;
+ goto bad_reg;
case 2: /* Coprocessor access register. */
return env->cp15.c1_coproc;
default:
case 0:
return env->cp15.c6_data;
case 1:
+ /* Arm9 doesn't have an IFAR, but implementing it anyway shouldn't
+ do any harm. */
return env->cp15.c6_insn;
default:
goto bad_reg;