Skip to content

Commit

Permalink
target-arm: convert cp15 crn=7 registers
Browse files Browse the repository at this point in the history
Convert the cp15 crn=7 registers to the new scheme.
Note that to do this we have to distinguish some registers
used on the ARM9 and ARM10 from some which are ARM1176
only. This is because the old code returned a value of 0
but always set the Z flag (by clearing env->ZF, since we
store the Z flag in CPUState inverted). This is inconsistent
with actual ARM CPU behaviour, which only sets flags for
reads to r15 and sets them based on the top bits of the result.
However it happened to work for the two common use cases for
cp15 crn=7 reads:
 * On ARM9 and ARM10 the cache clean-and-test operations are
typically done with a destination of r15 so that you can do
a "loop: mrc ... ; bne loop" to keep cleaning until the cache
is finally clean; always setting the Z flag means this loop
terminates immediately
 * on ARM1176 the Cache Dirty Status Register reads as zero
if the cache is dirty; returning 0 means this is correctly
implemented for QEMU

Since the new coprocessor register framework does the right
thing of always setting flags based on the returned result
for reads to r15, we need to split these up so that we can
return (1<<30) for the ARM9/ARM10 registers but 0 for the
ARM1176 one.

This allows us to remove the nasty hack which always sets Z.

Signed-off-by: Peter Maydell <[email protected]>
  • Loading branch information
pm215 committed Jun 20, 2012
1 parent 4a50160 commit c480421
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 11 deletions.
19 changes: 19 additions & 0 deletions target-arm/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ static void arm926_initfn(Object *obj)
ARMCPU *cpu = ARM_CPU(obj);
set_feature(&cpu->env, ARM_FEATURE_V5);
set_feature(&cpu->env, ARM_FEATURE_VFP);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN);
cpu->midr = ARM_CPUID_ARM926;
cpu->reset_fpsid = 0x41011090;
cpu->ctr = 0x1dd20d2;
Expand All @@ -231,6 +233,7 @@ static void arm946_initfn(Object *obj)
ARMCPU *cpu = ARM_CPU(obj);
set_feature(&cpu->env, ARM_FEATURE_V5);
set_feature(&cpu->env, ARM_FEATURE_MPU);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
cpu->midr = ARM_CPUID_ARM946;
cpu->ctr = 0x0f004006;
cpu->reset_sctlr = 0x00000078;
Expand All @@ -242,6 +245,8 @@ static void arm1026_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_V5);
set_feature(&cpu->env, ARM_FEATURE_VFP);
set_feature(&cpu->env, ARM_FEATURE_AUXCR);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN);
cpu->midr = ARM_CPUID_ARM1026;
cpu->reset_fpsid = 0x410110a0;
cpu->ctr = 0x1dd20d2;
Expand All @@ -260,6 +265,9 @@ static void arm1136_r2_initfn(Object *obj)
*/
set_feature(&cpu->env, ARM_FEATURE_V6);
set_feature(&cpu->env, ARM_FEATURE_VFP);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG);
set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS);
cpu->midr = ARM_CPUID_ARM1136_R2;
cpu->reset_fpsid = 0x410120b4;
cpu->mvfr0 = 0x11111111;
Expand All @@ -286,6 +294,9 @@ static void arm1136_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_V6K);
set_feature(&cpu->env, ARM_FEATURE_V6);
set_feature(&cpu->env, ARM_FEATURE_VFP);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG);
set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS);
cpu->midr = ARM_CPUID_ARM1136;
cpu->reset_fpsid = 0x410120b4;
cpu->mvfr0 = 0x11111111;
Expand All @@ -312,6 +323,9 @@ static void arm1176_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_V6K);
set_feature(&cpu->env, ARM_FEATURE_VFP);
set_feature(&cpu->env, ARM_FEATURE_VAPA);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG);
set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS);
cpu->midr = ARM_CPUID_ARM1176;
cpu->reset_fpsid = 0x410120b5;
cpu->mvfr0 = 0x11111111;
Expand All @@ -338,6 +352,7 @@ static void arm11mpcore_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_V6K);
set_feature(&cpu->env, ARM_FEATURE_VFP);
set_feature(&cpu->env, ARM_FEATURE_VAPA);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
cpu->midr = ARM_CPUID_ARM11MPCORE;
cpu->reset_fpsid = 0x410120b4;
cpu->mvfr0 = 0x11111111;
Expand Down Expand Up @@ -372,6 +387,7 @@ static void cortex_a8_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_VFP3);
set_feature(&cpu->env, ARM_FEATURE_NEON);
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
cpu->midr = ARM_CPUID_CORTEXA8;
cpu->reset_fpsid = 0x410330c0;
cpu->mvfr0 = 0x11110222;
Expand Down Expand Up @@ -483,6 +499,7 @@ static void cortex_a15_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_ARM_DIV);
set_feature(&cpu->env, ARM_FEATURE_V7MP);
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
cpu->midr = ARM_CPUID_CORTEXA15;
cpu->reset_fpsid = 0x410430f0;
cpu->mvfr0 = 0x10110222;
Expand Down Expand Up @@ -522,6 +539,7 @@ static void sa1100_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
set_feature(&cpu->env, ARM_FEATURE_STRONGARM);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
cpu->midr = ARM_CPUID_SA1100;
cpu->reset_sctlr = 0x00000070;
}
Expand All @@ -530,6 +548,7 @@ static void sa1110_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
set_feature(&cpu->env, ARM_FEATURE_STRONGARM);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
cpu->midr = ARM_CPUID_SA1110;
cpu->reset_sctlr = 0x00000070;
}
Expand Down
3 changes: 3 additions & 0 deletions target-arm/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,9 @@ enum arm_features {
ARM_FEATURE_GENERIC_TIMER,
ARM_FEATURE_MVFR, /* Media and VFP Feature Registers 0 and 1 */
ARM_FEATURE_DUMMY_C15_REGS, /* RAZ/WI all of cp15 crn=15 */
ARM_FEATURE_CACHE_TEST_CLEAN, /* 926/1026 style test-and-clean ops */
ARM_FEATURE_CACHE_DIRTY_REG, /* 1136/1176 cache dirty status register */
ARM_FEATURE_CACHE_BLOCK_OPS, /* v6 optional cache block operations */
};

static inline int arm_feature(CPUARMState *env, int feature)
Expand Down
63 changes: 52 additions & 11 deletions target-arm/helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ static const ARMCPRegInfo cp_reginfo[] = {
.opc1 = CP_ANY, .opc2 = 2, .access = PL1_W, .writefn = tlbiasid_write, },
{ .name = "TLBIMVAA", .cp = 15, .crn = 8, .crm = CP_ANY,
.opc1 = CP_ANY, .opc2 = 3, .access = PL1_W, .writefn = tlbimvaa_write, },
/* Cache maintenance ops; some of this space may be overridden later. */
{ .name = "CACHEMAINT", .cp = 15, .crn = 7, .crm = CP_ANY,
.opc1 = 0, .opc2 = CP_ANY, .access = PL1_W,
.type = ARM_CP_NOP | ARM_CP_OVERRIDE },
REGINFO_SENTINEL
};

Expand Down Expand Up @@ -622,6 +626,17 @@ static int omap_wfi_write(CPUARMState *env, const ARMCPRegInfo *ri,
return 0;
}

static int omap_cachemaint_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
/* On OMAP there are registers indicating the max/min index of dcache lines
* containing a dirty line; cache flush operations have to reset these.
*/
env->cp15.c15_i_max = 0x000;
env->cp15.c15_i_min = 0xff0;
return 0;
}

static const ARMCPRegInfo omap_cp_reginfo[] = {
{ .name = "DFSR", .cp = 15, .crn = 5, .crm = CP_ANY,
.opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type = ARM_CP_OVERRIDE,
Expand Down Expand Up @@ -650,6 +665,9 @@ static const ARMCPRegInfo omap_cp_reginfo[] = {
* base address at $rn & ~0xfff and map size of 0x200 << ($rn & 0xfff),
* when MMU is off.
*/
{ .name = "OMAP_CACHEMAINT", .cp = 15, .crn = 7, .crm = CP_ANY,
.opc1 = 0, .opc2 = CP_ANY, .access = PL1_W, .type = ARM_CP_OVERRIDE,
.writefn = omap_cachemaint_write },
REGINFO_SENTINEL
};

Expand Down Expand Up @@ -685,6 +703,31 @@ static const ARMCPRegInfo dummy_c15_cp_reginfo[] = {
REGINFO_SENTINEL
};

static const ARMCPRegInfo cache_dirty_status_cp_reginfo[] = {
/* Cache status: RAZ because we have no cache so it's always clean */
{ .name = "CDSR", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 6,
.access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 },
REGINFO_SENTINEL
};

static const ARMCPRegInfo cache_block_ops_cp_reginfo[] = {
/* We never have a a block transfer operation in progress */
{ .name = "BXSR", .cp = 15, .crn = 7, .crm = 12, .opc1 = 0, .opc2 = 4,
.access = PL0_R, .type = ARM_CP_CONST, .resetvalue = 0 },
REGINFO_SENTINEL
};

static const ARMCPRegInfo cache_test_clean_cp_reginfo[] = {
/* The cache test-and-clean instructions always return (1 << 30)
* to indicate that there are no dirty cache lines.
*/
{ .name = "TC_DCACHE", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 3,
.access = PL0_R, .type = ARM_CP_CONST, .resetvalue = (1 << 30) },
{ .name = "TCI_DCACHE", .cp = 15, .crn = 7, .crm = 14, .opc1 = 0, .opc2 = 3,
.access = PL0_R, .type = ARM_CP_CONST, .resetvalue = (1 << 30) },
REGINFO_SENTINEL
};

void register_cp_regs_for_features(ARMCPU *cpu)
{
/* Register all the coprocessor registers based on feature bits */
Expand Down Expand Up @@ -738,6 +781,15 @@ void register_cp_regs_for_features(ARMCPU *cpu)
if (arm_feature(env, ARM_FEATURE_VAPA)) {
define_arm_cp_regs(cpu, vapa_cp_reginfo);
}
if (arm_feature(env, ARM_FEATURE_CACHE_TEST_CLEAN)) {
define_arm_cp_regs(cpu, cache_test_clean_cp_reginfo);
}
if (arm_feature(env, ARM_FEATURE_CACHE_DIRTY_REG)) {
define_arm_cp_regs(cpu, cache_dirty_status_cp_reginfo);
}
if (arm_feature(env, ARM_FEATURE_CACHE_BLOCK_OPS)) {
define_arm_cp_regs(cpu, cache_block_ops_cp_reginfo);
}
if (arm_feature(env, ARM_FEATURE_OMAPCP)) {
define_arm_cp_regs(cpu, omap_cp_reginfo);
}
Expand Down Expand Up @@ -1896,13 +1948,6 @@ void HELPER(set_cp15)(CPUARMState *env, uint32_t insn, uint32_t val)
}
}
break;
case 7: /* Cache control. */
env->cp15.c15_i_max = 0x000;
env->cp15.c15_i_min = 0xff0;
if (op1 != 0) {
goto bad_reg;
}
break;
case 9:
if (arm_feature(env, ARM_FEATURE_OMAPCP))
break;
Expand Down Expand Up @@ -2108,10 +2153,6 @@ uint32_t HELPER(get_cp15)(CPUARMState *env, uint32_t insn)
goto bad_reg;
}
}
case 7: /* Cache control. */
/* FIXME: Should only clear Z flag if destination is r15. */
env->ZF = 0;
return 0;
case 9:
switch (crm) {
case 0: /* Cache lockdown */
Expand Down

0 comments on commit c480421

Please sign in to comment.