p += vex_sprintf(p, "%u", d);
}
if (x != 0) {
- p += vex_sprintf(p, "(%s,%s)", gpr_operand(x), gpr_operand(b));
+ p += vex_sprintf(p, "(%s,%s)", gpr_operand(x),
+ b != 0 ? gpr_operand(b) : "0");
} else {
if (b != 0) {
p += vex_sprintf(p, "(%s)", gpr_operand(b));
{
p += vex_sprintf(p, "%u", d);
p += vex_sprintf(p, "(%u", length + 1); // actual length is +1
- p += vex_sprintf(p, ",%s", gpr_operand(b));
+ p += vex_sprintf(p, ",%s", b != 0 ? gpr_operand(b) : "0");
p += vex_sprintf(p, ")");
return p;
p += vex_sprintf(p, "%u", d);
}
p += vex_sprintf(p, "(%s", vr_operand(v));
- p += vex_sprintf(p, ",%s", gpr_operand(b));
+ p += vex_sprintf(p, ",%s", b != 0 ? gpr_operand(b) : "0");
p += vex_sprintf(p, ")");
return p;
const HChar *xmnm;
UInt mask = opnds[1].mask;
- if (mask == 0)
+ if (mask == 0) {
xmnm = "nop";
- else if (mask == 15)
+ if (opnds[2].d == 0 && opnds[2].b == 0 && opnds[2].x == 0)
+ return p += vex_sprintf(p, "nop");
+ } else if (mask == 15)
xmnm = "b";
else
xmnm = construct_mnemonic("b", "", mask);
}
+static Int
+rotate_mh(UInt ix __attribute__((unused)), UInt mask, UInt *value)
+{
+ *value = mask;
+ if (ix == 5 && mask == 0) return 0;
+ if (ix == 3) // rosbg, etc
+ *value = mask & ~0x80;
+ if (ix == 4) // risbg
+ *value = mask & ~0x80;
+ return 1;
+}
+
+
+HChar *
+rotate_disasm(const s390_opnd *opnds, HChar *p)
+{
+ const HChar *base = opnds[0].xmnm.base;
+ UInt len = vex_strlen(base);
+ HChar xmnm[len + 1];
+
+ if (opnds[0].xmnm.base[1] == 'i')
+ vex_sprintf(xmnm, "%s%c", base, (opnds[4].u & 0x80) ? 'z' : '\0');
+ else
+ vex_sprintf(xmnm, "%s%c", base, (opnds[3].u & 0x80) ? 't' : '\0');
+
+ return s390_disasm_aux(opnds, xmnm, p, rotate_mh);
+}
+
+
/* Write out OPNDS. MH is a mask handler. It decides whether or not a
MASK operand is written and if so, massages the mask value as needed. */
static HChar *
"rll r1,r3,d20(b2)",
"rllg r1,r3,d20(b2)",
- "rnsbg r1,r2,i3:u8,i4:u8,i5:u8", // gie FIXME un/signed i3/4/5 ? t-bit ? z-bit?
- "rxsbg r1,r2,i3:u8,i4:u8,i5:u8", // gie FIXME ditto
- "rosbg r1,r2,i3:u8,i4:u8,i5:u8", // gie FIXME ditto
-
- "risbg r1,r2,i3:u8,i4:u8,i5:u8", // gie FIXME ditto
- "risbgn r1,r2,i3:u8,i4:u8,i5:u8", // mi1 FIXME ditto
-
- "risbhg r1,r2,i3:u8,i4:u8,i5:u8", // hiwo FIXME ditto
- "risblg r1,r2,i3:u8,i4:u8,i5:u8", // hiwo FIXME ditto
+ // Rotate and .... opcodes require special handling
+ //
+ // For rosbg and friends
+ // - Bit #0 of i3 is the T-bit and bit #1 of i3 ought to be 0.
+ // - i5 is optional and will not be written when 0
+ //
+ // For risbg and friends
+ // - Bit #0 of i4 is the Z-bit and bit #1 of i4 ought to be 0.
+ // - i5 is optional and will not be written when 0
+ //
+ // This implies that we need to model i3, i4 and i5 as masks so
+ // we can manipulate their value when disassembling or suppress
+ // the mask altogether. Note that we limit the set of allowed values
+ // for those masks to avoid excessively large numbers of testcases.
+ "rnsbg r1,r2,m3:u8{0,1,2,63,128,129,191},m4:u6{0,1,2,63},m5:u6{0,1,2,63}", // gie
+ "rxsbg r1,r2,m3:u8{0,1,2,63,128,129,191},m4:u6{0,1,2,63},m5:u6{0,1,2,63}", // gie
+ "rosbg r1,r2,m3:u8{0,1,2,63,128,129,191},m4:u6{0,1,2,63},m5:u6{0,1,2,63}", // gie
+
+ "risbg r1,r2,m3:u6{0,1,2,63},m4:u8{0,1,2,63,128,129,191},m5:u6{0,1,2,63}", // gie
+ "risbgn r1,r2,m3:u6{0,1,2,63},m4:u8{0,1,2,63,128,129,191},m5:u6{0,1,2,63}", // mi1
+
+ "risbhg r1,r2,m3:u5{0,1,2,31},m4:u8{0,1,2,31,128,129,159},m5:u6{0,1,2,63}", // hiwo
+ "risblg r1,r2,m3:u5{0,1,2,31},m4:u8{0,1,2,31,128,129,159},m5:u6{0,1,2,63}", // hiwo
"srst r1,r2",