diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 4f499e0c..d0eb9ab1 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -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 diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index 4a5a3172..39960aa5 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -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$(,)?)+ }$(,)? diff --git a/riscv/src/register/misa.rs b/riscv/src/register/misa.rs index fd4f2167..8d9b8571 100644 --- a/riscv/src/register/misa.rs +++ b/riscv/src/register/misa.rs @@ -1,58 +1,59 @@ //! 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; } @@ -60,13 +61,39 @@ impl Misa { } } -read_csr!(0x301); - -/// Reads the CSR #[inline] -pub fn read() -> Option { - 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)); + }); + } } diff --git a/riscv/src/register/mstatus.rs b/riscv/src/register/mstatus.rs index 32986d34..f172c647 100644 --- a/riscv/src/register/mstatus.rs +++ b/riscv/src/register/mstatus.rs @@ -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(), } } @@ -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(), } } diff --git a/riscv/src/register/sstatus.rs b/riscv/src/register/sstatus.rs index 81a25fbf..565827c3 100644 --- a/riscv/src/register/sstatus.rs +++ b/riscv/src/register/sstatus.rs @@ -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(), } } diff --git a/riscv/src/register/tests/read_only_csr.rs b/riscv/src/register/tests/read_only_csr.rs index 477e884e..8bc93ffc 100644 --- a/riscv/src/register/tests/read_only_csr.rs +++ b/riscv/src/register/tests/read_only_csr.rs @@ -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, diff --git a/riscv/src/register/tests/read_write_csr.rs b/riscv/src/register/tests/read_write_csr.rs index bcad6478..a831c8c5 100644 --- a/riscv/src/register/tests/read_write_csr.rs +++ b/riscv/src/register/tests/read_write_csr.rs @@ -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, diff --git a/riscv/src/register/tests/write_only_csr.rs b/riscv/src/register/tests/write_only_csr.rs index 4c550f55..6f51be18 100644 --- a/riscv/src/register/tests/write_only_csr.rs +++ b/riscv/src/register/tests/write_only_csr.rs @@ -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,