}
}
-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
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;
}
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;
}
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 {
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:
/* 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:
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);
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]);
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) {
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);