> -----Original Message-----
> From: Matheus Bernardino (QUIC) <quic_mathb...@quicinc.com>
> Sent: Friday, April 26, 2024 1:16 PM
> To: qemu-devel@nongnu.org
> Cc: Brian Cain <bc...@quicinc.com>; Sid Manning <sidn...@quicinc.com>;
> a...@rev.ng; a...@rev.ng; ltaylorsimp...@gmail.com
> Subject: [PATCH] Hexagon: add PC alignment check and exception
>
> The Hexagon Programmer's Reference Manual says that the exception 0x1e
> should be raised upon an unaligned program counter. Let's implement that
> and also add tests for both the most common case as well as packets with
> multiple change-of-flow instructions.
>
> Signed-off-by: Matheus Tavares Bernardino <quic_mathb...@quicinc.com>
Reviewed-by: Brian Cain <bc...@quicinc.com>
> ---
> target/hexagon/cpu_bits.h | 1 +
> target/hexagon/translate.h | 2 ++
> target/hexagon/genptr.c | 21 ++++++++++++++++-----
> target/hexagon/translate.c | 2 +-
> tests/tcg/hexagon/Makefile.target | 13 +++++++++++++
> tests/tcg/hexagon/unaligned_pc.S | 10 ++++++++++
> tests/tcg/hexagon/unaligned_pc_multi_cof.S | 13 +++++++++++++
> 7 files changed, 56 insertions(+), 6 deletions(-)
> create mode 100644 tests/tcg/hexagon/unaligned_pc.S
> create mode 100644 tests/tcg/hexagon/unaligned_pc_multi_cof.S
>
> diff --git a/target/hexagon/cpu_bits.h b/target/hexagon/cpu_bits.h
> index 96fef71729..d6900c8bda 100644
> --- a/target/hexagon/cpu_bits.h
> +++ b/target/hexagon/cpu_bits.h
> @@ -23,6 +23,7 @@
> #define HEX_EXCP_FETCH_NO_UPAGE 0x012
> #define HEX_EXCP_INVALID_PACKET 0x015
> #define HEX_EXCP_INVALID_OPCODE 0x015
> +#define HEX_EXCP_PC_NOT_ALIGNED 0x01e
> #define HEX_EXCP_PRIV_NO_UREAD 0x024
> #define HEX_EXCP_PRIV_NO_UWRITE 0x025
>
> diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h
> index 4dd59c6726..daf11eb584 100644
> --- a/target/hexagon/translate.h
> +++ b/target/hexagon/translate.h
> @@ -75,6 +75,8 @@ typedef struct DisasContext {
> TCGv dczero_addr;
> } DisasContext;
>
> +void gen_exception_end_tb(DisasContext *ctx, int excp);
> +
> static inline void ctx_log_pred_write(DisasContext *ctx, int pnum)
> {
> if (!test_bit(pnum, ctx->pregs_written)) {
> diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
> index dbae6c570a..c96edd9379 100644
> --- a/target/hexagon/genptr.c
> +++ b/target/hexagon/genptr.c
> @@ -473,6 +473,7 @@ static void gen_write_new_pc_addr(DisasContext
> *ctx, TCGv addr,
> TCGCond cond, TCGv pred)
> {
> TCGLabel *pred_false = NULL;
> + TCGLabel *branch_taken = NULL;
> if (cond != TCG_COND_ALWAYS) {
> pred_false = gen_new_label();
> tcg_gen_brcondi_tl(cond, pred, 0, pred_false);
> @@ -480,12 +481,22 @@ static void gen_write_new_pc_addr(DisasContext
> *ctx, TCGv addr,
>
> if (ctx->pkt->pkt_has_multi_cof) {
> /* If there are multiple branches in a packet, ignore the second one
> */
> - tcg_gen_movcond_tl(TCG_COND_NE, hex_gpr[HEX_REG_PC],
> - ctx->branch_taken, tcg_constant_tl(0),
> - hex_gpr[HEX_REG_PC], addr);
> + branch_taken = gen_new_label();
> + tcg_gen_brcondi_tl(TCG_COND_NE, ctx->branch_taken, 0,
> branch_taken);
> tcg_gen_movi_tl(ctx->branch_taken, 1);
> - } else {
> - tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], addr);
> + }
> +
> + TCGLabel *pc_aligned = gen_new_label();
> + TCGv pc_remainder = tcg_temp_new();
> + tcg_gen_andi_tl(pc_remainder, addr, PCALIGN_MASK);
> + tcg_gen_brcondi_tl(TCG_COND_EQ, pc_remainder, 0, pc_aligned);
> + gen_exception_end_tb(ctx, HEX_EXCP_PC_NOT_ALIGNED);
> + gen_set_label(pc_aligned);
> +
> + tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], addr);
> +
> + if (ctx->pkt->pkt_has_multi_cof) {
> + gen_set_label(branch_taken);
> }
>
> if (cond != TCG_COND_ALWAYS) {
> diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
> index f163eefe97..e6ee63a53e 100644
> --- a/target/hexagon/translate.c
> +++ b/target/hexagon/translate.c
> @@ -185,7 +185,7 @@ static void gen_end_tb(DisasContext *ctx)
> ctx->base.is_jmp = DISAS_NORETURN;
> }
>
> -static void gen_exception_end_tb(DisasContext *ctx, int excp)
> +void gen_exception_end_tb(DisasContext *ctx, int excp)
> {
> gen_exec_counters(ctx);
> tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->next_PC);
> diff --git a/tests/tcg/hexagon/Makefile.target
> b/tests/tcg/hexagon/Makefile.target
> index f839b2c0d5..02d7fff34c 100644
> --- a/tests/tcg/hexagon/Makefile.target
> +++ b/tests/tcg/hexagon/Makefile.target
> @@ -51,6 +51,19 @@ HEX_TESTS += scatter_gather
> HEX_TESTS += hvx_misc
> HEX_TESTS += hvx_histogram
> HEX_TESTS += invalid-slots
> +HEX_TESTS += unaligned_pc
> +HEX_TESTS += unaligned_pc_multi_cof
> +
> +run-unaligned_pc: unaligned_pc
> +run-unaligned_pc_multi_cof: unaligned_pc_multi_cof
> +run-unaligned_pc run-unaligned_pc_multi_cof:
> + $(call run-test, $<, $(QEMU) $< 2> $<.stderr,"$< on
> $(TARGET_NAME)"); \
> + if [ $$? -ne 1 ] ; then \
> + return 1; \
> + fi
> + $(call quiet-command, \
> + grep -q "exception 0x1e" $<.stderr, \
> + "GREP", "exception 0x1e");
>
> run-and-check-exception = $(call run-test,$2,$3 2>$2.stderr; \
> test $$? -eq 1 && grep -q "exception $(strip $1)" $2.stderr)
> diff --git a/tests/tcg/hexagon/unaligned_pc.S
> b/tests/tcg/hexagon/unaligned_pc.S
> new file mode 100644
> index 0000000000..39d6b2060b
> --- /dev/null
> +++ b/tests/tcg/hexagon/unaligned_pc.S
> @@ -0,0 +1,10 @@
> +test:
> + allocframe(#0x8)
> + r0 = #0xffffffff
> + framekey = r0
> + dealloc_return
> +
> +.global _start
> +_start:
> + call test
> + jump pass
> diff --git a/tests/tcg/hexagon/unaligned_pc_multi_cof.S
> b/tests/tcg/hexagon/unaligned_pc_multi_cof.S
> new file mode 100644
> index 0000000000..a83e248ece
> --- /dev/null
> +++ b/tests/tcg/hexagon/unaligned_pc_multi_cof.S
> @@ -0,0 +1,13 @@
> +.org 0x3
> +test:
> + nop
> + jumpr r31
> +
> +.global _start
> +_start:
> + p0 = cmp.eq(r0, r0)
> + {
> + if (p0) jump test
> + jump pass
> + }
> + jump pass
> --
> 2.37.2