lib/isa/src/x86/instruction.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const x86 = @import("root.zig");
3
4 pub const Family = enum(u5) {
5 move = 0,
6 extend = 1,
7 address = 2,
8 string = 3,
9 arithmetic = 4,
10 logic = 5,
11 unary = 6,
12 shift = 7,
13 multiply = 8,
14 divide = 9,
15 condition = 10,
16 control = 11,
17 stack = 12,
18 swap = 13,
19 carry = 14,
20 nop = 15,
21 boundary = 16,
22 system = 17,
23 vector = 18,
24 exchange = 19,
25 interrupt = 20,
26 };
27
28 pub const Operation = enum(u8) {
29 add = 0,
30 and_ = 1,
31 bswap = 2,
32 call = 3,
33 cmc = 4,
34 cmovae = 5,
35 cmove = 6,
36 cmovne = 7,
37 cmp = 8,
38 dec = 9,
39 div = 10,
40 hlt = 11,
41 imul = 12,
42 inc = 13,
43 ja = 14,
44 jae = 15,
45 jb = 16,
46 jbe = 17,
47 je = 18,
48 jmp = 19,
49 jne = 20,
50 lea = 21,
51 mov = 22,
52 movs = 23,
53 movsx = 24,
54 movzx = 25,
55 mul = 26,
56 nop = 27,
57 not_ = 28,
58 or_ = 29,
59 out = 30,
60 pop = 31,
61 push = 32,
62 ret = 33,
63 rol = 34,
64 sbb = 35,
65 seta = 36,
66 setae = 37,
67 setb = 38,
68 setbe = 39,
69 sete = 40,
70 setne = 41,
71 shl = 42,
72 shr = 43,
73 stos = 44,
74 sub = 45,
75 test_ = 46,
76 ud2 = 47,
77 xor_ = 48,
78 adc = 49,
79 cli = 50,
80 cmova = 51,
81 cmovb = 52,
82 cmpxchg = 53,
83 cpuid = 54,
84 idiv = 55,
85 int_ = 56,
86 movdqu = 57,
87 movups = 58,
88 neg = 59,
89 pshufd = 60,
90 pushf = 61,
91 rdmsr = 62,
92 ror = 63,
93 sar = 64,
94 sti = 65,
95 wrmsr = 66,
96 xchg = 67,
97 seto = 68,
98 jl = 69,
99 jge = 70,
100 jle = 71,
101 jg = 72,
102 setl = 73,
103 setge = 74,
104 setle = 75,
105 setg = 76,
106
107 pub fn family(self: Operation) Family {
108 return switch (self) {
109 .mov => .move,
110 .movsx, .movzx => .extend,
111 .lea => .address,
112 .movs, .stos => .string,
113 .add, .adc, .cmp, .sbb, .sub => .arithmetic,
114 .and_, .or_, .test_, .xor_ => .logic,
115 .dec, .inc, .neg, .not_ => .unary,
116 .rol, .ror, .sar, .shl, .shr => .shift,
117 .imul, .mul => .multiply,
118 .div, .idiv => .divide,
119 .cmova,
120 .cmovae,
121 .cmovb,
122 .cmove,
123 .cmovne,
124 .ja,
125 .jae,
126 .jb,
127 .jbe,
128 .je,
129 .jne,
130 .seta,
131 .setae,
132 .setb,
133 .setbe,
134 .sete,
135 .setne,
136 .seto,
137 .jl,
138 .jge,
139 .jle,
140 .jg,
141 .setl,
142 .setge,
143 .setle,
144 .setg,
145 => .condition,
146 .call, .jmp, .ret => .control,
147 .pop, .push, .pushf => .stack,
148 .bswap => .swap,
149 .cmc => .carry,
150 .nop => .nop,
151 .hlt, .out, .ud2 => .boundary,
152 .cli, .cpuid, .rdmsr, .sti, .wrmsr => .system,
153 .movdqu, .movups, .pshufd => .vector,
154 .cmpxchg, .xchg => .exchange,
155 .int_ => .interrupt,
156 };
157 }
158 };
159
160 pub const implicit_registers_max: usize = 4;
161
162 pub const Instruction = struct {
163 form: x86.Form,
164 operation: Operation,
165 family: Family,
166 bytes: u4,
167 register: ?x86.Register = null,
168 register_access: x86.Access = .none,
169 operand: x86.Operand = .none,
170 operand_access: x86.Access = .none,
171 embedded: ?x86.Register = null,
172 embedded_access: x86.Access = .none,
173 immediate: ?x86.Immediate = null,
174 relative: ?i32 = null,
175 modrm_mode: ?u2 = null,
176 modrm_operand: ?u4 = null,
177 implicit: [implicit_registers_max]x86.RegisterAccess = @splat(.{}),
178 implicit_count: u3 = 0,
179
180 pub fn implicitRegisters(self: *const Instruction) []const x86.RegisterAccess {
181 std.debug.assert(self.implicit_count <= self.implicit.len);
182 return self.implicit[0..self.implicit_count];
183 }
184 };
185
186 comptime {
187 std.debug.assert(@backingInt(Operation.xor_) == 48);
188 std.debug.assert(implicit_registers_max <= std.math.maxInt(u3));
189 }