1use super::{TranslationPreference, ValueKind, check_single_wordlength};
2use crate::wave_container::{ScopeId, VarId, VariableMeta};
3
4use eyre::Result;
5use instruction_decoder::{Decoder, specs};
6use surfer_translation_types::{BasicTranslator, VariableValue, check_vector_variable};
7
8pub struct InstructionTranslator {
9 pub name: String,
10 pub decoder: Decoder,
11 pub num_bits: u32,
12}
13
14impl BasicTranslator<VarId, ScopeId> for InstructionTranslator {
15 fn name(&self) -> String {
16 self.name.clone()
17 }
18
19 fn basic_translate(&self, num_bits: u32, value: &VariableValue) -> (String, ValueKind) {
20 let u64_value = match value {
21 VariableValue::BigUint(v) => v.to_u64_digits().last().copied(),
22 VariableValue::String(s) => match check_vector_variable(s) {
23 Some(v) => return v,
24 None => u64::from_str_radix(s, 2).ok(),
25 },
26 }
27 .unwrap_or(0);
28
29 match self
30 .decoder
31 .decode_from_i64(u64_value as i64, num_bits as usize)
32 {
33 Ok(iform) => (iform, ValueKind::Normal),
34 _ => (
35 format!(
36 "UNKNOWN INSN ({:#0width$x})",
37 u64_value,
38 width = num_bits.div_ceil(4) as usize + 2
39 ),
40 ValueKind::Warn,
41 ),
42 }
43 }
44
45 fn translates(&self, variable: &VariableMeta) -> Result<TranslationPreference> {
46 check_single_wordlength(variable.num_bits, self.num_bits)
47 }
48}
49
50#[must_use]
51pub fn new_rv32_translator() -> InstructionTranslator {
52 InstructionTranslator {
53 name: "RV32".into(),
54 decoder: Decoder::new(
55 &specs::rv32::RV32
56 .iter()
57 .map(std::string::ToString::to_string)
58 .collect::<Vec<String>>(),
59 )
60 .expect("Can't build RV32 decoder"),
61 num_bits: 32,
62 }
63}
64
65#[must_use]
66pub fn new_rv64_translator() -> InstructionTranslator {
67 InstructionTranslator {
68 name: "RV64".into(),
69 decoder: Decoder::new(
70 &specs::rv64::RV64
71 .iter()
72 .map(std::string::ToString::to_string)
73 .collect::<Vec<String>>(),
74 )
75 .expect("Can't build RV64 decoder"),
76 num_bits: 32,
77 }
78}
79
80#[must_use]
81pub fn new_mips_translator() -> InstructionTranslator {
82 InstructionTranslator {
83 name: "MIPS".into(),
84 decoder: Decoder::new(&[specs::MIPS.to_owned()]).expect("Can't build mips decoder"),
85 num_bits: 32,
86 }
87}
88
89#[must_use]
90pub fn new_la64_translator() -> InstructionTranslator {
91 InstructionTranslator {
92 name: "LA64".into(),
93 decoder: Decoder::new(&[specs::LA64.to_owned()]).expect("Can't build LA64 decoder"),
94 num_bits: 32,
95 }
96}
97
98#[cfg(test)]
99mod test {
100
101 use super::*;
102
103 #[test]
104 fn riscv_from_bigunit() {
105 let rv32_translator = new_rv32_translator();
106 let rv64_translator = new_rv64_translator();
107 assert_eq!(
108 rv32_translator
109 .basic_translate(32, &VariableValue::BigUint(1u32.into()))
110 .0,
111 "c.nop"
112 );
113 assert_eq!(
114 rv32_translator
115 .basic_translate(32, &VariableValue::BigUint(0b1000000010011111u32.into()))
116 .0,
117 "UNKNOWN INSN (0x0000809f)"
118 );
119 assert_eq!(
120 rv32_translator
121 .basic_translate(
122 32,
123 &VariableValue::BigUint(0b1000_0001_0011_0101_0000_0101_1001_0011_u32.into())
124 )
125 .0,
126 "addi a1, a0, -2029"
127 );
128 assert_eq!(
129 rv64_translator
130 .basic_translate(32, &VariableValue::BigUint(1u32.into()))
131 .0,
132 "c.nop"
133 );
134 assert_eq!(
135 rv64_translator
136 .basic_translate(32, &VariableValue::BigUint(0b1000000010011111u32.into()))
137 .0,
138 "UNKNOWN INSN (0x0000809f)"
139 );
140 assert_eq!(
141 rv64_translator
142 .basic_translate(
143 32,
144 &VariableValue::BigUint(0b1000_0001_0011_0101_0000_0101_1001_0011_u32.into())
145 )
146 .0,
147 "addi a1, a0, -2029"
148 );
149 }
150 #[test]
151 fn riscv_from_string() {
152 let rv32_translator = new_rv32_translator();
153 assert_eq!(
154 rv32_translator
155 .basic_translate(32, &VariableValue::String("1".to_owned()))
156 .0,
157 "c.nop"
158 );
159 assert_eq!(
160 rv32_translator
161 .basic_translate(
162 32,
163 &VariableValue::String("01001000100010001000100011111111".to_owned())
164 )
165 .0,
166 "UNKNOWN INSN (0x488888ff)"
167 );
168 assert_eq!(
169 rv32_translator
170 .basic_translate(
171 32,
172 &VariableValue::String("01xzz-hlw0010001000100010001000".to_owned())
173 )
174 .0,
175 "UNDEF"
176 );
177 assert_eq!(
178 rv32_translator
179 .basic_translate(
180 32,
181 &VariableValue::String("010zz-hlw0010001000100010001000".to_owned())
182 )
183 .0,
184 "HIGHIMP"
185 );
186 assert_eq!(
187 rv32_translator
188 .basic_translate(
189 32,
190 &VariableValue::String("01011-hlw0010001000100010001000".to_owned())
191 )
192 .0,
193 "DON'T CARE"
194 );
195 }
196
197 #[test]
198 fn mips_from_bigunit() {
199 let mips_translator = new_mips_translator();
200 assert_eq!(
201 mips_translator
202 .basic_translate(32, &VariableValue::BigUint(0x3a873u32.into()))
203 .0,
204 "UNKNOWN INSN (0x0003a873)"
205 );
206 assert_eq!(
207 mips_translator
208 .basic_translate(32, &VariableValue::BigUint(0x24210000u32.into()))
209 .0,
210 "addiu $at, $at, 0"
211 );
212 }
213
214 #[test]
215 fn mips_from_string() {
216 let mips_translator = new_mips_translator();
217 assert_eq!(
218 mips_translator
219 .basic_translate(
220 32,
221 &VariableValue::String("10101111110000010000000000000000".to_owned())
222 )
223 .0,
224 "sw $at, 0($fp)"
225 );
226 assert_eq!(
227 mips_translator
228 .basic_translate(
229 32,
230 &VariableValue::String("01xzz-hlw0010001000100010001000".to_owned())
231 )
232 .0,
233 "UNDEF"
234 );
235 assert_eq!(
236 mips_translator
237 .basic_translate(
238 32,
239 &VariableValue::String("010zz-hlw0010001000100010001000".to_owned())
240 )
241 .0,
242 "HIGHIMP"
243 );
244 assert_eq!(
245 mips_translator
246 .basic_translate(
247 32,
248 &VariableValue::String("01011-hlw0010001000100010001000".to_owned())
249 )
250 .0,
251 "DON'T CARE"
252 );
253 }
254
255 #[test]
256 fn la64_from_bigunit() {
257 let la64_translator = new_la64_translator();
258 assert_eq!(
259 la64_translator
260 .basic_translate(32, &VariableValue::BigUint(0xffffffffu32.into()))
261 .0,
262 "UNKNOWN INSN (0xffffffff)"
263 );
264 assert_eq!(
265 la64_translator
266 .basic_translate(32, &VariableValue::BigUint(0x1a000004u32.into()))
267 .0,
268 "pcalau12i $a0, 0"
269 );
270 }
271
272 #[test]
273 fn la64_from_string() {
274 let la64_translator = new_la64_translator();
275 assert_eq!(
276 la64_translator
277 .basic_translate(
278 32,
279 &VariableValue::String("00101001101111111011001011001100".to_owned())
280 )
281 .0,
282 "st.w $t0, $fp, -20"
283 );
284 assert_eq!(
285 la64_translator
286 .basic_translate(
287 32,
288 &VariableValue::String("01xzz-hlw0010001000100010001000".to_owned())
289 )
290 .0,
291 "UNDEF"
292 );
293 assert_eq!(
294 la64_translator
295 .basic_translate(
296 32,
297 &VariableValue::String("010zz-hlw0010001000100010001000".to_owned())
298 )
299 .0,
300 "HIGHIMP"
301 );
302 assert_eq!(
303 la64_translator
304 .basic_translate(
305 32,
306 &VariableValue::String("01011-hlw0010001000100010001000".to_owned())
307 )
308 .0,
309 "DON'T CARE"
310 );
311 }
312}