1use serde::{Deserialize, Serialize};
2
3use crate::{errors::DisassemblerError, opcodes::OpCode};
4
5#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
6pub struct Ix {
7 pub op: OpCode,
8 pub dst: u8,
9 pub src: u8,
10 pub off: i16,
11 pub imm: i64,
12}
13
14impl Ix {
15 pub fn off_str(&self) -> String {
16 match self.off.is_negative() {
17 true => self.off.to_string(),
18 false => format!("+{}", self.off),
19 }
20 }
21
22 pub fn dst_off(&self) -> String {
23 format!("[r{}{}]", self.dst, self.off_str())
24 }
25
26 pub fn src_off(&self) -> String {
27 format!("[r{}{}]", self.src, self.off_str())
28 }
29
30 pub fn op_imm_bits(&self) -> Result<String, DisassemblerError> {
31 Ok(match self.imm {
32 16 => format!("{}16", self.op),
33 32 => format!("{}32", self.op),
34 64 => format!("{}64", self.op),
35 _ => return Err(DisassemblerError::InvalidImmediate),
36 })
37 }
38}
39
40impl Ix {
41 pub fn from_bytes(b: &[u8]) -> Result<Self, DisassemblerError> {
42 if b.len() < 8 {
43 return Err(DisassemblerError::InvalidDataLength);
44 }
45
46 let op = OpCode::try_from(b[0])?;
47 let reg = b[1];
48 let src = reg >> 4;
49 let dst = reg & 0x0f;
50 let off = i16::from_le_bytes([b[2], b[3]]);
51
52 let imm = match op {
53 OpCode::Lddw => {
54 if b.len() < 16 {
55 return Err(DisassemblerError::InvalidDataLength);
56 }
57 let mut imm_bytes = [0u8; 8];
58 imm_bytes[0..4].copy_from_slice(&b[4..8]);
59
60 if u32::from_le_bytes([b[8], b[9], b[10], b[11]]) != 0 {
61 return Err(DisassemblerError::InvalidImmediate);
62 }
63
64 imm_bytes[4..8].copy_from_slice(&b[12..16]);
65 i64::from_le_bytes(imm_bytes)
66 }
67 _ => i32::from_le_bytes([b[4], b[5], b[6], b[7]]) as i64,
68 };
69
70 Ok(Ix {
71 op,
72 src,
73 dst,
74 off,
75 imm,
76 })
77 }
78
79 pub fn to_bytes(&self) -> Vec<u8> {
80 let mut b = vec![self.op.clone() as u8, self.src << 4 | self.dst];
81 b.extend_from_slice(&self.off.to_le_bytes());
82 b.extend_from_slice(&self.imm.to_le_bytes()[..4]);
83 if self.op == OpCode::Lddw {
84 b.extend_from_slice(&[0; 4]);
85 b.extend_from_slice(&self.imm.to_le_bytes()[4..]);
86 }
87 b
88 }
89
90 pub fn to_asm(&self) -> Result<String, DisassemblerError> {
91 Ok(match self.op {
92 OpCode::Lddw => format!("{} r{}, {}", self.op, self.dst, self.imm),
97 OpCode::Ldxb |
100 OpCode::Ldxh |
101 OpCode::Ldxw |
102 OpCode::Ldxdw => format!("{} r{}, {}", self.op, self.dst, self.src_off()),
103 OpCode::Stb |
105 OpCode::Sth |
106 OpCode::Stw |
107 OpCode::Stdw => format!("{} {}, {}", self.op, self.dst_off(), self.imm),
108 OpCode::Stxb |
111 OpCode::Stxh |
112 OpCode::Stxw |
113 OpCode::Stxdw => format!("{} {}, r{}", self.op, self.dst_off(), self.src),
114 OpCode::Neg32 | OpCode::Neg64 => format!("{} r{}", self.op, self.dst),
117 OpCode::Le |
122 OpCode::Be => format!("{}{}", self.op_imm_bits()?, self.dst), OpCode::Add32Imm |
125 OpCode::Sub32Imm |
126 OpCode::Mul32Imm |
127 OpCode::Div32Imm |
128 OpCode::Or32Imm |
129 OpCode::And32Imm |
130 OpCode::Lsh32Imm |
131 OpCode::Rsh32Imm |
132 OpCode::Mod32Imm |
133 OpCode::Xor32Imm |
134 OpCode::Arsh32Imm |
135 OpCode::Mov32Imm |
136 OpCode::Lmul32Imm |
137 OpCode::Udiv32Imm |
138 OpCode::Urem32Imm |
139 OpCode::Sdiv32Imm |
140 OpCode::Srem32Imm |
141 OpCode::Add64Imm |
142 OpCode::Sub64Imm |
143 OpCode::Mul64Imm |
144 OpCode::Div64Imm |
145 OpCode::Or64Imm |
146 OpCode::And64Imm |
147 OpCode::Lsh64Imm |
148 OpCode::Rsh64Imm |
149 OpCode::Mod64Imm |
150 OpCode::Xor64Imm |
151 OpCode::Mov64Imm |
152 OpCode::Arsh64Imm |
153 OpCode::Hor64Imm |
154 OpCode::Lmul64Imm |
155 OpCode::Uhmul64Imm |
156 OpCode::Udiv64Imm |
157 OpCode::Urem64Imm |
158 OpCode::Shmul64Imm |
159 OpCode::Sdiv64Imm |
160 OpCode::Srem64Imm => format!("{} r{}, {}", self.op, self.dst, self.imm),
161 OpCode::Add32Reg |
163 OpCode::Sub32Reg |
164 OpCode::Mul32Reg |
165 OpCode::Div32Reg |
166 OpCode::Or32Reg |
167 OpCode::And32Reg |
168 OpCode::Lsh32Reg |
169 OpCode::Rsh32Reg |
170 OpCode::Mod32Reg |
171 OpCode::Xor32Reg |
172 OpCode::Mov32Reg |
173 OpCode::Arsh32Reg |
174 OpCode::Lmul32Reg |
175 OpCode::Udiv32Reg |
176 OpCode::Urem32Reg |
177 OpCode::Sdiv32Reg |
178 OpCode::Srem32Reg |
179 OpCode::Add64Reg |
180 OpCode::Sub64Reg |
181 OpCode::Mul64Reg |
182 OpCode::Div64Reg |
183 OpCode::Or64Reg |
184 OpCode::And64Reg |
185 OpCode::Lsh64Reg |
186 OpCode::Rsh64Reg |
187 OpCode::Mod64Reg |
188 OpCode::Xor64Reg |
189 OpCode::Mov64Reg |
190 OpCode::Arsh64Reg |
191 OpCode::Lmul64Reg |
192 OpCode::Uhmul64Reg |
193 OpCode::Udiv64Reg |
194 OpCode::Urem64Reg |
195 OpCode::Shmul64Reg |
196 OpCode::Sdiv64Reg |
197 OpCode::Srem64Reg => format!("{} r{}, r{}", self.op, self.dst, self.src),
198
199 OpCode::Ja => format!("{} {}", self.op, self.off_str()),
201
202 OpCode::JeqImm |
204 OpCode::JgtImm |
205 OpCode::JgeImm |
206 OpCode::JltImm |
207 OpCode::JleImm |
208 OpCode::JsetImm |
209 OpCode::JneImm |
210 OpCode::JsgtImm |
211 OpCode::JsgeImm |
212 OpCode::JsltImm |
213 OpCode::JsleImm => format!("{} r{}, {}, {}", self.op, self.dst, self.imm, self.off_str()),
214 OpCode::JeqReg |
216 OpCode::JgtReg |
217 OpCode::JgeReg |
218 OpCode::JltReg |
219 OpCode::JleReg |
220 OpCode::JsetReg |
221 OpCode::JneReg |
222 OpCode::JsgtReg |
223 OpCode::JsgeReg |
224 OpCode::JsltReg |
225 OpCode::JsleReg => format!("{} r{}, r{}, {}", self.op, self.dst, self.src, self.off_str()),
226
227
228 OpCode::Call => format!("call {}", self.imm),
230 OpCode::Callx => format!("call r{}", self.src),
231 OpCode::Exit => format!("{}", self.op),
232 })
233 }
234}
235
236#[cfg(test)]
237mod test {
238 use hex_literal::hex;
239
240 use crate::instructions::Ix;
241
242 #[test]
243 fn serialize_e2e() {
244 let b = hex!("9700000000000000");
245 let i = Ix::from_bytes(&b).unwrap();
246 assert_eq!(i.to_bytes(), &b);
247 }
248
249 #[test]
250 fn serialize_e2e_lddw() {
251 let b = hex!("18010000000000000000000000000000");
252 let i = Ix::from_bytes(&b).unwrap();
253 assert_eq!(i.to_bytes(), &b);
254 }
255}