Added few more stubs so that control reaches to DestroyDevice().
[mesa.git] / src / freedreno / afuc / disasm.c
index 2a2571074b990474bf051a247aa723af83c63f13..0e013f59a3a03deddf977b34681e0c100e4d44f0 100644 (file)
@@ -158,20 +158,9 @@ static void print_alu_name(afuc_opc opc, uint32_t instr)
        }
 }
 
-static char *getpm4(uint32_t id)
+static const char *getpm4(uint32_t id)
 {
-       struct rnnenum *en = rnn_findenum(ctx->db, "adreno_pm4_type3_packets");
-       if (en) {
-               int i;
-               for (i = 0; i < en->valsnum; i++)
-                       if (en->vals[i]->valvalid && en->vals[i]->value == id) {
-                               const char *v = en->vals[i]->varinfo.variantsstr;
-                               if (v && !strstr(v, variant))
-                                       continue;
-                               return en->vals[i]->name;
-                       }
-       }
-       return NULL;
+       return rnndec_decode_enum(ctx, "adreno_pm4_type3_packets", id);
 }
 
 static inline unsigned
@@ -253,7 +242,7 @@ label_name(uint32_t offset, bool allow_jt)
                        int j;
                        for (j = 0; j < jump_labels[lidx].num_jump_labels; j++) {
                                uint32_t jump_label = jump_labels[lidx].jump_labels[j];
-                               char *str = getpm4(jump_label);
+                               const char *str = getpm4(jump_label);
                                if (str)
                                        return str;
                        }
@@ -349,6 +338,10 @@ static void disasm(uint32_t *buf, int sizedwords)
                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;
                }
@@ -373,7 +366,7 @@ static void disasm(uint32_t *buf, int sizedwords)
                        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];
-                               char *name = getpm4(jump_label);
+                               const char *name = getpm4(jump_label);
                                if (name) {
                                        printlbl("%s", name);
                                } else {
@@ -513,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:
@@ -538,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:
@@ -663,9 +706,12 @@ static void disasm(uint32_t *buf, int sizedwords)
                        break;
                case OPC_RET:
                        assert(!rep);
-                       if (instr->pad)
+                       if (instr->ret.pad)
                                printf("[%08x]  ; ", instrs[i]);
-                       printf("ret");
+                       if (instr->ret.interrupt)
+                               printf("iret");
+                       else
+                               printf("ret");
                        break;
                case OPC_WIN:
                        assert(!rep);
@@ -678,9 +724,22 @@ static void disasm(uint32_t *buf, int sizedwords)
                case OPC_PREEMPTLEAVE6:
                        if (gpuver < 6) {
                                printf("[%08x]  ; op38", instrs[i]);
+                       } else {
+                               printf("preemptleave #");
+                               printlbl("%s", label_name(instr->call.uoff, true));
                        }
-                       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[i]);
+                       printf("setsecure $02, #");
+                       printlbl("%s", label_name(i + 3, true));
                        break;
                default:
                        printerr("[%08x]", instrs[i]);
@@ -701,7 +760,7 @@ static void disasm(uint32_t *buf, int sizedwords)
                for (i = 0; i < 0x7f; i++) {
                        int n = i;// + CP_NOP;
                        uint32_t offset = jmptbl[i];
-                       char *name = getpm4(n);
+                       const char *name = getpm4(n);
                        printf("%3d %02x: ", n, n);
                        printf("%04x", offset);
                        if (name) {
@@ -823,6 +882,8 @@ int main(int argc, char **argv)
        dom[1] = rnn_finddomain(db, "AXXX");
        control_regs = rnn_finddomain(db, control_reg_name);
 
+       rnndec_varadd(ctx, "chip", variant);
+
        buf = (uint32_t *)readfile(file, &sz);
 
        printf("; Disassembling microcode: %s\n", file);