riscy_isa/
decoding_stream.rs

1use byteorder::{LittleEndian, ReadBytesExt};
2use std::io::Cursor;
3
4use crate::Instruction;
5
6/// Converts a block of bytes into a stream of RISC-V instructions represented by [Instruction] structs.
7///
8/// # Example
9///
10/// ```
11/// use riscy_isa::{Opcode, DecodingStream, Instruction, Register, OpImmFunction};
12/// let bytes: [u8; 4] = [19, 5, 0, 0];
13/// let mut stream = DecodingStream::new(&bytes);
14///
15/// // Decodes to an `addi a0, x0, 0` instruction
16/// assert_eq!(stream.next(), Some(Instruction::I {
17///     opcode: Opcode::OpImm(OpImmFunction::ADDI),
18///     rd: Register::A0,
19///     rs1: Register::Zero,
20///     imm: 0,
21/// }));
22///
23/// // There's only one instruction in the byte array so any further calls to
24/// // `next` return `None`.
25/// assert_eq!(stream.next(), None);
26/// ```
27pub struct DecodingStream<'a> {
28    cursor: Cursor<&'a [u8]>,
29}
30
31impl<'a> DecodingStream<'a> {
32    /// Constructs a [DecodingStream] from a block of bytes.
33    pub fn new(bytes: &'a [u8]) -> DecodingStream {
34        DecodingStream {
35            cursor: Cursor::new(bytes),
36        }
37    }
38}
39
40impl<'a> Iterator for DecodingStream<'a> {
41    type Item = Instruction;
42
43    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
44        let base: u16 = self.cursor.read_u16::<LittleEndian>().ok()?;
45
46        if base == 0 {
47            return None;
48        }
49
50        let ones = base.trailing_ones();
51
52        match ones {
53            0..=1 => Some(Instruction::from_16bits(base)),
54
55            2..=4 => {
56                let second: u32 = self.cursor.read_u16::<LittleEndian>().unwrap() as u32;
57                let encoded: u32 = (second << 16) | (base as u32);
58
59                Some(Instruction::from_32bits(encoded))
60            }
61
62            5 => {
63                let parcels = [
64                    base,
65                    self.cursor.read_u16::<LittleEndian>().unwrap(),
66                    self.cursor.read_u16::<LittleEndian>().unwrap(),
67                ];
68
69                unimplemented!("48-bit instruction: {:?}", parcels);
70            }
71
72            6 => {
73                let parcels = [
74                    base,
75                    self.cursor.read_u16::<LittleEndian>().unwrap(),
76                    self.cursor.read_u16::<LittleEndian>().unwrap(),
77                    self.cursor.read_u16::<LittleEndian>().unwrap(),
78                ];
79
80                unimplemented!("64-bit instruction: {:?}", parcels);
81            }
82
83            7..=11 => unimplemented!("Large instruction ({} trailing ones): {:#018b}", ones, base),
84            _ => unimplemented!(
85                "Invalid instruction ({} trailing ones): {:#018b}",
86                ones,
87                base
88            ),
89        }
90    }
91}