static (int gprSizeBits, string regStr) GetRegInfo(OpCodeOperandKindDef def, bool kr = false) { string suffix; if (def.RegPlus1) { suffix = "p1"; } else if (def.RegPlus3) { suffix = "p3"; } else { suffix = string.Empty; } var(gprSizeBits, regStr) = def.Register switch { Register.AL => (8, "r8"), Register.AX => (16, "r16"), Register.EAX => (32, "r32"), Register.RAX => (64, "r64"), Register.ES => (0, "Sreg"), Register.MM0 => (0, "mm"), Register.XMM0 => (0, "xmm"), Register.YMM0 => (0, "ymm"), Register.ZMM0 => (0, "zmm"), Register.TMM0 => (0, "tmm"), Register.BND0 => (0, "bnd"), Register.K0 => (0, suffix == string.Empty && kr ? "kr" : "k"), Register.CR0 => (0, "cr"), Register.DR0 => (0, "dr"), Register.TR0 => (0, "tr"), Register.ST0 => (0, "sti"), _ => throw new InvalidOperationException(), }; return(gprSizeBits, regStr + suffix); }
public OpCodeOperandKindDef[] Read() { var defs = new List <OpCodeOperandKindDef>(); var argCounts = new Dictionary <string, int>(StringComparer.Ordinal) { { "br-near", 2 }, { "br-near-x", 1 }, { "br-disp", 1 }, { "br-far", 1 }, { "imm8-const", 1 }, { "imm", 2 }, { "imp-reg", 1 }, { "isx", 2 }, { "opcode", 1 }, { "reg", 1 }, { "rm-reg", 1 }, { "vvvv", 1 }, { "rm", 1 }, { "vsib", 2 }, }; var lines = File.ReadAllLines(filename); for (int i = 0; i < lines.Length; i++) { var line = lines[i]; if (line.Length == 0 || line[0] == '#') { continue; } var parts = line.Split(',').Select(a => a.Trim()).ToArray(); if (parts.Length != 3) { throw new InvalidOperationException($"Line {i + 1}: Expected 2 commas"); } if (!toOpCodeOperandKind.TryGetValue(parts[0], out var enumValue)) { throw new InvalidOperationException($"Line {i + 1}: Invalid enum name or duplicate def: {parts[0]}"); } toOpCodeOperandKind.Remove(parts[0]); var flags = OpCodeOperandKindDefFlags.None; foreach (var flagStr in parts[2].Split(' ', StringSplitOptions.RemoveEmptyEntries)) { flags |= flagStr switch { "lock-bit" => OpCodeOperandKindDefFlags.LockBit, "p1" => OpCodeOperandKindDefFlags.RegPlus1, "p3" => OpCodeOperandKindDefFlags.RegPlus3, "mem" => OpCodeOperandKindDefFlags.Memory, "mpx" => OpCodeOperandKindDefFlags.MPX, "mib" => OpCodeOperandKindDefFlags.MIB, "sib" => OpCodeOperandKindDefFlags.SibRequired, _ => throw new InvalidOperationException($"Line {i + 1}: Invalid flag: {flagStr}"), }; } var(key, value) = ParserUtils.GetKeyValue(parts[1]); argCounts.TryGetValue(key, out var argCount); var args = value == string.Empty ? Array.Empty <string>() : value.Split(';'); if (args.Length != argCount) { throw new InvalidOperationException($"Line {i + 1}: Expected {argCount} args but got {args.Length}: {value}"); } OpCodeOperandKindDef def; int arg1, arg2; Register register; switch (key) { case "none": def = new OpCodeOperandKindDef(enumValue, flags, OperandEncoding.None, 0, 0, Register.None); break; case "br-near": arg1 = int.Parse(args[0]); arg2 = int.Parse(args[1]); def = new OpCodeOperandKindDef(enumValue, flags, OperandEncoding.NearBranch, arg1, arg2, Register.None); break; case "br-near-x": arg1 = int.Parse(args[0]); def = new OpCodeOperandKindDef(enumValue, flags, OperandEncoding.Xbegin, arg1, 0, Register.None); break; case "br-disp": arg1 = int.Parse(args[0]); def = new OpCodeOperandKindDef(enumValue, flags, OperandEncoding.AbsNearBranch, arg1, 0, Register.None); break; case "br-far": arg1 = int.Parse(args[0]); def = new OpCodeOperandKindDef(enumValue, flags, OperandEncoding.FarBranch, arg1, 0, Register.None); break; case "imm4": flags |= OpCodeOperandKindDefFlags.M2Z; def = new OpCodeOperandKindDef(enumValue, flags, OperandEncoding.Immediate, 4, 4, Register.None); break; case "imm8-const": arg1 = int.Parse(args[0]); def = new OpCodeOperandKindDef(enumValue, flags, OperandEncoding.ImpliedConst, arg1, 0, Register.None); break; case "imm": arg1 = int.Parse(args[0]); arg2 = int.Parse(args[1]); def = new OpCodeOperandKindDef(enumValue, flags, OperandEncoding.Immediate, arg1, arg2, Register.None); break; case "imp-reg": register = (Register)toRegister[args[0]].Value; def = new OpCodeOperandKindDef(enumValue, flags, OperandEncoding.ImpliedRegister, 0, 0, register); break; case "seg-rbx-al": flags |= OpCodeOperandKindDefFlags.Memory; def = new OpCodeOperandKindDef(enumValue, flags, OperandEncoding.SegRBX, 0, 0, Register.None); break; case "seg-rsi": flags |= OpCodeOperandKindDefFlags.Memory; def = new OpCodeOperandKindDef(enumValue, flags, OperandEncoding.SegRSI, 0, 0, Register.None); break; case "seg-rdi": flags |= OpCodeOperandKindDefFlags.Memory; def = new OpCodeOperandKindDef(enumValue, flags, OperandEncoding.SegRDI, 0, 0, Register.None); break; case "es-rdi": flags |= OpCodeOperandKindDefFlags.Memory; def = new OpCodeOperandKindDef(enumValue, flags, OperandEncoding.ESRDI, 0, 0, Register.None); break; case "isx": register = (Register)toRegister[args[0]].Value; switch (int.Parse(args[1])) { case 4: break; case 5: flags |= OpCodeOperandKindDefFlags.Is5; break; default: throw new InvalidOperationException(); } def = new OpCodeOperandKindDef(enumValue, flags, OperandEncoding.RegImm, 0, 0, register); break; case "opcode": register = (Register)toRegister[args[0]].Value; def = new OpCodeOperandKindDef(enumValue, flags, OperandEncoding.RegOpCode, 0, 0, register); break; case "reg": flags |= OpCodeOperandKindDefFlags.Modrm; register = (Register)toRegister[args[0]].Value; def = new OpCodeOperandKindDef(enumValue, flags, OperandEncoding.RegModrmReg, 0, 0, register); break; case "rm-reg": flags |= OpCodeOperandKindDefFlags.Modrm; register = (Register)toRegister[args[0]].Value; def = new OpCodeOperandKindDef(enumValue, flags, OperandEncoding.RegModrmRm, 0, 0, register); break; case "vvvv": register = (Register)toRegister[args[0]].Value; def = new OpCodeOperandKindDef(enumValue, flags, OperandEncoding.RegVvvvv, 0, 0, register); break; case "rm": flags |= OpCodeOperandKindDefFlags.Modrm; flags |= OpCodeOperandKindDefFlags.Memory; register = (Register)toRegister[args[0]].Value; def = new OpCodeOperandKindDef(enumValue, flags, OperandEncoding.RegMemModrmRm, 0, 0, register); break; case "rm-mem": flags |= OpCodeOperandKindDefFlags.Modrm; flags |= OpCodeOperandKindDefFlags.Memory; def = new OpCodeOperandKindDef(enumValue, flags, OperandEncoding.MemModrmRm, 0, 0, Register.None); break; case "vsib": flags |= OpCodeOperandKindDefFlags.Modrm; flags |= OpCodeOperandKindDefFlags.Memory; register = (Register)toRegister[args[0]].Value; flags |= (int.Parse(args[1])) switch { 32 => OpCodeOperandKindDefFlags.Vsib32, 64 => OpCodeOperandKindDefFlags.Vsib64, _ => throw new InvalidOperationException($"Line {i + 1}: Unknown vsib size: {args[1]}"), }; def = new OpCodeOperandKindDef(enumValue, flags, OperandEncoding.MemModrmRm, 0, 0, register); break; case "moffs": flags |= OpCodeOperandKindDefFlags.Memory; def = new OpCodeOperandKindDef(enumValue, flags, OperandEncoding.MemOffset, 0, 0, Register.None); break; default: throw new InvalidOperationException($"Line {i + 1}: Unknown key: {key}"); } defs.Add(def); } if (toOpCodeOperandKind.Count != 0) { throw new InvalidOperationException($"Missing {nameof(OpCodeOperandKind)} definitions"); } return(defs.OrderBy(a => a.EnumValue.Value).ToArray()); }