Now we can calculate when the next event stream event is we can re-use the wfxt_timer and configure it to fire as we enter a WFE that is going to sleep. Reverse the M-profile logic so we can enter a sleep state in both profiles.
Signed-off-by: Alex Bennée <[email protected]> --- target/arm/cpu.h | 2 ++ target/arm/cpu.c | 5 +++++ target/arm/tcg/op_helper.c | 37 ++++++++++++++++++------------------- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 9c25b60ae83..6a7d92d73db 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -967,6 +967,8 @@ struct ArchCPU { QEMUTimer *pmu_timer; /* Timer used for WFxT timeouts */ QEMUTimer *wfxt_timer; + /* Are we in a WFE */ + bool waiting_for_event; /* GPIO outputs for generic timer */ qemu_irq gt_timer_outputs[NUM_GTIMERS]; diff --git a/target/arm/cpu.c b/target/arm/cpu.c index d51599dfdab..a0569f74cd5 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -780,6 +780,11 @@ static void arm_wfxt_timer_cb(void *opaque) ARMCPU *cpu = opaque; CPUState *cs = CPU(cpu); + if (cpu->waiting_for_event) { + CPUARMState *env = &cpu->env; + env->event_register.as_bool = true; + } + /* * We expect the CPU to be halted; this will cause arm_cpu_is_work() * to return true (so we will come out of halt even with no other diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c index d513045269c..fbe160ab70a 100644 --- a/target/arm/tcg/op_helper.c +++ b/target/arm/tcg/op_helper.c @@ -494,31 +494,30 @@ void HELPER(wfe)(CPUARMState *env) #else /* * WFE (Wait For Event) is a hint instruction. - * For Cortex-M (M-profile), we implement the strict architectural behavior: + * * 1. Check the Event Register (set by SEV or SEVONPEND). * 2. If set, clear it and continue (consume the event). */ - if (arm_feature(env, ARM_FEATURE_M)) { - CPUState *cs = env_cpu(env); + CPUState *cs = env_cpu(env); + ARMCPU *cpu = ARM_CPU(cs); - if (env->event_register.as_bool) { - env->event_register.as_bool = false; - return; - } + if (env->event_register.as_bool) { + env->event_register.as_bool = false; + return; + } - cs->exception_index = EXCP_HLT; - cs->halted = 1; - cpu_loop_exit(cs); - } else { - /* - * For A-profile and others, we rely on the existing "yield" behavior. - * Don't actually halt the CPU, just yield back to top - * level loop. This is not going into a "low power state" - * (ie halting until some event occurs), so we never take - * a configurable trap to a different exception level - */ - HELPER(yield)(env); + /* For A-profile we also can be woken by the event stream */ + if (arm_feature(env, ARM_FEATURE_AARCH64) && cpu->wfxt_timer) { + int64_t next_event = gt_calc_next_event_stream(env); + if (next_event > 0) { + cpu->waiting_for_event = true; + timer_mod(cpu->wfxt_timer, next_event); + } } + + cs->exception_index = EXCP_HLT; + cs->halted = 1; + cpu_loop_exit(cs); #endif } -- 2.47.3
