Commit 1099acc19a for qemu.org
commit 1099acc19a9973dabb7079242efe38eec6ab0ca4
Author: Brian Cain <brian.cain@oss.qualcomm.com>
Date: Wed Sep 23 10:15:15 2026 -0700
target/hexagon: share HVX contexts among CPUs
The HVX register file belongs to an extension context, not a hardware thread.
Model each system-emulation context as a QOM device, link the contexts to
each vCPU, and use SSR:XA to select the active context.
Keep one embedded context per linux-user CPU. Carry the selected register-file
base with HVX operands so translated code can address the selected context
at run time.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
diff --git a/hw/hexagon/hex-subsys.c b/hw/hexagon/hex-subsys.c
index 4e3a418340..9818cf5887 100644
--- a/hw/hexagon/hex-subsys.c
+++ b/hw/hexagon/hex-subsys.c
@@ -9,6 +9,7 @@
#include "qapi/error.h"
#include "hw/hexagon/hex-subsys.h"
#include "hw/hexagon/hexagon_globalreg.h"
+#include "hw/hexagon/hexagon_hvx_context.h"
#include "hw/hexagon/hexagon_tlb.h"
#include "hw/intc/hex-l2vic.h"
#include "hw/timer/qct-qtimer.h"
@@ -98,6 +99,27 @@ static DeviceState *tlb_create(HexagonCommonMachineState *hms,
return tlb;
}
+/*
+ * Create the core's HVX extension contexts. There are fewer of them than
+ * there are hardware threads, and SSR:XA picks which one a thread uses, so
+ * they belong to the subsystem rather than to any one CPU.
+ */
+static void hvx_contexts_create(HexagonCommonMachineState *hms,
+ const struct hexagon_machine_config *m_cfg)
+{
+ unsigned n = m_cfg->cfgtable.ext_contexts;
+ assert(n <= HVX_CONTEXTS_MAX);
+ for (unsigned i = 0; i < n; i++) {
+ DeviceState *ctx = qdev_new(TYPE_HEXAGON_HVX_CONTEXT);
+ g_autofree char *name = g_strdup_printf("hvx-context[%u]", i);
+
+ object_property_add_child(OBJECT(hms), name, OBJECT(ctx));
+ qdev_prop_set_uint32(ctx, "index", i);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(ctx), &error_fatal);
+ }
+ hms->num_hvx_ctx = n;
+}
+
static DeviceState *cluster_create(HexagonCommonMachineState *hms)
{
DeviceState *cluster = qdev_new(TYPE_CPU_CLUSTER);
@@ -140,6 +162,7 @@ void hex_subsys_create(HexagonCommonMachineState *hms,
hms->qtimer = qtimer_create(hms, m_cfg);
hms->glob_regs = globalreg_create(hms, m_cfg, rev);
hms->tlb = tlb_create(hms, m_cfg);
+ hvx_contexts_create(hms, m_cfg);
}
void hex_subsys_add_cpu(HexagonCommonMachineState *hms, DeviceState *cpu)
@@ -151,6 +174,12 @@ void hex_subsys_add_cpu(HexagonCommonMachineState *hms, DeviceState *cpu)
&error_fatal);
object_property_set_link(OBJECT(cpu), "l2vic", OBJECT(hms->l2vic),
&error_fatal);
+ for (unsigned i = 0; i < hms->num_hvx_ctx; i++) {
+ g_autofree char *name = g_strdup_printf("hvx-context[%u]", i);
+ Object *ctx = object_resolve_path_component(OBJECT(hms), name);
+
+ object_property_set_link(OBJECT(cpu), name, ctx, &error_fatal);
+ }
}
void hex_subsys_realize_cluster(HexagonCommonMachineState *hms)
diff --git a/hw/hexagon/hexagon_hvx_context.c b/hw/hexagon/hexagon_hvx_context.c
new file mode 100644
index 0000000000..3b73498298
--- /dev/null
+++ b/hw/hexagon/hexagon_hvx_context.c
@@ -0,0 +1,84 @@
+/*
+ * Hexagon HVX Extension Context QOM Object
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/hexagon/hexagon_hvx_context.h"
+#include "hw/core/qdev-properties.h"
+#include "migration/vmstate.h"
+
+static void hexagon_hvx_context_reset_hold(Object *obj, ResetType type)
+{
+ HexagonHVXContextState *s = HEXAGON_HVX_CONTEXT(obj);
+
+ memset(&s->regs, 0, sizeof(s->regs));
+}
+
+/* gvec needs VRegs/QRegs 16-aligned within the struct. */
+QEMU_BUILD_BUG_ON(offsetof(HexagonHVXContextState, regs) % 16 != 0);
+
+static const VMStateDescription vmstate_mmvector = {
+ .name = "hexagon_mmvector",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]){
+ VMSTATE_UINT64_ARRAY(ud, MMVector, MAX_VEC_SIZE_BYTES / 8),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_mmqreg = {
+ .name = "hexagon_mmqreg",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]){
+ VMSTATE_UINT64_ARRAY(ud, MMQReg, MAX_VEC_SIZE_BYTES / 8 / 8),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_hexagon_hvx_context = {
+ .name = "hexagon_hvx_context",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]){
+ VMSTATE_STRUCT_ARRAY(regs.VRegs, HexagonHVXContextState, NUM_VREGS,
+ 1, vmstate_mmvector, MMVector),
+ VMSTATE_STRUCT_ARRAY(regs.QRegs, HexagonHVXContextState, NUM_QREGS,
+ 1, vmstate_mmqreg, MMQReg),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const Property hexagon_hvx_context_properties[] = {
+ DEFINE_PROP_UINT32("index", HexagonHVXContextState, index, 0),
+};
+
+static void hexagon_hvx_context_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ rc->phases.hold = hexagon_hvx_context_reset_hold;
+ dc->vmsd = &vmstate_hexagon_hvx_context;
+ dc->user_creatable = false;
+ device_class_set_props(dc, hexagon_hvx_context_properties);
+}
+
+static const TypeInfo hexagon_hvx_context_info = {
+ .name = TYPE_HEXAGON_HVX_CONTEXT,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(HexagonHVXContextState),
+ .instance_align = __alignof(HexagonHVXContextState),
+ .class_init = hexagon_hvx_context_class_init,
+};
+
+static void hexagon_hvx_context_register_types(void)
+{
+ type_register_static(&hexagon_hvx_context_info);
+}
+
+type_init(hexagon_hvx_context_register_types)
diff --git a/hw/hexagon/meson.build b/hw/hexagon/meson.build
index 720a5d54dc..c4b257dfa2 100644
--- a/hw/hexagon/meson.build
+++ b/hw/hexagon/meson.build
@@ -1,6 +1,7 @@
hexagon_ss = ss.source_set()
hexagon_ss.add(files('hexagon_tlb.c'))
hexagon_ss.add(files('hexagon_globalreg.c'))
+hexagon_ss.add(files('hexagon_hvx_context.c'))
hexagon_ss.add(when: 'CONFIG_HEX_DSP', if_true: files('hex-subsys.c'))
hexagon_ss.add(when: 'CONFIG_HEX_DSP', if_true: files('hexagon_dsp.c'))
hexagon_ss.add(when: 'CONFIG_HEX_VIRT', if_true: files('virt.c'))
diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h
index 62398eeb35..9b5d33ffc3 100644
--- a/include/hw/hexagon/hexagon.h
+++ b/include/hw/hexagon/hexagon.h
@@ -173,6 +173,7 @@ struct HexagonCommonMachineState {
DeviceState *qtimer;
DeviceState *glob_regs;
DeviceState *tlb;
+ unsigned num_hvx_ctx;
};
#endif
diff --git a/include/hw/hexagon/hexagon_hvx_context.h b/include/hw/hexagon/hexagon_hvx_context.h
new file mode 100644
index 0000000000..ab85816a7f
--- /dev/null
+++ b/include/hw/hexagon/hexagon_hvx_context.h
@@ -0,0 +1,27 @@
+/*
+ * Hexagon HVX Extension Context QOM Object
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HEXAGON_HVX_CONTEXT_H
+#define HEXAGON_HVX_CONTEXT_H
+
+#include "hw/core/sysbus.h"
+#include "qom/object.h"
+#include "target/hexagon/cpu.h"
+
+#define TYPE_HEXAGON_HVX_CONTEXT "hexagon-hvx-context"
+OBJECT_DECLARE_SIMPLE_TYPE(HexagonHVXContextState, HEXAGON_HVX_CONTEXT)
+
+struct HexagonHVXContextState {
+ SysBusDevice parent_obj;
+
+ /* Physical context number, as SSR:XA maps to it. */
+ uint32_t index;
+
+ HexagonHVXContext regs;
+};
+
+#endif /* HEXAGON_HVX_CONTEXT_H */
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 7298cd27a0..912bae7b6c 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -43,6 +43,7 @@
#include "exec/page-protection.h"
#include "exec/target_page.h"
#include "hw/hexagon/hexagon_globalreg.h"
+#include "hw/hexagon/hexagon_hvx_context.h"
#endif
static ObjectClass *hexagon_cpu_class_by_name(const char *cpu_model)
@@ -328,6 +329,9 @@ static TCGTBCPUState hexagon_get_tb_cpu_state(CPUState *cs)
CPUHexagonState *env = cpu_env(cs);
vaddr pc = env->gpr[HEX_REG_PC];
uint32_t hex_flags = 0;
+#ifndef CONFIG_USER_ONLY
+ HexagonCPU *cpu;
+#endif
if (pc == env->gpr[HEX_REG_SA0]) {
hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, IS_TIGHT_LOOP, 1);
@@ -338,10 +342,12 @@ static TCGTBCPUState hexagon_get_tb_cpu_state(CPUState *cs)
}
#ifndef CONFIG_USER_ONLY
+ cpu = env_archcpu(env);
hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX,
cpu_mmu_index(env_cpu(env), false));
hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, PCYCLE_ENABLED, 1);
hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, HVX_COPROC_ENABLED,
+ cpu->hvx_ctx[0] &&
GET_SSR_FIELD(SSR_XE, env->t_sreg[HEX_SREG_SSR]));
#else
hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX, MMU_USER_IDX);
@@ -449,6 +455,7 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType type)
env->t_sreg[HEX_SREG_HTID] = cpu->htid;
env->threadId = cpu->htid;
hexagon_cpu_soft_reset(env);
+ hexagon_hvx_select_context(env, env->t_sreg[HEX_SREG_SSR]);
env->cause_code = HEX_EVENT_NONE;
env->gpr[HEX_REG_PC] = cpu->boot_addr;
#endif
@@ -554,7 +561,16 @@ static void hexagon_cpu_init(Object *obj)
{
#ifndef CONFIG_USER_ONLY
HexagonCPU *cpu = HEXAGON_CPU(obj);
+
qdev_init_gpio_in(DEVICE(cpu), hexagon_cpu_set_irq, 8);
+
+ for (int i = 0; i < HVX_CONTEXTS_MAX; i++) {
+ object_property_add_link(obj, "hvx-context[*]",
+ TYPE_HEXAGON_HVX_CONTEXT,
+ (Object **)&cpu->hvx_ctx[i],
+ qdev_prop_allow_set_link_before_realize,
+ OBJ_PROP_LINK_STRONG);
+ }
#endif
}
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index 965abe4f6d..df4c018224 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -29,6 +29,7 @@
typedef struct HexagonTLBState HexagonTLBState;
typedef struct HexagonGlobalRegState HexagonGlobalRegState;
+typedef struct HexagonHVXContextState HexagonHVXContextState;
#include "cpu-qom.h"
#include "exec/cpu-common.h"
@@ -49,6 +50,7 @@ typedef struct HexagonGlobalRegState HexagonGlobalRegState;
#define REG_WRITES_MAX 32
#define PRED_WRITES_MAX 5 /* 4 insns + endloop */
#define VSTORES_MAX 2
+#define HVX_CONTEXTS_MAX 8
#define MAX_TLB_ENTRIES 1024
#define THREADS_MAX 16
@@ -120,6 +122,11 @@ typedef struct {
/* Maximum number of vector temps in a packet */
#define VECTOR_TEMPS_MAX 4
+typedef struct HexagonHVXContext {
+ MMVector VRegs[NUM_VREGS];
+ MMQReg QRegs[NUM_QREGS];
+} QEMU_ALIGNED(16) HexagonHVXContext;
+
typedef struct CPUArchState {
target_ulong gpr[TOTAL_PER_THREAD_REGS];
target_ulong pred[NUM_PREGS];
@@ -159,11 +166,15 @@ typedef struct CPUArchState {
target_ulong llsc_val;
uint64_t llsc_val_i64;
- MMVector VRegs[NUM_VREGS] QEMU_ALIGNED(16);
+#ifdef CONFIG_USER_ONLY
+ HexagonHVXContext hvx_ctx;
+#else
+ HexagonHVXContext *hvx;
+#endif
+
MMVector future_VRegs[VECTOR_TEMPS_MAX] QEMU_ALIGNED(16);
MMVector tmp_VRegs[VECTOR_TEMPS_MAX] QEMU_ALIGNED(16);
- MMQReg QRegs[NUM_QREGS] QEMU_ALIGNED(16);
MMQReg future_QRegs[NUM_QREGS] QEMU_ALIGNED(16);
/* Temporaries used within instructions */
@@ -196,6 +207,7 @@ struct ArchCPU {
CPUHexagonState env;
HexagonCPUConfig cfg;
#ifndef CONFIG_USER_ONLY
+ HexagonHVXContextState *hvx_ctx[HVX_CONTEXTS_MAX];
HexagonTLBState *tlb;
uint32_t boot_addr;
HexagonGlobalRegState *globalregs;
@@ -204,9 +216,13 @@ struct ArchCPU {
#endif
};
-static inline CPUHexagonState *hex_hvx(CPUHexagonState *env)
+static inline HexagonHVXContext *hex_hvx(CPUHexagonState *env)
{
- return env;
+#ifdef CONFIG_USER_ONLY
+ return &env->hvx_ctx;
+#else
+ return env->hvx;
+#endif
}
FIELD(TB_FLAGS, IS_TIGHT_LOOP, 0, 1)
diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c
index eea5f60b46..cf0762ff05 100644
--- a/target/hexagon/cpu_helper.c
+++ b/target/hexagon/cpu_helper.c
@@ -11,6 +11,7 @@
#include "hw/core/boards.h"
#include "hw/hexagon/hexagon.h"
#include "hw/hexagon/hexagon_globalreg.h"
+#include "hw/hexagon/hexagon_hvx_context.h"
#include "hex_interrupts.h"
#include "hex_mmu.h"
#include "system/runstate.h"
@@ -246,6 +247,75 @@ void hexagon_resume_threads(CPUHexagonState *current_env, uint32_t mask)
}
}
+static unsigned hexagon_hvx_context_count(HexagonCPU *cpu)
+{
+ unsigned n;
+
+ for (n = 0; n < HVX_CONTEXTS_MAX; n++) {
+ if (!cpu->hvx_ctx[n]) {
+ break;
+ }
+ }
+ return n;
+}
+
+static unsigned hexagon_hvx_context_index(HexagonCPU *cpu, uint8_t xa)
+{
+ unsigned n = hexagon_hvx_context_count(cpu);
+
+ if (n == 0) {
+ return 0;
+ }
+ if (xa >= n) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "SSR.XA %u is out of range for %u HVX contexts\n",
+ xa, n);
+ }
+ /*
+ * The behavior here is unspecified, reference simulator uses
+ * mappings that effectively keep the context in-range. The
+ * modulus seems just as good as any.
+ */
+ return xa % n;
+}
+
+/*
+ * Diagnostic only. Called separately from hexagon_hvx_select_context()
+ * so migration post_load, where other CPUs' env->hvx may still be stale,
+ * doesn't trip a false positive.
+ */
+static void hexagon_hvx_check_overcommit(CPUHexagonState *env, unsigned idx)
+{
+ CPUState *cs;
+ unsigned users = 0;
+
+ CPU_FOREACH(cs) {
+ CPUHexagonState *other = cpu_env(cs);
+
+ if (other->hvx == env->hvx &&
+ GET_SSR_FIELD(SSR_XE, other->t_sreg[HEX_SREG_SSR])) {
+ users++;
+ }
+ }
+
+ if (users > 1) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "HVX context %u is enabled for %u hardware threads "
+ "at once, which is undefined\n", idx, users);
+ }
+}
+
+unsigned hexagon_hvx_select_context(CPUHexagonState *env, uint32_t ssr)
+{
+ HexagonCPU *cpu = env_archcpu(env);
+ unsigned idx = hexagon_hvx_context_index(cpu, GET_SSR_FIELD(SSR_XA, ssr));
+
+ if (cpu->hvx_ctx[0]) {
+ env->hvx = &cpu->hvx_ctx[idx]->regs;
+ }
+ return idx;
+}
+
void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old)
{
bool old_EX, old_UM, old_GM, old_IE;
@@ -269,6 +339,18 @@ void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old)
hex_mmu_mode_change(env);
}
+ bool xa_changed = GET_SSR_FIELD(SSR_XA, new) != GET_SSR_FIELD(SSR_XA, old);
+ bool xe_changed = GET_SSR_FIELD(SSR_XE, new) != GET_SSR_FIELD(SSR_XE, old);
+
+ if (xa_changed || xe_changed) {
+ unsigned idx = xa_changed
+ ? hexagon_hvx_select_context(env, new)
+ : hexagon_hvx_context_index(env_archcpu(env),
+ GET_SSR_FIELD(SSR_XA, new));
+
+ hexagon_hvx_check_overcommit(env, idx);
+ }
+
old_asid = GET_SSR_FIELD(SSR_ASID, old);
new_asid = GET_SSR_FIELD(SSR_ASID, new);
if (new_asid != old_asid) {
diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h
index 12512efd74..afb4df59f8 100644
--- a/target/hexagon/cpu_helper.h
+++ b/target/hexagon/cpu_helper.h
@@ -15,6 +15,7 @@ void hexagon_peek_memory_range(CPUHexagonState *env, uint32_t start_addr,
uint32_t length, uintptr_t retaddr);
uint32_t hexagon_get_pmu_counter(CPUHexagonState *cur_env, int index);
void hexagon_modify_ssr(CPUHexagonState *env, uint32_t new, uint32_t old);
+unsigned hexagon_hvx_select_context(CPUHexagonState *env, uint32_t ssr);
int get_cpu_mode(const CPUHexagonState *env);
int get_exe_mode(const CPUHexagonState *env);
void clear_wait_mode(CPUHexagonState *env);
diff --git a/target/hexagon/machine.c b/target/hexagon/machine.c
index bf4646f4a8..179b6f53a2 100644
--- a/target/hexagon/machine.c
+++ b/target/hexagon/machine.c
@@ -7,11 +7,23 @@
#include "qemu/osdep.h"
#include "migration/vmstate.h"
#include "cpu.h"
+#include "cpu_helper.h"
+
+static int hexagon_cpu_post_load(void *opaque, int version_id)
+{
+ HexagonCPU *cpu = opaque;
+ CPUHexagonState *env = &cpu->env;
+
+ hexagon_hvx_select_context(env, env->t_sreg[HEX_SREG_SSR]);
+
+ return 0;
+}
const VMStateDescription vmstate_hexagon_cpu = {
.name = "cpu",
.version_id = 2,
.minimum_version_id = 2,
+ .post_load = hexagon_cpu_post_load,
.fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(env.gpr, HexagonCPU, TOTAL_PER_THREAD_REGS),
VMSTATE_UINT32_ARRAY(env.pred, HexagonCPU, NUM_PREGS),
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index bebfeb2dac..827859e052 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -70,6 +70,9 @@ TCGv hex_imprecise_exception;
TCGv hex_vstore_addr[VSTORES_MAX];
TCGv hex_vstore_size[VSTORES_MAX];
TCGv hex_vstore_pending[VSTORES_MAX];
+#ifndef CONFIG_USER_ONLY
+TCGv_ptr hex_hvx_ptr;
+#endif
#ifndef CONFIG_USER_ONLY
TCGv_i32 hex_greg[NUM_GREGS];
@@ -1070,7 +1073,7 @@ static void gen_commit_hvx(DisasContext *ctx)
/*
* for (i = 0; i < ctx->vreg_log_idx; i++) {
* int rnum = ctx->vreg_log[i];
- * hex_hvx(env)->VRegs[rnum] = env->future_VRegs[rnum];
+ * env->hvx->VRegs[rnum] = env->future_VRegs[rnum];
* }
*/
for (i = 0; i < ctx->vreg_log_idx; i++) {
@@ -1087,7 +1090,7 @@ static void gen_commit_hvx(DisasContext *ctx)
/*
* for (i = 0; i < ctx->qreg_log_idx; i++) {
* int rnum = ctx->qreg_log[i];
- * hex_hvx(env)->QRegs[rnum] = env->future_QRegs[rnum];
+ * env->hvx->QRegs[rnum] = env->future_QRegs[rnum];
* }
*/
for (i = 0; i < ctx->qreg_log_idx; i++) {
@@ -1421,6 +1424,8 @@ void hexagon_translate_init(void)
opcode_init();
#ifndef CONFIG_USER_ONLY
+ hex_hvx_ptr = tcg_global_mem_new_ptr(tcg_env,
+ offsetof(CPUHexagonState, hvx), "hvx");
for (i = 0; i < NUM_GREGS; i++) {
hex_greg[i] = tcg_global_mem_new_i32(tcg_env,
offsetof(CPUHexagonState, greg[i]),
diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h
index d5940b9376..e17261761b 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -363,8 +363,13 @@ extern TCGv_i64 hex_llsc_val_i64;
extern TCGv hex_vstore_addr[VSTORES_MAX];
extern TCGv hex_vstore_size[VSTORES_MAX];
extern TCGv hex_vstore_pending[VSTORES_MAX];
+#ifdef CONFIG_USER_ONLY
#define hex_hvx_ptr tcg_env
-#define HEX_HVX_OFFSET(member) offsetof(CPUHexagonState, member)
+#define HEX_HVX_OFFSET(member) offsetof(CPUHexagonState, hvx_ctx.member)
+#else
+extern TCGv_ptr hex_hvx_ptr;
+#define HEX_HVX_OFFSET(member) offsetof(HexagonHVXContext, member)
+#endif
#ifndef CONFIG_USER_ONLY
extern TCGv_i32 hex_greg[NUM_GREGS];
extern TCGv_i32 hex_t_sreg[NUM_SREGS];