From: Brian Cain <bc...@quicinc.com> Signed-off-by: Brian Cain <brian.c...@oss.qualcomm.com> --- target/hexagon/cpu_helper.h | 1 + target/hexagon/cpu_helper.c | 40 +++++++++++++++++++++++++++++++++++++ target/hexagon/op_helper.c | 6 +++++- 3 files changed, 46 insertions(+), 1 deletion(-)
diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h index 95a0cc0788..e8d89d8526 100644 --- a/target/hexagon/cpu_helper.h +++ b/target/hexagon/cpu_helper.h @@ -20,6 +20,7 @@ void clear_wait_mode(CPUHexagonState *env); void hexagon_ssr_set_cause(CPUHexagonState *env, uint32_t cause); void hexagon_start_threads(CPUHexagonState *env, uint32_t mask); void hexagon_stop_thread(CPUHexagonState *env); +void hexagon_wait_thread(CPUHexagonState *env, target_ulong PC); static inline void arch_set_thread_reg(CPUHexagonState *env, uint32_t reg, uint32_t val) diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c index 3e2364a7b0..e64568b9fc 100644 --- a/target/hexagon/cpu_helper.c +++ b/target/hexagon/cpu_helper.c @@ -71,6 +71,46 @@ void hexagon_set_sys_pcycle_count(CPUHexagonState *env, uint64_t cycles) g_assert_not_reached(); } +static void set_wait_mode(CPUHexagonState *env) +{ + g_assert(bql_locked()); + + const uint32_t modectl = arch_get_system_reg(env, HEX_SREG_MODECTL); + uint32_t thread_wait_mask = GET_FIELD(MODECTL_W, modectl); + thread_wait_mask |= 0x1 << env->threadId; + SET_SYSTEM_FIELD(env, HEX_SREG_MODECTL, MODECTL_W, thread_wait_mask); +} + +void hexagon_wait_thread(CPUHexagonState *env, target_ulong PC) +{ + g_assert(bql_locked()); + + if (qemu_loglevel_mask(LOG_GUEST_ERROR) && + (env->k0_lock_state != HEX_LOCK_UNLOCKED || + env->tlb_lock_state != HEX_LOCK_UNLOCKED)) { + qemu_log("WARNING: executing wait() with acquired lock" + "may lead to deadlock\n"); + } + g_assert(get_exe_mode(env) != HEX_EXE_MODE_WAIT); + + CPUState *cs = env_cpu(env); + /* + * The addtion of cpu_has_work is borrowed from arm's wfi helper + * and is critical for our stability + */ + if ((cs->exception_index != HEX_EVENT_NONE) || + (cpu_has_work(cs))) { + qemu_log_mask(CPU_LOG_INT, + "%s: thread %d skipping WAIT mode, have some work\n", + __func__, env->threadId); + return; + } + set_wait_mode(env); + env->wait_next_pc = PC + 4; + + cpu_interrupt(cs, CPU_INTERRUPT_HALT); +} + static MMVector VRegs[VECTOR_UNIT_MAX][NUM_VREGS]; static MMQReg QRegs[VECTOR_UNIT_MAX][NUM_QREGS]; diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 83088cfaa3..03bed11f6e 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -1458,7 +1458,11 @@ void HELPER(stop)(CPUHexagonState *env) void HELPER(wait)(CPUHexagonState *env, target_ulong PC) { - g_assert_not_reached(); + BQL_LOCK_GUARD(); + + if (!fIN_DEBUG_MODE(env->threadId)) { + hexagon_wait_thread(env, PC); + } } void HELPER(resume)(CPUHexagonState *env, uint32_t mask) -- 2.34.1