switch (_OPC(6, cat6->opc)) {
case OPC_PREFETCH:
+ break;
case OPC_RESINFO:
+ printf(".%dd", cat6->ldgb.d + 1);
break;
case OPC_LDGB:
printf(".%s", cat6->ldgb.typed ? "typed" : "untyped");
printf(".%d", cat6->ldgb.type_size + 1);
break;
case OPC_STGB:
+ case OPC_STIB:
printf(".%s", cat6->stgb.typed ? "typed" : "untyped");
printf(".%dd", cat6->stgb.d + 1);
printf(".%s", type[cat6->type]);
case OPC_ATOMIC_OR:
case OPC_ATOMIC_XOR:
ss = cat6->g ? 'g' : 'l';
- printf(".%c", ss);
+ printf(".%s", cat6->ldgb.typed ? "typed" : "untyped");
+ printf(".%dd", cat6->ldgb.d + 1);
printf(".%s", type[cat6->type]);
+ printf(".%d", cat6->ldgb.type_size + 1);
+ printf(".%c", ss);
break;
default:
dst.im = cat6->g && !cat6->dst_off;
break;
}
- if (_OPC(6, cat6->opc) == OPC_STGB) {
+ if ((_OPC(6, cat6->opc) == OPC_STGB) || (_OPC(6, cat6->opc) == OPC_STIB)) {
struct reginfo src3;
memset(&src3, 0, sizeof(src3));
return;
}
- if ((_OPC(6, cat6->opc) == OPC_LDGB) || is_atomic(_OPC(6, cat6->opc))) {
+ if (is_atomic(_OPC(6, cat6->opc))) {
src1.reg = (reg_t)(cat6->ldgb.src1);
src1.im = cat6->ldgb.src1_im;
print_src(&dst);
printf(", ");
- printf("g[%u], ", cat6->ldgb.src_ssbo);
- print_src(&src1);
- printf(", ");
- print_src(&src2);
-
- if (is_atomic(_OPC(6, cat6->opc))) {
+ if (ss == 'g') {
struct reginfo src3;
memset(&src3, 0, sizeof(src3));
+
src3.reg = (reg_t)(cat6->ldgb.src3);
src3.full = true;
+ /* For images, the ".typed" variant is used and src2 is
+ * the ivecN coordinates, ie ivec2 for 2d.
+ *
+ * For SSBOs, the ".untyped" variant is used and src2 is
+ * a simple dword offset.. src3 appears to be
+ * uvec2(offset * 4, 0). Not sure the point of that.
+ */
+
+ printf("g[%u], ", cat6->ldgb.src_ssbo);
+ print_src(&src1); /* value */
printf(", ");
- print_src(&src3);
+ print_src(&src2); /* offset/coords */
+ printf(", ");
+ print_src(&src3); /* 64b byte offset.. */
+
+ if (debug & PRINT_VERBOSE) {
+ printf(" (pad0=%x, pad3=%x, mustbe0=%x)", cat6->ldgb.pad0,
+ cat6->ldgb.pad3, cat6->ldgb.mustbe0);
+ }
+ } else { /* ss == 'l' */
+ printf("l[");
+ print_src(&src1); /* simple byte offset */
+ printf("], ");
+ print_src(&src2); /* value */
+
+ if (debug & PRINT_VERBOSE) {
+ printf(" (src3=%x, pad0=%x, pad3=%x, mustbe0=%x)",
+ cat6->ldgb.src3, cat6->ldgb.pad0,
+ cat6->ldgb.pad3, cat6->ldgb.mustbe0);
+ }
}
+ return;
+ } else if (_OPC(6, cat6->opc) == OPC_RESINFO) {
+ dst.reg = (reg_t)(cat6->ldgb.dst);
+
+ print_src(&dst);
+ printf(", ");
+ printf("g[%u]", cat6->ldgb.src_ssbo);
+
+ return;
+ } else if (_OPC(6, cat6->opc) == OPC_LDGB) {
+
+ src1.reg = (reg_t)(cat6->ldgb.src1);
+ src1.im = cat6->ldgb.src1_im;
+ src2.reg = (reg_t)(cat6->ldgb.src2);
+ src2.im = cat6->ldgb.src2_im;
+ dst.reg = (reg_t)(cat6->ldgb.dst);
+
+ print_src(&dst);
+ printf(", ");
+ printf("g[%u], ", cat6->ldgb.src_ssbo);
+ print_src(&src1);
+ printf(", ");
+ print_src(&src2);
+
if (debug & PRINT_VERBOSE)
printf(" (pad0=%x, pad3=%x, mustbe0=%x)", cat6->ldgb.pad0, cat6->ldgb.pad3, cat6->ldgb.mustbe0);
uint32_t pad0 : 15;
} instr_cat6d_t;
-/* ldgb and atomics.. atomics use 3rd src and pad0=1, pad3=3. For
- * ldgb pad0=0, pad3=2
+/* ldgb and atomics..
+ *
+ * ldgb: pad0=0, pad3=1
+ * atomic .g: pad0=1, pad3=1
+ * .l: pad0=1, pad3=0
*/
typedef struct PACKED {
/* dword0: */
uint32_t mustbe0 : 1;
uint32_t src_ssbo : 8;
uint32_t pad2 : 3; // type
- uint32_t pad3 : 2;
+ uint32_t g : 1;
+ uint32_t pad3 : 1;
uint32_t pad4 : 10; // opc/jmp_tgt/sync/opc_cat
} instr_cat6ldgb_t;
}
}
+static inline bool is_ssbo(opc_t opc)
+{
+ switch (opc) {
+ case OPC_RESFMT:
+ case OPC_RESINFO:
+ case OPC_LDGB:
+ case OPC_STGB:
+ case OPC_STIB:
+ return true;
+ default:
+ return false;
+ }
+}
+
#endif /* INSTR_A3XX_H_ */
src2 = (instr->regs_count >= 3) ? instr->regs[2] : NULL;
}
-
/* TODO we need a more comprehensive list about which instructions
* can be encoded which way. Or possibly use IR3_INSTR_0 flag to
* indicate to use the src_off encoding even if offset is zero
* (but then what to do about dst_off?)
*/
- if ((instr->opc == OPC_LDGB) || is_atomic(instr->opc)) {
+ if (is_atomic(instr->opc)) {
+ instr_cat6ldgb_t *ldgb = ptr;
+
+ /* maybe these two bits both determine the instruction encoding? */
+ cat6->src_off = false;
+
+ ldgb->d = instr->cat6.d - 1;
+ ldgb->typed = instr->cat6.typed;
+ ldgb->type_size = instr->cat6.iim_val - 1;
+
+ ldgb->dst = reg(dst, info, instr->repeat, IR3_REG_R | IR3_REG_HALF);
+
+ if (ldgb->g) {
+ struct ir3_register *src3 = instr->regs[3];
+ struct ir3_register *src4 = instr->regs[4];
+
+ /* first src is src_ssbo: */
+ iassert(src1->flags & IR3_REG_IMMED);
+ ldgb->src_ssbo = src1->uim_val;
+
+ ldgb->src1 = reg(src2, info, instr->repeat, IR3_REG_IMMED);
+ ldgb->src1_im = !!(src2->flags & IR3_REG_IMMED);
+ ldgb->src2 = reg(src3, info, instr->repeat, IR3_REG_IMMED);
+ ldgb->src2_im = !!(src3->flags & IR3_REG_IMMED);
+
+ ldgb->src3 = reg(src4, info, instr->repeat, 0);
+ ldgb->pad0 = 0x1;
+ ldgb->pad3 = 0x1;
+ } else {
+ ldgb->src1 = reg(src1, info, instr->repeat, IR3_REG_IMMED);
+ ldgb->src1_im = !!(src1->flags & IR3_REG_IMMED);
+ ldgb->src2 = reg(src2, info, instr->repeat, IR3_REG_IMMED);
+ ldgb->src2_im = !!(src2->flags & IR3_REG_IMMED);
+ ldgb->pad0 = 0x1;
+ ldgb->pad3 = 0x0;
+ }
+
+ return 0;
+ } else if (instr->opc == OPC_LDGB) {
struct ir3_register *src3 = instr->regs[3];
instr_cat6ldgb_t *ldgb = ptr;
/* maybe these two bits both determine the instruction encoding? */
cat6->src_off = false;
- ldgb->d = 4 - 1; /* always .4d ? */
- ldgb->typed = false; /* TODO true for images */
+ ldgb->d = instr->cat6.d - 1;
+ ldgb->typed = instr->cat6.typed;
ldgb->type_size = instr->cat6.iim_val - 1;
ldgb->dst = reg(dst, info, instr->repeat, IR3_REG_R | IR3_REG_HALF);
ldgb->src2 = reg(src3, info, instr->repeat, IR3_REG_IMMED);
ldgb->src2_im = !!(src3->flags & IR3_REG_IMMED);
- if (is_atomic(instr->opc)) {
- struct ir3_register *src4 = instr->regs[4];
- ldgb->src3 = reg(src4, info, instr->repeat, 0);
- ldgb->pad0 = 0x1;
- ldgb->pad3 = 0x3;
- } else {
- ldgb->pad0 = 0x0;
- ldgb->pad3 = 0x2;
- }
+ ldgb->pad0 = 0x0;
+ ldgb->pad3 = 0x1;
+
+ return 0;
+ } else if (instr->opc == OPC_RESINFO) {
+ instr_cat6ldgb_t *ldgb = ptr;
+
+ ldgb->d = instr->cat6.d - 1;
+
+ ldgb->dst = reg(dst, info, instr->repeat, IR3_REG_R | IR3_REG_HALF);
+
+ /* first src is src_ssbo: */
+ iassert(src1->flags & IR3_REG_IMMED);
+ ldgb->src_ssbo = src1->uim_val;
return 0;
- } else if (instr->opc == OPC_STGB) {
+ } else if ((instr->opc == OPC_STGB) || (instr->opc == OPC_STIB)) {
struct ir3_register *src3 = instr->regs[4];
instr_cat6stgb_t *stgb = ptr;
cat6->src_off = true;
stgb->pad3 = 0x2;
- stgb->d = 4 - 1; /* always .4d ? */
- stgb->typed = false;
+ stgb->d = instr->cat6.d - 1;
+ stgb->typed = instr->cat6.typed;
stgb->type_size = instr->cat6.iim_val - 1;
/* first src is dst_ssbo: */
stgb->src3_im = !!(src3->flags & IR3_REG_IMMED);
return 0;
- } else if (instr->cat6.src_offset || (instr->opc == OPC_LDG)) {
+ } else if (instr->cat6.src_offset || (instr->opc == OPC_LDG) ||
+ (instr->opc == OPC_LDL)) {
instr_cat6a_t *cat6a = ptr;
cat6->src_off = true;
}
}
- if (instr->cat6.dst_offset || (instr->opc == OPC_STG)) {
+ if (instr->cat6.dst_offset || (instr->opc == OPC_STG) ||
+ (instr->opc == OPC_STL)) {
instr_cat6c_t *cat6c = ptr;
cat6->dst_off = true;
cat6c->dst = reg(dst, info, instr->repeat, IR3_REG_R | IR3_REG_HALF);
type_t type;
int src_offset;
int dst_offset;
- int iim_val; /* for ldgb/stgb, # of components */
+ int iim_val : 3; /* for ldgb/stgb, # of components */
+ int d : 3;
+ bool typed : 1;
} cat6;
struct {
unsigned w : 1; /* write */
switch (instr->opc) {
case OPC_STG:
case OPC_STGB:
+ case OPC_STIB:
case OPC_STP:
case OPC_STL:
case OPC_STLW: