Skip to content

Commit

Permalink
Merge pull request #244 from rmsyn/riscv/misa-csr-macro
Browse files Browse the repository at this point in the history
riscv: define misa using CSR macros
  • Loading branch information
romancardenas authored Nov 20, 2024
2 parents fdc3bb6 + 100b6a1 commit 517d52b
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 49 deletions.
1 change: 1 addition & 0 deletions riscv/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Use CSR helper macros to define `mcounteren` register
- Use CSR helper macros to define `mie` register
- Use CSR helper macros to define `mimpid` register
- Use CSR helper macros to define `misa` register

## [v0.12.1] - 2024-10-20

Expand Down
1 change: 0 additions & 1 deletion riscv/src/register/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,6 @@ macro_rules! csr {
macro_rules! csr_field_enum {
($(#[$field_ty_doc:meta])*
$field_ty:ident {
range: [$field_start:literal : $field_end:literal],
default: $default_variant:ident,
$($variant:ident = $value:expr$(,)?)+
}$(,)?
Expand Down
111 changes: 69 additions & 42 deletions riscv/src/register/misa.rs
Original file line number Diff line number Diff line change
@@ -1,72 +1,99 @@
//! misa register
use core::num::NonZeroUsize;

/// misa register
#[derive(Clone, Copy, Debug)]
pub struct Misa {
bits: NonZeroUsize,
#[cfg(target_arch = "riscv32")]
read_only_csr! {
/// `misa` register
Misa: 0x301,
mask: 0xc3ff_ffff,
sentinel: 0,
}

/// Base integer ISA width
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum XLEN {
XLEN32 = 1,
XLEN64 = 2,
XLEN128 = 3,
#[cfg(not(target_arch = "riscv32"))]
read_only_csr! {
/// `misa` register
Misa: 0x301,
mask: 0xc000_0000_03ff_ffff,
sentinel: 0,
}

impl XLEN {
/// Converts a number into an ISA width
pub(crate) fn from(value: u8) -> Self {
match value {
1 => XLEN::XLEN32,
2 => XLEN::XLEN64,
3 => XLEN::XLEN128,
_ => unreachable!(),
}
csr_field_enum! {
/// Base integer ISA width
XLEN {
default: XLEN32,
XLEN32 = 1,
XLEN64 = 2,
XLEN128 = 3,
}
}

impl Misa {
/// Returns the contents of the register as raw bits
#[inline]
pub fn bits(&self) -> usize {
self.bits.get()
}
#[cfg(target_arch = "riscv32")]
read_only_csr_field! {
Misa,
/// Effective xlen in M-mode (i.e., `MXLEN`).
mxl,
XLEN: [30:31],
}

#[cfg(not(target_arch = "riscv32"))]
read_only_csr_field! {
Misa,
/// Effective xlen in M-mode (i.e., `MXLEN`).
#[inline]
pub fn mxl(&self) -> XLEN {
let value = (self.bits() >> (usize::BITS - 2)) as u8;
XLEN::from(value)
}
mxl,
XLEN: [62:63],
}

impl Misa {
/// Returns true when a given extension is implemented.
///
/// # Example
///
/// ```no_run
/// let misa = unsafe { riscv::register::misa::read() }.unwrap();
/// let misa = unsafe { riscv::register::misa::try_read() }.unwrap();
/// assert!(misa.has_extension('A')); // panics if atomic extension is not implemented
/// ```
#[inline]
pub fn has_extension(&self, extension: char) -> bool {
let bit = extension as u8 - 65;
let bit = ext_char_to_bit(extension);
if bit > 25 {
return false;
}
self.bits() & (1 << bit) == (1 << bit)
}
}

read_csr!(0x301);

/// Reads the CSR
#[inline]
pub fn read() -> Option<Misa> {
let r = unsafe { _read() };
// When misa is hardwired to zero it means that the misa csr
// isn't implemented.
NonZeroUsize::new(r).map(|bits| Misa { bits })
const fn ext_char_to_bit(extension: char) -> u8 {
(extension as u8).saturating_sub(b'A')
}

#[cfg(test)]
mod tests {
use super::*;
use crate::result::Error;

#[test]
fn test_misa() {
(1..=3)
.zip([XLEN::XLEN32, XLEN::XLEN64, XLEN::XLEN128])
.for_each(|(raw, exp_xlen)| {
assert_eq!(XLEN::try_from(raw), Ok(exp_xlen));
assert_eq!(usize::from(exp_xlen), raw);

let misa = Misa::from_bits(raw << (usize::BITS - 2));
assert_eq!(misa.try_mxl(), Ok(exp_xlen));
assert_eq!(misa.mxl(), exp_xlen);
});

(0..62).map(|b| 1 << b).for_each(|invalid_mxl| {
assert_eq!(
Misa::from_bits(invalid_mxl).try_mxl(),
Err(Error::InvalidVariant(0))
);
});

('A'..='Z').for_each(|ext| {
assert!(!Misa::from_bits(0).has_extension(ext));
assert!(Misa::from_bits(1 << ext_char_to_bit(ext)).has_extension(ext));
});
}
}
4 changes: 2 additions & 2 deletions riscv/src/register/mstatus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ impl Mstatus {
#[cfg(riscv32)]
() => XLEN::XLEN32,
#[cfg(not(riscv32))]
() => XLEN::from(bf_extract(self.bits, 32, 2) as u8),
() => XLEN::try_from(bf_extract(self.bits, 32, 2)).unwrap_or_default(),
}
}

Expand All @@ -431,7 +431,7 @@ impl Mstatus {
#[cfg(riscv32)]
() => XLEN::XLEN32,
#[cfg(not(riscv32))]
() => XLEN::from(bf_extract(self.bits, 34, 2) as u8),
() => XLEN::try_from(bf_extract(self.bits, 34, 2)).unwrap_or_default(),
}
}

Expand Down
2 changes: 1 addition & 1 deletion riscv/src/register/sstatus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ impl Sstatus {
#[cfg(riscv32)]
() => XLEN::XLEN32,
#[cfg(not(riscv32))]
() => XLEN::from((self.bits >> 32) as u8 & 0x3),
() => XLEN::try_from((self.bits >> 32) & 0x3).unwrap_or_default(),
}
}

Expand Down
1 change: 0 additions & 1 deletion riscv/src/register/tests/read_only_csr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ read_only_csr_field! {
csr_field_enum! {
/// field enum type with valid field variants
MtestFieldEnum {
range: [8:11],
default: Field1,
Field1 = 1,
Field2 = 2,
Expand Down
1 change: 0 additions & 1 deletion riscv/src/register/tests/read_write_csr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ read_write_csr_field! {
csr_field_enum! {
/// field enum type with valid field variants
MtestFieldEnum {
range: [8:11],
default: Field1,
Field1 = 1,
Field2 = 2,
Expand Down
1 change: 0 additions & 1 deletion riscv/src/register/tests/write_only_csr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ write_only_csr_field! {
csr_field_enum! {
/// field enum type with valid field variants
MtestFieldEnum {
range: [8:11],
default: Field1,
Field1 = 1,
Field2 = 2,
Expand Down

0 comments on commit 517d52b

Please sign in to comment.