mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-03-28 15:46:52 +00:00
target/arm: Send interrupts on PMU counter overflow
Whenever we notice that a counter overflow has occurred, send an interrupt. This is made more reliable with the addition of a timer in a follow-on commit. Backports commit f4efb4b2a17528837cb445f9bdfaef8df4a5acf7 from qemu
This commit is contained in:
parent
edfb13f8eb
commit
0dd5bf84fc
|
@ -843,6 +843,7 @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
|
|||
/* Definitions for the PMU registers */
|
||||
#define PMCRN_MASK 0xf800
|
||||
#define PMCRN_SHIFT 11
|
||||
#define PMCRLC 0x40
|
||||
#define PMCRDP 0x10
|
||||
#define PMCRD 0x8
|
||||
#define PMCRC 0x4
|
||||
|
@ -1155,6 +1156,14 @@ static bool pmu_counter_enabled(CPUARMState *env, uint8_t counter)
|
|||
return enabled && !prohibited && !filtered;
|
||||
}
|
||||
|
||||
static void pmu_update_irq(CPUARMState *env)
|
||||
{
|
||||
/* Unicorn: Commented out
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
qemu_set_irq(cpu->pmu_interrupt, (env->cp15.c9_pmcr & PMCRE) &&
|
||||
(env->cp15.c9_pminten & env->cp15.c9_pmovsr));*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure c15_ccnt is the guest-visible count so that operations such as
|
||||
* enabling/disabling the counter or filtering, modifying the count itself,
|
||||
|
@ -1172,7 +1181,16 @@ void pmccntr_op_start(CPUARMState *env)
|
|||
eff_cycles /= 64;
|
||||
}
|
||||
|
||||
env->cp15.c15_ccnt = eff_cycles - env->cp15.c15_ccnt_delta;
|
||||
uint64_t new_pmccntr = eff_cycles - env->cp15.c15_ccnt_delta;
|
||||
|
||||
uint64_t overflow_mask = env->cp15.c9_pmcr & PMCRLC ? \
|
||||
1ull << 63 : 1ull << 31;
|
||||
if (env->cp15.c15_ccnt & ~new_pmccntr & overflow_mask) {
|
||||
env->cp15.c9_pmovsr |= (1 << 31);
|
||||
pmu_update_irq(env);
|
||||
}
|
||||
|
||||
env->cp15.c15_ccnt = new_pmccntr;
|
||||
}
|
||||
env->cp15.c15_ccnt_delta = cycles;
|
||||
}
|
||||
|
@ -1207,8 +1225,13 @@ static void pmevcntr_op_start(CPUARMState *env, uint8_t counter)
|
|||
}
|
||||
|
||||
if (pmu_counter_enabled(env, counter)) {
|
||||
env->cp15.c14_pmevcntr[counter] =
|
||||
count - env->cp15.c14_pmevcntr_delta[counter];
|
||||
uint32_t new_pmevcntr = count - env->cp15.c14_pmevcntr_delta[counter];
|
||||
|
||||
if (env->cp15.c14_pmevcntr[counter] & ~new_pmevcntr & INT32_MIN) {
|
||||
env->cp15.c9_pmovsr |= (1 << counter);
|
||||
pmu_update_irq(env);
|
||||
}
|
||||
env->cp15.c14_pmevcntr[counter] = new_pmevcntr;
|
||||
}
|
||||
env->cp15.c14_pmevcntr_delta[counter] = count;
|
||||
}
|
||||
|
@ -1285,7 +1308,20 @@ static void pmswinc_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
/* counter is SW_INCR */
|
||||
(env->cp15.c14_pmevtyper[i] & PMXEVTYPER_EVTCOUNT) == 0x0) {
|
||||
pmevcntr_op_start(env, i);
|
||||
env->cp15.c14_pmevcntr[i]++;
|
||||
|
||||
/*
|
||||
* Detect if this write causes an overflow since we can't predict
|
||||
* PMSWINC overflows like we can for other events
|
||||
*/
|
||||
uint32_t new_pmswinc = env->cp15.c14_pmevcntr[i] + 1;
|
||||
|
||||
if (env->cp15.c14_pmevcntr[i] & ~new_pmswinc & INT32_MIN) {
|
||||
env->cp15.c9_pmovsr |= (1 << i);
|
||||
pmu_update_irq(env);
|
||||
}
|
||||
|
||||
env->cp15.c14_pmevcntr[i] = new_pmswinc;
|
||||
|
||||
pmevcntr_op_finish(env, i);
|
||||
}
|
||||
}
|
||||
|
@ -1370,6 +1406,7 @@ static void pmovsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
{
|
||||
value &= pmu_counter_mask(env);
|
||||
env->cp15.c9_pmovsr &= ~value;
|
||||
pmu_update_irq(env);
|
||||
}
|
||||
|
||||
static void pmovsset_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
|
@ -1377,6 +1414,7 @@ static void pmovsset_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
{
|
||||
value &= pmu_counter_mask(env);
|
||||
env->cp15.c9_pmovsr |= value;
|
||||
pmu_update_irq(env);
|
||||
}
|
||||
|
||||
static void pmevtyper_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
|
@ -1564,6 +1602,7 @@ static void pmintenset_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
/* We have no event counters so only the C bit can be changed */
|
||||
value &= pmu_counter_mask(env);
|
||||
env->cp15.c9_pminten |= value;
|
||||
pmu_update_irq(env);
|
||||
}
|
||||
|
||||
static void pmintenclr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
|
@ -1571,6 +1610,7 @@ static void pmintenclr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
{
|
||||
value &= pmu_counter_mask(env);
|
||||
env->cp15.c9_pminten &= ~value;
|
||||
pmu_update_irq(env);
|
||||
}
|
||||
|
||||
static void vbar_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
|
@ -1698,16 +1738,16 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
|
|||
ARM_CP_ALIAS, PL0_RW, 0, NULL, 0, offsetof(CPUARMState, cp15.c9_pmcnten), {0, 0},
|
||||
pmreg_access, NULL, pmcntenclr_write },
|
||||
{ "PMOVSR", 15,9,12, 0,0,3, 0,
|
||||
0, PL0_RW, 0, NULL, 0, offsetoflow32(CPUARMState, cp15.c9_pmovsr), {0, 0},
|
||||
ARM_CP_IO, PL0_RW, 0, NULL, 0, offsetoflow32(CPUARMState, cp15.c9_pmovsr), {0, 0},
|
||||
pmreg_access, NULL, pmovsr_write, NULL, raw_write },
|
||||
{ "PMOVSCLR_EL0", 0,9,12, 3,3,3, ARM_CP_STATE_AA64, ARM_CP_ALIAS,
|
||||
{ "PMOVSCLR_EL0", 0,9,12, 3,3,3, ARM_CP_STATE_AA64, ARM_CP_ALIAS | ARM_CP_IO,
|
||||
PL0_RW, 0, NULL, 0, offsetof(CPUARMState, cp15.c9_pmovsr), {0, 0},
|
||||
pmreg_access, NULL, pmovsr_write, NULL, raw_write },
|
||||
{ "PMSWINC", 15,9,12, 0,0,4, 0,
|
||||
ARM_CP_NO_RAW, PL0_W, 0, NULL, 0, 0, {0, 0},
|
||||
ARM_CP_NO_RAW | ARM_CP_IO, PL0_W, 0, NULL, 0, 0, {0, 0},
|
||||
pmreg_access_swinc, NULL, pmswinc_write },
|
||||
{ "PMSWINC_EL0", 0,9,12, 3,3,4, ARM_CP_STATE_AA64,
|
||||
ARM_CP_NO_RAW, PL0_W, 0, NULL, 0, 0, {0, 0},
|
||||
ARM_CP_NO_RAW | ARM_CP_IO, PL0_W, 0, NULL, 0, 0, {0, 0},
|
||||
pmreg_access_swinc, NULL, pmswinc_write },
|
||||
{ "PMSELR", 15,9,12, 0,0,5, 0, ARM_CP_ALIAS,
|
||||
PL0_RW, 0, NULL, 0, offsetoflow32(CPUARMState, cp15.c9_pmselr), {0, 0},
|
||||
|
@ -1855,10 +1895,10 @@ static const ARMCPRegInfo v7mp_cp_reginfo[] = {
|
|||
|
||||
static const ARMCPRegInfo pmovsset_cp_reginfo[] = {
|
||||
/* PMOVSSET is not implemented in v7 before v7ve */
|
||||
{ "PMOVSSET", 15,9,14, 0,0,3, 0, ARM_CP_ALIAS, PL0_RW, 0,
|
||||
{ "PMOVSSET", 15,9,14, 0,0,3, 0, ARM_CP_ALIAS | ARM_CP_IO, PL0_RW, 0,
|
||||
NULL, 0, offsetoflow32(CPUARMState, cp15.c9_pmovsr), {0, 0},
|
||||
pmreg_access, NULL, pmovsset_write, NULL, raw_write },
|
||||
{ "PMOVSSET_EL0", 0,9,14, 3,3,3, ARM_CP_STATE_AA64, ARM_CP_ALIAS, PL0_RW, 0,
|
||||
{ "PMOVSSET_EL0", 0,9,14, 3,3,3, ARM_CP_STATE_AA64, ARM_CP_ALIAS | ARM_CP_IO, PL0_RW, 0,
|
||||
NULL, 0, offsetof(CPUARMState, cp15.c9_pmovsr), {0, 0},
|
||||
pmreg_access, NULL, pmovsset_write, NULL, raw_write },
|
||||
REGINFO_SENTINEL
|
||||
|
|
Loading…
Reference in a new issue