Skip to content

Commit

Permalink
Merge pull request #15 from Alignof/release/v1.0.0-beta.1
Browse files Browse the repository at this point in the history
Ver 1.0.0-beta.1
  • Loading branch information
Alignof committed Aug 13, 2024
2 parents 326a1a6 + 28ce666 commit da85a53
Show file tree
Hide file tree
Showing 16 changed files with 258 additions and 104 deletions.
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
[package]
name = "raki"
version = "0.1.3"
version = "1.0.0-beta.1"
edition = "2021"
authors = ["Norimasa Takana <alignof@outlook.com>"]
repository = "https://github.com/Alignof/raki"
keywords = ["risc-v", "decoder"]
categories = ["encoding", "embedded", "hardware-support", "no-std", "parsing"]
description = "RISC-V instruction decoder written in Rust."
license = "MIT"
readme = "README.md"

[lints.clippy]
pedantic = "warn"
Expand Down
36 changes: 27 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,38 @@ RISC-V instruction decoder written in Rust.
## Usage
Call the `decode` as u16/u32 method.
```rust
use raki::Isa;
use raki::decode::Decode;
use raki::instruction::Instruction;
use raki::{BaseIOpcode, Decode, Instruction, Isa, OpcodeKind};

let inst: u32 = 0b1110_1110_1100_0010_1000_0010_1001_0011;
let inst: Instruction = match inst.decode(Isa::Rv32) {
Ok(inst) => inst,
Err(e) => panic!("decoding failed due to {e:?}"),
};
println!("{inst}");
fn main() {
let inst_bytes: u32 = 0b1110_1110_1100_0010_1000_0010_1001_0011;
let inst: Instruction = match inst_bytes.decode(Isa::Rv32) {
Ok(inst) => inst,
Err(e) => panic!("decoding failed due to {e:?}"),
};

assert_eq!(inst.opc, OpcodeKind::BaseI(BaseIOpcode::ADDI));
println!("{inst}");
}
// --output--
// addi t0, t0, -276
```

## Support
- [x] BaseI (RV32I, RV64I)
- [x] M
- [x] A
- [ ] D
- [ ] G
- [ ] Q
- [x] C
- [ ] B
- [ ] P
- [ ] V
- [ ] H
- [x] Zicsr
- [x] Zifencei
- [ ] Priv (Now only supports `mret`, `sret`, `wfi`, `sfence.vma`)

## License
This crate is licensed under MIT.
See `LICENSE` for details.
31 changes: 18 additions & 13 deletions src/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
mod inst_16;
mod inst_32;

use crate::instruction::{Extensions, Instruction, Opcode, OpcodeKind};
use crate::Isa;
use crate::instruction::{Instruction, Opcode, OpcodeKind};
use crate::{Extensions, Isa};

/// Return Err if given opcode is only available on Rv64.
fn only_rv64<T: Opcode>(opcode: T, isa: Isa) -> Result<T, DecodingError> {
Expand All @@ -18,9 +18,7 @@ fn only_rv64<T: Opcode>(opcode: T, isa: Isa) -> Result<T, DecodingError> {
///
/// # Example
/// ```
/// use raki::Isa;
/// use raki::decode::{Decode, DecodingError};
/// use raki::instruction::Instruction;
/// use raki::{Isa, Decode, DecodingError, Instruction};
///
/// // try to decode illegal instruction.
/// let illegal_inst: u32 = 0b0000_0000_0000_0000_0000_0000_0000_0000;
Expand All @@ -34,7 +32,7 @@ fn only_rv64<T: Opcode>(opcode: T, isa: Isa) -> Result<T, DecodingError> {
/// assert!(matches!(error, DecodingError::OnlyRv64Inst));
/// }
/// ```
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub enum DecodingError {
/// 32bit instructions are expected, but it is compressed instruction.
Not16BitInst,
Expand All @@ -59,13 +57,13 @@ pub enum DecodingError {
}

/// A trait to decode an instruction from u16/u32.
/// This trait provides public api.
///
/// # Usage
/// `decode` method is implemented for u16/u32.
/// thus, just call `decode` as method of u16/u32.
/// ```
/// use raki::Isa;
/// use raki::decode::Decode;
/// use raki::{Isa, Decode};
///
/// let inst: u32 = 0b1110_1110_1100_0010_1000_0010_1001_0011;
/// println!("{:?}", inst.decode(Isa::Rv64));
Expand All @@ -76,31 +74,31 @@ pub trait Decode {
/// # Errors
/// It will throws an error if target bytes is invalid for decoding.
fn decode(&self, isa: Isa) -> Result<Instruction, DecodingError>;
/// Parse extension from a u16/u32 value.
///
/// # Errors
/// It will throws `UnknownExtension` if the extension is unsupported.
fn parse_extension(self) -> Result<Extensions, DecodingError>;

/// Parse opcode.
///
/// # Errors
/// It will throws an error if opcode is unknown.
fn parse_opcode(self, isa: Isa) -> Result<OpcodeKind, DecodingError>;

/// Parse destination register.
///
/// # Errors
/// It will throws an error if rd is invalid.
fn parse_rd(self, opkind: &OpcodeKind) -> Result<Option<usize>, DecodingError>;

/// Parse source register 1.
///
/// # Errors
/// It will throws an error if rs1 is invalid.
fn parse_rs1(self, opkind: &OpcodeKind) -> Result<Option<usize>, DecodingError>;

/// Parse source register 2.
///
/// # Errors
/// It will throws an error if rs2 is invalid.
fn parse_rs2(self, opkind: &OpcodeKind) -> Result<Option<usize>, DecodingError>;

/// Parse immediate.
///
/// # Errors
Expand All @@ -109,6 +107,7 @@ pub trait Decode {
}

/// A trait to help decoding.
/// This trait provides private api.
trait DecodeUtil {
/// Obtains bits in a specified range.
/// The range is `[end, start]`.
Expand All @@ -134,6 +133,12 @@ trait DecodeUtil {
/// * `mask` - It contain the bit order.
fn set(self, mask: &[u32]) -> u32;

/// Parse extension from a u16/u32 value.
///
/// # Errors
/// It will throws `UnknownExtension` if the extension is unsupported.
fn parse_extension(self) -> Result<Extensions, DecodingError>;

/// Convert i32 to a sign-extended any size number.
/// # Arguments
/// * `imm32` - The value to be converted.
Expand Down
12 changes: 6 additions & 6 deletions src/decode/inst_16.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
mod c_extension;

use super::{Decode, DecodeUtil, DecodingError};
use crate::instruction::{Extensions, InstFormat, Instruction, OpcodeKind};
use crate::Isa;
use crate::instruction::{InstFormat, Instruction, OpcodeKind};
use crate::{Extensions, Isa};

impl Decode for u16 {
fn decode(&self, isa: Isa) -> Result<Instruction, DecodingError> {
Expand All @@ -28,10 +28,6 @@ impl Decode for u16 {
})
}

fn parse_extension(self) -> Result<Extensions, DecodingError> {
Ok(Extensions::C)
}

fn parse_opcode(self, isa: Isa) -> Result<OpcodeKind, DecodingError> {
let extension = self.parse_extension();

Expand Down Expand Up @@ -75,6 +71,10 @@ impl DecodeUtil for u16 {
(self >> start) & (2_u16.pow(end - start + 1) - 1)
}

fn parse_extension(self) -> Result<Extensions, DecodingError> {
Ok(Extensions::C)
}

fn set(self, mask: &[u32]) -> u32 {
let mut inst: u32 = 0;
for (i, m) in mask.iter().rev().enumerate() {
Expand Down
77 changes: 47 additions & 30 deletions src/decode/inst_32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ mod base_i;
mod m_extension;
mod priv_extension;
mod zicsr_extension;
mod zifencei_extension;

use super::{Decode, DecodeUtil, DecodingError};
use crate::instruction::{Extensions, InstFormat, Instruction, OpcodeKind};
use crate::Isa;
use crate::instruction::{InstFormat, Instruction, OpcodeKind};
use crate::{Extensions, Isa};

#[allow(non_snake_case)]
impl Decode for u32 {
Expand All @@ -28,40 +29,16 @@ impl Decode for u32 {
})
}

fn parse_extension(self) -> Result<Extensions, DecodingError> {
let opmap: u8 = u8::try_from(self.slice(6, 0)).unwrap();
let funct3: u8 = u8::try_from(self.slice(14, 12)).unwrap();
let funct7: u8 = u8::try_from(self.slice(31, 25)).unwrap();

match opmap {
0b010_1111 => Ok(Extensions::A),
0b011_0011 => match funct7 {
0b000_0001 => Ok(Extensions::M),
_ => Ok(Extensions::BaseI),
},
0b011_1011 => match funct7 {
0b000_0000 | 0b010_0000 => Ok(Extensions::BaseI),
0b000_0001 => Ok(Extensions::M),
_ => Err(DecodingError::UnknownExtension),
},
0b111_0011 => match funct3 {
0b000 => match funct7 {
0b000_0000 => Ok(Extensions::BaseI),
_ => Ok(Extensions::Priv),
},
_ => Ok(Extensions::Zicsr),
},
_ => Ok(Extensions::BaseI),
}
}

fn parse_opcode(self, isa: Isa) -> Result<OpcodeKind, DecodingError> {
let extension = self.parse_extension();

match extension {
Ok(Extensions::BaseI) => Ok(OpcodeKind::BaseI(base_i::parse_opcode(self, isa)?)),
Ok(Extensions::M) => Ok(OpcodeKind::M(m_extension::parse_opcode(self, isa)?)),
Ok(Extensions::A) => Ok(OpcodeKind::A(a_extension::parse_opcode(self, isa)?)),
Ok(Extensions::Zifencei) => Ok(OpcodeKind::Zifencei(zifencei_extension::parse_opcode(
self,
)?)),
Ok(Extensions::Zicsr) => Ok(OpcodeKind::Zicsr(zicsr_extension::parse_opcode(self)?)),
Ok(Extensions::Priv) => Ok(OpcodeKind::Priv(priv_extension::parse_opcode(self)?)),
Ok(Extensions::C) => Err(DecodingError::Not32BitInst),
Expand All @@ -74,6 +51,7 @@ impl Decode for u32 {
OpcodeKind::BaseI(opc) => Ok(base_i::parse_rd(self, opc)),
OpcodeKind::M(opc) => Ok(m_extension::parse_rd(self, opc)),
OpcodeKind::A(opc) => Ok(a_extension::parse_rd(self, opc)),
OpcodeKind::Zifencei(opc) => Ok(zifencei_extension::parse_rd(self, opc)),
OpcodeKind::Zicsr(opc) => Ok(zicsr_extension::parse_rd(self, opc)),
OpcodeKind::Priv(opc) => Ok(priv_extension::parse_rd(self, opc)),
OpcodeKind::C(_) => Err(DecodingError::Not32BitInst),
Expand All @@ -85,6 +63,7 @@ impl Decode for u32 {
OpcodeKind::BaseI(opc) => Ok(base_i::parse_rs1(self, opc)),
OpcodeKind::M(opc) => Ok(m_extension::parse_rs1(self, opc)),
OpcodeKind::A(opc) => Ok(a_extension::parse_rs1(self, opc)),
OpcodeKind::Zifencei(opc) => Ok(zifencei_extension::parse_rs1(self, opc)),
OpcodeKind::Zicsr(opc) => Ok(zicsr_extension::parse_rs1(self, opc)),
OpcodeKind::Priv(opc) => Ok(priv_extension::parse_rs1(self, opc)),
OpcodeKind::C(_) => Err(DecodingError::Not32BitInst),
Expand All @@ -96,6 +75,7 @@ impl Decode for u32 {
OpcodeKind::BaseI(opc) => Ok(base_i::parse_rs2(self, opc)),
OpcodeKind::M(opc) => Ok(m_extension::parse_rs2(self, opc)),
OpcodeKind::A(opc) => Ok(a_extension::parse_rs2(self, opc)),
OpcodeKind::Zifencei(opc) => Ok(zifencei_extension::parse_rs2(self, opc)),
OpcodeKind::Zicsr(opc) => Ok(zicsr_extension::parse_rs2(self, opc)),
OpcodeKind::Priv(opc) => Ok(priv_extension::parse_rs2(self, opc)),
OpcodeKind::C(_) => Err(DecodingError::Not32BitInst),
Expand All @@ -107,6 +87,7 @@ impl Decode for u32 {
OpcodeKind::BaseI(opc) => Ok(base_i::parse_imm(self, opc, isa)),
OpcodeKind::M(opc) => Ok(m_extension::parse_imm(self, opc)),
OpcodeKind::A(opc) => Ok(a_extension::parse_imm(self, opc)),
OpcodeKind::Zifencei(opc) => Ok(zifencei_extension::parse_imm(self, opc)),
OpcodeKind::Zicsr(opc) => Ok(zicsr_extension::parse_imm(self, opc)),
OpcodeKind::Priv(opc) => Ok(priv_extension::parse_imm(self, opc)),
OpcodeKind::C(_) => Err(DecodingError::Not32BitInst),
Expand All @@ -119,6 +100,34 @@ impl DecodeUtil for u32 {
(self >> start) & (2_u32.pow(end - start + 1) - 1)
}

fn parse_extension(self) -> Result<Extensions, DecodingError> {
let opmap: u8 = u8::try_from(self.slice(6, 0)).unwrap();
let funct3: u8 = u8::try_from(self.slice(14, 12)).unwrap();
let funct7: u8 = u8::try_from(self.slice(31, 25)).unwrap();

match opmap {
0b000_1111 => Ok(Extensions::Zifencei),
0b010_1111 => Ok(Extensions::A),
0b011_0011 => match funct7 {
0b000_0001 => Ok(Extensions::M),
_ => Ok(Extensions::BaseI),
},
0b011_1011 => match funct7 {
0b000_0000 | 0b010_0000 => Ok(Extensions::BaseI),
0b000_0001 => Ok(Extensions::M),
_ => Err(DecodingError::UnknownExtension),
},
0b111_0011 => match funct3 {
0b000 => match funct7 {
0b000_0000 => Ok(Extensions::BaseI),
_ => Ok(Extensions::Priv),
},
_ => Ok(Extensions::Zicsr),
},
_ => Ok(Extensions::BaseI),
}
}

fn set(self, mask: &[u32]) -> u32 {
let mut inst: u32 = 0;
for (i, m) in mask.iter().rev().enumerate() {
Expand All @@ -136,7 +145,7 @@ mod decode_32 {
#[allow(overflowing_literals)]
fn decoding_32bit_inst_test() {
use super::*;
use crate::instruction::{a_extension::AOpcode, base_i::BaseIOpcode, m_extension::MOpcode};
use crate::{AOpcode, BaseIOpcode, MOpcode, ZifenceiOpcode};

let test_32 = |inst_32: u32,
op: OpcodeKind,
Expand Down Expand Up @@ -288,5 +297,13 @@ mod decode_32 {
Some(8),
None,
);
test_32(
0b0000_0011_0011_0000_0000_0000_0000_1111,
OpcodeKind::Zifencei(ZifenceiOpcode::FENCE),
Some(0),
Some(0),
None,
Some(0x033),
)
}
}
1 change: 0 additions & 1 deletion src/decode/inst_32/base_i.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ pub fn parse_opcode(inst: u32, isa: Isa) -> Result<BaseIOpcode, DecodingError> {
0b111 => Ok(BaseIOpcode::AND),
_ => Err(DecodingError::InvalidFunct3),
},
0b000_1111 => Ok(BaseIOpcode::FENCE),
0b111_0011 => match funct3 {
0b000 => match funct7 {
0b000_0000 => match funct5 {
Expand Down
Loading

0 comments on commit da85a53

Please sign in to comment.