lib/isa/src/x86/form.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 
  3 pub const FormKey = u64;
  4 
  5 pub const Prefix = enum(u5) {
  6     none = 0,
  7     rex = 1,
  8     rex_b = 2,
  9     rex_r = 3,
 10     rex_rb = 4,
 11     rex_rxb = 5,
 12     rex_w = 6,
 13     rex_wb = 7,
 14     rex_wr = 8,
 15     rex_wrb = 9,
 16     operand16 = 10,
 17     operand16_cs = 11,
 18     operand16_rex_b = 12,
 19     operand16_rex_r = 13,
 20     operand16_rex_rb = 14,
 21     lock_rex = 15,
 22     lock_rex_b = 16,
 23     lock_rex_w = 17,
 24     repeat = 18,
 25     repeat_rex_b = 19,
 26     rex_x = 20,
 27     rex_xb = 21,
 28     rex_rx = 22,
 29     rex_wx = 23,
 30     rex_wxb = 24,
 31     rex_wrx = 25,
 32     rex_wrxb = 26,
 33     repeat_rex_w = 27,
 34     operand16_2_cs = 28,
 35     operand16_4_cs = 29,
 36     operand16_5_cs = 30,
 37     operand16_3_cs = 31,
 38 
 39     pub fn bytes(self: Prefix) []const u8 {
 40         return switch (self) {
 41             .none => &.{},
 42             .rex => &.{0x40},
 43             .rex_b => &.{0x41},
 44             .rex_r => &.{0x44},
 45             .rex_rb => &.{0x45},
 46             .rex_rxb => &.{0x47},
 47             .rex_w => &.{0x48},
 48             .rex_wb => &.{0x49},
 49             .rex_wr => &.{0x4c},
 50             .rex_wrb => &.{0x4d},
 51             .operand16 => &.{0x66},
 52             .operand16_cs => &.{ 0x66, 0x2e },
 53             .operand16_rex_b => &.{ 0x66, 0x41 },
 54             .operand16_rex_r => &.{ 0x66, 0x44 },
 55             .operand16_rex_rb => &.{ 0x66, 0x45 },
 56             .lock_rex => &.{ 0xf0, 0x40 },
 57             .lock_rex_b => &.{ 0xf0, 0x41 },
 58             .lock_rex_w => &.{ 0xf0, 0x48 },
 59             .repeat => &.{0xf3},
 60             .repeat_rex_b => &.{ 0xf3, 0x41 },
 61             .rex_x => &.{0x42},
 62             .rex_xb => &.{0x43},
 63             .rex_rx => &.{0x46},
 64             .rex_wx => &.{0x4a},
 65             .rex_wxb => &.{0x4b},
 66             .rex_wrx => &.{0x4e},
 67             .rex_wrxb => &.{0x4f},
 68             .repeat_rex_w => &.{ 0xf3, 0x48 },
 69             .operand16_2_cs => &.{ 0x66, 0x66, 0x2e },
 70             .operand16_4_cs => &.{ 0x66, 0x66, 0x66, 0x66, 0x2e },
 71             .operand16_5_cs => &.{ 0x66, 0x66, 0x66, 0x66, 0x66, 0x2e },
 72             .operand16_3_cs => &.{ 0x66, 0x66, 0x66, 0x2e },
 73         };
 74     }
 75 
 76     pub fn fromBytes(value: []const u8) ?Prefix {
 77         inline for (@typeInfo(Prefix).@"enum".field_names) |name| {
 78             const candidate: Prefix = @fromBackingInt(@intCast(@backingInt(@field(Prefix, name))));
 79             if (std.mem.eql(u8, value, candidate.bytes())) return candidate;
 80         }
 81         return null;
 82     }
 83 
 84     pub fn rexByte(self: Prefix) u8 {
 85         return switch (self) {
 86             .rex, .lock_rex => 0x40,
 87             .rex_b, .operand16_rex_b, .lock_rex_b, .repeat_rex_b => 0x41,
 88             .rex_x => 0x42,
 89             .rex_xb => 0x43,
 90             .rex_r, .operand16_rex_r => 0x44,
 91             .rex_rb, .operand16_rex_rb => 0x45,
 92             .rex_rx => 0x46,
 93             .rex_rxb => 0x47,
 94             .rex_w, .lock_rex_w => 0x48,
 95             .rex_wb => 0x49,
 96             .rex_wx => 0x4a,
 97             .rex_wxb => 0x4b,
 98             .rex_wr => 0x4c,
 99             .rex_wrb => 0x4d,
100             .rex_wrx => 0x4e,
101             .rex_wrxb => 0x4f,
102             .repeat_rex_w => 0x48,
103             else => 0,
104         };
105     }
106 
107     pub fn wide(self: Prefix) bool {
108         return self.rexByte() & 0x08 != 0;
109     }
110 
111     pub fn hasOperand16(self: Prefix) bool {
112         return switch (self) {
113             .operand16,
114             .operand16_cs,
115             .operand16_rex_b,
116             .operand16_rex_r,
117             .operand16_rex_rb,
118             .operand16_2_cs,
119             .operand16_4_cs,
120             .operand16_5_cs,
121             .operand16_3_cs,
122             => true,
123             else => false,
124         };
125     }
126 
127     pub fn repeatedOperand16(self: Prefix) bool {
128         return self == .operand16_2_cs or
129             self == .operand16_4_cs or
130             self == .operand16_5_cs or
131             self == .operand16_3_cs;
132     }
133 
134     pub fn locked(self: Prefix) bool {
135         return switch (self) {
136             .lock_rex, .lock_rex_b, .lock_rex_w => true,
137             else => false,
138         };
139     }
140 
141     pub fn repeated(self: Prefix) bool {
142         return switch (self) {
143             .repeat, .repeat_rex_b, .repeat_rex_w => true,
144             else => false,
145         };
146     }
147 };
148 
149 pub const Map = enum(u1) {
150     one = 0,
151     two = 1,
152 };
153 
154 pub const Width = enum(u3) {
155     none = 0,
156     byte = 1,
157     word = 2,
158     dword = 3,
159     qword = 4,
160     vector128 = 5,
161 
162     pub fn bytes(self: Width) u8 {
163         return switch (self) {
164             .none => 0,
165             .byte => 1,
166             .word => 2,
167             .dword => 4,
168             .qword => 8,
169             .vector128 => 16,
170         };
171     }
172 };
173 
174 pub const Extension = enum(u4) {
175     zero = 0,
176     one = 1,
177     two = 2,
178     three = 3,
179     four = 4,
180     five = 5,
181     six = 6,
182     seven = 7,
183     none = 8,
184 
185     pub fn fromRaw(value: u3) Extension {
186         return @fromBackingInt(@intCast(value));
187     }
188 };
189 
190 pub const Mode = enum(u3) {
191     none = 0,
192     memory = 1,
193     displacement8 = 2,
194     displacement32 = 3,
195     register = 4,
196 };
197 
198 pub const Role = enum(u2) {
199     none = 0,
200     ordinary = 1,
201     rsp = 2,
202     rbp = 3,
203 };
204 
205 pub const AddressKind = enum(u3) {
206     none = 0,
207     base = 1,
208     base_indexed = 2,
209     rip_relative = 3,
210     absolute = 4,
211     absolute_indexed = 5,
212 };
213 
214 pub const Access = enum(u2) {
215     none = 0,
216     read = 1,
217     write = 2,
218     read_write = 3,
219 };
220 
221 pub const Form = packed struct(u64) {
222     prefix: Prefix = .none,
223     map: Map = .one,
224     opcode: u8 = 0,
225     width: Width = .none,
226     extension: Extension = .none,
227     mode: Mode = .none,
228     register_role: Role = .none,
229     register_access: Access = .none,
230     operand_role: Role = .none,
231     operand_access: Access = .none,
232     address: AddressKind = .none,
233     base_role: Role = .none,
234     index_role: Role = .none,
235     embedded_role: Role = .none,
236     embedded_access: Access = .none,
237     immediate: u8 = 0,
238     reserved: u13 = 0,
239 
240     pub fn key(self: Form) FormKey {
241         return @bitCast(self);
242     }
243 
244     pub fn encodedKey(self: Form) [8]u8 {
245         var result: [8]u8 = undefined;
246         std.mem.writeInt(u64, &result, self.key(), .little);
247         return result;
248     }
249 };
250 
251 pub const Diagnostic = struct {
252     candidate: Form = .{},
253     prefix: [15]u8 = @splat(0),
254     prefix_count: u4 = 0,
255     active: bool = false,
256     normalized: bool = false,
257 
258     pub fn captureForm(self: *Diagnostic, value: Form) void {
259         self.* = .{
260             .candidate = value,
261             .active = true,
262             .normalized = true,
263         };
264     }
265 
266     pub fn capturePrefix(self: *Diagnostic, value: []const u8) void {
267         std.debug.assert(value.len <= self.prefix.len);
268         self.* = .{
269             .prefix_count = @intCast(value.len),
270             .active = true,
271         };
272         @memcpy(self.prefix[0..value.len], value);
273     }
274 
275     pub fn normalizedForm(self: Diagnostic) ?Form {
276         if (!self.active or !self.normalized) return null;
277         return self.candidate;
278     }
279 
280     pub fn prefixBytes(self: *const Diagnostic) []const u8 {
281         return self.prefix[0..self.prefix_count];
282     }
283 };
284 
285 pub fn modeled(value: Form) bool {
286     if (value.reserved != 0) return false;
287     return switch (value.map) {
288         .one => modeledOne(value.opcode),
289         .two => modeledTwo(value.opcode),
290     };
291 }
292 
293 fn modeledOne(opcode: u8) bool {
294     if (opcode <= 0x05) return true;
295     if (opcode >= 0x08 and opcode <= 0x0b) return true;
296     if (opcode == 0x0d) return true;
297     if (opcode >= 0x18 and opcode <= 0x1d) return true;
298     if (opcode >= 0x20 and opcode <= 0x25) return true;
299     if (opcode >= 0x28 and opcode <= 0x2d) return true;
300     if (opcode >= 0x30 and opcode <= 0x35) return true;
301     if (opcode == 0x38 or opcode == 0x39 or
302         (opcode >= 0x3b and opcode <= 0x3d)) return true;
303     if (opcode >= 0x50 and opcode <= 0x5f) return true;
304     if ((opcode >= 0x72 and opcode <= 0x77) or
305         (opcode >= 0x7c and opcode <= 0x7f)) return true;
306     if (opcode >= 0xb0 and opcode <= 0xbf) return true;
307     return switch (opcode) {
308         0x69,
309         0x6a,
310         0x6b,
311         0x80,
312         0x81,
313         0x83,
314         0x84,
315         0x85,
316         0x88,
317         0x89,
318         0x8a,
319         0x8b,
320         0x8d,
321         0x90,
322         0x9c,
323         0xa4,
324         0xa5,
325         0xa8,
326         0xa9,
327         0xaa,
328         0xab,
329         0xc0,
330         0xc1,
331         0xc3,
332         0xc6,
333         0xc7,
334         0xcd,
335         0xd0,
336         0xd1,
337         0xd2,
338         0xd3,
339         0xe8,
340         0xe9,
341         0xeb,
342         0xee,
343         0xf4,
344         0xf5,
345         0xf6,
346         0xf7,
347         0xfa,
348         0xfb,
349         0xfe,
350         0xff,
351         => true,
352         else => false,
353     };
354 }
355 
356 fn modeledTwo(opcode: u8) bool {
357     if ((opcode >= 0x82 and opcode <= 0x87) or
358         (opcode >= 0x8c and opcode <= 0x8f)) return true;
359     if ((opcode >= 0x92 and opcode <= 0x97) or
360         (opcode >= 0x9c and opcode <= 0x9f)) return true;
361     if (opcode >= 0xc8 and opcode <= 0xcf) return true;
362     return switch (opcode) {
363         0x0b,
364         0x10,
365         0x11,
366         0x1f,
367         0x30,
368         0x32,
369         0x42,
370         0x43,
371         0x44,
372         0x45,
373         0x47,
374         0x6f,
375         0x70,
376         0x7f,
377         0x90,
378         0xa2,
379         0xaf,
380         0xb0,
381         0xb6,
382         0xb7,
383         0xbe,
384         0xbf,
385         => true,
386         else => false,
387     };
388 }
389 
390 comptime {
391     std.debug.assert(@sizeOf(Form) == @sizeOf(FormKey));
392     std.debug.assert(@bitSizeOf(Form) == 64);
393 }