From: Brian Cain <bc...@quicinc.com> Signed-off-by: Brian Cain <brian.c...@oss.qualcomm.com> --- target/hexagon/translate.h | 1 + target/hexagon/translate.c | 102 ++++++++++++++++++++++++++++++++++++- 2 files changed, 101 insertions(+), 2 deletions(-)
diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h index 0bdf526a9e..08194a3309 100644 --- a/target/hexagon/translate.h +++ b/target/hexagon/translate.h @@ -84,6 +84,7 @@ typedef struct DisasContext { TCGv branch_taken; TCGv dczero_addr; bool pcycle_enabled; + bool pkt_ends_tb; uint32_t num_cycles; } DisasContext; diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index a71fa33ccf..92adc60d1a 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -258,6 +258,16 @@ static bool check_for_attrib(Packet *pkt, int attrib) return false; } +static bool check_for_opcode(Packet *pkt, uint16_t opcode) +{ + for (int i = 0; i < pkt->num_insns; i++) { + if (pkt->insn[i].opcode == opcode) { + return true; + } + } + return false; +} + static bool need_slot_cancelled(Packet *pkt) { /* We only need slot_cancelled for conditional store instructions */ @@ -271,6 +281,90 @@ static bool need_slot_cancelled(Packet *pkt) return false; } +#ifndef CONFIG_USER_ONLY +static bool sreg_write_to_global(int reg_num) +{ + return reg_num == HEX_SREG_SSR || + reg_num == HEX_SREG_STID || + reg_num == HEX_SREG_IMASK || + reg_num == HEX_SREG_IPENDAD || + reg_num == HEX_SREG_BESTWAIT || + reg_num == HEX_SREG_SCHEDCFG; +} + +static bool has_sreg_write_to_global(Packet const *pkt) +{ + for (int i = 0; i < pkt->num_insns; i++) { + Insn const *insn = &pkt->insn[i]; + uint16_t opcode = insn->opcode; + if (opcode == Y2_tfrsrcr) { + /* Write to a single sreg */ + int reg_num = insn->regno[0]; + if (sreg_write_to_global(reg_num)) { + return true; + } + } else if (opcode == Y4_tfrspcp) { + /* Write to a sreg pair */ + int reg_num = insn->regno[0]; + if (sreg_write_to_global(reg_num)) { + return true; + } + if (sreg_write_to_global(reg_num + 1)) { + return true; + } + } + } + return false; +} +#endif + +static bool pkt_ends_tb(Packet *pkt) +{ + if (pkt->pkt_has_cof) { + return true; + } +#ifndef CONFIG_USER_ONLY + /* System mode instructions that end TLB */ + if (check_for_opcode(pkt, Y2_swi) || + check_for_opcode(pkt, Y2_cswi) || + check_for_opcode(pkt, Y2_ciad) || + check_for_opcode(pkt, Y4_siad) || + check_for_opcode(pkt, Y2_wait) || + check_for_opcode(pkt, Y2_resume) || + check_for_opcode(pkt, Y2_iassignw) || + check_for_opcode(pkt, Y2_setimask) || + check_for_opcode(pkt, Y4_nmi) || + check_for_opcode(pkt, Y2_setprio) || + check_for_opcode(pkt, Y2_start) || + check_for_opcode(pkt, Y2_stop) || + check_for_opcode(pkt, Y2_k0lock) || + check_for_opcode(pkt, Y2_k0unlock) || + check_for_opcode(pkt, Y2_tlblock) || + check_for_opcode(pkt, Y2_tlbunlock) || + check_for_opcode(pkt, Y2_break) || + check_for_opcode(pkt, Y2_isync) || + check_for_opcode(pkt, Y2_syncht) || + check_for_opcode(pkt, Y2_tlbp) || + check_for_opcode(pkt, Y2_tlbw) || + check_for_opcode(pkt, Y5_ctlbw) || + check_for_opcode(pkt, Y5_tlbasidi)) { + return true; + } + + /* + * Check for sreg writes that would end the TB + */ + if (check_for_attrib(pkt, A_IMPLICIT_WRITES_SSR)) { + return true; + } + if (has_sreg_write_to_global(pkt)) { + return true; + } +#endif + return false; +} + + static bool need_next_PC(DisasContext *ctx) { Packet *pkt = ctx->pkt; @@ -426,7 +520,10 @@ static void analyze_packet(DisasContext *ctx) static void gen_start_packet(DisasContext *ctx) { Packet *pkt = ctx->pkt; - target_ulong next_PC = ctx->base.pc_next + pkt->encod_pkt_size_in_bytes; + target_ulong next_PC = (check_for_opcode(pkt, Y2_k0lock) || + check_for_opcode(pkt, Y2_tlblock)) ? + ctx->base.pc_next : + ctx->base.pc_next + pkt->encod_pkt_size_in_bytes; int i; /* Clear out the disassembly context */ @@ -472,6 +569,7 @@ static void gen_start_packet(DisasContext *ctx) tcg_gen_movi_tl(hex_slot_cancelled, 0); } ctx->branch_taken = NULL; + ctx->pkt_ends_tb = pkt_ends_tb(pkt); if (pkt->pkt_has_cof) { ctx->branch_taken = tcg_temp_new(); if (pkt->pkt_has_multi_cof) { @@ -926,7 +1024,7 @@ static void gen_commit_packet(DisasContext *ctx) pkt->vhist_insn->generate(ctx); } - if (pkt->pkt_has_cof) { + if (ctx->pkt_ends_tb || ctx->base.is_jmp == DISAS_NORETURN) { gen_end_tb(ctx); } } -- 2.34.1