diff --git a/Cargo.toml b/Cargo.toml index b57f2e1..eecee70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,14 @@ [package] name = "raki" -version = "0.1.3" +version = "1.0.0-beta.1" edition = "2021" authors = ["Norimasa Takana "] 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" diff --git a/README.md b/README.md index cc494a3..5f164df 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/src/decode.rs b/src/decode.rs index 4807fbc..9c2348b 100644 --- a/src/decode.rs +++ b/src/decode.rs @@ -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(opcode: T, isa: Isa) -> Result { @@ -18,9 +18,7 @@ fn only_rv64(opcode: T, isa: Isa) -> Result { /// /// # 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; @@ -34,7 +32,7 @@ fn only_rv64(opcode: T, isa: Isa) -> Result { /// assert!(matches!(error, DecodingError::OnlyRv64Inst)); /// } /// ``` -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum DecodingError { /// 32bit instructions are expected, but it is compressed instruction. Not16BitInst, @@ -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)); @@ -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; - /// Parse extension from a u16/u32 value. - /// - /// # Errors - /// It will throws `UnknownExtension` if the extension is unsupported. - fn parse_extension(self) -> Result; + /// Parse opcode. /// /// # Errors /// It will throws an error if opcode is unknown. fn parse_opcode(self, isa: Isa) -> Result; + /// Parse destination register. /// /// # Errors /// It will throws an error if rd is invalid. fn parse_rd(self, opkind: &OpcodeKind) -> Result, DecodingError>; + /// Parse source register 1. /// /// # Errors /// It will throws an error if rs1 is invalid. fn parse_rs1(self, opkind: &OpcodeKind) -> Result, DecodingError>; + /// Parse source register 2. /// /// # Errors /// It will throws an error if rs2 is invalid. fn parse_rs2(self, opkind: &OpcodeKind) -> Result, DecodingError>; + /// Parse immediate. /// /// # Errors @@ -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]`. @@ -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; + /// Convert i32 to a sign-extended any size number. /// # Arguments /// * `imm32` - The value to be converted. diff --git a/src/decode/inst_16.rs b/src/decode/inst_16.rs index 93e879a..a10fd09 100644 --- a/src/decode/inst_16.rs +++ b/src/decode/inst_16.rs @@ -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 { @@ -28,10 +28,6 @@ impl Decode for u16 { }) } - fn parse_extension(self) -> Result { - Ok(Extensions::C) - } - fn parse_opcode(self, isa: Isa) -> Result { let extension = self.parse_extension(); @@ -75,6 +71,10 @@ impl DecodeUtil for u16 { (self >> start) & (2_u16.pow(end - start + 1) - 1) } + fn parse_extension(self) -> Result { + Ok(Extensions::C) + } + fn set(self, mask: &[u32]) -> u32 { let mut inst: u32 = 0; for (i, m) in mask.iter().rev().enumerate() { diff --git a/src/decode/inst_32.rs b/src/decode/inst_32.rs index ac4dd75..bb86fac 100644 --- a/src/decode/inst_32.rs +++ b/src/decode/inst_32.rs @@ -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 { @@ -28,33 +29,6 @@ impl Decode for u32 { }) } - fn parse_extension(self) -> Result { - 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 { let extension = self.parse_extension(); @@ -62,6 +36,9 @@ impl Decode for u32 { 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), @@ -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), @@ -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), @@ -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), @@ -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), @@ -119,6 +100,34 @@ impl DecodeUtil for u32 { (self >> start) & (2_u32.pow(end - start + 1) - 1) } + fn parse_extension(self) -> Result { + 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() { @@ -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, @@ -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), + ) } } diff --git a/src/decode/inst_32/base_i.rs b/src/decode/inst_32/base_i.rs index 2f9d93e..6ed30ce 100644 --- a/src/decode/inst_32/base_i.rs +++ b/src/decode/inst_32/base_i.rs @@ -91,7 +91,6 @@ pub fn parse_opcode(inst: u32, isa: Isa) -> Result { 0b111 => Ok(BaseIOpcode::AND), _ => Err(DecodingError::InvalidFunct3), }, - 0b000_1111 => Ok(BaseIOpcode::FENCE), 0b111_0011 => match funct3 { 0b000 => match funct7 { 0b000_0000 => match funct5 { diff --git a/src/decode/inst_32/zifencei_extension.rs b/src/decode/inst_32/zifencei_extension.rs new file mode 100644 index 0000000..5c74674 --- /dev/null +++ b/src/decode/inst_32/zifencei_extension.rs @@ -0,0 +1,44 @@ +use super::super::{DecodeUtil, DecodingError}; +use crate::instruction::zifencei_extension::ZifenceiOpcode; + +pub fn parse_opcode(inst: u32) -> Result { + let opmap: u8 = u8::try_from(inst.slice(6, 0)).unwrap(); + + match opmap { + 0b000_1111 => Ok(ZifenceiOpcode::FENCE), + _ => Err(DecodingError::InvalidOpcode), + } +} + +#[allow(clippy::unnecessary_wraps)] +pub fn parse_rd(inst: u32, opkind: &ZifenceiOpcode) -> Option { + let rd: usize = inst.slice(11, 7) as usize; + + match opkind { + ZifenceiOpcode::FENCE => Some(rd), + } +} + +#[allow(clippy::unnecessary_wraps)] +pub fn parse_rs1(inst: u32, opkind: &ZifenceiOpcode) -> Option { + let rs1: usize = inst.slice(19, 15) as usize; + + match opkind { + ZifenceiOpcode::FENCE => Some(rs1), + } +} + +#[allow(clippy::unnecessary_wraps)] +pub fn parse_rs2(_inst: u32, opkind: &ZifenceiOpcode) -> Option { + match opkind { + ZifenceiOpcode::FENCE => None, + } +} + +#[allow(clippy::cast_possible_wrap, clippy::unnecessary_wraps)] +pub fn parse_imm(inst: u32, opkind: &ZifenceiOpcode) -> Option { + let fm_pred_succ: u32 = inst.slice(31, 20); + match opkind { + ZifenceiOpcode::FENCE => Some(fm_pred_succ as i32), + } +} diff --git a/src/instruction.rs b/src/instruction.rs index a74abcf..364c568 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -6,6 +6,7 @@ pub mod c_extension; pub mod m_extension; pub mod priv_extension; pub mod zicsr_extension; +pub mod zifencei_extension; use core::fmt::{self, Display, Formatter}; @@ -15,9 +16,10 @@ use c_extension::COpcode; use m_extension::MOpcode; use priv_extension::PrivOpcode; use zicsr_extension::ZicsrOpcode; +use zifencei_extension::ZifenceiOpcode; /// Instruction -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub struct Instruction { /// Opcode pub opc: OpcodeKind, @@ -219,6 +221,7 @@ impl Display for Instruction { } } +/// Convert register number to string. fn reg2str(rd_value: usize) -> &'static str { match rd_value { 0 => "zero", @@ -257,26 +260,9 @@ fn reg2str(rd_value: usize) -> &'static str { } } -/// RISC-V extensions -#[derive(Debug)] -pub enum Extensions { - /// Base Integer Instruction Set - BaseI, - /// Integer Multiplication and Division - M, - /// Atomic Instructions - A, - /// Compressed Instructions - C, - /// Control and Status Register Instructions - Zicsr, - /// Privileged Instructions - Priv, -} - /// Instruction format #[allow(non_camel_case_types)] -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum InstFormat { /// Regular format /// ```ignore @@ -428,7 +414,7 @@ pub trait Opcode { } /// Extension type and Instruction name. -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum OpcodeKind { /// Base Integer Instruction Set BaseI(BaseIOpcode), @@ -438,6 +424,8 @@ pub enum OpcodeKind { A(AOpcode), /// Compressed Instructions C(COpcode), + /// Instruction-Fetch Fence, + Zifencei(ZifenceiOpcode), /// Control and Status Register Instructions Zicsr(ZicsrOpcode), /// Privileged Instructions @@ -451,6 +439,7 @@ impl Display for OpcodeKind { Self::M(opc) => write!(f, "{opc}"), Self::A(opc) => write!(f, "{opc}"), Self::C(opc) => write!(f, "{opc}"), + Self::Zifencei(opc) => write!(f, "{opc}"), Self::Zicsr(opc) => write!(f, "{opc}"), Self::Priv(opc) => write!(f, "{opc}"), } @@ -465,6 +454,7 @@ impl OpcodeKind { Self::M(opc) => opc.get_format(), Self::A(opc) => opc.get_format(), Self::C(opc) => opc.get_format(), + Self::Zifencei(opc) => opc.get_format(), Self::Zicsr(opc) => opc.get_format(), Self::Priv(opc) => opc.get_format(), } diff --git a/src/instruction/a_extension.rs b/src/instruction/a_extension.rs index c58f739..02a23fa 100644 --- a/src/instruction/a_extension.rs +++ b/src/instruction/a_extension.rs @@ -5,7 +5,7 @@ use core::fmt::{self, Display, Formatter}; /// Insturctions in A Extension. #[allow(non_camel_case_types)] -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum AOpcode { LR_W, SC_W, diff --git a/src/instruction/base_i.rs b/src/instruction/base_i.rs index 84b1894..8b09ad0 100644 --- a/src/instruction/base_i.rs +++ b/src/instruction/base_i.rs @@ -5,7 +5,7 @@ use core::fmt::{self, Display, Formatter}; /// Insturctions in Base-I. #[allow(non_camel_case_types, clippy::module_name_repetitions)] -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum BaseIOpcode { LUI, AUIPC, @@ -44,7 +44,6 @@ pub enum BaseIOpcode { SRA, OR, AND, - FENCE, ECALL, EBREAK, @@ -103,7 +102,6 @@ impl Display for BaseIOpcode { BaseIOpcode::SRA => write!(f, "sra"), BaseIOpcode::OR => write!(f, "or"), BaseIOpcode::AND => write!(f, "and"), - BaseIOpcode::FENCE => write!(f, "fence"), BaseIOpcode::ECALL => write!(f, "ecall"), BaseIOpcode::EBREAK => write!(f, "ebreak"), BaseIOpcode::LWU => write!(f, "lwu"), @@ -172,9 +170,7 @@ impl Opcode for BaseIOpcode { } BaseIOpcode::JAL => InstFormat::Jformat, BaseIOpcode::LUI | BaseIOpcode::AUIPC => InstFormat::Uformat, - BaseIOpcode::ECALL | BaseIOpcode::FENCE | BaseIOpcode::EBREAK => { - InstFormat::Uncategorized - } + BaseIOpcode::ECALL | BaseIOpcode::EBREAK => InstFormat::Uncategorized, } } } diff --git a/src/instruction/c_extension.rs b/src/instruction/c_extension.rs index c943264..12cd1ad 100644 --- a/src/instruction/c_extension.rs +++ b/src/instruction/c_extension.rs @@ -5,7 +5,7 @@ use core::fmt::{self, Display, Formatter}; /// Insturctions in C Extension. #[allow(non_camel_case_types)] -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum COpcode { ADDI4SPN, LW, diff --git a/src/instruction/m_extension.rs b/src/instruction/m_extension.rs index 090acf8..20ece8b 100644 --- a/src/instruction/m_extension.rs +++ b/src/instruction/m_extension.rs @@ -4,8 +4,8 @@ use super::{InstFormat, Opcode}; use core::fmt::{self, Display, Formatter}; /// Insturctions in M Extension. -#[allow(non_camel_case_types)] -#[derive(Debug)] +#[allow(non_camel_case_types, clippy::upper_case_acronyms)] +#[derive(Debug, PartialEq)] pub enum MOpcode { MUL, MULH, diff --git a/src/instruction/priv_extension.rs b/src/instruction/priv_extension.rs index 96e8ede..37ac94c 100644 --- a/src/instruction/priv_extension.rs +++ b/src/instruction/priv_extension.rs @@ -5,10 +5,10 @@ use core::fmt::{self, Display, Formatter}; /// Privileged Insturctions. #[allow(non_camel_case_types)] -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum PrivOpcode { - SRET, MRET, + SRET, WFI, SFENCE_VMA, } diff --git a/src/instruction/zicsr_extension.rs b/src/instruction/zicsr_extension.rs index e14cc52..6240712 100644 --- a/src/instruction/zicsr_extension.rs +++ b/src/instruction/zicsr_extension.rs @@ -5,7 +5,7 @@ use core::fmt::{self, Display, Formatter}; /// Insturctions in Zicsr Extension. #[allow(non_camel_case_types)] -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum ZicsrOpcode { CSRRW, CSRRS, diff --git a/src/instruction/zifencei_extension.rs b/src/instruction/zifencei_extension.rs new file mode 100644 index 0000000..e3169b7 --- /dev/null +++ b/src/instruction/zifencei_extension.rs @@ -0,0 +1,27 @@ +//! Zicsr extension Instruction. + +use super::{InstFormat, Opcode}; +use core::fmt::{self, Display, Formatter}; + +/// Insturctions in Zifencei Extension. +#[allow(non_camel_case_types)] +#[derive(Debug, PartialEq)] +pub enum ZifenceiOpcode { + FENCE, +} + +impl Display for ZifenceiOpcode { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + ZifenceiOpcode::FENCE => write!(f, "fence.i"), + } + } +} + +impl Opcode for ZifenceiOpcode { + fn get_format(&self) -> InstFormat { + match self { + ZifenceiOpcode::FENCE => InstFormat::Uncategorized, + } + } +} diff --git a/src/lib.rs b/src/lib.rs index cfe71c8..e7f8b7b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,22 +9,32 @@ //! # Usage //! Call the `decode` as u16/u32 method. //! ``` -//! 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 example() { +//! 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 //! ``` -pub mod decode; -pub mod instruction; +mod decode; +mod instruction; + +// re-export +pub use crate::decode::{Decode, DecodingError}; +pub use crate::instruction::{ + a_extension::AOpcode, base_i::BaseIOpcode, c_extension::COpcode, m_extension::MOpcode, + priv_extension::PrivOpcode, zicsr_extension::ZicsrOpcode, zifencei_extension::ZifenceiOpcode, + InstFormat, Instruction, OpcodeKind, +}; /// Target isa. #[derive(Copy, Clone)] @@ -35,6 +45,25 @@ pub enum Isa { Rv64, } +/// RISC-V extensions +#[derive(Debug)] +enum Extensions { + /// Base Integer Instruction Set + BaseI, + /// Integer Multiplication and Division + M, + /// Atomic Instructions + A, + /// Compressed Instructions + C, + /// Instruction-Fetch Fence + Zifencei, + /// Control and Status Register Instructions + Zicsr, + /// Privileged Instructions + Priv, +} + #[cfg(test)] mod tests { #[test] @@ -90,4 +119,31 @@ mod tests { println!("{inst}"); } } + + #[test] + fn inst_eq_test() { + use crate::decode::Decode; + use crate::instruction::{base_i::BaseIOpcode, InstFormat, Instruction, OpcodeKind}; + use crate::Isa; + + assert_eq!( + 0b1111_1111_1001_1111_1111_0000_0110_1111_u32.decode(Isa::Rv64), + Ok(Instruction { + opc: OpcodeKind::BaseI(BaseIOpcode::JAL), + rd: Some(0), + rs1: None, + rs2: None, + imm: Some(-8), + inst_format: InstFormat::Jformat, + }) + ); + + assert_eq!( + 0b1111_1111_1001_1111_1111_0000_0110_1111_u32 + .decode(Isa::Rv64) + .unwrap() + .opc, + OpcodeKind::BaseI(BaseIOpcode::JAL), + ) + } }