public static string GetEncodingString(Opcode opcode, InstructionEncoding encoding) { var str = new StringBuilder(30); var xexType = opcode & Opcode.XexType_Mask; if (xexType == Opcode.XexType_LegacyOrRex) { // Legacy Xex: 66 REX.W 0F 38 switch (opcode & Opcode.SimdPrefix_Mask) { case Opcode.SimdPrefix_None: break; case Opcode.SimdPrefix_66: str.Append("66 "); break; case Opcode.SimdPrefix_F2: str.Append("F2 "); break; case Opcode.SimdPrefix_F3: str.Append("F3 "); break; default: throw new UnreachableException(); } if ((encoding & InstructionEncoding.RexW_Mask) != InstructionEncoding.RexW_Ignored && (opcode & Opcode.RexW) == Opcode.RexW) { str.Append("REX.W "); } switch (opcode & Opcode.Map_Mask) { case Opcode.Map_Default: break; case Opcode.Map_0F: str.Append("0F "); break; case Opcode.Map_0F38: str.Append("0F 38 "); break; case Opcode.Map_0F3A: str.Append("0F 3A "); break; default: throw new UnreachableException(); } } else { // Vex/Xop/EVex: VEX.NDS.LIG.66.0F3A.WIG switch (xexType) { case Opcode.XexType_Vex: str.Append("VEX"); break; case Opcode.XexType_Xop: str.Append("XOP"); break; case Opcode.XexType_EVex: str.Append("EVEX"); break; default: throw new UnreachableException(); } // TODO: Pretty print .NDS or similar switch (encoding & InstructionEncoding.VexL_Mask) { case InstructionEncoding.VexL_Fixed: switch (opcode & Opcode.VexL_Mask) { case Opcode.VexL_0: str.Append(".L0"); break; case Opcode.VexL_1: str.Append(".L1"); break; case Opcode.VexL_2: str.Append(".L2"); break; default: throw new UnreachableException(); } break; case InstructionEncoding.VexL_Ignored: str.Append(".LIG"); break; default: throw new NotImplementedException(); } switch (opcode & Opcode.SimdPrefix_Mask) { case Opcode.SimdPrefix_None: break; case Opcode.SimdPrefix_66: str.Append(".66"); break; case Opcode.SimdPrefix_F2: str.Append(".F2"); break; case Opcode.SimdPrefix_F3: str.Append(".F3"); break; default: throw new UnreachableException(); } if (xexType == Opcode.XexType_Xop) { switch (opcode & Opcode.Map_Mask) { case Opcode.Map_Xop8: str.Append(".M8"); break; case Opcode.Map_Xop9: str.Append(".M9"); break; case Opcode.Map_Xop10: str.Append(".M10"); break; default: throw new UnreachableException(); } } else { switch (opcode & Opcode.Map_Mask) { case Opcode.Map_0F: str.Append(".0F"); break; case Opcode.Map_0F38: str.Append(".0F38"); break; case Opcode.Map_0F3A: str.Append(".0F3A"); break; default: throw new UnreachableException(); } } switch (encoding & InstructionEncoding.RexW_Mask) { case InstructionEncoding.RexW_Fixed: str.Append((opcode & Opcode.RexW) == Opcode.RexW ? ".W1" : ".W0"); break; case InstructionEncoding.RexW_Ignored: str.Append(".WIG"); break; default: throw new NotImplementedException(); } str.Append(' '); } // String tail: opcode byte and what follows 0B /r ib // The opcode itself str.AppendFormat(CultureInfo.InvariantCulture, "{0:X2}", opcode.GetMainByte()); // Suffixes switch (encoding & InstructionEncoding.OpcodeFormat_Mask) { case InstructionEncoding.OpcodeFormat_FixedByte: break; case InstructionEncoding.OpcodeFormat_EmbeddedRegister: str.Append("+r"); break; case InstructionEncoding.OpcodeFormat_EmbeddedConditionCode: str.Append("+cc"); break; default: throw new UnreachableException(); } switch (encoding & InstructionEncoding.ModRM_Mask) { case InstructionEncoding.ModRM_Fixed: str.AppendFormat(CultureInfo.InvariantCulture, " {0:X2}", opcode.GetExtraByte()); break; case InstructionEncoding.ModRM_FixedModReg: str.AppendFormat(CultureInfo.InvariantCulture, " {0:X2}+r", opcode.GetExtraByte()); break; case InstructionEncoding.ModRM_FixedReg: str.Append(" /"); str.Append((char)('0' + (opcode.GetExtraByte() >> 3))); break; case InstructionEncoding.ModRM_Any: str.Append(" /r"); break; case InstructionEncoding.ModRM_None: break; default: throw new UnreachableException(); } AppendImmediate(str, encoding.GetFirstImmediateSize()); AppendImmediate(str, encoding.GetSecondImmediateSize()); return str.ToString(); }