target-arm: Implements the ARM PMCCNTR register
This patch implements the ARM PMCCNTR register including the disable and reset components of the PMCR register. Signed-off-by: Alistair Francis <alistair.francis@xilinx.com> Message-id: bbf405e1feaf352cf39d5db402c9efcbd0f57c78.1393459802.git.alistair.francis@xilinx.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
af5199347a
commit
7c2cb42b50
@ -222,6 +222,10 @@ typedef struct CPUARMState {
|
||||
uint64_t dbgbcr[16]; /* breakpoint control registers */
|
||||
uint64_t dbgwvr[16]; /* watchpoint value registers */
|
||||
uint64_t dbgwcr[16]; /* watchpoint control registers */
|
||||
/* If the counter is enabled, this stores the last time the counter
|
||||
* was reset. Otherwise it stores the counter value
|
||||
*/
|
||||
uint32_t c15_ccnt;
|
||||
} cp15;
|
||||
|
||||
struct {
|
||||
|
@ -13,6 +13,11 @@ static inline int get_phys_addr(CPUARMState *env, uint32_t address,
|
||||
int access_type, int is_user,
|
||||
hwaddr *phys_ptr, int *prot,
|
||||
target_ulong *page_size);
|
||||
|
||||
/* Definitions for the PMCCNTR and PMCR registers */
|
||||
#define PMCRD 0x8
|
||||
#define PMCRC 0x4
|
||||
#define PMCRE 0x1
|
||||
#endif
|
||||
|
||||
static int vfp_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg)
|
||||
@ -478,14 +483,85 @@ static CPAccessResult pmreg_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
return CP_ACCESS_OK;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
static void pmcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
/* Don't computer the number of ticks in user mode */
|
||||
uint32_t temp_ticks;
|
||||
|
||||
temp_ticks = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) *
|
||||
get_ticks_per_sec() / 1000000;
|
||||
|
||||
if (env->cp15.c9_pmcr & PMCRE) {
|
||||
/* If the counter is enabled */
|
||||
if (env->cp15.c9_pmcr & PMCRD) {
|
||||
/* Increment once every 64 processor clock cycles */
|
||||
env->cp15.c15_ccnt = (temp_ticks/64) - env->cp15.c15_ccnt;
|
||||
} else {
|
||||
env->cp15.c15_ccnt = temp_ticks - env->cp15.c15_ccnt;
|
||||
}
|
||||
}
|
||||
|
||||
if (value & PMCRC) {
|
||||
/* The counter has been reset */
|
||||
env->cp15.c15_ccnt = 0;
|
||||
}
|
||||
|
||||
/* only the DP, X, D and E bits are writable */
|
||||
env->cp15.c9_pmcr &= ~0x39;
|
||||
env->cp15.c9_pmcr |= (value & 0x39);
|
||||
|
||||
if (env->cp15.c9_pmcr & PMCRE) {
|
||||
if (env->cp15.c9_pmcr & PMCRD) {
|
||||
/* Increment once every 64 processor clock cycles */
|
||||
temp_ticks /= 64;
|
||||
}
|
||||
env->cp15.c15_ccnt = temp_ticks - env->cp15.c15_ccnt;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t pmccntr_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
uint32_t total_ticks;
|
||||
|
||||
if (!(env->cp15.c9_pmcr & PMCRE)) {
|
||||
/* Counter is disabled, do not change value */
|
||||
return env->cp15.c15_ccnt;
|
||||
}
|
||||
|
||||
total_ticks = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) *
|
||||
get_ticks_per_sec() / 1000000;
|
||||
|
||||
if (env->cp15.c9_pmcr & PMCRD) {
|
||||
/* Increment once every 64 processor clock cycles */
|
||||
total_ticks /= 64;
|
||||
}
|
||||
return total_ticks - env->cp15.c15_ccnt;
|
||||
}
|
||||
|
||||
static void pmccntr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
uint32_t total_ticks;
|
||||
|
||||
if (!(env->cp15.c9_pmcr & PMCRE)) {
|
||||
/* Counter is disabled, set the absolute value */
|
||||
env->cp15.c15_ccnt = value;
|
||||
return;
|
||||
}
|
||||
|
||||
total_ticks = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) *
|
||||
get_ticks_per_sec() / 1000000;
|
||||
|
||||
if (env->cp15.c9_pmcr & PMCRD) {
|
||||
/* Increment once every 64 processor clock cycles */
|
||||
total_ticks /= 64;
|
||||
}
|
||||
env->cp15.c15_ccnt = total_ticks - value;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void pmcntenset_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
@ -604,10 +680,12 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
|
||||
{ .name = "PMSELR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 5,
|
||||
.access = PL0_RW, .type = ARM_CP_CONST, .resetvalue = 0,
|
||||
.accessfn = pmreg_access },
|
||||
/* Unimplemented, RAZ/WI. */
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
{ .name = "PMCCNTR", .cp = 15, .crn = 9, .crm = 13, .opc1 = 0, .opc2 = 0,
|
||||
.access = PL0_RW, .type = ARM_CP_CONST, .resetvalue = 0,
|
||||
.access = PL0_RW, .resetvalue = 0, .type = ARM_CP_IO,
|
||||
.readfn = pmccntr_read, .writefn = pmccntr_write,
|
||||
.accessfn = pmreg_access },
|
||||
#endif
|
||||
{ .name = "PMXEVTYPER", .cp = 15, .crn = 9, .crm = 13, .opc1 = 0, .opc2 = 1,
|
||||
.access = PL0_RW,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c9_pmxevtyper),
|
||||
@ -1873,8 +1951,10 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||
}
|
||||
if (arm_feature(env, ARM_FEATURE_V7)) {
|
||||
/* v7 performance monitor control register: same implementor
|
||||
* field as main ID register, and we implement no event counters.
|
||||
* field as main ID register, and we implement only the cycle
|
||||
* count register.
|
||||
*/
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
ARMCPRegInfo pmcr = {
|
||||
.name = "PMCR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 0,
|
||||
.access = PL0_RW, .resetvalue = cpu->midr & 0xff000000,
|
||||
@ -1882,12 +1962,13 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||
.accessfn = pmreg_access, .writefn = pmcr_write,
|
||||
.raw_writefn = raw_write,
|
||||
};
|
||||
define_one_arm_cp_reg(cpu, &pmcr);
|
||||
#endif
|
||||
ARMCPRegInfo clidr = {
|
||||
.name = "CLIDR", .state = ARM_CP_STATE_BOTH,
|
||||
.opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 1,
|
||||
.access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->clidr
|
||||
};
|
||||
define_one_arm_cp_reg(cpu, &pmcr);
|
||||
define_one_arm_cp_reg(cpu, &clidr);
|
||||
define_arm_cp_regs(cpu, v7_cp_reginfo);
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user