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, 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}