risc_v_disassembler/
lib.rs

1//! A simple disassembler for the RISC-V instruction set architecture.
2//! It currently only supports 32 bit RV32I instructions.
3//!
4//! ### Supported Instruction Sets
5//!  - RV32I
6//!
7//! Parses a byte array slice into a `ParsedInstruction32` enum representing a RISC-V instruction.
8//!
9//! ### Arguments
10//!
11//! * `bytes` - A slice of bytes representing the encoded instruction to be parsed.
12//! * `is_big_endian` - A boolean indicating whether the bytes are in big endian format.
13//!
14//! ### Returns
15//!
16//! * `Ok(ParsedInstruction32)` - If the parsing is successful, returns the parsed instruction.
17//! * `Err(DisassemblerError)` - If the parsing fails, returns an error indicating the reason for failure.
18//!
19//! ### Example
20//!
21//! ```
22//! use risc_v_disassembler::{
23//!     parse,
24//!     ParsedInstruction32,
25//!     parsed_instructions::*
26//! };
27//!
28//! let bytes = [0x93, 0x00, 0x51, 0x00];
29//! let is_big_endian = false;
30//! let use_abi_register_names = false;
31//! let parsed_instruction = parse(&bytes, is_big_endian, use_abi_register_names).unwrap();
32//!
33//! assert_eq!(parsed_instruction, ParsedInstruction32::addi (addi {
34//!     rd: "x1",
35//!     rs1: "x2",
36//!     imm: 5
37//! }));
38//! ```
39//!
40//! Or using ABI register names:
41//! ```
42//! use risc_v_disassembler::{
43//!     parse,
44//!     ParsedInstruction32,
45//!     parsed_instructions::*
46//! };
47//!
48//! let bytes = [0x93, 0x00, 0x41, 0x00];
49//! let is_big_endian = false;
50//! let use_abi_register_names = true;
51//! let parsed_instruction = parse(&bytes, is_big_endian, use_abi_register_names).unwrap();
52
53//! assert_eq!(parsed_instruction, ParsedInstruction32::addi (addi {
54//!    rd: "ra",
55//!    rs1: "sp",
56//!    imm: 4
57//! }));
58//! ``` `
59
60mod decoder;
61mod instructions;
62mod macros;
63mod parser;
64mod registers;
65
66pub use instructions::{parsed_instructions, ParsedInstruction32};
67use instructions::{DecodeInstruction32, Instruction32, ParseInstruction32};
68pub use registers::Register;
69use thiserror::Error;
70
71pub fn parse(
72    bytes: &[u8],
73    is_big_endian: bool,
74    use_abi_register_names: bool,
75) -> Result<ParsedInstruction32, DisassemblerError> {
76    if bytes.len() != 4 {
77        return Err(DisassemblerError::UnsupportedInstructionLength(bytes.len()));
78    }
79
80    let instruction = if is_big_endian {
81        Instruction32::from_be_bytes(bytes.try_into().unwrap())
82    } else {
83        Instruction32::from_le_bytes(bytes.try_into().unwrap())
84    };
85
86    let decoded_instruction = instruction.decode_instruction32()?;
87
88    let parsed_instruction = if use_abi_register_names {
89        decoded_instruction.parse_instruction32::<registers::ABIRegister>()?
90    } else {
91        decoded_instruction.parse_instruction32::<registers::NumberedRegister>()?
92    };
93
94    Ok(parsed_instruction)
95}
96
97#[derive(Debug, Error, PartialEq)]
98pub enum DisassemblerError {
99    #[error(
100        "Unsupported instruction length: {0}. The length of the instruction is not supported."
101    )]
102    UnsupportedInstructionLength(usize),
103
104    #[error(
105        "Invalid funct3 field with value {0:b}. The value is not valid for the given instruction."
106    )]
107    InvalidFunct3(u8),
108
109    #[error(
110        "Invalid funct7 field with value {0:b}. The value is not valid for the given instruction."
111    )]
112    InvalidFunct7(u8),
113
114    #[error(
115        "Invalid opcode field with value {0:b}. The value is not valid for the given instruction."
116    )]
117    InvalidOpcode(u8),
118
119    #[error(
120        "Invalid immediate: {0:b}. The immediate value is not valid for the given instruction."
121    )]
122    InvalidImmediate(i32),
123
124    #[error("Invalid register: {0:?}. The register index is out of bounds.")]
125    InvalidRegister(u8),
126
127    #[error("Bit extraction error: {0}.")]
128    BitExtractionError(&'static str),
129
130    #[error("Bit extension error: {0}.")]
131    BitExtensionError(&'static str),
132}