diff --git a/hw/hexagon/hex-subsys.c b/hw/hexagon/hex-subsys.c
index 1e6578255e..1a043818f6 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_hlx.h"
#include "hw/hexagon/hexagon_hvx_context.h"
#include "hw/hexagon/hexagon_tlb.h"
#include "hw/intc/hex-l2vic.h"
@@ -120,6 +121,18 @@ static void hvx_contexts_create(HexagonCommonMachineState
*hms,
hms->num_hvx_ctx = n;
}
+static DeviceState *hlx_create(HexagonCommonMachineState *hms,
+ const struct hexagon_machine_config *m_cfg)
+{
+ DeviceState *hlx = qdev_new(TYPE_HEXAGON_HLX);
+
+ object_property_add_child(OBJECT(hms), "hexagon-hlx", OBJECT(hlx));
+ qdev_prop_set_uint32(hlx, "contexts-bitmap", m_cfg->cfgtable.coproc2_reg2);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(hlx), &error_fatal);
+
+ return hlx;
+}
+
static DeviceState *cluster_create(HexagonCommonMachineState *hms)
{
DeviceState *cluster = qdev_new(TYPE_CPU_CLUSTER);
@@ -167,6 +180,7 @@ void hex_subsys_create(HexagonCommonMachineState *hms,
hms->glob_regs = globalreg_create(hms, m_cfg, rev);
hms->tlb = tlb_create(hms, m_cfg);
hvx_contexts_create(hms, m_cfg);
+ hms->hlx = hlx_create(hms, m_cfg);
}
void hex_subsys_add_cpu(HexagonCommonMachineState *hms, DeviceState *cpu)
@@ -178,6 +192,8 @@ void hex_subsys_add_cpu(HexagonCommonMachineState *hms,
DeviceState *cpu)
&error_fatal);
object_property_set_link(OBJECT(cpu), "l2vic", OBJECT(hms->l2vic),
&error_fatal);
+ object_property_set_link(OBJECT(cpu), "hlx", OBJECT(hms->hlx),
+ &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);
diff --git a/hw/hexagon/hexagon_hlx.c b/hw/hexagon/hexagon_hlx.c
new file mode 100644
index 0000000000..3ac21500e0
--- /dev/null
+++ b/hw/hexagon/hexagon_hlx.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/host-utils.h"
+#include "hw/core/qdev-properties.h"
+#include "hw/hexagon/hexagon_hlx.h"
+#include "migration/vmstate.h"
+
+static int hlx_xa3_to_pool_idx(uint32_t contexts_bitmap, uint32_t xa3)
+{
+ uint32_t below_mask;
+
+ if (!((contexts_bitmap >> xa3) & 1u)) {
+ return -1;
+ }
+ below_mask = (xa3 == 0) ? 0u : ((1u << xa3) - 1u);
+ return ctpop32(contexts_bitmap & below_mask);
+}
+
+HexagonHLXContext *hexagon_hlx_get_context(HexagonHLXState *s, uint32_t xa3)
+{
+ int idx = hlx_xa3_to_pool_idx(s->contexts_bitmap, xa3);
+ if (idx < 0 || idx >= s->num_contexts) {
+ return NULL;
+ }
+ return &s->contexts[idx];
+}
+
+void hexagon_hlx_reset_all(HexagonHLXState *s)
+{
+ if (!s->contexts) {
+ return;
+ }
+ memset(s->contexts, 0, sizeof(HexagonHLXContext) *
(size_t)s->num_contexts);
+}
+
+static void hexagon_hlx_realize(DeviceState *dev, Error **errp)
+{
+ HexagonHLXState *s = HEXAGON_HLX(dev);
+
+ s->num_contexts = (int32_t)ctpop32(s->contexts_bitmap);
+ if (s->num_contexts == 0) {
+ s->contexts = NULL;
+ return;
+ }
+ s->contexts = g_new0(HexagonHLXContext, (size_t)s->num_contexts);
+}
+
+static void hexagon_hlx_unrealize(DeviceState *dev)
+{
+ HexagonHLXState *s = HEXAGON_HLX(dev);
+ g_clear_pointer(&s->contexts, g_free);
+ s->num_contexts = 0;
+}
+
+static const Property hexagon_hlx_properties[] = {
+ DEFINE_PROP_UINT32("contexts-bitmap", HexagonHLXState, contexts_bitmap, 0),
+};
+
+/* VMSTATE_BUFFER requires a uint8_t array field. */
+static const VMStateDescription vmstate_hexagon_hlx_context = {
+ .name = "hexagon-hlx-context",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_BUFFER_UNSAFE_INFO_TEST(LRegs, HexagonHLXContext, NULL,
+ 0, vmstate_info_buffer,
+ sizeof_field(HexagonHLXContext,
+ LRegs)),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_hexagon_hlx = {
+ .name = TYPE_HEXAGON_HLX,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32(contexts_bitmap, HexagonHLXState),
+ VMSTATE_INT32(num_contexts, HexagonHLXState),
+ VMSTATE_STRUCT_VARRAY_ALLOC(contexts, HexagonHLXState,
+ num_contexts, 1,
+ vmstate_hexagon_hlx_context,
+ HexagonHLXContext),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void hexagon_hlx_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ dc->realize = hexagon_hlx_realize;
+ dc->unrealize = hexagon_hlx_unrealize;
+ dc->vmsd = &vmstate_hexagon_hlx;
+ device_class_set_props(dc, hexagon_hlx_properties);
+}
+
+static const TypeInfo hexagon_hlx_info = {
+ .name = TYPE_HEXAGON_HLX,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(HexagonHLXState),
+ .class_init = hexagon_hlx_class_init,
+};
+
+static void hexagon_hlx_register_types(void)
+{
+ type_register_static(&hexagon_hlx_info);
+}
+
+type_init(hexagon_hlx_register_types)
diff --git a/hw/hexagon/meson.build b/hw/hexagon/meson.build
index fa5bc5eb9f..46e9f8de9c 100644
--- a/hw/hexagon/meson.build
+++ b/hw/hexagon/meson.build
@@ -3,6 +3,7 @@ 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(files('hexagon_hlx.c'))
hexagon_ss.add(when: 'CONFIG_HEX_DSP', if_true: files('hexagon_dsp.c'))
hexagon_ss.add(when: 'CONFIG_HEX_BOARD', if_true: files('hex-board.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 678e658a6d..e01e2bb464 100644
--- a/include/hw/hexagon/hexagon.h
+++ b/include/hw/hexagon/hexagon.h
@@ -187,6 +187,7 @@ struct HexagonCommonMachineState {
DeviceState *qtimer;
DeviceState *glob_regs;
DeviceState *tlb;
+ DeviceState *hlx;
unsigned num_hvx_ctx;
};
diff --git a/include/hw/hexagon/hexagon_hlx.h b/include/hw/hexagon/hexagon_hlx.h
new file mode 100644
index 0000000000..68c3f001aa
--- /dev/null
+++ b/include/hw/hexagon/hexagon_hlx.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_HEXAGON_HEXAGON_HLX_H
+#define HW_HEXAGON_HEXAGON_HLX_H
+
+#include "hw/core/qdev.h"
+#include "hw/core/sysbus.h"
+#include "qom/object.h"
+#include "target/hexagon/hlx/hlx.h"
+
+#define TYPE_HEXAGON_HLX "hexagon-hlx"
+OBJECT_DECLARE_SIMPLE_TYPE(HexagonHLXState, HEXAGON_HLX)
+
+typedef struct HexagonHLXContext {
+ HLXVector LRegs[NUM_LREGS] QEMU_ALIGNED(16);
+} HexagonHLXContext;
+
+struct HexagonHLXState {
+ SysBusDevice parent_obj;
+
+ uint32_t contexts_bitmap;
+ int32_t num_contexts;
+ HexagonHLXContext *contexts;
+};
+
+HexagonHLXContext *hexagon_hlx_get_context(HexagonHLXState *s, uint32_t xa3);
+
+void hexagon_hlx_reset_all(HexagonHLXState *s);
+
+#endif
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 281d201250..c3930ab4e4 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -42,6 +42,7 @@
#include "hexswi.h"
#include "exec/cpu-interrupt.h"
#include "exec/page-protection.h"
+#include "hw/hexagon/hexagon_hlx.h"
#include "exec/target_page.h"
#include "hw/hexagon/hexagon_globalreg.h"
#include "hw/hexagon/hexagon_hvx_context.h"
@@ -72,6 +73,8 @@ static const Property hexagon_cpu_properties[] = {
DEFINE_PROP_LINK("global-regs", HexagonCPU, globalregs,
TYPE_HEXAGON_GLOBALREG, HexagonGlobalRegState *),
DEFINE_PROP_UINT32("htid", HexagonCPU, htid, 0),
+ DEFINE_PROP_LINK("hlx", HexagonCPU, hlx,
+ TYPE_HEXAGON_HLX, HexagonHLXState *),
#endif
DEFINE_PROP_BOOL("lldb-compat", HexagonCPU, cfg.lldb_compat, false),
DEFINE_PROP_UNSIGNED("lldb-stack-adjust", HexagonCPU,
cfg.lldb_stack_adjust,
@@ -498,6 +501,12 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType
type)
env->cfi_active = 0;
env->cfi_active_log = 0;
env->cfi_updated = 0;
+#ifdef CONFIG_USER_ONLY
+ memset(&env->hlx_user_ctx, 0, sizeof(env->hlx_user_ctx));
+ env->hlx_ctx = &env->hlx_user_ctx;
+#else
+ env->hlx_ctx = NULL;
+#endif
#ifndef CONFIG_USER_ONLY
memset(env->t_sreg, 0, sizeof(uint32_t) * NUM_SREGS);
memset(env->greg, 0, sizeof(uint32_t) * NUM_GREGS);
@@ -508,11 +517,18 @@ static void hexagon_cpu_reset_hold(Object *obj, ResetType
type)
env->t_sreg[HEX_SREG_HTID] = cpu->htid;
env->threadId = cpu->htid;
+ if (cs->cpu_index == 0 && cpu->hlx) {
+ hexagon_hlx_reset_all(cpu->hlx);
+ }
+
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
+
+ memset(env->future_LRegs, 0, sizeof(env->future_LRegs));
+ memset(env->tmp_LRegs, 0, sizeof(env->tmp_LRegs));
}
static void hexagon_cpu_disas_set_info(const CPUState *cs,
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index feb8036823..904dcc2e7d 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -18,6 +18,13 @@
#ifndef HEXAGON_CPU_H
#define HEXAGON_CPU_H
+typedef struct HexagonHLXContext HexagonHLXContext;
+
+#ifdef CONFIG_USER_ONLY
+/* linux-user embeds an HLX context and needs the full type. */
+#include "hw/hexagon/hexagon_hlx.h"
+#endif
+
#include "fpu/softfloat-types.h"
#ifndef CONFIG_USER_ONLY
@@ -30,11 +37,13 @@
typedef struct HexagonTLBState HexagonTLBState;
typedef struct HexagonGlobalRegState HexagonGlobalRegState;
typedef struct HexagonHVXContextState HexagonHVXContextState;
+typedef struct HexagonHLXState HexagonHLXState;
#include "cpu-qom.h"
#include "exec/cpu-common.h"
#include "exec/target_long.h"
#include "hex_regs.h"
+#include "hlx/hlx.h"
#include "mmvec/mmvec.h"
#include "hw/core/registerfields.h"
#include "qemu/bitmap.h"
@@ -186,6 +195,16 @@ typedef struct CPUArchState {
MMQReg future_QRegs[NUM_QREGS] QEMU_ALIGNED(16);
+ /* Active HLX context, or NULL when disabled or unavailable. */
+ HexagonHLXContext *hlx_ctx;
+
+#ifdef CONFIG_USER_ONLY
+ HexagonHLXContext hlx_user_ctx;
+#endif
+
+ HLXVector future_LRegs[NUM_LREGS] QEMU_ALIGNED(16);
+ HLXVector tmp_LRegs[NUM_LREGS] QEMU_ALIGNED(16);
+
/* Temporaries used within instructions */
MMVectorPair VuuV QEMU_ALIGNED(16);
MMVectorPair VvvV QEMU_ALIGNED(16);
@@ -222,6 +241,7 @@ struct ArchCPU {
HexagonGlobalRegState *globalregs;
uint32_t htid;
HexL2VicInterface *l2vic;
+ HexagonHLXState *hlx;
#endif
};
diff --git a/target/hexagon/cpu_helper.c b/target/hexagon/cpu_helper.c
index baffe6bbaa..940c724be9 100644
--- a/target/hexagon/cpu_helper.c
+++ b/target/hexagon/cpu_helper.c
@@ -25,6 +25,7 @@
#include "macros.h"
#include "sys_macros.h"
#include "arch.h"
+#include "hw/hexagon/hexagon_hlx.h"
#ifndef CONFIG_USER_ONLY
@@ -327,6 +328,41 @@ static uint32_t set_enable_mask(CPUHexagonState *env)
return thread_enabled_mask;
}
+void hexagon_modify_ccr(CPUHexagonState *env, uint32_t new, uint32_t old)
+{
+ const uint32_t mask = (1u << reg_field_info[CCR_XA3].offset) |
+ (1u << reg_field_info[CCR_XE3].offset);
+ bool old_XE3;
+ bool new_XE3;
+ uint32_t old_XA3;
+ uint32_t new_XA3;
+ HexagonCPU *cpu;
+ HexagonHLXState *pool;
+
+ g_assert(bql_locked());
+
+ if (((old ^ new) & mask) == 0) {
+ return;
+ }
+
+ old_XE3 = GET_FIELD(CCR_XE3, old);
+ new_XE3 = GET_FIELD(CCR_XE3, new);
+ old_XA3 = GET_FIELD(CCR_XA3, old);
+ new_XA3 = GET_FIELD(CCR_XA3, new);
+ cpu = HEXAGON_CPU(env_cpu(env));
+ pool = cpu->hlx;
+
+ if (!new_XE3) {
+ env->hlx_ctx = NULL;
+ return;
+ }
+
+ if (!old_XE3 || old_XA3 != new_XA3) {
+ env->hlx_ctx = pool ? hexagon_hlx_get_context(pool, new_XA3) : NULL;
+ /* A missing XA3 context makes HLX instructions trap. */
+ }
+}
+
static uint32_t clear_enable_mask(CPUHexagonState *env)
{
HexagonCPU *cpu;
diff --git a/target/hexagon/cpu_helper.h b/target/hexagon/cpu_helper.h
index b261b9177b..5c0c129dfd 100644
--- a/target/hexagon/cpu_helper.h
+++ b/target/hexagon/cpu_helper.h
@@ -13,6 +13,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);
+void hexagon_modify_ccr(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);
diff --git a/target/hexagon/gdbstub.c b/target/hexagon/gdbstub.c
index 85d9845cc9..5b79e42c4d 100644
--- a/target/hexagon/gdbstub.c
+++ b/target/hexagon/gdbstub.c
@@ -23,6 +23,7 @@
#ifndef CONFIG_USER_ONLY
#include "cpu_helper.h"
#include "hw/hexagon/hexagon_globalreg.h"
+#include "hw/hexagon/hexagon_hlx.h"
#endif
int hexagon_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
@@ -120,6 +121,10 @@ int hexagon_sys_gdb_write_register(CPUState *cs, uint8_t
*mem_buf, int n)
uint32_t old = env->t_sreg[HEX_SREG_SSR];
env->t_sreg[HEX_SREG_SSR] = val;
hexagon_modify_ssr(env, val, old);
+ } else if (n == HEX_SREG_CCR) {
+ uint32_t old = env->t_sreg[HEX_SREG_CCR];
+ env->t_sreg[HEX_SREG_CCR] = val;
+ hexagon_modify_ccr(env, val, old);
} else if (n < HEX_SREG_GLB_START) {
env->t_sreg[n] = val;
} else if (cpu->globalregs) {
diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index 7ef36e336f..d0aabacf35 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -287,7 +287,7 @@ static const uint32_t sreg_immut_masks[NUM_SREGS] = {
[HEX_SREG_STID] = 0xff00ff00,
[HEX_SREG_ELR] = 0x00000003,
[HEX_SREG_SSR] = 0x00008000,
- [HEX_SREG_CCR] = 0x10e0ff24,
+ [HEX_SREG_CCR] = 0x00c0ff24,
[HEX_SREG_HTID] = IMMUTABLE,
[HEX_SREG_GEVB] = 0x000000ff,
};
@@ -308,7 +308,8 @@ static void gen_log_sreg_write(DisasContext *ctx, int rnum,
TCGv_i32 val)
if (reg_mask != IMMUTABLE) {
if (rnum < HEX_SREG_GLB_START) {
gen_masked_reg_write(val, hex_t_sreg[rnum], reg_mask);
- if (ctx->need_commit || rnum == HEX_SREG_SSR) {
+ if (ctx->need_commit || rnum == HEX_SREG_SSR ||
+ rnum == HEX_SREG_CCR) {
tcg_gen_mov_i32(ctx->t_sreg_new_value[rnum], val);
} else {
tcg_gen_mov_i32(hex_t_sreg[rnum], val);
diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h
index 8c49e79809..8a2a6563d2 100644
--- a/target/hexagon/helper.h
+++ b/target/hexagon/helper.h
@@ -147,6 +147,7 @@ DEF_HELPER_1(wait, void, env)
DEF_HELPER_2(resume, void, env, i32)
DEF_HELPER_1(resched, void, env)
DEF_HELPER_3(modify_ssr, void, env, i32, i32)
+DEF_HELPER_3(modify_ccr, void, env, i32, i32)
DEF_HELPER_1(pending_interrupt, void, env)
DEF_HELPER_2(tlbinvasid, void, env, i32)
#endif
diff --git a/target/hexagon/hlx/hlx.h b/target/hexagon/hlx/hlx.h
new file mode 100644
index 0000000000..81c0434df7
--- /dev/null
+++ b/target/hexagon/hlx/hlx.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef HEXAGON_HLX_H
+#define HEXAGON_HLX_H
+
+#define NUM_LREGS 16
+#define HLX_VEC_SIZE_BYTES 2048
+
+typedef union {
+ uint8_t ub[4];
+ int8_t b[4];
+ uint16_t uh[2];
+ int16_t h[2];
+ uint32_t uw;
+ int32_t w;
+} lreg_element_t;
+
+typedef struct {
+ union {
+ uint64_t ud[HLX_VEC_SIZE_BYTES / 8];
+ int64_t d[HLX_VEC_SIZE_BYTES / 8];
+ uint32_t uw[HLX_VEC_SIZE_BYTES / 4];
+ int32_t w[HLX_VEC_SIZE_BYTES / 4];
+ uint16_t uh[HLX_VEC_SIZE_BYTES / 2];
+ int16_t h[HLX_VEC_SIZE_BYTES / 2];
+ uint8_t ub[HLX_VEC_SIZE_BYTES / 1];
+ int8_t b[HLX_VEC_SIZE_BYTES / 1];
+ };
+} HLXVector;
+
+typedef union {
+ lreg_element_t l[HLX_VEC_SIZE_BYTES / 2];
+} HLXVectorPair;
+
+static inline HLXVector hlx_zero_vector(void)
+{
+ HLXVector ret;
+ memset(&ret, 0, sizeof(ret));
+ return ret;
+}
+
+/* Interleave separate low and high halfwords as {lo, hi}. */
+static inline void hlx_interleave_pair(HLXVectorPair *pair,
+ const HLXVector *lo,
+ const HLXVector *hi)
+{
+ for (int i = 0; i < HLX_VEC_SIZE_BYTES / 2; i++) {
+ pair->l[i].h[0] = lo->h[i];
+ pair->l[i].h[1] = hi->h[i];
+ }
+}
+
+static inline void hlx_deinterleave_pair(HLXVector *lo, HLXVector *hi,
+ const HLXVectorPair *pair)
+{
+ for (int i = 0; i < HLX_VEC_SIZE_BYTES / 2; i++) {
+ lo->h[i] = pair->l[i].h[0];
+ hi->h[i] = pair->l[i].h[1];
+ }
+}
+
+#endif
diff --git a/target/hexagon/machine.c b/target/hexagon/machine.c
index 6a41551d8f..4d2b09c519 100644
--- a/target/hexagon/machine.c
+++ b/target/hexagon/machine.c
@@ -5,23 +5,67 @@
*/
#include "qemu/osdep.h"
+#include "migration/cpu.h"
+#include "migration/qemu-file-types.h"
#include "migration/vmstate.h"
#include "cpu.h"
#include "cpu_helper.h"
+#include "macros.h"
+#include "hlx/hlx.h"
+#include "hw/hexagon/hexagon_hlx.h"
static int hexagon_cpu_post_load(void *opaque, int version_id)
{
HexagonCPU *cpu = opaque;
CPUHexagonState *env = &cpu->env;
+ uint32_t ccr;
+ bool xe3;
+ uint32_t xa3;
hexagon_hvx_select_context(env, env->t_sreg[HEX_SREG_SSR]);
+ if (!cpu->hlx) {
+ env->hlx_ctx = NULL;
+ return 0;
+ }
+ ccr = env->t_sreg[HEX_SREG_CCR];
+ xe3 = GET_FIELD(CCR_XE3, ccr);
+ xa3 = GET_FIELD(CCR_XA3, ccr);
+ env->hlx_ctx = xe3 ? hexagon_hlx_get_context(cpu->hlx, xa3) : NULL;
return 0;
}
+static int get_hlxvector(QEMUFile *f, void *pv, size_t size,
+ const VMStateField *field)
+{
+ HLXVector *v = pv;
+ for (int i = 0; i < HLX_VEC_SIZE_BYTES / 8; i++) {
+ v->ud[i] = qemu_get_be64(f);
+ }
+ return 0;
+}
+
+static int put_hlxvector(QEMUFile *f, void *pv, size_t size,
+ const VMStateField *field, JSONWriter *vmdesc)
+{
+ HLXVector *v = pv;
+ for (int i = 0; i < HLX_VEC_SIZE_BYTES / 8; i++) {
+ qemu_put_be64(f, v->ud[i]);
+ }
+ return 0;
+}
+
+static const VMStateInfo vmstate_info_hlxvector = {
+ .name = "hlxvector",
+ .get = get_hlxvector,
+ .put = put_hlxvector,
+};
+
+#define VMSTATE_HLXVECTOR_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_SUB_ARRAY(_f, _s, 0, _n, _v, vmstate_info_hlxvector, HLXVector)
const VMStateDescription vmstate_hexagon_cpu = {
.name = "cpu",
- .version_id = 3,
+ .version_id = 4,
.minimum_version_id = 2,
.post_load = hexagon_cpu_post_load,
.fields = (const VMStateField[]) {
@@ -38,6 +82,7 @@ const VMStateDescription vmstate_hexagon_cpu = {
VMSTATE_UNUSED(sizeof(uint64_t)),
VMSTATE_UINT32(env.imprecise_exception, HexagonCPU),
VMSTATE_UINT32_V(env.cfi_active, HexagonCPU, 3),
+ VMSTATE_HLXVECTOR_ARRAY_V(env.future_LRegs, HexagonCPU, NUM_LREGS, 4),
VMSTATE_END_OF_LIST()
},
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 6076a5f29f..477c8d6b66 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1356,6 +1356,12 @@ void HELPER(modify_ssr)(CPUHexagonState *env, uint32_t
new, uint32_t old)
hexagon_modify_ssr(env, new, old);
}
+void HELPER(modify_ccr)(CPUHexagonState *env, uint32_t new, uint32_t old)
+{
+ BQL_LOCK_GUARD();
+ hexagon_modify_ccr(env, new, old);
+}
+
static void hex_k0_lock(CPUHexagonState *env, uint32_t PC)
{
HexagonCPU *cpu = env_archcpu(env);
diff --git a/target/hexagon/reg_fields_def.h.inc
b/target/hexagon/reg_fields_def.h.inc
index 21babbbb98..a490b0e07f 100644
--- a/target/hexagon/reg_fields_def.h.inc
+++ b/target/hexagon/reg_fields_def.h.inc
@@ -130,10 +130,12 @@ DEF_REG_FIELD(CCR_HFIL2, 18, 1)
DEF_REG_FIELD(CCR_HFDL2, 19, 1)
DEF_REG_FIELD(CCR_SFD, 20, 1)
+DEF_REG_FIELD(CCR_XA3, 21, 1)
DEF_REG_FIELD(CCR_GIE, 24, 1)
DEF_REG_FIELD(CCR_GTE, 25, 1)
DEF_REG_FIELD(CCR_GEE, 26, 1)
DEF_REG_FIELD(CCR_GRE, 27, 1)
+DEF_REG_FIELD(CCR_XE3, 28, 1)
DEF_REG_FIELD(CCR_VV1, 29, 1)
DEF_REG_FIELD(CCR_VV2, 30, 1)
DEF_REG_FIELD(CCR_VV3, 31, 1)
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index 91925d2ddb..ed246e226f 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -345,6 +345,7 @@ static bool need_slot_cancelled(Packet *pkt)
static bool sreg_write_ends_tb(int reg_num)
{
return reg_num == HEX_SREG_SSR ||
+ reg_num == HEX_SREG_CCR ||
reg_num == HEX_SREG_STID ||
reg_num == HEX_SREG_IMASK ||
reg_num == HEX_SREG_IPENDAD ||
@@ -986,6 +987,13 @@ static void gen_sreg_writes(DisasContext *ctx)
tcg_gen_mov_tl(hex_t_sreg[reg_num],
ctx->t_sreg_new_value[reg_num]);
gen_helper_modify_ssr(tcg_env, ctx->t_sreg_new_value[reg_num],
old_reg);
+ } else if (reg_num == HEX_SREG_CCR) {
+ tcg_gen_mov_tl(old_reg, hex_t_sreg[reg_num]);
+ tcg_gen_mov_tl(hex_t_sreg[reg_num],
ctx->t_sreg_new_value[reg_num]);
+ gen_helper_modify_ccr(tcg_env, ctx->t_sreg_new_value[reg_num],
+ old_reg);
+ /* A CCR write can change context, so end the TB. */
+ ctx->base.is_jmp = DISAS_NORETURN;
} else if ((reg_num == HEX_SREG_STID) ||
(reg_num == HEX_SREG_IMASK) ||
(reg_num == HEX_SREG_IPENDAD) ||