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
