raki/
lib.rs

1//! raki
2//!
3//! `raki` is a RISC-V instruction decoder written in Rust.
4//!
5//! - Both 32/64bit support.
6//! - Support `rv32/64imac`, `Zicsr`, `Zifencei` extensions.
7//! - Implement Display trait for formatting.
8//!
9//! # Usage
10//! Call the `decode` as u16/u32 method.
11//! ```
12//! use raki::{BaseIOpcode, Decode, Instruction, Isa, OpcodeKind};
13//!
14//! fn example() {
15//!     let inst_bytes: u32 = 0b1110_1110_1100_0010_1000_0010_1001_0011;
16//!     let inst: Instruction = match inst_bytes.decode(Isa::Rv32) {
17//!         Ok(inst) => inst,
18//!         Err(e) => panic!("decoding failed due to {e:?}"),
19//!     };
20//!
21//!     assert_eq!(inst.opc, OpcodeKind::BaseI(BaseIOpcode::ADDI));
22//!     println!("{inst}");
23//! }
24//! // --output--
25//! // addi t0, t0, -276
26//! ```
27#![cfg_attr(not(test), no_std)]
28
29mod decode;
30mod instruction;
31
32// re-export
33pub use crate::decode::{Decode, DecodingError};
34pub use crate::instruction::{
35    a_extension::AOpcode, base_i::BaseIOpcode, c_extension::COpcode, m_extension::MOpcode,
36    priv_extension::PrivOpcode, zicboz_extension::ZicbozOpcode, zicfiss_extension::ZicfissOpcode,
37    zicntr_extension::ZicntrOpcode, zicsr_extension::ZicsrOpcode,
38    zifencei_extension::ZifenceiOpcode, InstFormat, Instruction, OpcodeKind,
39};
40
41/// Target isa.
42#[derive(Copy, Clone)]
43pub enum Isa {
44    /// 32 bit architecture.
45    Rv32,
46    /// 64 bit architecture.
47    Rv64,
48}
49
50/// RISC-V extensions
51#[derive(Debug)]
52enum Extensions {
53    /// Base Integer Instruction Set
54    BaseI,
55    /// Integer Multiplication and Division
56    M,
57    /// Atomic Instructions
58    A,
59    /// Compressed Instructions
60    C,
61    /// Instruction-Fetch Fence
62    Zifencei,
63    /// Cache-Block Zero Instructions
64    Zicboz,
65    /// Control and Status Register Instructions
66    Zicsr,
67    /// Shadow Stack
68    Zicfiss,
69    /// Base Counters and Timers
70    Zicntr,
71    /// Privileged Instructions
72    Priv,
73}
74
75impl TryFrom<usize> for Instruction {
76    type Error = DecodingError;
77    fn try_from(inst: usize) -> Result<Self, Self::Error> {
78        if inst & 0b11 == 0b11 {
79            u32::try_from(inst)
80                .expect("Truncation of usize to u32 failed.")
81                .decode(Isa::Rv64)
82        } else {
83            u16::try_from(inst)
84                .expect("Truncation of usize to u16 failed.")
85                .decode(Isa::Rv64)
86        }
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    #[test]
93    fn usize_try_from_test() {
94        use crate::instruction::{
95            base_i::BaseIOpcode, c_extension::COpcode, InstFormat, Instruction, OpcodeKind,
96        };
97
98        assert_eq!(
99            Instruction::try_from(0b1111_1111_1001_1111_1111_0000_0110_1111_usize),
100            Ok(Instruction {
101                opc: OpcodeKind::BaseI(BaseIOpcode::JAL),
102                rd: Some(0),
103                rs1: None,
104                rs2: None,
105                imm: Some(-8),
106                inst_format: InstFormat::JFormat,
107                is_compressed: false,
108            })
109        );
110
111        assert_eq!(
112            Instruction::try_from(0x880ausize),
113            Ok(Instruction {
114                opc: OpcodeKind::C(COpcode::MV),
115                rd: Some(16),
116                rs1: None,
117                rs2: Some(2),
118                imm: None,
119                inst_format: InstFormat::CrFormat,
120                is_compressed: true,
121            })
122        );
123
124        assert_ne!(
125            Instruction::try_from(0x880busize),
126            Ok(Instruction {
127                opc: OpcodeKind::C(COpcode::MV),
128                rd: Some(16),
129                rs1: None,
130                rs2: Some(2),
131                imm: None,
132                inst_format: InstFormat::CrFormat,
133                is_compressed: true,
134            })
135        );
136
137        assert_eq!(
138            Instruction::try_from(0b1111_1111_1001_1111_1111_0000_0110_1111_usize)
139                .unwrap()
140                .opc,
141            OpcodeKind::BaseI(BaseIOpcode::JAL),
142        );
143    }
144
145    #[test]
146    fn inst_eq_test() {
147        use crate::decode::Decode;
148        use crate::instruction::{base_i::BaseIOpcode, InstFormat, Instruction, OpcodeKind};
149        use crate::Isa;
150
151        assert_eq!(
152            0b1111_1111_1001_1111_1111_0000_0110_1111_u32.decode(Isa::Rv64),
153            Ok(Instruction {
154                opc: OpcodeKind::BaseI(BaseIOpcode::JAL),
155                rd: Some(0),
156                rs1: None,
157                rs2: None,
158                imm: Some(-8),
159                inst_format: InstFormat::JFormat,
160                is_compressed: false,
161            })
162        );
163
164        assert_eq!(
165            0b1111_1111_1001_1111_1111_0000_0110_1111_u32
166                .decode(Isa::Rv64)
167                .unwrap()
168                .opc,
169            OpcodeKind::BaseI(BaseIOpcode::JAL),
170        );
171    }
172}