Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions robustone-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ edition = "2024"

[dependencies]
hex = "0.4"
bitflags = "2.10.0"

[features]
default = ["riscv"]
Expand Down
45 changes: 13 additions & 32 deletions robustone-core/src/riscv/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
//! is implemented as a separate module, making the codebase more maintainable
//! and easier to extend with new instructions.

use super::extensions::{InstructionExtension, create_extensions, extension_masks};
use super::extensions::standard::Standard;
use super::extensions::{Extensions, InstructionExtension, create_extensions};
use super::types::*;
use crate::error::DisasmError;

Expand All @@ -19,13 +20,13 @@ pub enum Xlen {
/// Refactored RISC-V instruction decoder using extension modules.
pub struct RiscVDecoder {
xlen: Xlen,
extensions: u32,
extensions: Extensions,
extension_handlers: Vec<Box<dyn InstructionExtension>>,
}

impl RiscVDecoder {
/// Construct a decoder with the provided XLEN and extension bitmask.
pub fn new(xlen: Xlen, extensions: u32) -> Self {
pub fn new(xlen: Xlen, extensions: Extensions) -> Self {
let extension_handlers = create_extensions();
Self {
xlen,
Expand All @@ -36,28 +37,12 @@ impl RiscVDecoder {

/// Create a decoder with full RV32GC support.
pub fn rv32gc() -> Self {
Self::new(
Xlen::X32,
extension_masks::I
| extension_masks::M
| extension_masks::A
| extension_masks::F
| extension_masks::C
| extension_masks::XTHEADCONDMOV,
)
Self::new(Xlen::X32, Extensions::rv32gc())
}

/// Create a decoder with full RV64GC support.
pub fn rv64gc() -> Self {
Self::new(
Xlen::X64,
extension_masks::I
| extension_masks::M
| extension_masks::A
| extension_masks::F
| extension_masks::D
| extension_masks::C,
)
Self::new(Xlen::X64, Extensions::rv64gc())
}

/// Decode a single instruction located at `address`.
Expand Down Expand Up @@ -131,7 +116,7 @@ impl RiscVDecoder {

// Try each enabled extension in order
for extension in &self.extension_handlers {
if !extension.is_enabled(self.extensions) {
if !extension.is_enabled(&self.extensions) {
continue;
}

Expand Down Expand Up @@ -229,13 +214,13 @@ impl RiscVDecoder {
| ((instruction >> 6) & 0x1) << 6 // imm[6] from instruction[6]
| ((instruction >> 9) & 0x3) << 7; // imm[8:7] from instruction[9:8]

if self.extensions & extension_masks::C == 0 {
if !self.extensions.standard.contains(Standard::C) {
eprintln!("Warning: Decoding compressed instruction while C extension is disabled");
}

// Try each enabled extension for compressed instructions
for extension in &self.extension_handlers {
if !extension.is_enabled(self.extensions) {
if !extension.is_enabled(&self.extensions) {
continue;
}

Expand Down Expand Up @@ -334,20 +319,16 @@ mod tests {
fn test_refactored_decoder_creation() {
let decoder = RiscVDecoder::rv32gc();
assert_eq!(decoder.xlen, Xlen::X32);
assert!(decoder.extensions & extension_masks::I != 0);
assert!(decoder.extensions.standard.contains(Standard::I));

let decoder = RiscVDecoder::rv64gc();
assert_eq!(decoder.xlen, Xlen::X64);
assert!(decoder.extensions & extension_masks::I != 0);
assert!(decoder.extensions.standard.contains(Standard::I));

let decoder = RiscVDecoder::rv64gc();
assert_eq!(decoder.xlen, Xlen::X64);
assert!(decoder.extensions & extension_masks::I != 0);
assert!(decoder.extensions & extension_masks::M != 0);
assert!(decoder.extensions & extension_masks::A != 0);
assert!(decoder.extensions & extension_masks::F != 0);
assert!(decoder.extensions & extension_masks::D != 0);
assert!(decoder.extensions & extension_masks::C != 0);
assert!(decoder.extensions.standard.contains(Standard::G));
assert!(decoder.extensions.standard.contains(Standard::C));
}

#[test]
Expand Down
85 changes: 47 additions & 38 deletions robustone-core/src/riscv/extensions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,45 @@
use super::decoder::{RiscVDecodedInstruction, Xlen};
use crate::error::DisasmError;

// Submodules grouping standard and custom-specific extensions.
pub mod standard;
pub mod thead;

use standard::Standard;
use thead::THead;

/// Aggregated extension configuration passed to RISC-V extension handlers.
pub struct Extensions {
pub(crate) standard: Standard,
pub(crate) thead: THead,
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In extensions module, This struct is called Extensions. So StandardExtensions, this Extensions is redundant. Just call it Standard

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I will also change THeadExtensions to THead

impl Extensions {
/// Convenience configuration for RV32GC profile with all standard and
/// no T-Head custom extensions enabled.
pub fn rv32gc() -> Self {
Self {
standard: Standard::G | Standard::C,
thead: THead::empty(),
}
}

/// Convenience configuration for RV64GC profile with all standard and
/// no T-Head custom extensions enabled.
pub fn rv64gc() -> Self {
Self {
standard: Standard::G | Standard::C,
thead: THead::empty(),
}
}

/// Enables all available T-Head custom extensions on this configuration.
pub fn thead(mut self) -> Self {
self.thead |= THead::all();
self
}
}

/// Trait that all instruction set extensions must implement.
#[allow(clippy::too_many_arguments)]
pub trait InstructionExtension: Sync {
Expand Down Expand Up @@ -65,48 +104,18 @@ pub trait InstructionExtension: Sync {
fn name(&self) -> &'static str;

/// Check if this extension is enabled for the given configuration.
fn is_enabled(&self, extensions: u32) -> bool;
fn is_enabled(&self, extensions: &Extensions) -> bool;
}

// Standard RISC-V extension modules
pub mod rva; // RVA - Atomic Instructions
pub mod rvc; // RVC - Compressed Instructions
pub mod rvd; // RVD - Double-Precision Floating-Point
pub mod rvf; // RVF - Single-Precision Floating-Point
pub mod rvi; // RV32I/RV64I - Base Integer Instruction Set
pub mod rvm; // RVM - Multiply and Divide Instructions

// XuanTie vendor extension modules
pub mod xtheadcondmov; // XTheadCondMov - Conditional Move Instructions

use rva::RvaExtension;
use rvc::RvcExtension;
use rvd::RvdExtension;
use rvf::RvfExtension;
use rvi::RviExtension;
use rvm::RvmExtension;
use xtheadcondmov::XTheadCondMovExtension;

/// Create all available standard RISC-V extensions.
pub fn create_extensions() -> Vec<Box<dyn InstructionExtension>> {
vec![
Box::new(RviExtension::new()),
Box::new(RvaExtension::new()),
Box::new(RvmExtension::new()),
Box::new(RvfExtension::new()),
Box::new(RvdExtension::new()),
Box::new(RvcExtension::new()),
Box::new(XTheadCondMovExtension::new()),
Box::new(standard::Rvi::new()),
Box::new(standard::Rva::new()),
Box::new(standard::Rvm::new()),
Box::new(standard::Rvf::new()),
Box::new(standard::Rvd::new()),
Box::new(standard::Rvc::new()),
Box::new(thead::CMov::new()),
]
}

/// Extension bit masks for standard RISC-V and XuanTie extensions.
pub mod extension_masks {
pub const I: u32 = 0b001; // Base Integer Instruction Set
pub const M: u32 = 0b010; // Multiply and Divide
pub const A: u32 = 0b100; // Atomic Instructions
pub const F: u32 = 0b1000; // Single-Precision Floating-Point
pub const D: u32 = 0b10000; // Double-Precision Floating-Point
pub const C: u32 = 0b100000; // Compressed Instructions
pub const XTHEADCONDMOV: u32 = 0b1000000; // XTheadCondMov - Conditional Move
}
39 changes: 39 additions & 0 deletions robustone-core/src/riscv/extensions/standard/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//! Standard RISC-V extensions and configuration.
//!
//! This module defines the `StandardExtensions` bitflags for core RISC-V
//! extensions (I/M/A/F/D/C) and re-exports the corresponding extension
//! handler types under the `standard` namespace.

use bitflags::bitflags;

pub mod rva;
pub mod rvc;
pub mod rvd;
pub mod rvf;
pub mod rvi;
pub mod rvm;

pub use rva::Rva;
pub use rvc::Rvc;
pub use rvd::Rvd;
pub use rvf::Rvf;
pub use rvi::Rvi;
pub use rvm::Rvm;

bitflags! {
/// Bitflags representing enabled standard RISC-V extensions.
pub struct Standard: u32 {
const I = 1;
const M = 1 << 1;
const A = 1 << 2;
const F = 1 << 3;
const D = 1 << 4;
const C = 1 << 5;
/// Shorthand for the standard G profile (IMAFD).
const G = Self::I.bits()
| Self::M.bits()
| Self::A.bits()
| Self::F.bits()
| Self::D.bits();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,22 @@
//! This module implements the RISC-V atomic instructions extension (A extension),
//! which provides atomic memory operations for synchronization and concurrency.

use super::super::decoder::{RiscVDecodedInstruction, Xlen};
use super::super::shared::{
use super::Standard;
use crate::error::DisasmError;
use crate::riscv::decoder::{RiscVDecodedInstruction, Xlen};
use crate::riscv::extensions::{Extensions, InstructionExtension};
use crate::riscv::shared::{
operands::convenience,
registers::{RegisterManager, RegisterNameProvider},
};
use super::super::types::*;
use super::InstructionExtension;
use crate::error::DisasmError;
use crate::riscv::extensions::extension_masks;
use crate::riscv::types::*;

/// RVA Atomic Instructions Extension
pub struct RvaExtension {
pub struct Rva {
register_manager: RegisterManager,
}

impl RvaExtension {
impl Rva {
/// Create a new RVA extension instance.
pub fn new() -> Self {
Self {
Expand Down Expand Up @@ -111,14 +111,14 @@ impl RvaExtension {
}
}

impl InstructionExtension for RvaExtension {
impl InstructionExtension for Rva {
fn name(&self) -> &'static str {
"A"
}

fn is_enabled(&self, extensions: u32) -> bool {
fn is_enabled(&self, extensions: &Extensions) -> bool {
// A extension bit (bit 2)
extensions & extension_masks::A != 0
extensions.standard.contains(Standard::A)
}

fn try_decode_standard(
Expand Down Expand Up @@ -250,7 +250,7 @@ impl InstructionExtension for RvaExtension {
}
}

impl Default for RvaExtension {
impl Default for Rva {
fn default() -> Self {
Self::new()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,23 @@
//! This module implements the RISC-V compressed instruction extension (C extension),
//! which provides 16-bit compressed versions of common instructions to improve code density.

use super::super::decoder::{RiscVDecodedInstruction, Xlen};
use super::super::shared::{
use super::Standard;
use crate::error::DisasmError;
use crate::riscv::decoder::{RiscVDecodedInstruction, Xlen};
use crate::riscv::extensions::{Extensions, InstructionExtension};
use crate::riscv::shared::{
encoding::convenience as encoding_conv,
operands::convenience,
registers::{RegisterManager, RegisterNameProvider},
};
use super::super::types::*;
use super::InstructionExtension;
use crate::error::DisasmError;
use crate::riscv::extensions::extension_masks;
use crate::riscv::types::*;

/// RVC Compressed Instructions Extension
pub struct RvcExtension {
pub struct Rvc {
register_manager: RegisterManager,
}

impl RvcExtension {
impl Rvc {
/// Create a new RVC extension instance.
pub fn new() -> Self {
Self {
Expand Down Expand Up @@ -366,14 +366,14 @@ impl RvcExtension {
}
}

impl InstructionExtension for RvcExtension {
impl InstructionExtension for Rvc {
fn name(&self) -> &'static str {
"C"
}

fn is_enabled(&self, extensions: u32) -> bool {
fn is_enabled(&self, extensions: &Extensions) -> bool {
// C extension bit (bit 5)
extensions & extension_masks::C != 0
extensions.standard.contains(Standard::C)
}

fn try_decode_standard(
Expand Down Expand Up @@ -472,7 +472,7 @@ impl InstructionExtension for RvcExtension {
}
}

impl Default for RvcExtension {
impl Default for Rvc {
fn default() -> Self {
Self::new()
}
Expand Down
Loading
Loading