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