Skip to main content

libsurfer/translation/
instruction_translators.rs

1use super::{TranslationPreference, ValueKind, check_single_wordlength};
2use crate::wave_container::{ScopeId, VarId, VariableMeta};
3
4use eyre::Result;
5use instruction_decoder::Decoder;
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            include_str!("../../../instruction-decoder/toml/RV32I.toml").to_string(),
56            include_str!("../../../instruction-decoder/toml/RV32M.toml").to_string(),
57            include_str!("../../../instruction-decoder/toml/RV32A.toml").to_string(),
58            include_str!("../../../instruction-decoder/toml/RV32F.toml").to_string(),
59            include_str!("../../../instruction-decoder/toml/RV32_Zbb.toml").to_string(),
60            include_str!("../../../instruction-decoder/toml/RV32_Zbkb.toml").to_string(),
61            include_str!("../../../instruction-decoder/toml/RV32_Zbs.toml").to_string(),
62            include_str!("../../../instruction-decoder/toml/RV32_Zknd.toml").to_string(),
63            include_str!("../../../instruction-decoder/toml/RV32_Zkne.toml").to_string(),
64            include_str!("../../../instruction-decoder/toml/RV32_Zfa.toml").to_string(),
65            include_str!("../../../instruction-decoder/toml/RV32_Zicsr.toml").to_string(),
66            include_str!("../../../instruction-decoder/toml/RV32C-lower.toml").to_string(),
67            include_str!("../../../instruction-decoder/toml/RV32_Zcb-lower.toml").to_string(),
68            include_str!("../../../instruction-decoder/toml/RV32_Zcf-lower.toml").to_string(),
69            include_str!("../../../instruction-decoder/toml/RV32_Zacas.toml").to_string(),
70            include_str!("../../../instruction-decoder/toml/RV_Zcd-lower.toml").to_string(),
71            include_str!("../../../instruction-decoder/toml/RV_Zba.toml").to_string(),
72            include_str!("../../../instruction-decoder/toml/RV_Zbc.toml").to_string(),
73            include_str!("../../../instruction-decoder/toml/RV_Zbkc.toml").to_string(),
74            include_str!("../../../instruction-decoder/toml/RV_Zbkx.toml").to_string(),
75            include_str!("../../../instruction-decoder/toml/RV_Zfh.toml").to_string(),
76            include_str!("../../../instruction-decoder/toml/RV_Zknh.toml").to_string(),
77            include_str!("../../../instruction-decoder/toml/RV_Zksed.toml").to_string(),
78            include_str!("../../../instruction-decoder/toml/RV_Zksh.toml").to_string(),
79            include_str!("../../../instruction-decoder/toml/RV_Zawrs.toml").to_string(),
80            include_str!("../../../instruction-decoder/toml/RV_Zicond.toml").to_string(),
81            include_str!("../../../instruction-decoder/toml/RV_Zifencei.toml").to_string(),
82            include_str!("../../../instruction-decoder/toml/RV_Zicbo.toml").to_string(),
83            include_str!("../../../instruction-decoder/toml/RV_Zimop.toml").to_string(),
84            include_str!("../../../instruction-decoder/toml/RV_Zihintntl.toml").to_string(),
85            include_str!("../../../instruction-decoder/toml/RVV.toml").to_string(),
86        ])
87        .expect("Can't build RV32 decoder"),
88        num_bits: 32,
89    }
90}
91
92#[must_use]
93pub fn new_rv64_translator() -> InstructionTranslator {
94    InstructionTranslator {
95        name: "RV64".into(),
96        decoder: Decoder::new(&[
97            include_str!("../../../instruction-decoder/toml/RV64I.toml").to_string(),
98            include_str!("../../../instruction-decoder/toml/RV64M.toml").to_string(),
99            include_str!("../../../instruction-decoder/toml/RV64A.toml").to_string(),
100            include_str!("../../../instruction-decoder/toml/RV64D.toml").to_string(),
101            include_str!("../../../instruction-decoder/toml/RV64_Zbb.toml").to_string(),
102            include_str!("../../../instruction-decoder/toml/RV64_Zbkb.toml").to_string(),
103            include_str!("../../../instruction-decoder/toml/RV64_Zbs.toml").to_string(),
104            include_str!("../../../instruction-decoder/toml/RV64_Zknd.toml").to_string(),
105            include_str!("../../../instruction-decoder/toml/RV64_Zkne.toml").to_string(),
106            include_str!("../../../instruction-decoder/toml/RV64_Zacas.toml").to_string(),
107            include_str!("../../../instruction-decoder/toml/RV64_Zfa.toml").to_string(),
108            include_str!("../../../instruction-decoder/toml/RV64C-lower.toml").to_string(),
109            include_str!("../../../instruction-decoder/toml/RV64_Zcb-lower.toml").to_string(),
110            include_str!("../../../instruction-decoder/toml/RV64_Zcd-lower.toml").to_string(),
111            include_str!("../../../instruction-decoder/toml/RVV.toml").to_string(),
112            include_str!("../../../instruction-decoder/toml/RV_Zvbb.toml").to_string(),
113            include_str!("../../../instruction-decoder/toml/RV_Zvbc.toml").to_string(),
114            include_str!("../../../instruction-decoder/toml/RV_Zvkg.toml").to_string(),
115            include_str!("../../../instruction-decoder/toml/RV_Zvkned.toml").to_string(),
116            include_str!("../../../instruction-decoder/toml/RV_Zvknha.toml").to_string(),
117            include_str!("../../../instruction-decoder/toml/RV_Zvknhb.toml").to_string(),
118            include_str!("../../../instruction-decoder/toml/RV_Zvksed.toml").to_string(),
119            include_str!("../../../instruction-decoder/toml/RV_Zvksh.toml").to_string(),
120            include_str!("../../../instruction-decoder/toml/RV_Zcd-lower.toml").to_string(),
121            include_str!("../../../instruction-decoder/toml/RV_Zba.toml").to_string(),
122            include_str!("../../../instruction-decoder/toml/RV_Zbc.toml").to_string(),
123            include_str!("../../../instruction-decoder/toml/RV_Zbkc.toml").to_string(),
124            include_str!("../../../instruction-decoder/toml/RV_Zbkx.toml").to_string(),
125            include_str!("../../../instruction-decoder/toml/RV_Zfh.toml").to_string(),
126            include_str!("../../../instruction-decoder/toml/RV_Zknh.toml").to_string(),
127            include_str!("../../../instruction-decoder/toml/RV_Zksed.toml").to_string(),
128            include_str!("../../../instruction-decoder/toml/RV_Zksh.toml").to_string(),
129            include_str!("../../../instruction-decoder/toml/RV_Zawrs.toml").to_string(),
130            include_str!("../../../instruction-decoder/toml/RV_Zicond.toml").to_string(),
131            include_str!("../../../instruction-decoder/toml/RV_Zifencei.toml").to_string(),
132            include_str!("../../../instruction-decoder/toml/RV_Zicbo.toml").to_string(),
133            include_str!("../../../instruction-decoder/toml/RV_Zimop.toml").to_string(),
134            include_str!("../../../instruction-decoder/toml/RV_Zihintntl.toml").to_string(),
135        ])
136        .expect("Can't build RV64 decoder"),
137        num_bits: 32,
138    }
139}
140
141#[must_use]
142pub fn new_mips_translator() -> InstructionTranslator {
143    InstructionTranslator {
144        name: "MIPS".into(),
145        decoder: Decoder::new(&[
146            include_str!("../../../instruction-decoder/toml/mips.toml").to_string()
147        ])
148        .expect("Can't build mips decoder"),
149        num_bits: 32,
150    }
151}
152
153#[must_use]
154pub fn new_la64_translator() -> InstructionTranslator {
155    InstructionTranslator {
156        name: "LA64".into(),
157        decoder: Decoder::new(&[
158            include_str!("../../../instruction-decoder/toml/la64.toml").to_string()
159        ])
160        .expect("Can't build LA64 decoder"),
161        num_bits: 32,
162    }
163}
164
165#[cfg(test)]
166mod test {
167
168    use super::*;
169
170    #[test]
171    fn riscv_from_bigunit() {
172        let rv32_translator = new_rv32_translator();
173        let rv64_translator = new_rv64_translator();
174        assert_eq!(
175            rv32_translator
176                .basic_translate(32, &VariableValue::BigUint(1u32.into()))
177                .0,
178            "c.nop"
179        );
180        assert_eq!(
181            rv32_translator
182                .basic_translate(32, &VariableValue::BigUint(0b1000000010011111u32.into()))
183                .0,
184            "UNKNOWN INSN (0x0000809f)"
185        );
186        assert_eq!(
187            rv32_translator
188                .basic_translate(
189                    32,
190                    &VariableValue::BigUint(0b1000_0001_0011_0101_0000_0101_1001_0011_u32.into())
191                )
192                .0,
193            "addi a1, a0, -2029"
194        );
195        assert_eq!(
196            rv64_translator
197                .basic_translate(32, &VariableValue::BigUint(1u32.into()))
198                .0,
199            "c.nop"
200        );
201        assert_eq!(
202            rv64_translator
203                .basic_translate(32, &VariableValue::BigUint(0b1000000010011111u32.into()))
204                .0,
205            "UNKNOWN INSN (0x0000809f)"
206        );
207        assert_eq!(
208            rv64_translator
209                .basic_translate(
210                    32,
211                    &VariableValue::BigUint(0b1000_0001_0011_0101_0000_0101_1001_0011_u32.into())
212                )
213                .0,
214            "addi a1, a0, -2029"
215        );
216    }
217    #[test]
218    fn riscv_from_string() {
219        let rv32_translator = new_rv32_translator();
220        assert_eq!(
221            rv32_translator
222                .basic_translate(32, &VariableValue::String("1".to_owned()))
223                .0,
224            "c.nop"
225        );
226        assert_eq!(
227            rv32_translator
228                .basic_translate(
229                    32,
230                    &VariableValue::String("01001000100010001000100011111111".to_owned())
231                )
232                .0,
233            "UNKNOWN INSN (0x488888ff)"
234        );
235        assert_eq!(
236            rv32_translator
237                .basic_translate(
238                    32,
239                    &VariableValue::String("01xzz-hlw0010001000100010001000".to_owned())
240                )
241                .0,
242            "UNDEF"
243        );
244        assert_eq!(
245            rv32_translator
246                .basic_translate(
247                    32,
248                    &VariableValue::String("010zz-hlw0010001000100010001000".to_owned())
249                )
250                .0,
251            "HIGHIMP"
252        );
253        assert_eq!(
254            rv32_translator
255                .basic_translate(
256                    32,
257                    &VariableValue::String("01011-hlw0010001000100010001000".to_owned())
258                )
259                .0,
260            "DON'T CARE"
261        );
262    }
263
264    #[test]
265    fn mips_from_bigunit() {
266        let mips_translator = new_mips_translator();
267        assert_eq!(
268            mips_translator
269                .basic_translate(32, &VariableValue::BigUint(0x3a873u32.into()))
270                .0,
271            "UNKNOWN INSN (0x0003a873)"
272        );
273        assert_eq!(
274            mips_translator
275                .basic_translate(32, &VariableValue::BigUint(0x24210000u32.into()))
276                .0,
277            "addiu $at, $at, 0"
278        );
279    }
280
281    #[test]
282    fn mips_from_string() {
283        let mips_translator = new_mips_translator();
284        assert_eq!(
285            mips_translator
286                .basic_translate(
287                    32,
288                    &VariableValue::String("10101111110000010000000000000000".to_owned())
289                )
290                .0,
291            "sw $at, 0($fp)"
292        );
293        assert_eq!(
294            mips_translator
295                .basic_translate(
296                    32,
297                    &VariableValue::String("01xzz-hlw0010001000100010001000".to_owned())
298                )
299                .0,
300            "UNDEF"
301        );
302        assert_eq!(
303            mips_translator
304                .basic_translate(
305                    32,
306                    &VariableValue::String("010zz-hlw0010001000100010001000".to_owned())
307                )
308                .0,
309            "HIGHIMP"
310        );
311        assert_eq!(
312            mips_translator
313                .basic_translate(
314                    32,
315                    &VariableValue::String("01011-hlw0010001000100010001000".to_owned())
316                )
317                .0,
318            "DON'T CARE"
319        );
320    }
321
322    #[test]
323    fn la64_from_bigunit() {
324        let la64_translator = new_la64_translator();
325        assert_eq!(
326            la64_translator
327                .basic_translate(32, &VariableValue::BigUint(0xffffffffu32.into()))
328                .0,
329            "UNKNOWN INSN (0xffffffff)"
330        );
331        assert_eq!(
332            la64_translator
333                .basic_translate(32, &VariableValue::BigUint(0x1a000004u32.into()))
334                .0,
335            "pcalau12i $a0, 0"
336        );
337    }
338
339    #[test]
340    fn la64_from_string() {
341        let la64_translator = new_la64_translator();
342        assert_eq!(
343            la64_translator
344                .basic_translate(
345                    32,
346                    &VariableValue::String("00101001101111111011001011001100".to_owned())
347                )
348                .0,
349            "st.w $t0, $fp, -20"
350        );
351        assert_eq!(
352            la64_translator
353                .basic_translate(
354                    32,
355                    &VariableValue::String("01xzz-hlw0010001000100010001000".to_owned())
356                )
357                .0,
358            "UNDEF"
359        );
360        assert_eq!(
361            la64_translator
362                .basic_translate(
363                    32,
364                    &VariableValue::String("010zz-hlw0010001000100010001000".to_owned())
365                )
366                .0,
367            "HIGHIMP"
368        );
369        assert_eq!(
370            la64_translator
371                .basic_translate(
372                    32,
373                    &VariableValue::String("01011-hlw0010001000100010001000".to_owned())
374                )
375                .0,
376            "DON'T CARE"
377        );
378    }
379}