diff --git a/src/freedreno/afuc/asm.c b/src/freedreno/afuc/asm.c index 8c86fce061c..92bac423846 100644 --- a/src/freedreno/afuc/asm.c +++ b/src/freedreno/afuc/asm.c @@ -123,6 +123,14 @@ decl_jumptbl(void) instr_offset += 0x80; } +void +align_instr(unsigned alignment) +{ + while (instr_offset % (alignment / 4) != 0) { + next_instr(OPC_NOP); + } +} + static int resolve_label(const char *str) { diff --git a/src/freedreno/afuc/asm.h b/src/freedreno/afuc/asm.h index ece309c19ab..0b5b8a01735 100644 --- a/src/freedreno/afuc/asm.h +++ b/src/freedreno/afuc/asm.h @@ -38,6 +38,7 @@ struct asm_label { struct afuc_instr *next_instr(afuc_opc opc); void decl_label(const char *str); void decl_jumptbl(void); +void align_instr(unsigned alignment); static inline uint32_t parse_reg(const char *str) diff --git a/src/freedreno/afuc/disasm.c b/src/freedreno/afuc/disasm.c index 13dd2136ae4..799d4cad438 100644 --- a/src/freedreno/afuc/disasm.c +++ b/src/freedreno/afuc/disasm.c @@ -334,6 +334,15 @@ disasm(struct emu *emu) /* print jump table */ if (jumptbl_offset != ~0) { + if (gpuver >= 7) { + /* The BV/LPAC microcode must be aligned to 32 bytes. On a7xx, by + * convention the firmware aligns the jumptable preceding it instead + * of the microcode itself, with nop instructions. Insert this + * directive to make sure that it stays aligned when reassembling + * even if the user modifies the BR microcode. + */ + printf(".align 32\n"); + } printf("jumptbl:\n"); printf(".jumptbl\n"); @@ -367,6 +376,7 @@ disasm(struct emu *emu) isa_disasm(emu->instrs, MIN2(sizedwords, jumptbl_offset) * 4, stdout, &options); if (jumptbl_offset != ~0) { + printf(".align 32\n"); printf("jumptbl:\n"); printf(".jumptbl\n"); if (jumptbl_offset + ARRAY_SIZE(emu->jmptbl) != sizedwords) { diff --git a/src/freedreno/afuc/lexer.l b/src/freedreno/afuc/lexer.l index ba227044c64..9adf8741f5f 100644 --- a/src/freedreno/afuc/lexer.l +++ b/src/freedreno/afuc/lexer.l @@ -98,6 +98,7 @@ extern YYSTYPE yylval; "(sds"[1-3]")" yylval.num = yytext[4] - '0'; return T_SDS; "(peek)" return TOKEN(T_PEEK); +".align" return TOKEN(T_ALIGN); ".jumptbl" return TOKEN(T_JUMPTBL); "," return ','; diff --git a/src/freedreno/afuc/parser.y b/src/freedreno/afuc/parser.y index 1f9235d7463..fbba055319a 100644 --- a/src/freedreno/afuc/parser.y +++ b/src/freedreno/afuc/parser.y @@ -173,6 +173,7 @@ label(const char *str) %token T_XMOV %token T_SDS +%token T_ALIGN %token T_JUMPTBL %type reg @@ -194,6 +195,7 @@ instr_or_label: instr_r | branch_instr | other_instr | T_LABEL_DECL { decl_label($1); } +| T_ALIGN immediate { align_instr($2); } | T_JUMPTBL { decl_jumptbl(); } xmov: T_XMOV { $$ = $1; }