rrs_lib/
instruction_string_outputter.rs

1// Copyright 2021 Gregory Chadwick <mail@gregchadwick.co.uk>
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5//! An [InstructionProcessor] that outputs a string of the instruction disassembly
6//!
7//! # Example
8//!
9//! ```
10//! use rrs_lib;
11//! use rrs_lib::instruction_string_outputter::InstructionStringOutputter;
12//!
13//! let mut outputter = InstructionStringOutputter { insn_pc: 0 };
14//!
15//! assert_eq!(
16//!     rrs_lib::process_instruction(&mut outputter, 0x07b60893),
17//!     Some(String::from("addi x17, x12, 123"))
18//! );
19//! ```
20
21use super::instruction_formats;
22use super::InstructionProcessor;
23use paste::paste;
24
25pub struct InstructionStringOutputter {
26    /// PC of the instruction being output. Used to generate disassembly of instructions with PC
27    /// relative fields (such as BEQ and JAL).
28    pub insn_pc: u32,
29}
30
31// Macros to produce string outputs for various different instruction types
32macro_rules! string_out_for_alu_reg_op {
33    ($name:ident) => {
34        paste! {
35            fn [<process_ $name>](
36                &mut self,
37                dec_insn: instruction_formats::RType
38            ) -> Self::InstructionResult {
39                format!("{} x{}, x{}, x{}", stringify!($name), dec_insn.rd, dec_insn.rs1,
40                    dec_insn.rs2)
41            }
42        }
43    };
44}
45
46macro_rules! string_out_for_alu_reg_ops {
47    ($($name:ident),*) => {
48        $(
49            string_out_for_alu_reg_op! {$name}
50        )*
51    };
52}
53
54macro_rules! string_out_for_alu_imm_op {
55    ($name:ident) => {
56        paste! {
57            fn [<process_ $name i>](
58                &mut self,
59                dec_insn: instruction_formats::IType
60            ) -> Self::InstructionResult {
61                format!("{}i x{}, x{}, {}", stringify!($name), dec_insn.rd, dec_insn.rs1,
62                    dec_insn.imm)
63            }
64        }
65    };
66}
67
68macro_rules! string_out_for_alu_imm_shamt_op {
69    ($name:ident) => {
70        paste! {
71            fn [<process_ $name i>](
72                &mut self,
73                dec_insn: instruction_formats::ITypeShamt
74            ) -> Self::InstructionResult {
75                format!("{}i x{}, x{}, {}", stringify!($name), dec_insn.rd, dec_insn.rs1,
76                    dec_insn.shamt)
77            }
78        }
79    };
80}
81
82macro_rules! string_out_for_alu_ops {
83    ($($name:ident),*) => {
84        $(
85            string_out_for_alu_reg_op! {$name}
86            string_out_for_alu_imm_op! {$name}
87        )*
88    }
89}
90
91macro_rules! string_out_for_shift_ops {
92    ($($name:ident),*) => {
93        $(
94            string_out_for_alu_reg_op! {$name}
95            string_out_for_alu_imm_shamt_op! {$name}
96        )*
97    }
98}
99
100macro_rules! string_out_for_branch_ops {
101    ($($name:ident),*) => {
102        $(
103            paste! {
104                fn [<process_ $name>](
105                    &mut self,
106                    dec_insn: instruction_formats::BType
107                ) -> Self::InstructionResult {
108                    let branch_pc = self.insn_pc.wrapping_add(dec_insn.imm as u32);
109
110                    format!("{} x{}, x{}, 0x{:08x}", stringify!($name), dec_insn.rs1, dec_insn.rs2,
111                        branch_pc)
112                }
113            }
114        )*
115    }
116}
117
118macro_rules! string_out_for_load_ops {
119    ($($name:ident),*) => {
120        $(
121            paste! {
122                fn [<process_ $name>](
123                    &mut self,
124                    dec_insn: instruction_formats::IType
125                ) -> Self::InstructionResult {
126                    format!("{} x{}, {}(x{})", stringify!($name), dec_insn.rd, dec_insn.imm,
127                        dec_insn.rs1)
128                }
129            }
130        )*
131    }
132}
133
134macro_rules! string_out_for_store_ops {
135    ($($name:ident),*) => {
136        $(
137            paste! {
138                fn [<process_ $name>](
139                    &mut self,
140                    dec_insn: instruction_formats::SType
141                ) -> Self::InstructionResult {
142                    format!("{} x{}, {}(x{})", stringify!($name), dec_insn.rs2, dec_insn.imm,
143                        dec_insn.rs1)
144                }
145            }
146        )*
147    }
148}
149
150impl InstructionProcessor for InstructionStringOutputter {
151    type InstructionResult = String;
152
153    // TODO: Make one macro that takes all names as arguments and generates all the functions
154    // together
155    string_out_for_alu_ops! {add, slt, xor, or, and}
156    string_out_for_alu_reg_op! {sltu}
157    string_out_for_alu_reg_op! {sub}
158    string_out_for_shift_ops! {sll, srl, sra}
159
160    // This instructon is called sltiu in RISC-V, but the function is called `process_sltui` for
161    // consistency with other immediate based instructions here. A specific implemention is
162    // required here (not a macro one from above) so the right mnemonic is output.
163    fn process_sltui(&mut self, dec_insn: instruction_formats::IType) -> Self::InstructionResult {
164        format!(
165            "sltiu x{}, x{}, {}",
166            dec_insn.rd, dec_insn.rs1, dec_insn.imm
167        )
168    }
169
170    fn process_lui(&mut self, dec_insn: instruction_formats::UType) -> Self::InstructionResult {
171        format!("lui x{}, 0x{:08x}", dec_insn.rd, dec_insn.imm)
172    }
173
174    fn process_auipc(&mut self, dec_insn: instruction_formats::UType) -> Self::InstructionResult {
175        let final_imm = self.insn_pc.wrapping_add(dec_insn.imm as u32);
176        format!("auipc x{}, 0x{:08x}", dec_insn.rd, final_imm)
177    }
178
179    string_out_for_branch_ops! {beq, bne, bge, bgeu, blt, bltu}
180    string_out_for_load_ops! {lb, lbu, lh, lhu, lw}
181    string_out_for_store_ops! {sb, sh, sw}
182
183    fn process_jal(&mut self, dec_insn: instruction_formats::JType) -> Self::InstructionResult {
184        let target_pc = self.insn_pc.wrapping_add(dec_insn.imm as u32);
185        format!("jal x{}, 0x{:08x}", dec_insn.rd, target_pc)
186    }
187
188    fn process_jalr(&mut self, dec_insn: instruction_formats::IType) -> Self::InstructionResult {
189        format!(
190            "jalr x{}, 0x{:03x}(x{})",
191            dec_insn.rd, dec_insn.imm, dec_insn.rs1
192        )
193    }
194
195    string_out_for_alu_reg_ops! {mul, mulh, mulhu, mulhsu, div, divu, rem, remu}
196
197    fn process_fence(&mut self, _dec_insn: instruction_formats::IType) -> Self::InstructionResult {
198        String::from("fence")
199    }
200}
201
202#[cfg(test)]
203mod tests {
204    use super::*;
205    use crate::process_instruction;
206
207    #[test]
208    fn test_insn_string_output() {
209        let mut outputter = InstructionStringOutputter { insn_pc: 0 };
210
211        let test_insns = vec![
212            0x07b60893, 0x24dba193, 0x06f63813, 0x14044f13, 0x7804e893, 0x1ea6fa13, 0x00511693,
213            0x00f45713, 0x417dd213, 0x01798733, 0x40e18ab3, 0x009e1533, 0x00c02fb3, 0x014ab933,
214            0x0175cd33, 0x014350b3, 0x41a753b3, 0x00566fb3, 0x01de7db3, 0xdeadb637, 0x00064897,
215            0x04c004ef, 0x100183e7, 0x04d38263, 0x05349063, 0x03774e63, 0x03dbdc63, 0x035e6a63,
216            0x0398f863, 0x04c18983, 0x07841b83, 0x1883a403, 0x03af4b03, 0x15acd883, 0x0d320923,
217            0x18061323, 0x0b382523, 0x034684b3, 0x03679f33, 0x0324bbb3, 0x03d9a233, 0x03f549b3,
218            0x02ee5133, 0x02a6e9b3, 0x02c976b3, 0xabc0000f,
219        ];
220
221        assert_eq!(
222            process_instruction(&mut outputter, test_insns[0]),
223            Some(String::from("addi x17, x12, 123"))
224        );
225
226        assert_eq!(
227            process_instruction(&mut outputter, test_insns[1]),
228            Some(String::from("slti x3, x23, 589"))
229        );
230
231        assert_eq!(
232            process_instruction(&mut outputter, test_insns[2]),
233            Some(String::from("sltiu x16, x12, 111"))
234        );
235
236        assert_eq!(
237            process_instruction(&mut outputter, test_insns[3]),
238            Some(String::from("xori x30, x8, 320"))
239        );
240
241        assert_eq!(
242            process_instruction(&mut outputter, test_insns[4]),
243            Some(String::from("ori x17, x9, 1920"))
244        );
245
246        assert_eq!(
247            process_instruction(&mut outputter, test_insns[5]),
248            Some(String::from("andi x20, x13, 490"))
249        );
250
251        assert_eq!(
252            process_instruction(&mut outputter, test_insns[6]),
253            Some(String::from("slli x13, x2, 5"))
254        );
255
256        assert_eq!(
257            process_instruction(&mut outputter, test_insns[7]),
258            Some(String::from("srli x14, x8, 15"))
259        );
260
261        assert_eq!(
262            process_instruction(&mut outputter, test_insns[8]),
263            Some(String::from("srai x4, x27, 23"))
264        );
265
266        assert_eq!(
267            process_instruction(&mut outputter, test_insns[9]),
268            Some(String::from("add x14, x19, x23"))
269        );
270
271        assert_eq!(
272            process_instruction(&mut outputter, test_insns[10]),
273            Some(String::from("sub x21, x3, x14"))
274        );
275
276        assert_eq!(
277            process_instruction(&mut outputter, test_insns[11]),
278            Some(String::from("sll x10, x28, x9"))
279        );
280
281        assert_eq!(
282            process_instruction(&mut outputter, test_insns[12]),
283            Some(String::from("slt x31, x0, x12"))
284        );
285
286        assert_eq!(
287            process_instruction(&mut outputter, test_insns[13]),
288            Some(String::from("sltu x18, x21, x20"))
289        );
290
291        assert_eq!(
292            process_instruction(&mut outputter, test_insns[14]),
293            Some(String::from("xor x26, x11, x23"))
294        );
295
296        assert_eq!(
297            process_instruction(&mut outputter, test_insns[15]),
298            Some(String::from("srl x1, x6, x20"))
299        );
300
301        assert_eq!(
302            process_instruction(&mut outputter, test_insns[16]),
303            Some(String::from("sra x7, x14, x26"))
304        );
305
306        assert_eq!(
307            process_instruction(&mut outputter, test_insns[17]),
308            Some(String::from("or x31, x12, x5"))
309        );
310
311        assert_eq!(
312            process_instruction(&mut outputter, test_insns[18]),
313            Some(String::from("and x27, x28, x29"))
314        );
315
316        assert_eq!(
317            process_instruction(&mut outputter, test_insns[19]),
318            Some(String::from("lui x12, 0xdeadb000"))
319        );
320
321        outputter.insn_pc = 0x50;
322        assert_eq!(
323            process_instruction(&mut outputter, test_insns[20]),
324            Some(String::from("auipc x17, 0x00064050"))
325        );
326
327        outputter.insn_pc = 0x54;
328        assert_eq!(
329            process_instruction(&mut outputter, test_insns[21]),
330            Some(String::from("jal x9, 0x000000a0"))
331        );
332
333        assert_eq!(
334            process_instruction(&mut outputter, test_insns[22]),
335            Some(String::from("jalr x7, 0x100(x3)"))
336        );
337
338        outputter.insn_pc = 0x5c;
339        assert_eq!(
340            process_instruction(&mut outputter, test_insns[23]),
341            Some(String::from("beq x7, x13, 0x000000a0"))
342        );
343
344        outputter.insn_pc = 0x60;
345        assert_eq!(
346            process_instruction(&mut outputter, test_insns[24]),
347            Some(String::from("bne x9, x19, 0x000000a0"))
348        );
349
350        outputter.insn_pc = 0x64;
351        assert_eq!(
352            process_instruction(&mut outputter, test_insns[25]),
353            Some(String::from("blt x14, x23, 0x000000a0"))
354        );
355
356        outputter.insn_pc = 0x68;
357        assert_eq!(
358            process_instruction(&mut outputter, test_insns[26]),
359            Some(String::from("bge x23, x29, 0x000000a0"))
360        );
361
362        outputter.insn_pc = 0x6c;
363        assert_eq!(
364            process_instruction(&mut outputter, test_insns[27]),
365            Some(String::from("bltu x28, x21, 0x000000a0"))
366        );
367
368        outputter.insn_pc = 0x70;
369        assert_eq!(
370            process_instruction(&mut outputter, test_insns[28]),
371            Some(String::from("bgeu x17, x25, 0x000000a0"))
372        );
373
374        assert_eq!(
375            process_instruction(&mut outputter, test_insns[29]),
376            Some(String::from("lb x19, 76(x3)"))
377        );
378
379        assert_eq!(
380            process_instruction(&mut outputter, test_insns[30]),
381            Some(String::from("lh x23, 120(x8)"))
382        );
383
384        assert_eq!(
385            process_instruction(&mut outputter, test_insns[31]),
386            Some(String::from("lw x8, 392(x7)"))
387        );
388
389        assert_eq!(
390            process_instruction(&mut outputter, test_insns[32]),
391            Some(String::from("lbu x22, 58(x30)"))
392        );
393
394        assert_eq!(
395            process_instruction(&mut outputter, test_insns[33]),
396            Some(String::from("lhu x17, 346(x25)"))
397        );
398
399        assert_eq!(
400            process_instruction(&mut outputter, test_insns[34]),
401            Some(String::from("sb x19, 210(x4)"))
402        );
403
404        assert_eq!(
405            process_instruction(&mut outputter, test_insns[35]),
406            Some(String::from("sh x0, 390(x12)"))
407        );
408
409        assert_eq!(
410            process_instruction(&mut outputter, test_insns[36]),
411            Some(String::from("sw x19, 170(x16)"))
412        );
413
414        assert_eq!(
415            process_instruction(&mut outputter, test_insns[37]),
416            Some(String::from("mul x9, x13, x20"))
417        );
418
419        assert_eq!(
420            process_instruction(&mut outputter, test_insns[38]),
421            Some(String::from("mulh x30, x15, x22"))
422        );
423
424        assert_eq!(
425            process_instruction(&mut outputter, test_insns[39]),
426            Some(String::from("mulhu x23, x9, x18"))
427        );
428
429        assert_eq!(
430            process_instruction(&mut outputter, test_insns[40]),
431            Some(String::from("mulhsu x4, x19, x29"))
432        );
433
434        assert_eq!(
435            process_instruction(&mut outputter, test_insns[41]),
436            Some(String::from("div x19, x10, x31"))
437        );
438
439        assert_eq!(
440            process_instruction(&mut outputter, test_insns[42]),
441            Some(String::from("divu x2, x28, x14"))
442        );
443
444        assert_eq!(
445            process_instruction(&mut outputter, test_insns[43]),
446            Some(String::from("rem x19, x13, x10"))
447        );
448
449        assert_eq!(
450            process_instruction(&mut outputter, test_insns[44]),
451            Some(String::from("remu x13, x18, x12"))
452        );
453
454        assert_eq!(
455            process_instruction(&mut outputter, test_insns[45]),
456            Some(String::from("fence"))
457        );
458    }
459}