target/hexagon: Add pkt_ends_tb to translation

Reviewed-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
This commit is contained in:
Brian Cain
2026-06-22 15:28:46 -07:00
committed by Brian Cain
parent 49b5f7cc16
commit 5312546b4f
2 changed files with 100 additions and 3 deletions

View File

@@ -270,6 +270,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 */
@@ -283,6 +293,90 @@ static bool need_slot_cancelled(Packet *pkt)
return false;
}
#ifndef CONFIG_USER_ONLY
static bool sreg_write_ends_tb(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_ends_tb(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_ends_tb(reg_num)) {
return true;
}
} else if (opcode == Y4_tfrspcp) {
/* Write to a sreg pair */
int reg_num = insn->regno[0];
if (sreg_write_ends_tb(reg_num)) {
return true;
}
if (sreg_write_ends_tb(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_ends_tb(pkt)) {
return true;
}
#endif
return false;
}
static bool need_next_PC(DisasContext *ctx)
{
/* Check for conditional control flow or HW loop end */
@@ -439,7 +533,11 @@ static void analyze_packet(DisasContext *ctx)
static void gen_start_packet(DisasContext *ctx)
{
target_ulong next_PC = ctx->base.pc_next + ctx->pkt.encod_pkt_size_in_bytes;
Packet *pkt = &ctx->pkt;
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 */
@@ -944,7 +1042,7 @@ static void gen_commit_packet(DisasContext *ctx)
ctx->pkt.vhist_insn->generate(ctx);
}
if (ctx->pkt.pkt_has_cof) {
if (pkt_ends_tb(&ctx->pkt) || ctx->base.is_jmp == DISAS_NORETURN) {
gen_end_tb(ctx);
}
}

View File

@@ -86,7 +86,6 @@ typedef struct DisasContext {
TCGv branch_taken;
TCGv dczero_addr;
bool pcycle_enabled;
bool pkt_ends_tb;
uint32_t num_cycles;
} DisasContext;