From: Brian Cain <bc...@quicinc.com> Signed-off-by: Brian Cain <brian.c...@oss.qualcomm.com> --- target/hexagon/cpu.h | 3 ++ target/hexagon/cpu_bits.h | 1 + target/hexagon/cpu_helper.h | 3 ++ target/hexagon/cpu.c | 14 +++++- target/hexagon/cpu_helper.c | 94 +++++++++++++++++++++++++++++++++++++ target/hexagon/op_helper.c | 4 +- 6 files changed, 116 insertions(+), 3 deletions(-)
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index 894219fd20..1549c4f1f0 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -41,6 +41,7 @@ typedef struct CPUHexagonTLBContext CPUHexagonTLBContext; #define REG_WRITES_MAX 32 #define PRED_WRITES_MAX 5 /* 4 insns + endloop */ #define VSTORES_MAX 2 +#define VECTOR_UNIT_MAX 8 #ifndef CONFIG_USER_ONLY #define CPU_INTERRUPT_SWI CPU_INTERRUPT_TGT_INT_0 @@ -178,6 +179,7 @@ struct ArchCPU { #ifndef CONFIG_USER_ONLY uint32_t num_tlbs; uint32_t l2vic_base_addr; + uint32_t hvx_contexts; #endif }; @@ -194,6 +196,7 @@ G_NORETURN void hexagon_raise_exception_err(CPUHexagonState *env, uint32_t hexagon_greg_read(CPUHexagonState *env, uint32_t reg); uint32_t hexagon_sreg_read(CPUHexagonState *env, uint32_t reg); void hexagon_gdb_sreg_write(CPUHexagonState *env, uint32_t reg, uint32_t val); +void hexagon_cpu_soft_reset(CPUHexagonState *env); #endif #include "exec/cpu-all.h" diff --git a/target/hexagon/cpu_bits.h b/target/hexagon/cpu_bits.h index b559a7ba88..610094a759 100644 --- a/target/hexagon/cpu_bits.h +++ b/target/hexagon/cpu_bits.h @@ -52,6 +52,7 @@ enum hex_event { enum hex_cause { HEX_CAUSE_NONE = -1, + HEX_CAUSE_RESET = 0x000, HEX_CAUSE_TRAP0 = 0x172, HEX_CAUSE_FETCH_NO_UPAGE = 0x012, HEX_CAUSE_INVALID_PACKET = 0x015, diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h index 6f0c6697ad..95a0cc0788 100644 --- a/target/hexagon/cpu_helper.h +++ b/target/hexagon/cpu_helper.h @@ -17,6 +17,9 @@ void hexagon_set_sys_pcycle_count_high(CPUHexagonState *env, uint32_t); void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old); int get_exe_mode(CPUHexagonState *env); 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); static inline void arch_set_thread_reg(CPUHexagonState *env, uint32_t reg, uint32_t val) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index cb56b929cf..84a96a194b 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -32,6 +32,7 @@ #ifndef CONFIG_USER_ONLY #include "sys_macros.h" +#include "qemu/main-loop.h" #endif static void hexagon_v66_cpu_init(Object *obj) { } @@ -61,6 +62,7 @@ static const Property hexagon_cpu_properties[] = { DEFINE_PROP_UINT32("jtlb-entries", HexagonCPU, num_tlbs, MAX_TLB_ENTRIES), DEFINE_PROP_UINT32("l2vic-base-addr", HexagonCPU, l2vic_base_addr, 0xffffffffULL), + DEFINE_PROP_UINT32("hvx-contexts", HexagonCPU, hvx_contexts, 0), #endif DEFINE_PROP_BOOL("lldb-compat", HexagonCPU, lldb_compat, false), DEFINE_PROP_UNSIGNED("lldb-stack-adjust", HexagonCPU, lldb_stack_adjust, 0, @@ -295,9 +297,18 @@ static void mmu_reset(CPUHexagonState *env) memset(env->hex_tlb, 0, sizeof(*env->hex_tlb)); } } + +void hexagon_cpu_soft_reset(CPUHexagonState *env) +{ + BQL_LOCK_GUARD(); + arch_set_system_reg(env, HEX_SREG_SSR, 0); + hexagon_ssr_set_cause(env, HEX_CAUSE_RESET); + + target_ulong evb = arch_get_system_reg(env, HEX_SREG_EVB); + arch_set_thread_reg(env, HEX_REG_PC, evb); +} #endif - static void hexagon_cpu_reset_hold(Object *obj, ResetType type) { CPUState *cs = CPU(obj); @@ -327,6 +338,7 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type) } mmu_reset(env); arch_set_system_reg(env, HEX_SREG_HTID, cs->cpu_index); + hexagon_cpu_soft_reset(env); memset(env->t_sreg, 0, sizeof(target_ulong) * NUM_SREGS); memset(env->greg, 0, sizeof(target_ulong) * NUM_GREGS); env->threadId = cs->cpu_index; diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c index 9373e491d6..e151c6335a 100644 --- a/target/hexagon/cpu_helper.c +++ b/target/hexagon/cpu_helper.c @@ -84,8 +84,102 @@ void clear_wait_mode(CPUHexagonState *env) SET_SYSTEM_FIELD(env, HEX_SREG_MODECTL, MODECTL_W, thread_wait_mask); } +void hexagon_ssr_set_cause(CPUHexagonState *env, uint32_t cause) +{ + g_assert(bql_locked()); + + const uint32_t old = arch_get_system_reg(env, HEX_SREG_SSR); + SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_EX, 1); + SET_SYSTEM_FIELD(env, HEX_SREG_SSR, SSR_CAUSE, cause); + const uint32_t new = arch_get_system_reg(env, HEX_SREG_SSR); + + hexagon_modify_ssr(env, new, old); +} + + int get_exe_mode(CPUHexagonState *env) { g_assert_not_reached(); } + +static void set_enable_mask(CPUHexagonState *env) +{ + g_assert(bql_locked()); + + const uint32_t modectl = arch_get_system_reg(env, HEX_SREG_MODECTL); + uint32_t thread_enabled_mask = GET_FIELD(MODECTL_E, modectl); + thread_enabled_mask |= 0x1 << env->threadId; + SET_SYSTEM_FIELD(env, HEX_SREG_MODECTL, MODECTL_E, thread_enabled_mask); +} + +static uint32_t clear_enable_mask(CPUHexagonState *env) +{ + g_assert(bql_locked()); + + const uint32_t modectl = arch_get_system_reg(env, HEX_SREG_MODECTL); + uint32_t thread_enabled_mask = GET_FIELD(MODECTL_E, modectl); + thread_enabled_mask &= ~(0x1 << env->threadId); + SET_SYSTEM_FIELD(env, HEX_SREG_MODECTL, MODECTL_E, thread_enabled_mask); + return thread_enabled_mask; +} +static void do_start_thread(CPUState *cs, run_on_cpu_data tbd) +{ + BQL_LOCK_GUARD(); + + CPUHexagonState *env = cpu_env(cs); + + hexagon_cpu_soft_reset(env); + + set_enable_mask(env); + + cs->halted = 0; + cs->exception_index = HEX_EVENT_NONE; + cpu_resume(cs); +} + +void hexagon_start_threads(CPUHexagonState *current_env, uint32_t mask) +{ + CPUState *cs; + CPU_FOREACH(cs) { + CPUHexagonState *env = cpu_env(cs); + if (!(mask & (0x1 << env->threadId))) { + continue; + } + + if (current_env->threadId != env->threadId) { + async_safe_run_on_cpu(cs, do_start_thread, RUN_ON_CPU_NULL); + } + } +} + +/* + * When we have all threads stopped, the return + * value to the shell is register 2 from thread 0. + */ +static target_ulong get_thread0_r2(void) +{ + CPUState *cs; + CPU_FOREACH(cs) { + CPUHexagonState *thread = cpu_env(cs); + if (thread->threadId == 0) { + return thread->gpr[2]; + } + } + g_assert_not_reached(); +} + +void hexagon_stop_thread(CPUHexagonState *env) + +{ + BQL_LOCK_GUARD(); + + uint32_t thread_enabled_mask = clear_enable_mask(env); + CPUState *cs = env_cpu(env); + cpu_interrupt(cs, CPU_INTERRUPT_HALT); + if (!thread_enabled_mask) { + /* All threads are stopped, exit */ + exit(get_thread0_r2()); + } +} + #endif diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index ded6c80d62..9f79b1a20c 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -1448,12 +1448,12 @@ uint32_t HELPER(iassignr)(CPUHexagonState *env, uint32_t src) void HELPER(start)(CPUHexagonState *env, uint32_t imask) { - g_assert_not_reached(); + hexagon_start_threads(env, imask); } void HELPER(stop)(CPUHexagonState *env) { - g_assert_not_reached(); + hexagon_stop_thread(env); } void HELPER(wait)(CPUHexagonState *env, target_ulong PC) -- 2.34.1