1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7#[repr(u8)]
8#[derive(Default)]
9pub enum OpcodeMap {
10 #[default]
12 Default = 0,
13 Map0F = 1,
15 Map0F38 = 2,
17 Map0F3A = 3,
19 Map4 = 4,
21 Map5 = 5,
23 Map6 = 6,
25 Map7 = 7,
27 Xop8 = 8,
29 Xop9 = 9,
31 XopA = 10,
33}
34
35impl OpcodeMap {
36 #[must_use]
38 pub const fn from_vex_map(m: u8) -> Self {
39 match m {
40 1 => OpcodeMap::Map0F,
41 2 => OpcodeMap::Map0F38,
42 3 => OpcodeMap::Map0F3A,
43 8 => OpcodeMap::Xop8,
44 9 => OpcodeMap::Xop9,
45 10 => OpcodeMap::XopA,
46 _ => OpcodeMap::Default,
47 }
48 }
49
50 #[must_use]
52 pub const fn is_standard(&self) -> bool {
53 matches!(
54 self,
55 OpcodeMap::Default | OpcodeMap::Map0F | OpcodeMap::Map0F38 | OpcodeMap::Map0F3A
56 )
57 }
58
59 #[must_use]
61 pub const fn is_xop(&self) -> bool {
62 matches!(self, OpcodeMap::Xop8 | OpcodeMap::Xop9 | OpcodeMap::XopA)
63 }
64}
65
66#[must_use]
68pub const fn is_two_byte_escape(byte: u8) -> bool {
69 byte == 0x0F
70}
71
72#[must_use]
74pub const fn is_three_byte_escape(byte: u8) -> Option<OpcodeMap> {
75 match byte {
76 0x38 => Some(OpcodeMap::Map0F38),
77 0x3A => Some(OpcodeMap::Map0F3A),
78 _ => None,
79 }
80}
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq)]
84pub enum OpcodeEscape {
85 None,
87 TwoByte,
89 ThreeByte38,
91 ThreeByte3A,
93}
94
95impl OpcodeEscape {
96 #[must_use]
98 pub const fn opcode_map(&self) -> OpcodeMap {
99 match self {
100 OpcodeEscape::None => OpcodeMap::Default,
101 OpcodeEscape::TwoByte => OpcodeMap::Map0F,
102 OpcodeEscape::ThreeByte38 => OpcodeMap::Map0F38,
103 OpcodeEscape::ThreeByte3A => OpcodeMap::Map0F3A,
104 }
105 }
106
107 #[must_use]
109 pub const fn extra_bytes(&self) -> u8 {
110 match self {
111 OpcodeEscape::None => 0,
112 OpcodeEscape::TwoByte => 1,
113 OpcodeEscape::ThreeByte38 | OpcodeEscape::ThreeByte3A => 2,
114 }
115 }
116}
117
118#[must_use]
120pub const fn is_mandatory_prefix(byte: u8) -> bool {
121 matches!(byte, 0x66 | 0xF2 | 0xF3)
122}
123
124#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
126pub enum MandatoryPrefix {
127 #[default]
129 None,
130 P66,
132 PF2,
134 PF3,
136}
137
138impl MandatoryPrefix {
139 #[must_use]
141 pub const fn from_byte(byte: u8) -> Self {
142 match byte {
143 0x66 => MandatoryPrefix::P66,
144 0xF2 => MandatoryPrefix::PF2,
145 0xF3 => MandatoryPrefix::PF3,
146 _ => MandatoryPrefix::None,
147 }
148 }
149
150 #[must_use]
152 pub const fn to_byte(&self) -> Option<u8> {
153 match self {
154 MandatoryPrefix::None => None,
155 MandatoryPrefix::P66 => Some(0x66),
156 MandatoryPrefix::PF2 => Some(0xF2),
157 MandatoryPrefix::PF3 => Some(0xF3),
158 }
159 }
160}
161
162#[derive(Debug, Clone, Copy)]
164pub struct OpcodeDesc {
165 pub map: OpcodeMap,
167 pub prefix: MandatoryPrefix,
169 pub opcode: u8,
171}
172
173impl OpcodeDesc {
174 #[must_use]
176 pub const fn new(map: OpcodeMap, prefix: MandatoryPrefix, opcode: u8) -> Self {
177 Self {
178 map,
179 prefix,
180 opcode,
181 }
182 }
183
184 #[must_use]
186 pub const fn default_map(opcode: u8) -> Self {
187 Self::new(OpcodeMap::Default, MandatoryPrefix::None, opcode)
188 }
189
190 #[must_use]
192 pub const fn map_0f(opcode: u8) -> Self {
193 Self::new(OpcodeMap::Map0F, MandatoryPrefix::None, opcode)
194 }
195
196 #[must_use]
198 pub const fn map_0f_with_prefix(opcode: u8, prefix: MandatoryPrefix) -> Self {
199 Self::new(OpcodeMap::Map0F, prefix, opcode)
200 }
201}
202
203impl Default for OpcodeDesc {
204 fn default() -> Self {
205 Self::default_map(0)
206 }
207}
208
209#[cfg(test)]
210mod tests {
211 use super::*;
212
213 #[test]
214 fn test_opcode_map_from_vex() {
215 assert_eq!(OpcodeMap::from_vex_map(1), OpcodeMap::Map0F);
216 assert_eq!(OpcodeMap::from_vex_map(2), OpcodeMap::Map0F38);
217 assert_eq!(OpcodeMap::from_vex_map(3), OpcodeMap::Map0F3A);
218 assert_eq!(OpcodeMap::from_vex_map(0), OpcodeMap::Default);
219 }
220
221 #[test]
222 fn test_is_two_byte_escape() {
223 assert!(is_two_byte_escape(0x0F));
224 assert!(!is_two_byte_escape(0x90));
225 assert!(!is_two_byte_escape(0x00));
226 }
227
228 #[test]
229 fn test_is_three_byte_escape() {
230 assert_eq!(is_three_byte_escape(0x38), Some(OpcodeMap::Map0F38));
231 assert_eq!(is_three_byte_escape(0x3A), Some(OpcodeMap::Map0F3A));
232 assert_eq!(is_three_byte_escape(0x00), None);
233 }
234
235 #[test]
236 fn test_opcode_escape_extra_bytes() {
237 assert_eq!(OpcodeEscape::None.extra_bytes(), 0);
238 assert_eq!(OpcodeEscape::TwoByte.extra_bytes(), 1);
239 assert_eq!(OpcodeEscape::ThreeByte38.extra_bytes(), 2);
240 assert_eq!(OpcodeEscape::ThreeByte3A.extra_bytes(), 2);
241 }
242
243 #[test]
244 fn test_mandatory_prefix() {
245 assert_eq!(MandatoryPrefix::from_byte(0x66), MandatoryPrefix::P66);
246 assert_eq!(MandatoryPrefix::from_byte(0xF2), MandatoryPrefix::PF2);
247 assert_eq!(MandatoryPrefix::from_byte(0xF3), MandatoryPrefix::PF3);
248 assert_eq!(MandatoryPrefix::from_byte(0x00), MandatoryPrefix::None);
249
250 assert_eq!(MandatoryPrefix::P66.to_byte(), Some(0x66));
251 assert_eq!(MandatoryPrefix::None.to_byte(), None);
252 }
253
254 #[test]
255 fn test_opcode_desc() {
256 let desc = OpcodeDesc::map_0f(0x90);
257 assert_eq!(desc.map, OpcodeMap::Map0F);
258 assert_eq!(desc.opcode, 0x90);
259 assert_eq!(desc.prefix, MandatoryPrefix::None);
260
261 let desc2 = OpcodeDesc::map_0f_with_prefix(0x12, MandatoryPrefix::P66);
262 assert_eq!(desc2.prefix, MandatoryPrefix::P66);
263 }
264}