diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index ed246e226f..41b7d3b0fb 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -18,6 +18,7 @@
#define QEMU_GENERATE
#include "qemu/osdep.h"
#include "cpu.h"
+#include "hw/hexagon/hexagon_hlx.h"
#include "tcg/tcg-op.h"
#include "tcg/tcg-op-gvec.h"
#include "exec/helper-gen.h"
@@ -33,6 +34,8 @@
#include "genptr.h"
#include "printinsn.h"
#include "exec/target_page.h"
+#include "hlx/hlx.h"
+#include "trace.h"
#define HELPER_H "helper.h"
#include "exec/helper-info.c.inc"
@@ -341,6 +344,26 @@ static bool need_slot_cancelled(Packet *pkt)
return false;
}
+#ifndef CONFIG_USER_ONLY
+static void gen_hlx_check(DisasContext *ctx)
+{
+ TCGv xe = tcg_temp_new();
+ TCGv_ptr hlx_ctx = tcg_temp_new_ptr();
+ TCGLabel *raise = gen_new_label();
+ TCGLabel *enabled = gen_new_label();
+
+ tcg_gen_extract_tl(xe, hex_t_sreg[HEX_SREG_CCR],
+ reg_field_info[CCR_XE3].offset,
+ reg_field_info[CCR_XE3].width);
+ tcg_gen_brcondi_tl(TCG_COND_EQ, xe, 0, raise);
+ tcg_gen_ld_ptr(hlx_ctx, tcg_env, offsetof(CPUHexagonState, hlx_ctx));
+ tcg_gen_brcondi_ptr(TCG_COND_NE, hlx_ctx, 0, enabled);
+ gen_set_label(raise);
+ gen_precise_exception(HEX_CAUSE_NO_COPROC3_ENABLE, ctx->pkt.pc);
+ gen_set_label(enabled);
+}
+#endif
+
#ifndef CONFIG_USER_ONLY
static bool sreg_write_ends_tb(int reg_num)
{
@@ -678,6 +701,12 @@ static void clear_pkt_ctx(DisasContext *ctx)
bitmap_zero(ctx->qregs_multi_write, NUM_QREGS);
bitmap_zero(ctx->qregs_uncond, NUM_QREGS);
ctx->qreg_log_idx = 0;
+ ctx->lreg_log_idx = 0;
+ ctx->lreg_tmp_log_idx = 0;
+ bitmap_zero(ctx->lregs_updated, NUM_LREGS);
+ bitmap_zero(ctx->lregs_multi_write, NUM_LREGS);
+ bitmap_zero(ctx->lregs_updated_tmp, NUM_LREGS);
+ ctx->hlx_base_loaded = false;
for (i = 0; i < STORES_MAX; i++) {
ctx->store_width[i] = 0;
}
@@ -701,6 +730,11 @@ static bool pkt_has_write_conflict(DisasContext *ctx)
return true;
}
+ /* HLX instructions are unpredicated, so multiple writes conflict. */
+ if (!bitmap_empty(ctx->lregs_multi_write, NUM_LREGS)) {
+ return true;
+ }
+
#ifndef CONFIG_USER_ONLY
if (!bitmap_empty(ctx->gregs_multi_write, NUM_GREGS)) {
return true;
@@ -742,6 +776,17 @@ static void analyze_packet(DisasContext *ctx)
ctx->need_commit = need_commit(ctx);
}
+static bool pkt_has_hlx_store(Packet *pkt)
+{
+ for (int i = 0; i < pkt->num_insns; i++) {
+ int opcode = pkt->insn[i].opcode;
+ if (GET_ATTRIB(opcode, A_HLX) && GET_ATTRIB(opcode, A_STORE)) {
+ return true;
+ }
+ }
+ return false;
+}
+
static void gen_start_packet(DisasContext *ctx)
{
int i;
@@ -776,6 +821,11 @@ static void gen_start_packet(DisasContext *ctx)
if (need_slot_cancelled(&ctx->pkt)) {
tcg_gen_movi_tl(hex_slot_cancelled, 0);
}
+ if (pkt_has_hlx_store(&ctx->pkt)) {
+ /* An earlier fault can leave a store logged. */
+ tcg_gen_st8_i32(tcg_constant_i32(0), tcg_env,
+ offsetof(CPUHexagonState, hlx_store_pending));
+ }
ctx->branch_taken = NULL;
if (ctx->pkt.pkt_has_cof) {
ctx->branch_taken = tcg_temp_new();
@@ -860,6 +910,14 @@ static void gen_start_packet(DisasContext *ctx)
gen_precise_exception(HEX_CAUSE_NO_COPROC_ENABLE, ctx->pkt.pc);
ctx->hvx_check_emitted = true;
}
+ if (ctx->pkt.pkt_has_hlx) {
+ if (!ctx->hlx_coproc_enabled) {
+ gen_precise_exception(HEX_CAUSE_NO_COPROC3_ENABLE, ctx->pkt.pc);
+ } else if (!ctx->hlx_check_emitted) {
+ gen_hlx_check(ctx);
+ ctx->hlx_check_emitted = true;
+ }
+ }
#endif
}
@@ -1206,6 +1264,17 @@ static void gen_commit_hvx(DisasContext *ctx)
}
}
+static void gen_commit_hlx(DisasContext *ctx)
+{
+ int i;
+
+ for (i = 0; i < ctx->lreg_log_idx; i++) {
+ int rnum = ctx->lreg_log[i];
+ gen_helper_hlx_commit_reg(tcg_env, tcg_constant_i32(rnum));
+ }
+
+}
+
static void update_exec_counters(DisasContext *ctx)
{
int num_real_insns = 0;
@@ -1332,6 +1401,9 @@ static void gen_commit_packet(DisasContext *ctx)
}
process_store_log(ctx);
+ if (pkt_has_hlx_store(&ctx->pkt)) {
+ gen_helper_hlx_commit_store(tcg_env);
+ }
gen_reg_writes(ctx);
#ifndef CONFIG_USER_ONLY
@@ -1342,6 +1414,9 @@ static void gen_commit_packet(DisasContext *ctx)
if (ctx->pkt.pkt_has_hvx) {
gen_commit_hvx(ctx);
}
+ if (ctx->pkt.pkt_has_hlx) {
+ gen_commit_hlx(ctx);
+ }
update_exec_counters(ctx);
if (ctx->pkt.vhist_insn != NULL) {
@@ -1404,9 +1479,31 @@ static void decode_and_translate_packet(CPUHexagonState
*env, DisasContext *ctx)
}
#endif
gen_start_packet(ctx);
- for (i = 0; i < ctx->pkt.num_insns; i++) {
- ctx->insn = &ctx->pkt.insn[i];
- gen_insn(ctx);
+ if (ctx->pkt.pkt_has_hlx) {
+ /* Run .tmp loads first and stores last. */
+ for (int pass = 0; pass < 3; pass++) {
+ for (i = 0; i < ctx->pkt.num_insns; i++) {
+ Insn *insn = &ctx->pkt.insn[i];
+ bool tmp = GET_ATTRIB(insn->opcode, A_HLX_TMP);
+ bool store = !tmp && GET_ATTRIB(insn->opcode, A_STORE);
+ if (pass != (tmp ? 0 : store ? 2 : 1)) {
+ continue;
+ }
+ ctx->insn = insn;
+ if (GET_ATTRIB(insn->opcode, A_HLX) &&
+ trace_event_get_state_backends(
+ TRACE_HEXAGON_HLX_OP)) {
+ gen_helper_hlx_trace_op(tcg_env,
+ tcg_constant_i32(insn->opcode));
+ }
+ gen_insn(ctx);
+ }
+ }
+ } else {
+ for (i = 0; i < ctx->pkt.num_insns; i++) {
+ ctx->insn = &ctx->pkt.insn[i];
+ gen_insn(ctx);
+ }
}
gen_commit_packet(ctx);
ctx->base.pc_next += ctx->pkt.encod_pkt_size_in_bytes;
@@ -1426,6 +1523,11 @@ static void
hexagon_tr_init_disas_context(DisasContextBase *dcbase,
ctx->num_packets = 0;
ctx->num_insns = 0;
ctx->num_hvx_insns = 0;
+#ifndef CONFIG_USER_ONLY
+ ctx->hlx_coproc_enabled = hex_cpu->hlx != NULL &&
+ hex_cpu->hlx->contexts_bitmap != 0;
+ ctx->hlx_check_emitted = false;
+#endif
ctx->branch_cond = TCG_COND_NEVER;
ctx->is_tight_loop = FIELD_EX32(hex_flags, TB_FLAGS, IS_TIGHT_LOOP);
ctx->short_circuit = hex_cpu->cfg.short_circuit;
diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h
index bc5f202163..fa7e627200 100644
--- a/target/hexagon/translate.h
+++ b/target/hexagon/translate.h
@@ -91,6 +91,7 @@ typedef struct DisasContext {
TCGCond branch_cond;
target_ulong branch_dest;
bool is_tight_loop;
+ bool hlx_check_emitted;
bool short_circuit;
bool ieee_fp_extension;
bool read_after_write;
@@ -101,10 +102,57 @@ typedef struct DisasContext {
TCGv dczero_addr;
bool hvx_coproc_enabled;
bool hvx_check_emitted;
+ bool hlx_coproc_enabled;
+ TCGv_ptr hlx_base;
+ bool hlx_base_loaded;
+ int lreg_log[NUM_LREGS];
+ int lreg_log_idx;
+ int lreg_tmp_log[NUM_LREGS];
+ int lreg_tmp_log_idx;
+ DECLARE_BITMAP(lregs_updated, NUM_LREGS);
+ DECLARE_BITMAP(lregs_multi_write, NUM_LREGS);
+ DECLARE_BITMAP(lregs_updated_tmp, NUM_LREGS);
} DisasContext;
bool is_gather_store_insn(DisasContext *ctx);
+static inline TCGv_ptr ctx_get_hlx_base(DisasContext *ctx)
+{
+ if (!ctx->hlx_base_loaded) {
+ ctx->hlx_base = tcg_temp_new_ptr();
+ tcg_gen_ld_ptr(ctx->hlx_base, tcg_env,
+ offsetof(CPUHexagonState, hlx_ctx));
+ ctx->hlx_base_loaded = true;
+ }
+ return ctx->hlx_base;
+}
+
+static inline void ctx_log_lreg_write(DisasContext *ctx, int rnum)
+{
+ if (test_bit(rnum, ctx->lregs_updated)) {
+ set_bit(rnum, ctx->lregs_multi_write);
+ } else {
+ ctx->lreg_log[ctx->lreg_log_idx] = rnum;
+ ctx->lreg_log_idx++;
+ set_bit(rnum, ctx->lregs_updated);
+ }
+}
+
+static inline void ctx_log_lreg_write_pair(DisasContext *ctx, int rnum)
+{
+ ctx_log_lreg_write(ctx, rnum ^ 0);
+ ctx_log_lreg_write(ctx, rnum ^ 1);
+}
+
+static inline void ctx_log_lreg_tmp_write(DisasContext *ctx, int rnum)
+{
+ if (!test_bit(rnum, ctx->lregs_updated_tmp)) {
+ ctx->lreg_tmp_log[ctx->lreg_tmp_log_idx] = rnum;
+ ctx->lreg_tmp_log_idx++;
+ set_bit(rnum, ctx->lregs_updated_tmp);
+ }
+}
+
#ifndef CONFIG_USER_ONLY
static inline void ctx_log_greg_write(DisasContext *ctx, int rnum)
{