Mesa (main): freedreno/afuc: Split out instruction decode helper

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Tue Jun 1 00:30:14 UTC 2021


Module: Mesa
Branch: main
Commit: d367d84d8765d75726279ece43f481673bf5a454
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=d367d84d8765d75726279ece43f481673bf5a454

Author: Rob Clark <robdclark at chromium.org>
Date:   Sun May 16 12:15:31 2021 -0700

freedreno/afuc: Split out instruction decode helper

Split the giant switch/decode out into a helper function so that we can
re-use it for emulator mode.

Signed-off-by: Rob Clark <robdclark at chromium.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10944>

---

 src/freedreno/afuc/disasm.c | 806 ++++++++++++++++++++++----------------------
 1 file changed, 406 insertions(+), 400 deletions(-)

diff --git a/src/freedreno/afuc/disasm.c b/src/freedreno/afuc/disasm.c
index 14e9d2f4e9e..cefb60222a4 100644
--- a/src/freedreno/afuc/disasm.c
+++ b/src/freedreno/afuc/disasm.c
@@ -301,456 +301,462 @@ print_control_reg(uint32_t id)
 }
 
 static void
-disasm(uint32_t *buf, int sizedwords)
+disasm_instr(uint32_t *instrs, unsigned pc)
 {
-   uint32_t *instrs = buf;
-   const int jmptbl_start = instrs[1] & 0xffff;
-   uint32_t *jmptbl = &buf[jmptbl_start];
+   int jump_label_idx;
+   afuc_instr *instr = (void *)&instrs[pc];
+   const char *fname, *lname;
    afuc_opc opc;
    bool rep;
-   int i;
 
-   /* parse jumptable: */
-   for (i = 0; i < 0x80; i++) {
-      unsigned offset = jmptbl[i];
-      unsigned n = i; // + CP_NOP;
-      add_jump_table_entry(n, offset);
-   }
+   afuc_get_opc(instr, &opc, &rep);
 
-   /* do a pre-pass to find instructions that are potential branch targets,
-    * and add labels for them:
-    */
-   for (i = 0; i < jmptbl_start; i++) {
-      afuc_instr *instr = (void *)&instrs[i];
-
-      afuc_get_opc(instr, &opc, &rep);
+   lname = label_name(pc, false);
+   fname = fxn_name(pc);
+   jump_label_idx = get_jump_table_entry(pc);
 
-      switch (opc) {
-      case OPC_BRNEI:
-      case OPC_BREQI:
-      case OPC_BRNEB:
-      case OPC_BREQB:
-         label_idx(i + instr->br.ioff, true);
-         break;
-      case OPC_PREEMPTLEAVE6:
-         if (gpuver >= 6)
-            label_idx(instr->call.uoff, true);
-         break;
-      case OPC_CALL:
-         fxn_idx(instr->call.uoff, true);
-         break;
-      case OPC_SETSECURE:
-         /* this implicitly jumps to pc + 3 if successful */
-         label_idx(i + 3, true);
-         break;
-      default:
-         break;
+   if (jump_label_idx >= 0) {
+      int j;
+      printf("\n");
+      for (j = 0; j < jump_labels[jump_label_idx].num_jump_labels; j++) {
+         uint32_t jump_label = jump_labels[jump_label_idx].jump_labels[j];
+         const char *name = getpm4(jump_label);
+         if (name) {
+            printlbl("%s", name);
+         } else {
+            printlbl("UNKN%d", jump_label);
+         }
+         printf(":\n");
       }
    }
 
-   /* print instructions: */
-   for (i = 0; i < jmptbl_start; i++) {
-      int jump_label_idx;
-      afuc_instr *instr = (void *)&instrs[i];
-      const char *fname, *lname;
-      afuc_opc opc;
-      bool rep;
-
-      afuc_get_opc(instr, &opc, &rep);
+   if (fname) {
+      printlbl("%s", fname);
+      printf(":\n");
+   }
 
-      lname = label_name(i, false);
-      fname = fxn_name(i);
-      jump_label_idx = get_jump_table_entry(i);
+   if (lname) {
+      printlbl(" %s", lname);
+      printf(":");
+   } else {
+      printf("      ");
+   }
 
-      if (jump_label_idx >= 0) {
-         int j;
-         printf("\n");
-         for (j = 0; j < jump_labels[jump_label_idx].num_jump_labels; j++) {
-            uint32_t jump_label = jump_labels[jump_label_idx].jump_labels[j];
-            const char *name = getpm4(jump_label);
-            if (name) {
-               printlbl("%s", name);
-            } else {
-               printlbl("UNKN%d", jump_label);
-            }
-            printf(":\n");
-         }
-      }
+   if (verbose) {
+      printf("\t%04x: %08x  ", pc, instrs[pc]);
+   } else {
+      printf("  ");
+   }
 
-      if (fname) {
-         printlbl("%s", fname);
-         printf(":\n");
+   switch (opc) {
+   case OPC_NOP: {
+      /* a6xx changed the default immediate, and apparently 0
+       * is illegal now.
+       */
+      const uint32_t nop = gpuver >= 6 ? 0x1000000 : 0x0;
+      if (instrs[pc] != nop) {
+         printerr("[%08x]", instrs[pc]);
+         printf("  ; ");
       }
+      if (rep)
+         printf("(rep)");
+      printf("nop");
+      print_gpu_reg(instrs[pc]);
 
-      if (lname) {
-         printlbl(" %s", lname);
-         printf(":");
-      } else {
-         printf("      ");
+      break;
+   }
+   case OPC_ADD:
+   case OPC_ADDHI:
+   case OPC_SUB:
+   case OPC_SUBHI:
+   case OPC_AND:
+   case OPC_OR:
+   case OPC_XOR:
+   case OPC_NOT:
+   case OPC_SHL:
+   case OPC_USHR:
+   case OPC_ISHR:
+   case OPC_ROT:
+   case OPC_MUL8:
+   case OPC_MIN:
+   case OPC_MAX:
+   case OPC_CMP: {
+      bool src1 = true;
+
+      if (opc == OPC_NOT)
+         src1 = false;
+
+      if (rep)
+         printf("(rep)");
+
+      print_alu_name(opc, instrs[pc]);
+      print_dst(instr->alui.dst);
+      printf(", ");
+      if (src1) {
+         print_src(instr->alui.src);
+         printf(", ");
       }
+      printf("0x%04x", instr->alui.uimm);
+      print_gpu_reg(instr->alui.uimm);
 
+      /* print out unexpected bits: */
       if (verbose) {
-         printf("\t%04x: %08x  ", i, instrs[i]);
-      } else {
-         printf("  ");
+         if (instr->alui.src && !src1)
+            printerr("  (src=%02x)", instr->alui.src);
       }
 
-      switch (opc) {
-      case OPC_NOP: {
-         /* a6xx changed the default immediate, and apparently 0
-          * is illegal now.
+      break;
+   }
+   case OPC_MOVI: {
+      if (rep)
+         printf("(rep)");
+      printf("mov ");
+      print_dst(instr->movi.dst);
+      printf(", 0x%04x", instr->movi.uimm);
+      if (instr->movi.shift)
+         printf(" << %u", instr->movi.shift);
+
+      /* using mov w/ << 16 is popular way to construct a pkt7
+       * header to send (for ex, from PFP to ME), so check that
+       * case first
+       */
+      if ((instr->movi.shift == 16) &&
+          ((instr->movi.uimm & 0xff00) == 0x7000)) {
+         unsigned opc, p;
+
+         opc = instr->movi.uimm & 0x7f;
+         p = pm4_odd_parity_bit(opc);
+
+         /* So, you'd think that checking the parity bit would be
+          * a good way to rule out false positives, but seems like
+          * ME doesn't really care.. at least it would filter out
+          * things that look like actual legit packets between
+          * PFP and ME..
           */
-         const uint32_t nop = gpuver >= 6 ? 0x1000000 : 0x0;
-         if (instrs[i] != nop) {
-            printerr("[%08x]", instrs[i]);
-            printf("  ; ");
+         if (1 || p == ((instr->movi.uimm >> 7) & 0x1)) {
+            const char *name = getpm4(opc);
+            printf("\t; ");
+            if (name)
+               printlbl("%s", name);
+            else
+               printlbl("UNKN%u", opc);
+            break;
          }
-         if (rep)
-            printf("(rep)");
-         printf("nop");
-         print_gpu_reg(instrs[i]);
-
-         break;
       }
-      case OPC_ADD:
-      case OPC_ADDHI:
-      case OPC_SUB:
-      case OPC_SUBHI:
-      case OPC_AND:
-      case OPC_OR:
-      case OPC_XOR:
-      case OPC_NOT:
-      case OPC_SHL:
-      case OPC_USHR:
-      case OPC_ISHR:
-      case OPC_ROT:
-      case OPC_MUL8:
-      case OPC_MIN:
-      case OPC_MAX:
-      case OPC_CMP: {
-         bool src1 = true;
-
-         if (opc == OPC_NOT)
-            src1 = false;
-
-         if (rep)
-            printf("(rep)");
-
-         print_alu_name(opc, instrs[i]);
-         print_dst(instr->alui.dst);
-         printf(", ");
-         if (src1) {
-            print_src(instr->alui.src);
-            printf(", ");
-         }
-         printf("0x%04x", instr->alui.uimm);
-         print_gpu_reg(instr->alui.uimm);
 
-         /* print out unexpected bits: */
-         if (verbose) {
-            if (instr->alui.src && !src1)
-               printerr("  (src=%02x)", instr->alui.src);
-         }
+      print_gpu_reg(instr->movi.uimm << instr->movi.shift);
 
-         break;
-      }
-      case OPC_MOVI: {
-         if (rep)
-            printf("(rep)");
+      break;
+   }
+   case OPC_ALU: {
+      bool src1 = true;
+
+      if (instr->alu.alu == OPC_NOT || instr->alu.alu == OPC_MSB)
+         src1 = false;
+
+      if (instr->alu.pad)
+         printf("[%08x]  ; ", instrs[pc]);
+
+      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:
+       *      or $dst, $00, $src -> mov $dst, $src
+       *   Maybe add one for negate too, ie.
+       *      sub $dst, $00, $src ???
+       */
+      if ((instr->alu.alu == OPC_OR) && !instr->alu.src1) {
          printf("mov ");
-         print_dst(instr->movi.dst);
-         printf(", 0x%04x", instr->movi.uimm);
-         if (instr->movi.shift)
-            printf(" << %u", instr->movi.shift);
-
-         /* using mov w/ << 16 is popular way to construct a pkt7
-          * header to send (for ex, from PFP to ME), so check that
-          * case first
-          */
-         if ((instr->movi.shift == 16) &&
-             ((instr->movi.uimm & 0xff00) == 0x7000)) {
-            unsigned opc, p;
-
-            opc = instr->movi.uimm & 0x7f;
-            p = pm4_odd_parity_bit(opc);
-
-            /* So, you'd think that checking the parity bit would be
-             * a good way to rule out false positives, but seems like
-             * ME doesn't really care.. at least it would filter out
-             * things that look like actual legit packets between
-             * PFP and ME..
-             */
-            if (1 || p == ((instr->movi.uimm >> 7) & 0x1)) {
-               const char *name = getpm4(opc);
-               printf("\t; ");
-               if (name)
-                  printlbl("%s", name);
-               else
-                  printlbl("UNKN%u", opc);
-               break;
-            }
-         }
-
-         print_gpu_reg(instr->movi.uimm << instr->movi.shift);
-
-         break;
+         src1 = false;
+      } else {
+         print_alu_name(instr->alu.alu, instrs[pc]);
       }
-      case OPC_ALU: {
-         bool src1 = true;
 
-         if (instr->alu.alu == OPC_NOT || instr->alu.alu == OPC_MSB)
-            src1 = false;
+      print_dst(instr->alu.dst);
+      if (src1) {
+         printf(", ");
+         print_src(instr->alu.src1);
+      }
+      printf(", ");
+      print_src(instr->alu.src2);
 
+      /* print out unexpected bits: */
+      if (verbose) {
          if (instr->alu.pad)
-            printf("[%08x]  ; ", instrs[i]);
-
-         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:
-          *      or $dst, $00, $src -> mov $dst, $src
-          *   Maybe add one for negate too, ie.
-          *      sub $dst, $00, $src ???
-          */
-         if ((instr->alu.alu == OPC_OR) && !instr->alu.src1) {
-            printf("mov ");
-            src1 = false;
-         } else {
-            print_alu_name(instr->alu.alu, instrs[i]);
-         }
+            printerr("  (pad=%01x)", instr->alu.pad);
+         if (instr->alu.src1 && !src1)
+            printerr("  (src1=%02x)", instr->alu.src1);
+      }
 
-         print_dst(instr->alu.dst);
-         if (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.src1);
-         }
-         printf(", ");
-         print_src(instr->alu.src2);
-
-         /* print out unexpected bits: */
-         if (verbose) {
-            if (instr->alu.pad)
-               printerr("  (pad=%01x)", instr->alu.pad);
-            if (instr->alu.src1 && !src1)
-               printerr("  (src1=%02x)", instr->alu.src1);
+            print_src(instr->alu.src2);
          }
+      }
 
-         /* 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:
+   case OPC_CREAD6:
+   case OPC_STORE6:
+   case OPC_LOAD6: {
+      if (rep)
+         printf("(rep)");
+
+      bool is_control_reg = true;
+      if (gpuver >= 6) {
+         switch (opc) {
+         case OPC_CWRITE6:
+            printf("cwrite ");
+            break;
+         case OPC_CREAD6:
+            printf("cread ");
+            break;
+         case OPC_STORE6:
+            is_control_reg = false;
+            printf("store ");
+            break;
+         case OPC_LOAD6:
+            is_control_reg = false;
+            printf("load ");
+            break;
+         default:
+            assert(!"unreachable");
+         }
+      } else {
+         switch (opc) {
+         case OPC_CWRITE5:
+            printf("cwrite ");
+            break;
+         case OPC_CREAD5:
+            printf("cread ");
+            break;
+         default:
+            fprintf(stderr, "A6xx control opcode on A5xx?\n");
+            exit(1);
          }
-
-         break;
       }
-      case OPC_CWRITE6:
-      case OPC_CREAD6:
-      case OPC_STORE6:
-      case OPC_LOAD6: {
-         if (rep)
-            printf("(rep)");
-
-         bool is_control_reg = true;
-         if (gpuver >= 6) {
-            switch (opc) {
-            case OPC_CWRITE6:
-               printf("cwrite ");
-               break;
-            case OPC_CREAD6:
-               printf("cread ");
-               break;
-            case OPC_STORE6:
-               is_control_reg = false;
-               printf("store ");
-               break;
-            case OPC_LOAD6:
-               is_control_reg = false;
-               printf("load ");
-               break;
-            default:
-               assert(!"unreachable");
-            }
+
+      print_src(instr->control.src1);
+      printf(", [");
+      print_src(instr->control.src2);
+      printf(" + ");
+      if (is_control_reg && instr->control.flags != 0x4)
+         print_control_reg(instr->control.uimm);
+      else
+         printf("0x%03x", instr->control.uimm);
+      printf("], 0x%x", instr->control.flags);
+      break;
+   }
+   case OPC_BRNEI:
+   case OPC_BREQI:
+   case OPC_BRNEB:
+   case OPC_BREQB: {
+      unsigned off = pc + instr->br.ioff;
+
+      assert(!rep);
+
+      /* Since $00 reads back zero, it can be used as src for
+       * unconditional branches.  (This only really makes sense
+       * for the BREQB.. or possible BRNEI if imm==0.)
+       *
+       * If bit=0 then branch is taken if *all* bits are zero.
+       * Otherwise it is taken if bit (bit-1) is clear.
+       *
+       * Note the instruction after a jump/branch is executed
+       * regardless of whether branch is taken, so use nop or
+       * take that into account in code.
+       */
+      if (instr->br.src || (opc != OPC_BRNEB)) {
+         bool immed = false;
+
+         if (opc == OPC_BRNEI) {
+            printf("brne ");
+            immed = true;
+         } else if (opc == OPC_BREQI) {
+            printf("breq ");
+            immed = true;
+         } else if (opc == OPC_BRNEB) {
+            printf("brne ");
+         } else if (opc == OPC_BREQB) {
+            printf("breq ");
+         }
+         print_src(instr->br.src);
+         if (immed) {
+            printf(", 0x%x,", instr->br.bit_or_imm);
          } else {
-            switch (opc) {
-            case OPC_CWRITE5:
-               printf("cwrite ");
-               break;
-            case OPC_CREAD5:
-               printf("cread ");
-               break;
-            default:
-               fprintf(stderr, "A6xx control opcode on A5xx?\n");
-               exit(1);
-            }
+            printf(", b%u,", instr->br.bit_or_imm);
+         }
+      } else {
+         printf("jump");
+         if (verbose && instr->br.bit_or_imm) {
+            printerr("  (src=%03x, bit=%03x) ", instr->br.src,
+                     instr->br.bit_or_imm);
          }
+      }
 
-         print_src(instr->control.src1);
-         printf(", [");
-         print_src(instr->control.src2);
-         printf(" + ");
-         if (is_control_reg && instr->control.flags != 0x4)
-            print_control_reg(instr->control.uimm);
-         else
-            printf("0x%03x", instr->control.uimm);
-         printf("], 0x%x", instr->control.flags);
-         break;
+      printf(" #");
+      printlbl("%s", label_name(off, true));
+      if (verbose)
+         printf(" (#%d, %04x)", instr->br.ioff, off);
+      break;
+   }
+   case OPC_CALL:
+      assert(!rep);
+      printf("call #");
+      printlbl("%s", fxn_name(instr->call.uoff));
+      if (verbose) {
+         printf(" (%04x)", instr->call.uoff);
+         if (instr->br.bit_or_imm || instr->br.src) {
+            printerr("  (src=%03x, bit=%03x) ", instr->br.src,
+                     instr->br.bit_or_imm);
+         }
+      }
+      break;
+   case OPC_RET:
+      assert(!rep);
+      if (instr->ret.pad)
+         printf("[%08x]  ; ", instrs[pc]);
+      if (instr->ret.interrupt)
+         printf("iret");
+      else
+         printf("ret");
+      break;
+   case OPC_WIN:
+      assert(!rep);
+      if (instr->waitin.pad)
+         printf("[%08x]  ; ", instrs[pc]);
+      printf("waitin");
+      if (verbose && instr->waitin.pad)
+         printerr("  (pad=%x)", instr->waitin.pad);
+      break;
+   case OPC_PREEMPTLEAVE6:
+      if (gpuver < 6) {
+         printf("[%08x]  ; op38", instrs[pc]);
+      } else {
+         printf("preemptleave #");
+         printlbl("%s", label_name(instr->call.uoff, true));
       }
+      break;
+   case OPC_SETSECURE:
+      /* Note: This seems to implicitly read the secure/not-secure state
+       * to set from the low bit of $02, and implicitly jumps to pc + 3
+       * (i.e. skipping the next two instructions) if it succeeds. We
+       * print these implicit parameters to make reading the disassembly
+       * easier.
+       */
+      if (instr->pad)
+         printf("[%08x]  ; ", instrs[pc]);
+      printf("setsecure $02, #");
+      printlbl("%s", label_name(pc + 3, true));
+      break;
+   default:
+      printerr("[%08x]", instrs[pc]);
+      printf("  ; op%02x ", opc);
+      print_dst(instr->alui.dst);
+      printf(", ");
+      print_src(instr->alui.src);
+      print_gpu_reg(instrs[pc] & 0xffff);
+      break;
+   }
+   printf("\n");
+}
+
+static void
+disasm(uint32_t *buf, int sizedwords)
+{
+   uint32_t *instrs = buf;
+   const int jmptbl_start = instrs[1] & 0xffff;
+   uint32_t *jmptbl = &buf[jmptbl_start];
+   afuc_opc opc;
+   bool rep;
+   int i;
+
+   /* parse jumptable: */
+   for (i = 0; i < 0x80; i++) {
+      unsigned offset = jmptbl[i];
+      unsigned n = i; // + CP_NOP;
+      add_jump_table_entry(n, offset);
+   }
+
+   /* do a pre-pass to find instructions that are potential branch targets,
+    * and add labels for them:
+    */
+   for (i = 0; i < jmptbl_start; i++) {
+      afuc_instr *instr = (void *)&instrs[i];
+
+      afuc_get_opc(instr, &opc, &rep);
+
+      switch (opc) {
       case OPC_BRNEI:
       case OPC_BREQI:
       case OPC_BRNEB:
-      case OPC_BREQB: {
-         unsigned off = i + instr->br.ioff;
-
-         assert(!rep);
-
-         /* Since $00 reads back zero, it can be used as src for
-          * unconditional branches.  (This only really makes sense
-          * for the BREQB.. or possible BRNEI if imm==0.)
-          *
-          * If bit=0 then branch is taken if *all* bits are zero.
-          * Otherwise it is taken if bit (bit-1) is clear.
-          *
-          * Note the instruction after a jump/branch is executed
-          * regardless of whether branch is taken, so use nop or
-          * take that into account in code.
-          */
-         if (instr->br.src || (opc != OPC_BRNEB)) {
-            bool immed = false;
-
-            if (opc == OPC_BRNEI) {
-               printf("brne ");
-               immed = true;
-            } else if (opc == OPC_BREQI) {
-               printf("breq ");
-               immed = true;
-            } else if (opc == OPC_BRNEB) {
-               printf("brne ");
-            } else if (opc == OPC_BREQB) {
-               printf("breq ");
-            }
-            print_src(instr->br.src);
-            if (immed) {
-               printf(", 0x%x,", instr->br.bit_or_imm);
-            } else {
-               printf(", b%u,", instr->br.bit_or_imm);
-            }
-         } else {
-            printf("jump");
-            if (verbose && instr->br.bit_or_imm) {
-               printerr("  (src=%03x, bit=%03x) ", instr->br.src,
-                        instr->br.bit_or_imm);
-            }
-         }
-
-         printf(" #");
-         printlbl("%s", label_name(off, true));
-         if (verbose)
-            printf(" (#%d, %04x)", instr->br.ioff, off);
-         break;
-      }
-      case OPC_CALL:
-         assert(!rep);
-         printf("call #");
-         printlbl("%s", fxn_name(instr->call.uoff));
-         if (verbose) {
-            printf(" (%04x)", instr->call.uoff);
-            if (instr->br.bit_or_imm || instr->br.src) {
-               printerr("  (src=%03x, bit=%03x) ", instr->br.src,
-                        instr->br.bit_or_imm);
-            }
-         }
-         break;
-      case OPC_RET:
-         assert(!rep);
-         if (instr->ret.pad)
-            printf("[%08x]  ; ", instrs[i]);
-         if (instr->ret.interrupt)
-            printf("iret");
-         else
-            printf("ret");
-         break;
-      case OPC_WIN:
-         assert(!rep);
-         if (instr->waitin.pad)
-            printf("[%08x]  ; ", instrs[i]);
-         printf("waitin");
-         if (verbose && instr->waitin.pad)
-            printerr("  (pad=%x)", instr->waitin.pad);
+      case OPC_BREQB:
+         label_idx(i + instr->br.ioff, true);
          break;
       case OPC_PREEMPTLEAVE6:
-         if (gpuver < 6) {
-            printf("[%08x]  ; op38", instrs[i]);
-         } else {
-            printf("preemptleave #");
-            printlbl("%s", label_name(instr->call.uoff, true));
-         }
+         if (gpuver >= 6)
+            label_idx(instr->call.uoff, true);
+         break;
+      case OPC_CALL:
+         fxn_idx(instr->call.uoff, true);
          break;
       case OPC_SETSECURE:
-         /* Note: This seems to implicitly read the secure/not-secure state
-          * to set from the low bit of $02, and implicitly jumps to pc + 3
-          * (i.e. skipping the next two instructions) if it succeeds. We
-          * print these implicit parameters to make reading the disassembly
-          * easier.
-          */
-         if (instr->pad)
-            printf("[%08x]  ; ", instrs[i]);
-         printf("setsecure $02, #");
-         printlbl("%s", label_name(i + 3, true));
+         /* this implicitly jumps to pc + 3 if successful */
+         label_idx(i + 3, true);
          break;
       default:
-         printerr("[%08x]", instrs[i]);
-         printf("  ; op%02x ", opc);
-         print_dst(instr->alui.dst);
-         printf(", ");
-         print_src(instr->alui.src);
-         print_gpu_reg(instrs[i] & 0xffff);
          break;
       }
-      printf("\n");
+   }
+
+   /* print instructions: */
+   for (i = 0; i < jmptbl_start; i++) {
+      disasm_instr(instrs, i);
    }
 
    /* print jumptable: */



More information about the mesa-commit mailing list