freedreno/afuc: Handle xmov modifiers
authorConnor Abbott <cwabbott0@gmail.com>
Mon, 17 Aug 2020 17:44:14 +0000 (19:44 +0200)
committerMarge Bot <eric+marge@anholt.net>
Tue, 18 Aug 2020 16:17:31 +0000 (16:17 +0000)
Although it's kind-of similar to "(rptN)" in the shader ISA, I called it
"xmov" to make it clear that it's completely orthogonal to "(rep)",
although you certainly can use both modifiers on the same instruction.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6368>

src/freedreno/afuc/afuc.h
src/freedreno/afuc/asm.c
src/freedreno/afuc/asm.h
src/freedreno/afuc/disasm.c
src/freedreno/afuc/lexer.l
src/freedreno/afuc/parser.y

index 8233db044026f76e044c5166921b470ebd9e1a72..6ec268e3dcc3c43ed1d8e7c85a7eb824776babc8 100644 (file)
@@ -129,7 +129,8 @@ typedef union PACKED {
        } movi;
        struct PACKED {
                uint32_t alu     : 5;
-               uint32_t pad     : 6;
+               uint32_t pad     : 4;
+               uint32_t xmov    : 2; /* execute eXtra mov's based on $rem */
                uint32_t dst     : 5;
                uint32_t src2    : 5;
                uint32_t src1    : 5;
index a03a89a31fa33621a0a1bcf5ec88b3e933fcd34c..cb11439b9790c8bb6ce074843f3a49a64f12102a 100644 (file)
@@ -170,6 +170,10 @@ static void emit_instructions(int outfd)
                        if (ai->has_immed) {
                                /* MSB overlaps with STORE */
                                assert(ai->tok != T_OP_MSB);
+                               if (ai->xmov) {
+                                       fprintf(stderr, "ALU instruction cannot have immediate and xmov\n");
+                                       exit(1);
+                               }
                                opc = tok2alu(ai->tok);
                                instr.alui.dst = ai->dst;
                                instr.alui.src = ai->src1;
@@ -179,6 +183,7 @@ static void emit_instructions(int outfd)
                                instr.alu.dst  = ai->dst;
                                instr.alu.src1 = ai->src1;
                                instr.alu.src2 = ai->src2;
+                               instr.alu.xmov = ai->xmov;
                                instr.alu.alu = tok2alu(ai->tok);
                        }
                        break;
@@ -186,6 +191,10 @@ static void emit_instructions(int outfd)
                        /* move can either be encoded as movi (ie. move w/ immed) or
                         * an alu instruction
                         */
+                       if ((ai->has_immed || ai->label) && ai->xmov) {
+                               fprintf(stderr, "ALU instruction cannot have immediate and xmov\n");
+                               exit(1);
+                       }
                        if (ai->has_immed) {
                                opc = OPC_MOVI;
                                instr.movi.dst = ai->dst;
@@ -206,6 +215,7 @@ static void emit_instructions(int outfd)
                                instr.alu.dst  = ai->dst;
                                instr.alu.src1 = 0x00;      /* $00 reads-back 0 */
                                instr.alu.src2 = ai->src1;
+                               instr.alu.xmov = ai->xmov;
                                instr.alu.alu = OPC_OR;
                        }
                        break;
index 03fb1508907a5f2c1f2be21930e8dc06418e2266..e0e6033e9e8a60c75683abb5e4c721a9e43ef4bb 100644 (file)
@@ -44,6 +44,7 @@ struct asm_instruction {
        int immed;
        int shift;
        int bit;
+       int xmov;
        uint32_t literal;
        const char *label;
 
index f687058f615edfe77d550e3ca9baf288d98005cb..0e013f59a3a03deddf977b34681e0c100e4d44f0 100644 (file)
@@ -506,6 +506,8 @@ static void disasm(uint32_t *buf, int sizedwords)
 
                        if (rep)
                                printf("(rep)");
+                       if (instr->alu.xmov)
+                               printf("(xmov%d)", instr->alu.xmov);
 
                        /* special case mnemonics:
                         *   reading $00 seems to always yield zero, and so:
@@ -531,10 +533,58 @@ static void disasm(uint32_t *buf, int sizedwords)
                        /* print out unexpected bits: */
                        if (verbose) {
                                if (instr->alu.pad)
-                                       printerr("  (pad=%03x)", instr->alu.pad);
+                                       printerr("  (pad=%01x)", instr->alu.pad);
                                if (instr->alu.src1 && !src1)
                                        printerr("  (src1=%02x)", instr->alu.src1);
                        }
+
+                       /* xmov is a modifier that makes the processor execute up to 3
+                        * extra mov's after the current instruction. Given an ALU
+                        * instruction:
+                        *
+                        * (xmovN) alu $dst, $src1, $src2
+                        *
+                        * In all of the uses in the firmware blob, $dst and $src2 are one
+                        * of the "special" registers $data, $addr, $addr2. I've observed
+                        * that if $dst isn't "special" then it's replaced with $00
+                        * instead of $data, but I haven't checked what happens if $src2
+                        * isn't "special".  Anyway, in the usual case, the HW produces a
+                        * count M = min(N, $rem) and then does the following:
+                        *
+                        * M = 1:
+                        * mov $data, $src2
+                        *
+                        * M = 2:
+                        * mov $data, $src2
+                        * mov $data, $src2
+                        *
+                        * M = 3:
+                        * mov $data, $src2
+                        * mov $dst, $src2 (special case for CP_CONTEXT_REG_BUNCH)
+                        * mov $data, $src2
+                        *
+                        * It seems to be frequently used in combination with (rep) to
+                        * provide a kind of hardware-based loop unrolling, and there's
+                        * even a special case in the ISA to be able to do this with
+                        * CP_CONTEXT_REG_BUNCH. However (rep) isn't required.
+                        *
+                        * This dumps the expected extra instructions, assuming that $rem
+                        * isn't too small.
+                        */
+                       if (verbose && instr->alu.xmov) {
+                               for (int i = 0; i < instr->alu.xmov; i++) {
+                                       printf("\n        ; mov ");
+                                       if (instr->alu.dst < 0x1d)
+                                               printf("$00");
+                                       else if (instr->alu.xmov == 3 && i == 1)
+                                               print_dst(instr->alu.dst);
+                                       else
+                                               printf("$data");
+                                       printf(", ");
+                                       print_src(instr->alu.src2);
+                               }
+                       }
+
                        break;
                }
                case OPC_CWRITE6:
index 6b1ec07caded76bf073699eea89a2be26b08b369..8c3113d1c16f6f4e569f5b55ba89c98c734faaac 100644 (file)
@@ -86,6 +86,7 @@ extern YYSTYPE yylval;
 "setsecure"                      return TOKEN(T_OP_SETSECURE);
 "<<"                              return TOKEN(T_LSHIFT);
 "(rep)"                           return TOKEN(T_REP);
+"(xmov"[1-3]")"                          yylval.num = yytext[5] - '\0'; return T_XMOV;
 
 ","                               return ',';
 "["                               return '[';
index 657524a1f6ccfa54f301b8f36be3063b259f3060..5a8164e59fe224f51b8a0beb4293694cc2f50aeb 100644 (file)
@@ -161,6 +161,7 @@ label(const char *str)
 %token <tok> T_OP_SETSECURE
 %token <tok> T_LSHIFT
 %token <tok> T_REP
+%token <num> T_XMOV
 
 %type <num> reg
 %type <num> immediate
@@ -182,6 +183,7 @@ instr_or_label:    instr_r
 
 /* instructions that can optionally have (rep) flag: */
 instr_r:           alu_instr
+|                  T_XMOV alu_instr { instr->xmov = $1; }
 |                  config_instr
 
 /* need to special case: