Track HLX register updates and commit them at packet end. Run .tmp
loads, other instructions, and stores in separate passes.

Raise the disabled-coprocessor exception without an active context.

Signed-off-by: Marco Liebel <[email protected]>
Signed-off-by: Brian Cain <[email protected]>
---
 target/hexagon/translate.c | 108 +++++++++++++++++++++++++++++++++++--
 target/hexagon/translate.h |  48 +++++++++++++++++
 2 files changed, 153 insertions(+), 3 deletions(-)

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)
 {
-- 
2.43.0


Reply via email to