@@ -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"
@@ -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,
@@ -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)
@@ -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;
@@ -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
@@ -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)