mirror of https://github.com/xemu-project/xemu.git
ARM946 CPU support.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2783 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
9455455016
commit
ce8198612e
|
@ -251,7 +251,7 @@ static void pxa2xx_clkpwr_write(void *opaque, int op2, int reg, int crm,
|
||||||
ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
|
ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
|
||||||
s->env->cp15.c1_sys = 0;
|
s->env->cp15.c1_sys = 0;
|
||||||
s->env->cp15.c1_coproc = 0;
|
s->env->cp15.c1_coproc = 0;
|
||||||
s->env->cp15.c2 = 0;
|
s->env->cp15.c2_base = 0;
|
||||||
s->env->cp15.c3 = 0;
|
s->env->cp15.c3 = 0;
|
||||||
s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */
|
s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */
|
||||||
s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
|
s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
|
||||||
|
|
|
@ -77,7 +77,7 @@ For system emulation, the following hardware targets are supported:
|
||||||
@item Sun4m (32-bit Sparc processor)
|
@item Sun4m (32-bit Sparc processor)
|
||||||
@item Sun4u (64-bit Sparc processor, in progress)
|
@item Sun4u (64-bit Sparc processor, in progress)
|
||||||
@item Malta board (32-bit MIPS processor)
|
@item Malta board (32-bit MIPS processor)
|
||||||
@item ARM Integrator/CP (ARM926E or 1026E processor)
|
@item ARM Integrator/CP (ARM926E, 1026E or 946E processor)
|
||||||
@item ARM Versatile baseboard (ARM926E)
|
@item ARM Versatile baseboard (ARM926E)
|
||||||
@item ARM RealView Emulation baseboard (ARM926EJ-S)
|
@item ARM RealView Emulation baseboard (ARM926EJ-S)
|
||||||
@item Spitz, Akita, Borzoi and Terrier PDAs (PXA270 processor)
|
@item Spitz, Akita, Borzoi and Terrier PDAs (PXA270 processor)
|
||||||
|
@ -1722,7 +1722,7 @@ devices:
|
||||||
|
|
||||||
@itemize @minus
|
@itemize @minus
|
||||||
@item
|
@item
|
||||||
ARM926E or ARM1026E CPU
|
ARM926E, ARM1026E or ARM946E CPU
|
||||||
@item
|
@item
|
||||||
Two PL011 UARTs
|
Two PL011 UARTs
|
||||||
@item
|
@item
|
||||||
|
|
|
@ -83,10 +83,14 @@ typedef struct CPUARMState {
|
||||||
uint32_t c0_cachetype;
|
uint32_t c0_cachetype;
|
||||||
uint32_t c1_sys; /* System control register. */
|
uint32_t c1_sys; /* System control register. */
|
||||||
uint32_t c1_coproc; /* Coprocessor access register. */
|
uint32_t c1_coproc; /* Coprocessor access register. */
|
||||||
uint32_t c2; /* MMU translation table base. */
|
uint32_t c2_base; /* MMU translation table base. */
|
||||||
uint32_t c3; /* MMU domain access control register. */
|
uint32_t c2_data; /* MPU data cachable bits. */
|
||||||
|
uint32_t c2_insn; /* MPU instruction cachable bits. */
|
||||||
|
uint32_t c3; /* MMU domain access control register
|
||||||
|
MPU write buffer control. */
|
||||||
uint32_t c5_insn; /* Fault status registers. */
|
uint32_t c5_insn; /* Fault status registers. */
|
||||||
uint32_t c5_data;
|
uint32_t c5_data;
|
||||||
|
uint32_t c6_region[8]; /* MPU base/size registers. */
|
||||||
uint32_t c6_insn; /* Fault address registers. */
|
uint32_t c6_insn; /* Fault address registers. */
|
||||||
uint32_t c6_data;
|
uint32_t c6_data;
|
||||||
uint32_t c9_insn; /* Cache lockdown registers. */
|
uint32_t c9_insn; /* Cache lockdown registers. */
|
||||||
|
@ -241,7 +245,8 @@ enum arm_features {
|
||||||
ARM_FEATURE_VFP,
|
ARM_FEATURE_VFP,
|
||||||
ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */
|
ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */
|
||||||
ARM_FEATURE_XSCALE, /* Intel XScale extensions. */
|
ARM_FEATURE_XSCALE, /* Intel XScale extensions. */
|
||||||
ARM_FEATURE_IWMMXT /* Intel iwMMXt extension. */
|
ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension. */
|
||||||
|
ARM_FEATURE_MPU /* Only has Memory Protection Unit, not full MMU. */
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline int arm_feature(CPUARMState *env, int feature)
|
static inline int arm_feature(CPUARMState *env, int feature)
|
||||||
|
@ -258,6 +263,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
|
||||||
|
|
||||||
#define ARM_CPUID_ARM1026 0x4106a262
|
#define ARM_CPUID_ARM1026 0x4106a262
|
||||||
#define ARM_CPUID_ARM926 0x41069265
|
#define ARM_CPUID_ARM926 0x41069265
|
||||||
|
#define ARM_CPUID_ARM946 0x41059461
|
||||||
#define ARM_CPUID_PXA250 0x69052100
|
#define ARM_CPUID_PXA250 0x69052100
|
||||||
#define ARM_CPUID_PXA255 0x69052d00
|
#define ARM_CPUID_PXA255 0x69052d00
|
||||||
#define ARM_CPUID_PXA260 0x69052903
|
#define ARM_CPUID_PXA260 0x69052903
|
||||||
|
|
|
@ -19,6 +19,10 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
|
||||||
env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
|
env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
|
||||||
env->cp15.c0_cachetype = 0x1dd20d2;
|
env->cp15.c0_cachetype = 0x1dd20d2;
|
||||||
break;
|
break;
|
||||||
|
case ARM_CPUID_ARM946:
|
||||||
|
set_feature(env, ARM_FEATURE_MPU);
|
||||||
|
env->cp15.c0_cachetype = 0x0f004006;
|
||||||
|
break;
|
||||||
case ARM_CPUID_ARM1026:
|
case ARM_CPUID_ARM1026:
|
||||||
set_feature(env, ARM_FEATURE_VFP);
|
set_feature(env, ARM_FEATURE_VFP);
|
||||||
set_feature(env, ARM_FEATURE_AUXCR);
|
set_feature(env, ARM_FEATURE_AUXCR);
|
||||||
|
@ -90,6 +94,7 @@ struct arm_cpu_t {
|
||||||
|
|
||||||
static const struct arm_cpu_t arm_cpu_names[] = {
|
static const struct arm_cpu_t arm_cpu_names[] = {
|
||||||
{ ARM_CPUID_ARM926, "arm926"},
|
{ ARM_CPUID_ARM926, "arm926"},
|
||||||
|
{ ARM_CPUID_ARM946, "arm946"},
|
||||||
{ ARM_CPUID_ARM1026, "arm1026"},
|
{ ARM_CPUID_ARM1026, "arm1026"},
|
||||||
{ ARM_CPUID_PXA250, "pxa250" },
|
{ ARM_CPUID_PXA250, "pxa250" },
|
||||||
{ ARM_CPUID_PXA255, "pxa255" },
|
{ ARM_CPUID_PXA255, "pxa255" },
|
||||||
|
@ -392,13 +397,67 @@ static int get_phys_addr(CPUState *env, uint32_t address, int access_type,
|
||||||
address += env->cp15.c13_fcse;
|
address += env->cp15.c13_fcse;
|
||||||
|
|
||||||
if ((env->cp15.c1_sys & 1) == 0) {
|
if ((env->cp15.c1_sys & 1) == 0) {
|
||||||
/* MMU diusabled. */
|
/* MMU/MPU disabled. */
|
||||||
*phys_ptr = address;
|
*phys_ptr = address;
|
||||||
*prot = PAGE_READ | PAGE_WRITE;
|
*prot = PAGE_READ | PAGE_WRITE;
|
||||||
|
} else if (arm_feature(env, ARM_FEATURE_MPU)) {
|
||||||
|
int n;
|
||||||
|
uint32_t mask;
|
||||||
|
uint32_t base;
|
||||||
|
|
||||||
|
*phys_ptr = address;
|
||||||
|
for (n = 7; n >= 0; n--) {
|
||||||
|
base = env->cp15.c6_region[n];
|
||||||
|
if ((base & 1) == 0)
|
||||||
|
continue;
|
||||||
|
mask = 1 << ((base >> 1) & 0x1f);
|
||||||
|
/* Keep this shift separate from the above to avoid an
|
||||||
|
(undefined) << 32. */
|
||||||
|
mask = (mask << 1) - 1;
|
||||||
|
if (((base ^ address) & ~mask) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (n < 0)
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
if (access_type == 2) {
|
||||||
|
mask = env->cp15.c5_insn;
|
||||||
|
} else {
|
||||||
|
mask = env->cp15.c5_data;
|
||||||
|
}
|
||||||
|
mask = (mask >> (n * 4)) & 0xf;
|
||||||
|
switch (mask) {
|
||||||
|
case 0:
|
||||||
|
return 1;
|
||||||
|
case 1:
|
||||||
|
if (is_user)
|
||||||
|
return 1;
|
||||||
|
*prot = PAGE_READ | PAGE_WRITE;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
*prot = PAGE_READ;
|
||||||
|
if (!is_user)
|
||||||
|
*prot |= PAGE_WRITE;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
*prot = PAGE_READ | PAGE_WRITE;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
if (is_user)
|
||||||
|
return 1;
|
||||||
|
*prot = PAGE_READ;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
*prot = PAGE_READ;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Bad permission. */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Pagetable walk. */
|
/* Pagetable walk. */
|
||||||
/* Lookup l1 descriptor. */
|
/* Lookup l1 descriptor. */
|
||||||
table = (env->cp15.c2 & 0xffffc000) | ((address >> 18) & 0x3ffc);
|
table = (env->cp15.c2_base & 0xffffc000) | ((address >> 18) & 0x3ffc);
|
||||||
desc = ldl_phys(table);
|
desc = ldl_phys(table);
|
||||||
type = (desc & 3);
|
type = (desc & 3);
|
||||||
domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3;
|
domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3;
|
||||||
|
@ -539,18 +598,50 @@ uint32_t helper_get_cp(CPUState *env, uint32_t insn)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return basic MPU access permission bits. */
|
||||||
|
static uint32_t simple_mpu_ap_bits(uint32_t val)
|
||||||
|
{
|
||||||
|
uint32_t ret;
|
||||||
|
uint32_t mask;
|
||||||
|
int i;
|
||||||
|
ret = 0;
|
||||||
|
mask = 3;
|
||||||
|
for (i = 0; i < 16; i += 2) {
|
||||||
|
ret |= (val >> i) & mask;
|
||||||
|
mask <<= 2;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pad basic MPU access permission bits to extended format. */
|
||||||
|
static uint32_t extended_mpu_ap_bits(uint32_t val)
|
||||||
|
{
|
||||||
|
uint32_t ret;
|
||||||
|
uint32_t mask;
|
||||||
|
int i;
|
||||||
|
ret = 0;
|
||||||
|
mask = 3;
|
||||||
|
for (i = 0; i < 16; i += 2) {
|
||||||
|
ret |= (val & mask) << i;
|
||||||
|
mask <<= 2;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
|
void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
|
||||||
{
|
{
|
||||||
uint32_t op2;
|
uint32_t op2;
|
||||||
|
uint32_t crm;
|
||||||
|
|
||||||
op2 = (insn >> 5) & 7;
|
op2 = (insn >> 5) & 7;
|
||||||
|
crm = insn & 0xf;
|
||||||
switch ((insn >> 16) & 0xf) {
|
switch ((insn >> 16) & 0xf) {
|
||||||
case 0: /* ID codes. */
|
case 0: /* ID codes. */
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
case 1: /* System configuration. */
|
case 1: /* System configuration. */
|
||||||
switch (op2) {
|
switch (op2) {
|
||||||
case 0:
|
case 0:
|
||||||
if (!arm_feature(env, ARM_FEATURE_XSCALE) || (insn & 0xf) == 0)
|
if (!arm_feature(env, ARM_FEATURE_XSCALE) || crm == 0)
|
||||||
env->cp15.c1_sys = val;
|
env->cp15.c1_sys = val;
|
||||||
/* ??? Lots of these bits are not implemented. */
|
/* ??? Lots of these bits are not implemented. */
|
||||||
/* This may enable/disable the MMU, so do a TLB flush. */
|
/* This may enable/disable the MMU, so do a TLB flush. */
|
||||||
|
@ -571,36 +662,69 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2: /* MMU Page table control. */
|
case 2: /* MMU Page table control / MPU cache control. */
|
||||||
env->cp15.c2 = val;
|
if (arm_feature(env, ARM_FEATURE_MPU)) {
|
||||||
|
switch (op2) {
|
||||||
|
case 0:
|
||||||
|
env->cp15.c2_data = val;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
env->cp15.c2_insn = val;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto bad_reg;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
env->cp15.c2_base = val;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 3: /* MMU Domain access control. */
|
case 3: /* MMU Domain access control / MPU write buffer control. */
|
||||||
env->cp15.c3 = val;
|
env->cp15.c3 = val;
|
||||||
break;
|
break;
|
||||||
case 4: /* Reserved. */
|
case 4: /* Reserved. */
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
case 5: /* MMU Fault status. */
|
case 5: /* MMU Fault status / MPU access permission. */
|
||||||
switch (op2) {
|
switch (op2) {
|
||||||
case 0:
|
case 0:
|
||||||
|
if (arm_feature(env, ARM_FEATURE_MPU))
|
||||||
|
val = extended_mpu_ap_bits(val);
|
||||||
env->cp15.c5_data = val;
|
env->cp15.c5_data = val;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
|
if (arm_feature(env, ARM_FEATURE_MPU))
|
||||||
|
val = extended_mpu_ap_bits(val);
|
||||||
|
env->cp15.c5_insn = val;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (!arm_feature(env, ARM_FEATURE_MPU))
|
||||||
|
goto bad_reg;
|
||||||
|
env->cp15.c5_data = val;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (!arm_feature(env, ARM_FEATURE_MPU))
|
||||||
|
goto bad_reg;
|
||||||
env->cp15.c5_insn = val;
|
env->cp15.c5_insn = val;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 6: /* MMU Fault address. */
|
case 6: /* MMU Fault address / MPU base/size. */
|
||||||
switch (op2) {
|
if (arm_feature(env, ARM_FEATURE_MPU)) {
|
||||||
case 0:
|
if (crm >= 8)
|
||||||
env->cp15.c6_data = val;
|
goto bad_reg;
|
||||||
break;
|
env->cp15.c6_region[crm] = val;
|
||||||
case 1:
|
} else {
|
||||||
env->cp15.c6_insn = val;
|
switch (op2) {
|
||||||
break;
|
case 0:
|
||||||
default:
|
env->cp15.c6_data = val;
|
||||||
goto bad_reg;
|
break;
|
||||||
|
case 1:
|
||||||
|
env->cp15.c6_insn = val;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto bad_reg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 7: /* Cache control. */
|
case 7: /* Cache control. */
|
||||||
|
@ -629,14 +753,23 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 9: /* Cache lockdown. */
|
case 9:
|
||||||
switch (op2) {
|
switch (crm) {
|
||||||
case 0:
|
case 0: /* Cache lockdown. */
|
||||||
env->cp15.c9_data = val;
|
switch (op2) {
|
||||||
break;
|
case 0:
|
||||||
case 1:
|
env->cp15.c9_data = val;
|
||||||
env->cp15.c9_insn = val;
|
break;
|
||||||
|
case 1:
|
||||||
|
env->cp15.c9_insn = val;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto bad_reg;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
case 1: /* TCM memory region registers. */
|
||||||
|
/* Not implemented. */
|
||||||
|
goto bad_reg;
|
||||||
default:
|
default:
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
}
|
}
|
||||||
|
@ -644,12 +777,13 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
|
||||||
case 10: /* MMU TLB lockdown. */
|
case 10: /* MMU TLB lockdown. */
|
||||||
/* ??? TLB lockdown not implemented. */
|
/* ??? TLB lockdown not implemented. */
|
||||||
break;
|
break;
|
||||||
case 11: /* TCM DMA control. */
|
|
||||||
case 12: /* Reserved. */
|
case 12: /* Reserved. */
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
case 13: /* Process ID. */
|
case 13: /* Process ID. */
|
||||||
switch (op2) {
|
switch (op2) {
|
||||||
case 0:
|
case 0:
|
||||||
|
if (!arm_feature(env, ARM_FEATURE_MPU))
|
||||||
|
goto bad_reg;
|
||||||
/* Unlike real hardware the qemu TLB uses virtual addresses,
|
/* Unlike real hardware the qemu TLB uses virtual addresses,
|
||||||
not modified virtual addresses, so this causes a TLB flush.
|
not modified virtual addresses, so this causes a TLB flush.
|
||||||
*/
|
*/
|
||||||
|
@ -659,7 +793,8 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
/* This changes the ASID, so do a TLB flush. */
|
/* This changes the ASID, so do a TLB flush. */
|
||||||
if (env->cp15.c13_context != val)
|
if (env->cp15.c13_context != val
|
||||||
|
&& !arm_feature(env, ARM_FEATURE_MPU))
|
||||||
tlb_flush(env, 0);
|
tlb_flush(env, 0);
|
||||||
env->cp15.c13_context = val;
|
env->cp15.c13_context = val;
|
||||||
break;
|
break;
|
||||||
|
@ -671,7 +806,7 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
case 15: /* Implementation specific. */
|
case 15: /* Implementation specific. */
|
||||||
if (arm_feature(env, ARM_FEATURE_XSCALE)) {
|
if (arm_feature(env, ARM_FEATURE_XSCALE)) {
|
||||||
if (op2 == 0 && (insn & 0xf) == 1) {
|
if (op2 == 0 && crm == 1) {
|
||||||
/* Changes cp0 to cp13 behavior, so needs a TB flush. */
|
/* Changes cp0 to cp13 behavior, so needs a TB flush. */
|
||||||
tb_flush(env);
|
tb_flush(env);
|
||||||
env->cp15.c15_cpar = (val & 0x3fff) | 2;
|
env->cp15.c15_cpar = (val & 0x3fff) | 2;
|
||||||
|
@ -717,31 +852,64 @@ uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
|
||||||
default:
|
default:
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
}
|
}
|
||||||
case 2: /* MMU Page table control. */
|
case 2: /* MMU Page table control / MPU cache control. */
|
||||||
return env->cp15.c2;
|
if (arm_feature(env, ARM_FEATURE_MPU)) {
|
||||||
case 3: /* MMU Domain access control. */
|
switch (op2) {
|
||||||
|
case 0:
|
||||||
|
return env->cp15.c2_data;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
return env->cp15.c2_insn;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto bad_reg;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return env->cp15.c2_base;
|
||||||
|
}
|
||||||
|
case 3: /* MMU Domain access control / MPU write buffer control. */
|
||||||
return env->cp15.c3;
|
return env->cp15.c3;
|
||||||
case 4: /* Reserved. */
|
case 4: /* Reserved. */
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
case 5: /* MMU Fault status. */
|
case 5: /* MMU Fault status / MPU access permission. */
|
||||||
switch (op2) {
|
switch (op2) {
|
||||||
case 0:
|
case 0:
|
||||||
|
if (arm_feature(env, ARM_FEATURE_MPU))
|
||||||
|
return simple_mpu_ap_bits(env->cp15.c5_data);
|
||||||
return env->cp15.c5_data;
|
return env->cp15.c5_data;
|
||||||
case 1:
|
case 1:
|
||||||
|
if (arm_feature(env, ARM_FEATURE_MPU))
|
||||||
|
return simple_mpu_ap_bits(env->cp15.c5_data);
|
||||||
|
return env->cp15.c5_insn;
|
||||||
|
case 2:
|
||||||
|
if (!arm_feature(env, ARM_FEATURE_MPU))
|
||||||
|
goto bad_reg;
|
||||||
|
return env->cp15.c5_data;
|
||||||
|
case 3:
|
||||||
|
if (!arm_feature(env, ARM_FEATURE_MPU))
|
||||||
|
goto bad_reg;
|
||||||
return env->cp15.c5_insn;
|
return env->cp15.c5_insn;
|
||||||
default:
|
default:
|
||||||
goto bad_reg;
|
goto bad_reg;
|
||||||
}
|
}
|
||||||
case 6: /* MMU Fault address. */
|
case 6: /* MMU Fault address / MPU base/size. */
|
||||||
switch (op2) {
|
if (arm_feature(env, ARM_FEATURE_MPU)) {
|
||||||
case 0:
|
int n;
|
||||||
return env->cp15.c6_data;
|
n = (insn & 0xf);
|
||||||
case 1:
|
if (n >= 8)
|
||||||
/* Arm9 doesn't have an IFAR, but implementing it anyway shouldn't
|
goto bad_reg;
|
||||||
do any harm. */
|
return env->cp15.c6_region[n];
|
||||||
return env->cp15.c6_insn;
|
} else {
|
||||||
default:
|
switch (op2) {
|
||||||
goto bad_reg;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case 7: /* Cache control. */
|
case 7: /* Cache control. */
|
||||||
/* ??? This is for test, clean and invaidate operations that set the
|
/* ??? This is for test, clean and invaidate operations that set the
|
||||||
|
|
Loading…
Reference in New Issue