From a169176919f13236383baf169ba0cd487c064cd5 Mon Sep 17 00:00:00 2001 From: rmsyn Date: Thu, 30 May 2024 03:46:00 +0000 Subject: [PATCH 01/19] riscv: add CSR-defining macros Adds helper macros for defining CSR types. --- riscv/CHANGELOG.md | 1 + riscv/src/lib.rs | 2 +- riscv/src/register.rs | 3 + riscv/src/register/macros.rs | 406 ++++++++++++++++++++++++++++ riscv/src/register/mcountinhibit.rs | 111 ++------ riscv/src/register/tests.rs | 81 ++++++ 6 files changed, 512 insertions(+), 92 deletions(-) create mode 100644 riscv/src/register/tests.rs diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 98d1b7b4..04080506 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Add `Mstatus` vector extension support - Add fallible counterparts to all functions that `panic` - Add `riscv-pac` as a dependency +- Add CSR-defining macros to create in-memory types ### Fixed diff --git a/riscv/src/lib.rs b/riscv/src/lib.rs index 6290c18c..9408c8fe 100644 --- a/riscv/src/lib.rs +++ b/riscv/src/lib.rs @@ -36,7 +36,7 @@ #![allow(clippy::missing_safety_doc)] pub mod asm; -pub(crate) mod bits; +pub mod bits; pub mod delay; pub mod interrupt; pub mod register; diff --git a/riscv/src/register.rs b/riscv/src/register.rs index e99264b5..be788310 100644 --- a/riscv/src/register.rs +++ b/riscv/src/register.rs @@ -107,6 +107,9 @@ pub mod minstreth; mod mhpmeventx; pub use self::mhpmeventx::*; +#[cfg(test)] +mod tests; + // TODO: Debug/Trace Registers (shared with Debug Mode) // TODO: Debug Mode Registers diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index 1153dedc..bd37187b 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -600,3 +600,409 @@ macro_rules! clear_pmp { } }; } + + +/// Helper macro to define a CSR type. +/// +/// This macro creates a type represents a CSR register, without defining any bitfields. +/// +/// It is mainly used by [read_write_csr](crate::read_write_csr), +/// [read_only_csr](crate::read_only_csr), and [write_only_csr](crate::write_only_csr) macros. +#[macro_export] +macro_rules! csr { + ($doc:expr, $ty:ident: $csr:literal, $mask:literal) => { + #[repr(C)] + #[doc = $doc] + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub struct $ty { + bits: usize, + } + + impl $ty { + /// Bitmask for legal bitfields of the CSR type. + pub const BITMASK: usize = $mask; + + /// Creates a new CSR type from raw bits value. + /// + /// Only bits in the [BITMASK](Self::BITMASK) will be set. + pub const fn from_bits(bits: usize) -> Self { + Self { bits: bits & $mask } + } + + /// Gets the raw bits value. + pub const fn bits(&self) -> usize { + self.bits & $mask + } + + /// Gets the bitmask for the CSR type's bitfields. + pub const fn bitmask(&self) -> usize { + Self::BITMASK + } + } + }; +} + +/// Helper macro to create a read-write CSR type. +/// +/// The type allows to read the CSR value into memory, and update the field values in-memory. +/// +/// The user can then write the entire bitfield value back into the CSR with a single write. +#[macro_export] +macro_rules! read_write_csr { + ($doc:expr, + $ty:ident: $csr:tt, + $mask:tt, + $( + $field_doc:expr, + $field:ident: $get_bit:literal, + $set_field_doc:expr, + $set_field:ident: $set_bit:literal$(,)? + )+) => { + $crate::csr!($doc, $ty: $csr, $mask); + + $( + $crate::read_write_csr_field!( + $ty, + $field_doc, + $field: $get_bit, + $set_field_doc, + $set_field: $set_bit, + ); + )+ + + $crate::read_csr_as!($ty, $csr); + $crate::write_csr_as!($ty, $csr); + $crate::set!($csr); + $crate::clear!($csr); + }; + + ($doc:expr, + $ty:ident: $csr:tt, + $mask:tt, + $( + $field_doc:expr, + $field:ident: $get_bit_start:literal ..= $get_bit_end:literal, + $set_field_doc:expr, + $set_field:ident: $set_bit_start:literal ..= $set_bit_end:literal$(,)? + )+) => { + $crate::csr!($doc, $ty: $csr, $mask); + + $( + $crate::read_write_csr_field!( + $ty, + $field_doc, + $field: $get_bit_start ..= $get_bit_end, + $set_field_doc, + $set_field: $set_bit_start ..= $set_bit_end, + ); + )+ + + $crate::read_csr_as!($ty, $csr); + $crate::write_csr_as!($ty, $csr); + $crate::set!($csr); + $crate::clear!($csr); + }; + + ($doc:expr, + $ty:ident: $csr:tt, + $mask:tt, + $( + $field_doc:expr, + $field:ident: [$get_bit_start:literal : $get_bit_end:literal], + $set_field_doc:expr, + $set_field:ident: [$set_bit_start:literal : $set_bit_end:literal]$(,)? + )+) => { + $crate::csr!($doc, $ty: $csr, $mask); + + $( + $crate::read_write_csr_field!( + $ty, + $field_doc, + $field: [$get_bit_start : $get_bit_end], + $set_field_doc, + $set_field: [$set_bit_start : $set_bit_end], + ); + )+ + + $crate::read_csr_as!($ty, $csr); + $crate::write_csr_as!($ty, $csr); + $crate::set!($csr); + $crate::clear!($csr); + }; +} + +/// Helper macro to create a read-only CSR type. +/// +/// The type allows to read the CSR value into memory. +#[macro_export] +macro_rules! read_only_csr { + ($doc:expr, + $ty:ident: $csr:expr, + $mask:literal, + $( + $field_doc:expr, + $field:ident: [$bit_start:literal : $bit_end:literal]$(,)? + )+) => { + $crate::csr! { $doc, $ty: $csr, $mask } + + $( + $crate::read_only_csr_field! { + $ty, + $field_doc, + $field: [$bit_start:$bit_end], + } + )+ + }; + + ($doc:expr, $ty:ident: $csr:tt, $mask:tt, $($field_doc:expr, $field:ident, $bit:tt$(,)?)+) => { + $crate::csr! { $doc, $ty: $csr, $mask } + + $( + $crate::read_only_csr_field! { + $ty, + $field_doc, + $field: $bit..=$bit_end, + } + )+ + }; + + ($doc:expr, + $ty:ident: $csr:expr, + $mask:literal, + $( + $field_doc:expr, + $field:ident: $bit:tt ..= $bit_end:tt$(,)? + )+) => { + $crate::csr! { $doc, $ty: $csr, $mask } + + $( + $crate::read_only_csr_field! { + $ty, + $field_doc, + $field: $bit..=$bit_end, + } + )+ + + $crate::read_csr_as!($ty, $csr); + }; +} + +/// Helper macro to create a read-only CSR type. +/// +/// The type allows to read the CSR value into memory. +#[macro_export] +macro_rules! write_only_csr { + ($doc:expr, + $ty:ident: $csr:literal, + $mask:literal, + $($field_doc:expr, $field:ident: $bit:literal$(,)?)+) => { + $crate::csr! { $doc, $ty: $csr, $mask } + + $( + $crate::write_only_csr_field! { + $ty, + $field_doc, + $field: $bit, + } + )+ + + $crate::write_csr_as!($ty, $csr); + $crate::set!($csr); + $crate::clear!($csr); + }; + + ($doc:expr, + $ty:ident: $csr:literal, + $mask:literal, + $( + $field_doc:expr, + $field:ident: $bit_start:literal ..= $bit_end:literal$(,)? + )+) => { + $crate::csr! { $doc, $ty: $csr, $mask } + + $( + $crate::write_only_csr_field! { + $ty, + $field_doc, + $field: $bit_start..=$bit_end, + } + )+ + + $crate::write_csr_as!($ty, $csr); + $crate::set!($csr); + $crate::clear!($csr); + }; + + ($doc:expr, + $ty:ident: $csr:literal, + $mask:literal, + $( + $field_doc:expr, + $field:ident: [$bit_start:literal : $bit_end:literal]$(,)? + )+) => { + $crate::csr! { $doc, $ty: $csr, $mask } + + $( + $crate::write_only_csr_field! { + $ty, + $field_doc, + $field: [$bit_start:$bit_end], + } + )+ + + $crate::write_csr_as!($ty, $csr); + $crate::set!($csr); + $crate::clear!($csr); + }; +} + +/// Defines field accesor functions for a read-write CSR type. +#[macro_export] +macro_rules! read_write_csr_field { + ($ty:ident, + $field_doc:expr, + $field:ident: $get_bit:literal, + $set_field_doc:expr, + $set_field:ident: $set_bit:literal$(,)?) => { + impl $ty { + #[doc = $field_doc] + #[inline] + pub fn $field(&self) -> bool { + $crate::bits::bf_extract(self.bits, $get_bit, 1) != 0 + } + + #[doc = $set_field_doc] + #[inline] + pub fn $set_field(&mut self, $field: bool) { + self.bits = $crate::bits::bf_insert(self.bits, $set_bit, 1, $field as usize); + } + } + }; + + ($ty:ident, + $field_doc:expr, + $field:ident: $get_bit_start:literal ..= $get_bit_end:literal, + $set_field_doc:expr, + $set_field:ident: $set_bit_start:literal ..= $set_bit_end:literal$(,)?) => { + impl $ty { + #[doc = $field_doc] + #[inline] + pub fn $field(&self, index: usize) -> bool { + assert!(($get_bit_start..=$get_bit_end).contains(&index)); + $crate::bits::bf_extract(self.bits, index, 1) != 0 + } + + #[doc = $set_field_doc] + #[inline] + pub fn $set_field(&mut self, index: usize, $field: bool) { + assert!(($set_bit_start..=$set_bit_end).contains(&index)); + self.bits = $crate::bits::bf_insert(self.bits, index, 1, $field as usize); + } + } + }; + + ($ty:ident, + $field_doc:expr, + $field:ident: [$get_bit_start:literal : $get_bit_end:literal], + $set_field_doc:expr, + $set_field:ident: [$set_bit_start:literal : $set_bit_end:literal]$(,)?) => { + impl $ty { + #[doc = $field_doc] + #[inline] + pub fn $field(&self) -> usize { + $crate::bits::bf_extract( + self.bits, + $get_bit_start, + $get_bit_end - $get_bit_start + 1, + ) + } + + #[doc = $set_field_doc] + #[inline] + pub fn $set_field(&mut self, $field: usize) { + self.bits = $crate::bits::bf_insert( + self.bits, + $set_bit_start, + $set_bit_end - $set_bit_start + 1, + $field, + ); + } + } + }; +} + +/// Defines field accesor functions for a read-only CSR type. +#[macro_export] +macro_rules! read_only_csr_field { + ($ty:ident, $field_doc:expr, $field:ident: $bit:literal$(,)?) => { + impl $ty { + #[doc = $field_doc] + #[inline] + pub fn $field(&self) -> bool { + $crate::bits::bf_extract(self.bits, $bit, 1) != 0 + } + } + }; + + ($ty:ident, $field_doc:expr, $field:ident: $bit_start:literal..=$bit_end:literal$(,)?) => { + impl $ty { + #[doc = $field_doc] + #[inline] + pub fn $field(&self, index: usize) -> bool { + assert!(($bit_start..=$bit_end).contains(&index)); + $crate::bits::bf_extract(self.bits, index, 1) != 0 + } + } + }; + + ($ty:ident, $field_doc:expr, $field:ident: [$bit_start:literal : $bit_end:literal]$(,)?) => { + impl $ty { + #[doc = $field_doc] + #[inline] + pub fn $field(&self) -> bool { + $crate::bits::bf_extract(self.bits, $bit_start, $bit_end - $bit_start + 1) != 0 + } + } + }; +} + +/// Defines field accesor functions for a write-only CSR type. +#[macro_export] +macro_rules! write_only_csr_field { + ($ty:ident, $field_doc:expr, $field:ident: $bit:literal$(,)?) => { + impl $ty { + #[doc = $field_doc] + #[inline] + pub fn $field(&self) -> bool { + $crate::bits::bf_insert(self.bits, $bit, 1) != 0 + } + } + }; + + ($ty:ident, $field_doc:expr, $field:ident: $bit_start:literal..=$bit_end:literal$(,)?) => { + impl $ty { + #[doc = $field_doc] + #[inline] + pub fn $field(&mut self, index: usize, $field: bool) { + assert!(($bit_start..=$bit_end).contains(&index)); + self.bits = $crate::bits::bf_insert(self.bits, index, 1, $field as usize); + } + } + }; + + ($ty:ident, $field_doc:expr, $field:ident: [$bit_start:literal : $bit_end:literal]$(,)?) => { + impl $ty { + #[doc = $field_doc] + #[inline] + pub fn $field(&mut self, index: usize, $field: usize) { + assert!(($bit_start..=$bit_end).contains(&index)); + self.bits = $crate::bits::bf_insert( + self.bits, + $bit_start, + $bit_end - $bit_start + 1, + $field, + ); + } + } + }; +} diff --git a/riscv/src/register/mcountinhibit.rs b/riscv/src/register/mcountinhibit.rs index 60d32af3..d94e2b3a 100644 --- a/riscv/src/register/mcountinhibit.rs +++ b/riscv/src/register/mcountinhibit.rs @@ -1,100 +1,29 @@ //! `mcountinhibit` register -use crate::bits::{bf_extract, bf_insert}; -use crate::result::{Error, Result}; - -/// `mcountinhibit` register -#[derive(Clone, Copy, Debug)] -pub struct Mcountinhibit { - bits: usize, +use crate::read_write_csr; + +read_write_csr! { + "`mcountinhibit` register", + Mcountinhibit: 0x320, + 0xffff_fffd, + "Gets the `cycle[h]` inhibit field value.", + cy: 0, + "Sets the `cycle[h]` inhibit field value.\n\n**NOTE**: only updates the in-memory value without touching the CSR.", + set_cy: 0, + "Gets the `instret[h]` inhibit field value.", + ir: 2, + "Sets the `instret[h]` inhibit field value.\n\n**NOTE**: only updates the in-memory value without touching the CSR.", + set_ir: 2, } -impl Mcountinhibit { - /// Machine "cycle\[h\]" Disable - #[inline] - pub fn cy(&self) -> bool { - bf_extract(self.bits, 0, 1) != 0 - } - - /// Sets whether to inhibit the "cycle\[h\]" counter. - /// - /// Only updates the in-memory value, does not modify the `mcountinhibit` register. - #[inline] - pub fn set_cy(&mut self, cy: bool) { - self.bits = bf_insert(self.bits, 0, 1, cy as usize); - } - - /// Machine "instret\[h\]" Disable - #[inline] - pub fn ir(&self) -> bool { - bf_extract(self.bits, 2, 1) != 0 - } - - /// Sets whether to inhibit the "instret\[h\]" counter. - /// - /// Only updates the in-memory value, does not modify the `mcountinhibit` register. - #[inline] - pub fn set_ir(&mut self, ir: bool) { - self.bits = bf_insert(self.bits, 2, 1, ir as usize); - } - - /// Machine "hpm\[x\]" Disable (bits 3-31) - #[inline] - pub fn hpm(&self, index: usize) -> bool { - assert!((3..32).contains(&index)); - bf_extract(self.bits, index, 1) != 0 - } - - /// Machine "hpm\[x\]" Disable (bits 3-31) - /// - /// Attempts to read the "hpm\[x\]" value, and returns an error if the index is invalid. - #[inline] - pub fn try_hpm(&self, index: usize) -> Result { - if (3..32).contains(&index) { - Ok(bf_extract(self.bits, index, 1) != 0) - } else { - Err(Error::IndexOutOfBounds { - index, - min: 3, - max: 31, - }) - } - } - - /// Sets whether to inhibit the "hpm\[X\]" counter. - /// - /// Only updates the in-memory value, does not modify the `mcountinhibit` register. - #[inline] - pub fn set_hpm(&mut self, index: usize, hpm: bool) { - assert!((3..32).contains(&index)); - self.bits = bf_insert(self.bits, index, 1, hpm as usize); - } - - /// Sets whether to inhibit the "hpm\[X\]" counter. - /// - /// Only updates the in-memory value, does not modify the `mcountinhibit` register. - /// - /// Attempts to update the "hpm\[x\]" value, and returns an error if the index is invalid. - #[inline] - pub fn try_set_hpm(&mut self, index: usize, hpm: bool) -> Result<()> { - if (3..32).contains(&index) { - self.bits = bf_insert(self.bits, index, 1, hpm as usize); - Ok(()) - } else { - Err(Error::IndexOutOfBounds { - index, - min: 3, - max: 31, - }) - } - } +read_write_csr_field! { + Mcountinhibit, + "Gets the `mhpmcounterX[h]` inhibit field value.\n\n**WARN**: `index` must be in the range `[31:3]`.", + hpm: 3..=31, + "Sets the `mhpmcounterX[h]` inhibit field value.\n\n**WARN**: `index` must be in the range `[31:3]`.\n\n**NOTE**: only updates the in-memory value without touching the CSR.", + set_hpm: 3..=31, } -read_csr_as!(Mcountinhibit, 0x320); -write_csr_as!(Mcountinhibit, 0x320); -set!(0x320); -clear!(0x320); - set_clear_csr!( /// Machine cycle Disable , set_cy, clear_cy, 1 << 0); diff --git a/riscv/src/register/tests.rs b/riscv/src/register/tests.rs new file mode 100644 index 00000000..1aa94648 --- /dev/null +++ b/riscv/src/register/tests.rs @@ -0,0 +1,81 @@ +read_write_csr! { + "test CSR register type", + Mtest: 0x000, + 0b1111_1111, + "test single-bit field", + single: 0, + "setter test single-bit field", + set_single: 0, +} + +read_write_csr_field! { + Mtest, + "multiple single-bit field range", + multi_range: 1..=3, + "setter multiple single-bit field range", + set_multi_range: 1..=3, +} + +read_write_csr_field!( + Mtest, + "multi-bit field", + multi_field: [4:7], + "setter multi-bit field", + set_multi_field: [4:7], +); + +// we don't test the `read` and `write` functions, we are only testing in-memory functions. +#[allow(unused)] +pub fn _read_csr() -> Mtest { + read() +} + +#[allow(unused)] +pub fn _write_csr(csr: Mtest) { + write(csr); +} + +#[test] +fn test_mtest() { + let mut mtest = Mtest::from_bits(0); + + assert_eq!(mtest.bitmask(), Mtest::BITMASK); + assert_eq!(mtest.bits(), 0); + + // check that single bit field getter/setters work. + assert_eq!(mtest.single(), false); + + mtest.set_single(true); + assert_eq!(mtest.single(), true); + + mtest.set_single(false); + assert_eq!(mtest.single(), false); + + // check that single bit range field getter/setters work. + for i in 1..=3 { + assert_eq!(mtest.multi_range(i), false); + + mtest.set_multi_range(i, true); + assert_eq!(mtest.multi_range(i), true); + + mtest.set_multi_range(i, false); + assert_eq!(mtest.multi_range(i), false); + } + + // check that multi-bit field getter/setters work. + assert_eq!(mtest.multi_field(), 0); + + mtest.set_multi_field(0xf); + assert_eq!(mtest.multi_field(), 0xf); + + mtest.set_multi_field(0x3); + assert_eq!(mtest.multi_field(), 0x3); + + // check that only bits in the field are set. + mtest.set_multi_field(0xff); + assert_eq!(mtest.multi_field(), 0xf); + assert_eq!(mtest.bits(), 0xf << 4); + + mtest.set_multi_field(0x0); + assert_eq!(mtest.multi_field(), 0x0); +} From 9c431a73cd9d79ed881ebadb093b4b4f9f3d7b66 Mon Sep 17 00:00:00 2001 From: rmsyn Date: Thu, 6 Jun 2024 03:47:20 +0000 Subject: [PATCH 02/19] riscv: add enum branch to CSR macro Adds the ability to define CSR types using an enum field type. --- riscv/src/register/macros.rs | 310 +++++++++++++++++++-- riscv/src/register/tests.rs | 84 +----- riscv/src/register/tests/read_only_csr.rs | 102 +++++++ riscv/src/register/tests/read_write_csr.rs | 116 ++++++++ riscv/src/register/tests/write_only_csr.rs | 98 +++++++ 5 files changed, 610 insertions(+), 100 deletions(-) create mode 100644 riscv/src/register/tests/read_only_csr.rs create mode 100644 riscv/src/register/tests/read_write_csr.rs create mode 100644 riscv/src/register/tests/write_only_csr.rs diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index bd37187b..8a3ae0b4 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -601,7 +601,6 @@ macro_rules! clear_pmp { }; } - /// Helper macro to define a CSR type. /// /// This macro creates a type represents a CSR register, without defining any bitfields. @@ -642,6 +641,56 @@ macro_rules! csr { }; } +#[macro_export] +macro_rules! csr_field_enum { + ($field_ty_doc:expr, + $field_ty:ident { + range: [$field_start:literal : $field_end:literal], + default: $default_variant:ident, + $($variant:ident = $value:expr$(,)?)+ + }$(,)? + ) => { + #[doc = $field_ty_doc] + #[repr(usize)] + #[derive(Clone, Copy, Debug, Eq, PartialEq)] + pub enum $field_ty { + $($variant = $value),+ + } + + impl $field_ty { + /// Creates a new field variant. + pub const fn new() -> Self { + Self::$default_variant + } + + /// Attempts to convert a [`usize`] into a valid variant. + pub const fn from_usize(val: usize) -> Option { + match val { + $($value => Some(Self::$variant),)+ + _ => None, + } + } + + /// Converts the variant into a [`usize`]. + pub const fn into_usize(self) -> usize { + self as usize + } + } + + impl Default for $field_ty { + fn default() -> Self { + Self::new() + } + } + + impl From<$field_ty> for usize { + fn from(val: $field_ty) -> Self { + val.into_usize() + } + } + }; +} + /// Helper macro to create a read-write CSR type. /// /// The type allows to read the CSR value into memory, and update the field values in-memory. @@ -729,6 +778,45 @@ macro_rules! read_write_csr { $crate::set!($csr); $crate::clear!($csr); }; + + ($doc:expr, + $ty:ident: $csr:tt, + $mask:tt, + $( + $field_doc:expr, + $field:ident, + $set_field_doc:expr, + $set_field:ident, + $field_ty_doc:expr, + $field_ty:ident { + range: [$field_start:literal : $field_end:literal], + default: $default_variant:ident, + $($variant:ident = $value:expr$(,)?)+ + }$(,)? + )+) => { + $crate::csr!($doc, $ty: $csr, $mask); + + $( + $crate::read_write_csr_field!( + $ty, + $field_doc, + $field, + $set_field_doc, + $set_field, + $field_ty_doc, + $field_ty { + range: [$field_start : $field_end], + default: $field_default, + $($variant = $value),+ + }, + ); + )+ + + $crate::read_csr_as!($ty, $csr); + $crate::write_csr_as!($ty, $csr); + $crate::set!($csr); + $crate::clear!($csr); + }; } /// Helper macro to create a read-only CSR type. @@ -737,41 +825,49 @@ macro_rules! read_write_csr { #[macro_export] macro_rules! read_only_csr { ($doc:expr, - $ty:ident: $csr:expr, - $mask:literal, - $( - $field_doc:expr, - $field:ident: [$bit_start:literal : $bit_end:literal]$(,)? - )+) => { + $ty:ident: $csr:tt, + $mask:tt, + $($field_doc:expr, $field:ident: $bit:literal$(,)?)+ + ) => { $crate::csr! { $doc, $ty: $csr, $mask } $( $crate::read_only_csr_field! { $ty, $field_doc, - $field: [$bit_start:$bit_end], + $field: $bit, } )+ + + $crate::read_csr_as!($ty, $csr); }; - ($doc:expr, $ty:ident: $csr:tt, $mask:tt, $($field_doc:expr, $field:ident, $bit:tt$(,)?)+) => { + ($doc:expr, + $ty:ident: $csr:tt, + $mask:tt, + $( + $field_doc:expr, + $field:ident: $bit:literal ..= $bit_end:literal$(,)? + )+) => { $crate::csr! { $doc, $ty: $csr, $mask } $( $crate::read_only_csr_field! { $ty, $field_doc, - $field: $bit..=$bit_end, + $field: $bit ..= $bit_end, } )+ + + $crate::read_csr_as!($ty, $csr); }; ($doc:expr, - $ty:ident: $csr:expr, + $ty:ident: $csr:literal, $mask:literal, $( $field_doc:expr, - $field:ident: $bit:tt ..= $bit_end:tt$(,)? + $field:ident: [$bit:tt : $bit_end:tt]$(,)? )+) => { $crate::csr! { $doc, $ty: $csr, $mask } @@ -779,12 +875,44 @@ macro_rules! read_only_csr { $crate::read_only_csr_field! { $ty, $field_doc, - $field: $bit..=$bit_end, + $field: [$bit : $bit_end], } )+ $crate::read_csr_as!($ty, $csr); }; + + ($doc:expr, + $ty:ident: $csr:tt, + $mask:tt, + $( + $field_doc:expr, + $field:ident, + $field_ty_doc:expr, + $field_ty:ident { + range: [$field_start:literal : $field_end:literal], + default: $default_variant:ident, + $($variant:ident = $value:expr$(,)?)+ + }$(,)? + )+) => { + $crate::csr!($doc, $ty: $csr, $mask); + + $( + $crate::read_only_csr_field!( + $ty, + $field_doc, + $field, + $field_ty_doc, + $field_ty { + range: [$field_start : $field_end], + default: $field_default, + $($variant = $value),+ + }, + ); + )+ + + $crate::read_csr_as!($ty, $csr); + }; } /// Helper macro to create a read-only CSR type. @@ -854,6 +982,41 @@ macro_rules! write_only_csr { $crate::set!($csr); $crate::clear!($csr); }; + + ($doc:expr, + $ty:ident: $csr:tt, + $mask:tt, + $( + $field_doc:expr, + $field:ident, + $field_ty_doc:expr, + $field_ty:ident { + range: [$field_start:literal : $field_end:literal], + default: $default_variant:ident, + $($variant:ident = $value:expr$(,)?)+ + }$(,)? + )+) => { + $crate::csr!($doc, $ty: $csr, $mask); + + $( + $crate::write_only_csr_field!( + $ty, + $field_doc, + $field, + $field_ty_doc, + $field_ty { + range: [$field_start : $field_end], + default: $field_default, + $($variant = $value),+ + }, + ); + )+ + + $crate::read_csr_as!($ty, $csr); + $crate::write_csr_as!($ty, $csr); + $crate::set!($csr); + $crate::clear!($csr); + }; } /// Defines field accesor functions for a read-write CSR type. @@ -929,6 +1092,51 @@ macro_rules! read_write_csr_field { } } }; + + ($ty:ident, + $field_doc:expr, + $field:ident, + $set_field_doc:expr, + $set_field:ident, + $field_ty_doc:expr, + $field_ty:ident { + range: [$field_start:literal : $field_end:literal], + default: $default_variant:ident, + $($variant:ident = $value:expr$(,)?)+ + }$(,)? + ) => { + $crate::csr_field_enum!( + $field_ty_doc, + $field_ty { + range: [$field_start : $field_end], + default: $default_variant, + $($variant = $value,)+ + }, + ); + + impl $ty { + #[doc = $field_doc] + #[inline] + pub fn $field(&self) -> Option<$field_ty> { + $field_ty::from_usize($crate::bits::bf_extract( + self.bits, + $field_start, + $field_end - $field_start + 1, + )) + } + + #[doc = $set_field_doc] + #[inline] + pub fn $set_field(&mut self, $field: $field_ty) { + self.bits = $crate::bits::bf_insert( + self.bits, + $field_start, + $field_end - $field_start + 1, + $field.into(), + ); + } + } + }; } /// Defines field accesor functions for a read-only CSR type. @@ -959,11 +1167,43 @@ macro_rules! read_only_csr_field { impl $ty { #[doc = $field_doc] #[inline] - pub fn $field(&self) -> bool { - $crate::bits::bf_extract(self.bits, $bit_start, $bit_end - $bit_start + 1) != 0 + pub fn $field(&self) -> usize { + $crate::bits::bf_extract(self.bits, $bit_start, $bit_end - $bit_start + 1) } } }; + + ($ty:ident, + $field_doc:expr, + $field:ident, + $field_ty_doc:expr, + $field_ty:ident { + range: [$field_start:literal : $field_end:literal], + default: $default_variant:ident, + $($variant:ident = $value:expr$(,)?)+ + }$(,)? + ) => { + $crate::csr_field_enum!( + $field_ty_doc, + $field_ty { + range: [$field_start : $field_end], + default: $default_variant, + $($variant = $value,)+ + }, + ); + + impl $ty { + #[doc = $field_doc] + #[inline] + pub fn $field(&self) -> Option<$field_ty> { + $field_ty::from_usize($crate::bits::bf_extract( + self.bits, + $field_start, + $field_end - $field_start + 1, + )) + } + } + }; } /// Defines field accesor functions for a write-only CSR type. @@ -973,8 +1213,8 @@ macro_rules! write_only_csr_field { impl $ty { #[doc = $field_doc] #[inline] - pub fn $field(&self) -> bool { - $crate::bits::bf_insert(self.bits, $bit, 1) != 0 + pub fn $field(&mut self, $field: bool) { + self.bits = $crate::bits::bf_insert(self.bits, $bit, 1, $field as usize); } } }; @@ -994,8 +1234,7 @@ macro_rules! write_only_csr_field { impl $ty { #[doc = $field_doc] #[inline] - pub fn $field(&mut self, index: usize, $field: usize) { - assert!(($bit_start..=$bit_end).contains(&index)); + pub fn $field(&mut self, $field: usize) { self.bits = $crate::bits::bf_insert( self.bits, $bit_start, @@ -1005,4 +1244,37 @@ macro_rules! write_only_csr_field { } } }; + + ($ty:ident, + $field_doc:expr, + $field:ident, + $field_ty_doc:expr, + $field_ty:ident { + range: [$field_start:literal : $field_end:literal], + default: $default_variant:ident, + $($variant:ident = $value:expr$(,)?)+ + }$(,)? + ) => { + $crate::csr_field_enum!( + $field_ty_doc, + $field_ty { + range: [$field_start : $field_end], + default: $default_variant, + $($variant = $value,)+ + }, + ); + + impl $ty { + #[doc = $field_doc] + #[inline] + pub fn $field(&mut self, $field: $field_ty) { + self.bits = $crate::bits::bf_insert( + self.bits, + $field_start, + $field_end - $field_start + 1, + $field.into(), + ); + } + } + }; } diff --git a/riscv/src/register/tests.rs b/riscv/src/register/tests.rs index 1aa94648..639fd0df 100644 --- a/riscv/src/register/tests.rs +++ b/riscv/src/register/tests.rs @@ -1,81 +1,3 @@ -read_write_csr! { - "test CSR register type", - Mtest: 0x000, - 0b1111_1111, - "test single-bit field", - single: 0, - "setter test single-bit field", - set_single: 0, -} - -read_write_csr_field! { - Mtest, - "multiple single-bit field range", - multi_range: 1..=3, - "setter multiple single-bit field range", - set_multi_range: 1..=3, -} - -read_write_csr_field!( - Mtest, - "multi-bit field", - multi_field: [4:7], - "setter multi-bit field", - set_multi_field: [4:7], -); - -// we don't test the `read` and `write` functions, we are only testing in-memory functions. -#[allow(unused)] -pub fn _read_csr() -> Mtest { - read() -} - -#[allow(unused)] -pub fn _write_csr(csr: Mtest) { - write(csr); -} - -#[test] -fn test_mtest() { - let mut mtest = Mtest::from_bits(0); - - assert_eq!(mtest.bitmask(), Mtest::BITMASK); - assert_eq!(mtest.bits(), 0); - - // check that single bit field getter/setters work. - assert_eq!(mtest.single(), false); - - mtest.set_single(true); - assert_eq!(mtest.single(), true); - - mtest.set_single(false); - assert_eq!(mtest.single(), false); - - // check that single bit range field getter/setters work. - for i in 1..=3 { - assert_eq!(mtest.multi_range(i), false); - - mtest.set_multi_range(i, true); - assert_eq!(mtest.multi_range(i), true); - - mtest.set_multi_range(i, false); - assert_eq!(mtest.multi_range(i), false); - } - - // check that multi-bit field getter/setters work. - assert_eq!(mtest.multi_field(), 0); - - mtest.set_multi_field(0xf); - assert_eq!(mtest.multi_field(), 0xf); - - mtest.set_multi_field(0x3); - assert_eq!(mtest.multi_field(), 0x3); - - // check that only bits in the field are set. - mtest.set_multi_field(0xff); - assert_eq!(mtest.multi_field(), 0xf); - assert_eq!(mtest.bits(), 0xf << 4); - - mtest.set_multi_field(0x0); - assert_eq!(mtest.multi_field(), 0x0); -} +mod read_only_csr; +mod read_write_csr; +mod write_only_csr; diff --git a/riscv/src/register/tests/read_only_csr.rs b/riscv/src/register/tests/read_only_csr.rs new file mode 100644 index 00000000..0633fb76 --- /dev/null +++ b/riscv/src/register/tests/read_only_csr.rs @@ -0,0 +1,102 @@ +read_only_csr! { + "test CSR register type", + Mtest: 0x000, + 0b1111_1111_1111, + "test single-bit field", + single: 0, +} + +read_only_csr_field! { + Mtest, + "multiple single-bit field range", + multi_range: 1..=3, +} + +read_only_csr_field!( + Mtest, + "multi-bit field", + multi_field: [4:7], +); + +read_only_csr_field!( + Mtest, + "multi-bit field", + field_enum, + "field enum type with valid field variants", + MtestFieldEnum { + range: [7:11], + default: Field1, + Field1 = 1, + Field2 = 2, + Field3 = 3, + Field4 = 15, + }, +); + +// we don't test the `read` function, we are only testing in-memory functions. +#[allow(unused)] +pub fn _read_csr() -> Mtest { + read() +} + +#[test] +fn test_mtest_read_only() { + let mut mtest = Mtest::from_bits(0); + + assert_eq!(mtest.bitmask(), Mtest::BITMASK); + assert_eq!(mtest.bits(), 0); + + // check that single bit field getter/setters work. + assert_eq!(mtest.single(), false); + + mtest = Mtest::from_bits(1); + assert_eq!(mtest.single(), true); + + mtest = Mtest::from_bits(0); + + // check that single bit range field getter/setters work. + for i in 1..=3 { + assert_eq!(mtest.multi_range(i), false); + + mtest = Mtest::from_bits(1 << i); + assert_eq!(mtest.multi_range(i), true); + + mtest = Mtest::from_bits(0 << i); + assert_eq!(mtest.multi_range(i), false); + } + + // check that multi-bit field getter/setters work. + assert_eq!(mtest.multi_field(), 0); + + mtest = Mtest::from_bits(0xf << 4); + assert_eq!(mtest.multi_field(), 0xf); + + mtest = Mtest::from_bits(0x3 << 4); + assert_eq!(mtest.multi_field(), 0x3); + + // check that only bits in the field are set. + mtest = Mtest::from_bits(0xff << 4); + assert_eq!(mtest.multi_field(), 0xf); + assert_eq!(mtest.bits(), 0xff << 4); + + mtest = Mtest::from_bits(0x0 << 4); + assert_eq!(mtest.multi_field(), 0x0); + + assert_eq!(mtest.field_enum(), None); + + [ + MtestFieldEnum::Field1, + MtestFieldEnum::Field2, + MtestFieldEnum::Field3, + MtestFieldEnum::Field4, + ] + .into_iter() + .for_each(|variant| { + mtest = Mtest::from_bits(variant.into_usize() << 7); + assert_eq!(mtest.field_enum(), Some(variant)); + }); + + // check that setting an invalid variant returns `None` + mtest = Mtest::from_bits(0xbad << 7); + assert_eq!(mtest.field_enum(), None); +} diff --git a/riscv/src/register/tests/read_write_csr.rs b/riscv/src/register/tests/read_write_csr.rs new file mode 100644 index 00000000..26a864e3 --- /dev/null +++ b/riscv/src/register/tests/read_write_csr.rs @@ -0,0 +1,116 @@ +read_write_csr! { + "test CSR register type", + Mtest: 0x000, + 0b1111_1111_1111, + "test single-bit field", + single: 0, + "setter test single-bit field", + set_single: 0, +} + +read_write_csr_field! { + Mtest, + "multiple single-bit field range", + multi_range: 1..=3, + "setter multiple single-bit field range", + set_multi_range: 1..=3, +} + +read_write_csr_field!( + Mtest, + "multi-bit field", + multi_field: [4:7], + "setter multi-bit field", + set_multi_field: [4:7], +); + +read_write_csr_field!( + Mtest, + "multi-bit field", + field_enum, + "setter multi-bit field", + set_field_enum, + "field enum type with valid field variants", + MtestFieldEnum { + range: [7:11], + default: Field1, + Field1 = 1, + Field2 = 2, + Field3 = 3, + Field4 = 15, + }, +); + +// we don't test the `read` and `write` functions, we are only testing in-memory functions. +#[allow(unused)] +pub fn _read_csr() -> Mtest { + read() +} + +#[allow(unused)] +pub fn _write_csr(csr: Mtest) { + write(csr); +} + +#[test] +fn test_mtest_read_write() { + let mut mtest = Mtest::from_bits(0); + + assert_eq!(mtest.bitmask(), Mtest::BITMASK); + assert_eq!(mtest.bits(), 0); + + // check that single bit field getter/setters work. + assert_eq!(mtest.single(), false); + + mtest.set_single(true); + assert_eq!(mtest.single(), true); + + mtest.set_single(false); + assert_eq!(mtest.single(), false); + + // check that single bit range field getter/setters work. + for i in 1..=3 { + assert_eq!(mtest.multi_range(i), false); + + mtest.set_multi_range(i, true); + assert_eq!(mtest.multi_range(i), true); + + mtest.set_multi_range(i, false); + assert_eq!(mtest.multi_range(i), false); + } + + // check that multi-bit field getter/setters work. + assert_eq!(mtest.multi_field(), 0); + + mtest.set_multi_field(0xf); + assert_eq!(mtest.multi_field(), 0xf); + + mtest.set_multi_field(0x3); + assert_eq!(mtest.multi_field(), 0x3); + + // check that only bits in the field are set. + mtest.set_multi_field(0xff); + assert_eq!(mtest.multi_field(), 0xf); + assert_eq!(mtest.bits(), 0xf << 4); + + mtest.set_multi_field(0x0); + assert_eq!(mtest.multi_field(), 0x0); + + assert_eq!(mtest.field_enum(), None); + + [ + MtestFieldEnum::Field1, + MtestFieldEnum::Field2, + MtestFieldEnum::Field3, + MtestFieldEnum::Field4, + ] + .into_iter() + .for_each(|variant| { + mtest.set_field_enum(variant); + assert_eq!(mtest.field_enum(), Some(variant)); + }); + + // check that setting an invalid variant returns `None` + mtest = Mtest::from_bits(0xbad << 7); + assert_eq!(mtest.field_enum(), None); +} diff --git a/riscv/src/register/tests/write_only_csr.rs b/riscv/src/register/tests/write_only_csr.rs new file mode 100644 index 00000000..5e02ed35 --- /dev/null +++ b/riscv/src/register/tests/write_only_csr.rs @@ -0,0 +1,98 @@ +write_only_csr! { + "test CSR register type", + Mtest: 0x000, + 0b1111_1111_1111, + "setter test single-bit field", + set_single: 0, +} + +write_only_csr_field! { + Mtest, + "setter multiple single-bit field range", + set_multi_range: 1..=3, +} + +write_only_csr_field!( + Mtest, + "setter multi-bit field", + set_multi_field: [4:7], +); + +write_only_csr_field!( + Mtest, + "setter multi-bit field", + set_field_enum, + "field enum type with valid field variants", + MtestFieldEnum { + range: [7:11], + default: Field1, + Field1 = 1, + Field2 = 2, + Field3 = 3, + Field4 = 15, + }, +); + +// we don't test the `write` function, we are only testing in-memory functions. +#[allow(unused)] +pub fn _write_csr(csr: Mtest) { + write(csr); +} + +#[test] +fn test_mtest_write_only() { + let mut mtest = Mtest::from_bits(0); + + assert_eq!(mtest.bitmask(), Mtest::BITMASK); + assert_eq!(mtest.bits(), 0); + + // check that single bit field getter/setters work. + mtest.set_single(true); + assert_eq!(mtest.bits(), 1); + + mtest.set_single(false); + assert_eq!(mtest.bits(), 0); + + // check that single bit range field getter/setters work. + for i in 1..=3 { + mtest.set_multi_range(i, true); + assert_ne!(mtest.bits() & (1 << i), 0); + + mtest.set_multi_range(i, false); + assert_eq!(mtest.bits() & (1 << i), 0); + } + + // check that multi-bit field getter/setters work. + mtest.set_multi_field(0xf); + assert_eq!(mtest.bits() >> 4, 0xf); + + mtest.set_multi_field(0x3); + assert_eq!(mtest.bits() >> 4, 0x3); + + // check that only bits in the field are set. + mtest.set_multi_field(0xff); + assert_eq!(mtest.bits() >> 4, 0xf); + + mtest.set_multi_field(0x0); + assert_eq!(mtest.bits() >> 4, 0x0); + + mtest = Mtest::from_bits(0); + + assert_eq!(MtestFieldEnum::from_usize(mtest.bits() >> 7), None); + + [ + MtestFieldEnum::Field1, + MtestFieldEnum::Field2, + MtestFieldEnum::Field3, + MtestFieldEnum::Field4, + ] + .into_iter() + .for_each(|variant| { + mtest.set_field_enum(variant); + assert_eq!(MtestFieldEnum::from_usize(mtest.bits() >> 7), Some(variant)); + }); + + // check that setting an invalid variant returns `None` + mtest = Mtest::from_bits(0xbad << 7); + assert_eq!(MtestFieldEnum::from_usize(mtest.bits() >> 7), None); +} From 7f4f1f65b0d3479f1b7cee4fcd77c4088a1e6a4b Mon Sep 17 00:00:00 2001 From: rmsyn Date: Sat, 14 Sep 2024 05:27:55 +0000 Subject: [PATCH 03/19] fixup: fixes for rebase on latest HEAD Adds corrections to CSR creation macros for rebase on commit `a4d69614`. Includes: - additions of `try_*` function variants for fallible functions. - changing doc string macro arguments to idiomatic `///` comments --- riscv/src/register/macros.rs | 477 +++++++++++++++------ riscv/src/register/mcountinhibit.rs | 47 +- riscv/src/register/tests/read_only_csr.rs | 19 +- riscv/src/register/tests/read_write_csr.rs | 69 ++- riscv/src/register/tests/write_only_csr.rs | 19 +- 5 files changed, 459 insertions(+), 172 deletions(-) diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index 8a3ae0b4..55895f85 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -609,9 +609,11 @@ macro_rules! clear_pmp { /// [read_only_csr](crate::read_only_csr), and [write_only_csr](crate::write_only_csr) macros. #[macro_export] macro_rules! csr { - ($doc:expr, $ty:ident: $csr:literal, $mask:literal) => { + ($(#[$doc:meta])* + $ty:ident: $csr:literal, + $mask:literal) => { #[repr(C)] - #[doc = $doc] + $(#[$doc])* #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct $ty { bits: usize, @@ -643,14 +645,14 @@ macro_rules! csr { #[macro_export] macro_rules! csr_field_enum { - ($field_ty_doc:expr, + ($(#[$field_ty_doc:meta])* $field_ty:ident { range: [$field_start:literal : $field_end:literal], default: $default_variant:ident, $($variant:ident = $value:expr$(,)?)+ }$(,)? ) => { - #[doc = $field_ty_doc] + $(#[$field_ty_doc])* #[repr(usize)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum $field_ty { @@ -698,24 +700,32 @@ macro_rules! csr_field_enum { /// The user can then write the entire bitfield value back into the CSR with a single write. #[macro_export] macro_rules! read_write_csr { - ($doc:expr, + ($(#[$doc:meta])* $ty:ident: $csr:tt, $mask:tt, $( - $field_doc:expr, + $(#[$field_doc:meta])* $field:ident: $get_bit:literal, - $set_field_doc:expr, - $set_field:ident: $set_bit:literal$(,)? + $(#[$try_field_doc:meta])* + $try_field:ident: $try_get_bit:literal, + $(#[$set_field_doc:meta])* + $set_field:ident: $set_bit:literal, + $(#[$try_set_field_doc:meta])* + $try_set_field:ident: $try_set_bit:literal$(,)? )+) => { - $crate::csr!($doc, $ty: $csr, $mask); + $crate::csr!($(#[$doc])* $ty: $csr, $mask); $( $crate::read_write_csr_field!( $ty, - $field_doc, + $(#[$field_doc])* $field: $get_bit, - $set_field_doc, + $(#[$try_field_doc])* + $try_field: $try_get_bit, + $(#[$set_field_doc])* $set_field: $set_bit, + $(#[$try_set_field_doc])* + $try_set_field: $try_set_bit, ); )+ @@ -725,24 +735,32 @@ macro_rules! read_write_csr { $crate::clear!($csr); }; - ($doc:expr, + ($(#[$doc:meta])* $ty:ident: $csr:tt, $mask:tt, $( - $field_doc:expr, + $(#[$field_doc:meta])* $field:ident: $get_bit_start:literal ..= $get_bit_end:literal, - $set_field_doc:expr, - $set_field:ident: $set_bit_start:literal ..= $set_bit_end:literal$(,)? + $(#[$try_field_doc:meta])* + $try_field:ident: $try_get_bit_start:literal ..= $try_get_bit_end:literal, + $(#[$set_field_doc:meta])* + $set_field:ident: $set_bit_start:literal ..= $set_bit_end:literal, + $(#[$try_set_field_doc:meta])* + $try_set_field:ident: $try_set_bit_start:literal ..= $try_set_bit_end:literal$(,)? )+) => { - $crate::csr!($doc, $ty: $csr, $mask); + $crate::csr!($(#[$doc])*, $ty: $csr, $mask); $( $crate::read_write_csr_field!( $ty, - $field_doc, + $(#[$field_doc])* $field: $get_bit_start ..= $get_bit_end, - $set_field_doc, + $(#[$try_field_doc])* + $try_field: $try_get_bit_start ..= $try_get_bit_end, + $(#[$set_field_doc])* $set_field: $set_bit_start ..= $set_bit_end, + $(#[$try_set_field_doc])* + $try_set_field: $try_set_bit_start ..= $try_set_bit_end, ); )+ @@ -752,24 +770,32 @@ macro_rules! read_write_csr { $crate::clear!($csr); }; - ($doc:expr, + ($(#[$doc:meta])* $ty:ident: $csr:tt, $mask:tt, $( - $field_doc:expr, + $(#[$field_doc:meta])* $field:ident: [$get_bit_start:literal : $get_bit_end:literal], - $set_field_doc:expr, - $set_field:ident: [$set_bit_start:literal : $set_bit_end:literal]$(,)? + $(#[$try_field_doc:meta])* + $try_field:ident: [$try_get_bit_start:literal : $try_get_bit_end:literal], + $(#[$set_field_doc:meta])* + $set_field:ident: [$set_bit_start:literal : $set_bit_end:literal], + $(#[$try_set_field_doc:meta])* + $try_set_field:ident: [$try_set_bit_start:literal : $try_set_bit_end:literal]$(,)? )+) => { - $crate::csr!($doc, $ty: $csr, $mask); + $crate::csr!($(#[$doc])*, $ty: $csr, $mask); $( $crate::read_write_csr_field!( $ty, - $field_doc, + $(#[$field_doc])* $field: [$get_bit_start : $get_bit_end], - $set_field_doc, + $(#[$try_field_doc])* + $try_field: [$try_get_bit_start : $try_get_bit_end], + $(#[$set_field_doc])* $set_field: [$set_bit_start : $set_bit_end], + $(#[$try_set_field_doc])* + $try_set_field: [$try_set_bit_start : $try_set_bit_end], ); )+ @@ -779,31 +805,39 @@ macro_rules! read_write_csr { $crate::clear!($csr); }; - ($doc:expr, + ($(#[$doc:meta])* $ty:ident: $csr:tt, $mask:tt, $( - $field_doc:expr, + $(#[$field_doc:meta])* $field:ident, - $set_field_doc:expr, + $(#[$try_field_doc:meta])* + $try_field:ident, + $(#[$set_field_doc:meta])* $set_field:ident, - $field_ty_doc:expr, + $(#[$try_set_field_doc:meta])* + $try_set_field:ident, + $(#[$field_ty_doc:meta])* $field_ty:ident { range: [$field_start:literal : $field_end:literal], default: $default_variant:ident, $($variant:ident = $value:expr$(,)?)+ }$(,)? )+) => { - $crate::csr!($doc, $ty: $csr, $mask); + $crate::csr!($(#[$doc])* $ty: $csr, $mask); $( $crate::read_write_csr_field!( $ty, - $field_doc, + $(#[$field_doc])* $field, - $set_field_doc, + $(#[$try_field_doc])* + $try_field, + $(#[$set_field_doc])* $set_field, - $field_ty_doc, + $(#[$try_set_field_doc])* + $try_set_field, + $(#[$field_ty_doc])* $field_ty { range: [$field_start : $field_end], default: $field_default, @@ -824,17 +858,20 @@ macro_rules! read_write_csr { /// The type allows to read the CSR value into memory. #[macro_export] macro_rules! read_only_csr { - ($doc:expr, + ($(#[$doc:meta])* $ty:ident: $csr:tt, $mask:tt, - $($field_doc:expr, $field:ident: $bit:literal$(,)?)+ + $( + $(#[$field_doc:meta])* + $field:ident: $bit:literal$(,)? + )+ ) => { - $crate::csr! { $doc, $ty: $csr, $mask } + $crate::csr! { $(#[$doc])* $ty: $csr, $mask } $( $crate::read_only_csr_field! { $ty, - $field_doc, + $(#[$field_doc])* $field: $bit, } )+ @@ -842,19 +879,19 @@ macro_rules! read_only_csr { $crate::read_csr_as!($ty, $csr); }; - ($doc:expr, + ($(#[doc:meta])* $ty:ident: $csr:tt, $mask:tt, $( - $field_doc:expr, + $(#[$field_doc:meta])* $field:ident: $bit:literal ..= $bit_end:literal$(,)? )+) => { - $crate::csr! { $doc, $ty: $csr, $mask } + $crate::csr! { $(#[$doc])* $ty: $csr, $mask } $( $crate::read_only_csr_field! { $ty, - $field_doc, + $(#[$field_doc])* $field: $bit ..= $bit_end, } )+ @@ -862,19 +899,19 @@ macro_rules! read_only_csr { $crate::read_csr_as!($ty, $csr); }; - ($doc:expr, + ($(#[doc:meta])* $ty:ident: $csr:literal, $mask:literal, $( - $field_doc:expr, + $(#[field_doc:meta])* $field:ident: [$bit:tt : $bit_end:tt]$(,)? )+) => { - $crate::csr! { $doc, $ty: $csr, $mask } + $crate::csr! { $(#[$doc])* $ty: $csr, $mask } $( $crate::read_only_csr_field! { $ty, - $field_doc, + $(#[$field_doc])* $field: [$bit : $bit_end], } )+ @@ -882,27 +919,27 @@ macro_rules! read_only_csr { $crate::read_csr_as!($ty, $csr); }; - ($doc:expr, + ($(#[$doc:meta])* $ty:ident: $csr:tt, $mask:tt, $( - $field_doc:expr, + $(#[$field_doc:meta])* $field:ident, - $field_ty_doc:expr, + $(#[$field_ty_doc:meta])* $field_ty:ident { range: [$field_start:literal : $field_end:literal], default: $default_variant:ident, $($variant:ident = $value:expr$(,)?)+ }$(,)? )+) => { - $crate::csr!($doc, $ty: $csr, $mask); + $crate::csr!($(#[$doc])* $ty: $csr, $mask); $( $crate::read_only_csr_field!( $ty, - $field_doc, + $(#[$field_doc])* $field, - $field_ty_doc, + $(#[$field_ty_doc])* $field_ty { range: [$field_start : $field_end], default: $field_default, @@ -920,16 +957,19 @@ macro_rules! read_only_csr { /// The type allows to read the CSR value into memory. #[macro_export] macro_rules! write_only_csr { - ($doc:expr, + ($(#[$doc:meta])* $ty:ident: $csr:literal, $mask:literal, - $($field_doc:expr, $field:ident: $bit:literal$(,)?)+) => { - $crate::csr! { $doc, $ty: $csr, $mask } + $( + $(#[$field_doc:meta])* + $field:ident: $bit:literal$(,)? + )+) => { + $crate::csr! { $(#[$doc])* $ty: $csr, $mask } $( $crate::write_only_csr_field! { $ty, - $field_doc, + $(#[$field_doc])* $field: $bit, } )+ @@ -939,19 +979,19 @@ macro_rules! write_only_csr { $crate::clear!($csr); }; - ($doc:expr, + ($(#[$doc:meta])* $ty:ident: $csr:literal, $mask:literal, $( - $field_doc:expr, + $(#[field_doc:meta])* $field:ident: $bit_start:literal ..= $bit_end:literal$(,)? )+) => { - $crate::csr! { $doc, $ty: $csr, $mask } + $crate::csr! { $(#[$doc])* $ty: $csr, $mask } $( $crate::write_only_csr_field! { $ty, - $field_doc, + $(#[$field_doc])* $field: $bit_start..=$bit_end, } )+ @@ -961,19 +1001,19 @@ macro_rules! write_only_csr { $crate::clear!($csr); }; - ($doc:expr, + ($(#[doc:meta])* $ty:ident: $csr:literal, $mask:literal, $( - $field_doc:expr, + $(#[field_doc:meta])* $field:ident: [$bit_start:literal : $bit_end:literal]$(,)? )+) => { - $crate::csr! { $doc, $ty: $csr, $mask } + $crate::csr! { $(#[doc])*, $ty: $csr, $mask } $( $crate::write_only_csr_field! { $ty, - $field_doc, + $(#[$field_doc])*, $field: [$bit_start:$bit_end], } )+ @@ -983,27 +1023,27 @@ macro_rules! write_only_csr { $crate::clear!($csr); }; - ($doc:expr, + ($(#[$doc:meta])* $ty:ident: $csr:tt, $mask:tt, $( - $field_doc:expr, + $(#[$field_doc:meta])* $field:ident, - $field_ty_doc:expr, + $(#[$field_ty_doc:meta])* $field_ty:ident { range: [$field_start:literal : $field_end:literal], default: $default_variant:ident, $($variant:ident = $value:expr$(,)?)+ }$(,)? )+) => { - $crate::csr!($doc, $ty: $csr, $mask); + $crate::csr!($(#[$doc])* $ty: $csr, $mask); $( $crate::write_only_csr_field!( $ty, - $field_doc, + $(#[$field_doc])* $field, - $field_ty_doc, + $(#[$field_ty_doc])* $field_ty { range: [$field_start : $field_end], default: $field_default, @@ -1023,82 +1063,192 @@ macro_rules! write_only_csr { #[macro_export] macro_rules! read_write_csr_field { ($ty:ident, - $field_doc:expr, + $(#[$field_doc:meta])* $field:ident: $get_bit:literal, - $set_field_doc:expr, - $set_field:ident: $set_bit:literal$(,)?) => { + $(#[$try_field_doc:meta])* + $try_field:ident: $try_get_bit:literal, + $(#[$set_field_doc:meta])* + $set_field:ident: $set_bit:literal, + $(#[$try_set_field_doc:meta])* + $try_set_field:ident: $try_set_bit:literal$(,)? + ) => { impl $ty { - #[doc = $field_doc] + $(#[$field_doc])* #[inline] pub fn $field(&self) -> bool { - $crate::bits::bf_extract(self.bits, $get_bit, 1) != 0 + self.$try_field().unwrap() } - #[doc = $set_field_doc] + $(#[$try_field_doc])* + #[inline] + pub fn $try_field(&self) -> $crate::result::Result { + let max_width = core::mem::size_of_val(&self.bits) * 8; + + if $try_get_bit < max_width { + Ok($crate::bits::bf_extract(self.bits, $try_get_bit, 1) != 0) + } else { + Err($crate::result::Error::IndexOutOfBounds { + index: $try_get_bit, + min: 0, + max: max_width + }) + } + } + + $(#[$set_field_doc])* #[inline] pub fn $set_field(&mut self, $field: bool) { - self.bits = $crate::bits::bf_insert(self.bits, $set_bit, 1, $field as usize); + self.$try_set_field($field).unwrap(); + } + + $(#[$try_set_field_doc])* + #[inline] + pub fn $try_set_field(&mut self, $field: bool) -> $crate::result::Result<()> { + let max_width = core::mem::size_of_val(&self.bits) * 8; + + if $try_set_bit < max_width { + self.bits = $crate::bits::bf_insert(self.bits, $try_set_bit, 1, $field as usize); + Ok(()) + } else { + Err($crate::result::Error::IndexOutOfBounds { + index: $try_set_bit, + min: 0, + max: max_width + }) + } } } }; ($ty:ident, - $field_doc:expr, + $(#[$field_doc:meta])* $field:ident: $get_bit_start:literal ..= $get_bit_end:literal, - $set_field_doc:expr, - $set_field:ident: $set_bit_start:literal ..= $set_bit_end:literal$(,)?) => { + $(#[$try_field_doc:meta])* + $try_field:ident: $try_get_bit_start:literal ..= $try_get_bit_end:literal, + $(#[$set_field_doc:meta])* + $set_field:ident: $set_bit_start:literal ..= $set_bit_end:literal, + $(#[$try_set_field_doc:meta])* + $try_set_field:ident: $try_set_bit_start:literal ..= $try_set_bit_end:literal$(,)? + ) => { impl $ty { - #[doc = $field_doc] + $(#[$field_doc])* #[inline] pub fn $field(&self, index: usize) -> bool { - assert!(($get_bit_start..=$get_bit_end).contains(&index)); - $crate::bits::bf_extract(self.bits, index, 1) != 0 + self.$try_field(index).unwrap() + } + + $(#[$field_doc])* + #[inline] + pub fn $try_field(&self, index: usize) -> $crate::result::Result { + if ($get_bit_start..=$get_bit_end).contains(&index) { + Ok($crate::bits::bf_extract(self.bits, index, 1) != 0) + } else { + Err($crate::result::Error::IndexOutOfBounds { + index, + min: $try_get_bit_start, + max: $try_get_bit_end + }) + } } - #[doc = $set_field_doc] + $(#[$set_field_doc])* #[inline] pub fn $set_field(&mut self, index: usize, $field: bool) { - assert!(($set_bit_start..=$set_bit_end).contains(&index)); - self.bits = $crate::bits::bf_insert(self.bits, index, 1, $field as usize); + self.$try_set_field(index, $field).unwrap(); + } + + $(#[$try_set_field_doc])* + #[inline] + pub fn $try_set_field(&mut self, index: usize, $field: bool) -> $crate::result::Result<()> { + if ($try_set_bit_start..=$try_set_bit_end).contains(&index) { + self.bits = $crate::bits::bf_insert(self.bits, index, 1, $field as usize); + + Ok(()) + } else { + Err($crate::result::Error::IndexOutOfBounds { + index, + min: $try_get_bit_start, + max: $try_get_bit_end + }) + } } } }; ($ty:ident, - $field_doc:expr, + $(#[$field_doc:meta])* $field:ident: [$get_bit_start:literal : $get_bit_end:literal], - $set_field_doc:expr, - $set_field:ident: [$set_bit_start:literal : $set_bit_end:literal]$(,)?) => { + $(#[$try_field_doc:meta])* + $try_field:ident: [$try_get_bit_start:literal : $try_get_bit_end:literal], + $(#[$set_field_doc:meta])* + $set_field:ident: [$set_bit_start:literal : $set_bit_end:literal], + $(#[$try_set_field_doc:meta])* + $try_set_field:ident: [$try_set_bit_start:literal : $try_set_bit_end:literal]$(,)? + ) => { impl $ty { - #[doc = $field_doc] + $(#[$field_doc])* #[inline] pub fn $field(&self) -> usize { - $crate::bits::bf_extract( - self.bits, - $get_bit_start, - $get_bit_end - $get_bit_start + 1, - ) + self.$try_field().unwrap() } - #[doc = $set_field_doc] + $(#[$try_field_doc])* + #[inline] + pub fn $try_field(&self) -> $crate::result::Result { + if $try_get_bit_start <= $try_get_bit_end { + Ok($crate::bits::bf_extract( + self.bits, + $try_get_bit_start, + $try_get_bit_end - $try_get_bit_start + 1, + )) + } else { + Err($crate::result::Error::IndexOutOfBounds { + index: $try_get_bit_start, + min: $try_get_bit_start, + max: $try_get_bit_end + }) + } + } + + $(#[$set_field_doc])* #[inline] pub fn $set_field(&mut self, $field: usize) { - self.bits = $crate::bits::bf_insert( - self.bits, - $set_bit_start, - $set_bit_end - $set_bit_start + 1, - $field, - ); + self.$try_set_field($field).unwrap(); + } + + $(#[$try_set_field_doc])* + #[inline] + pub fn $try_set_field(&mut self, $field: usize) -> $crate::result::Result<()> { + if $try_set_bit_start <= $try_set_bit_end { + self.bits = $crate::bits::bf_insert( + self.bits, + $try_set_bit_start, + $try_set_bit_end - $try_set_bit_start + 1, + $field, + ); + + Ok(()) + } else { + Err($crate::result::Error::IndexOutOfBounds { + index: $field, + min: $try_get_bit_start, + max: $try_get_bit_end + }) + } } } }; ($ty:ident, - $field_doc:expr, + $(#[$field_doc:meta])* $field:ident, - $set_field_doc:expr, + $(#[$try_field_doc:meta])* + $try_field:ident, + $(#[$set_field_doc:meta])* $set_field:ident, - $field_ty_doc:expr, + $(#[$try_set_field_doc:meta])* + $try_set_field:ident, + $(#[$field_ty_doc:meta])* $field_ty:ident { range: [$field_start:literal : $field_end:literal], default: $default_variant:ident, @@ -1106,7 +1256,7 @@ macro_rules! read_write_csr_field { }$(,)? ) => { $crate::csr_field_enum!( - $field_ty_doc, + $(#[$field_ty_doc])* $field_ty { range: [$field_start : $field_end], default: $default_variant, @@ -1115,25 +1265,62 @@ macro_rules! read_write_csr_field { ); impl $ty { - #[doc = $field_doc] + $(#[$field_doc])* #[inline] - pub fn $field(&self) -> Option<$field_ty> { - $field_ty::from_usize($crate::bits::bf_extract( - self.bits, - $field_start, - $field_end - $field_start + 1, - )) + pub fn $field(&self) -> $field_ty { + self.$try_field().unwrap() } - #[doc = $set_field_doc] + $(#[$field_doc])* + #[inline] + pub fn $try_field(&self) -> $crate::result::Result<$field_ty> { + if $field_start <= $field_end { + let value = $crate::bits::bf_extract( + self.bits, + $field_start, + $field_end - $field_start + 1, + ); + + $field_ty::from_usize(value).ok_or( + $crate::result::Error::InvalidFieldVariant { + field: stringify!($field), + value, + } + ) + } else { + Err($crate::result::Error::IndexOutOfBounds { + index: $field_start, + min: $field_start, + max: $field_end + }) + } + } + + $(#[$set_field_doc])* #[inline] pub fn $set_field(&mut self, $field: $field_ty) { - self.bits = $crate::bits::bf_insert( - self.bits, - $field_start, - $field_end - $field_start + 1, - $field.into(), - ); + self.$try_set_field($field).unwrap() + } + + $(#[$try_set_field_doc])* + #[inline] + pub fn $try_set_field(&mut self, $field: $field_ty) -> $crate::result::Result<()> { + if $field_start <= $field_end { + self.bits = $crate::bits::bf_insert( + self.bits, + $field_start, + $field_end - $field_start + 1, + $field.into(), + ); + + Ok(()) + } else { + Err($crate::result::Error::IndexOutOfBounds { + index: $field_start, + min: $field_start, + max: $field_end + }) + } } } }; @@ -1142,9 +1329,11 @@ macro_rules! read_write_csr_field { /// Defines field accesor functions for a read-only CSR type. #[macro_export] macro_rules! read_only_csr_field { - ($ty:ident, $field_doc:expr, $field:ident: $bit:literal$(,)?) => { + ($ty:ident, + $(#[$field_doc:meta])* + $field:ident: $bit:literal$(,)?) => { impl $ty { - #[doc = $field_doc] + $(#[$field_doc])* #[inline] pub fn $field(&self) -> bool { $crate::bits::bf_extract(self.bits, $bit, 1) != 0 @@ -1152,9 +1341,11 @@ macro_rules! read_only_csr_field { } }; - ($ty:ident, $field_doc:expr, $field:ident: $bit_start:literal..=$bit_end:literal$(,)?) => { + ($ty:ident, + $(#[$field_doc:meta])* + $field:ident: $bit_start:literal..=$bit_end:literal$(,)?) => { impl $ty { - #[doc = $field_doc] + $(#[$field_doc])* #[inline] pub fn $field(&self, index: usize) -> bool { assert!(($bit_start..=$bit_end).contains(&index)); @@ -1163,9 +1354,11 @@ macro_rules! read_only_csr_field { } }; - ($ty:ident, $field_doc:expr, $field:ident: [$bit_start:literal : $bit_end:literal]$(,)?) => { + ($ty:ident, + $(#[$field_doc:meta])* + $field:ident: [$bit_start:literal : $bit_end:literal]$(,)?) => { impl $ty { - #[doc = $field_doc] + $(#[$field_doc])* #[inline] pub fn $field(&self) -> usize { $crate::bits::bf_extract(self.bits, $bit_start, $bit_end - $bit_start + 1) @@ -1174,9 +1367,9 @@ macro_rules! read_only_csr_field { }; ($ty:ident, - $field_doc:expr, + $(#[$field_doc:meta])* $field:ident, - $field_ty_doc:expr, + $(#[$field_ty_doc:meta])* $field_ty:ident { range: [$field_start:literal : $field_end:literal], default: $default_variant:ident, @@ -1184,7 +1377,7 @@ macro_rules! read_only_csr_field { }$(,)? ) => { $crate::csr_field_enum!( - $field_ty_doc, + $(#[$field_ty_doc])* $field_ty { range: [$field_start : $field_end], default: $default_variant, @@ -1193,7 +1386,7 @@ macro_rules! read_only_csr_field { ); impl $ty { - #[doc = $field_doc] + $(#[$field_doc])* #[inline] pub fn $field(&self) -> Option<$field_ty> { $field_ty::from_usize($crate::bits::bf_extract( @@ -1209,9 +1402,11 @@ macro_rules! read_only_csr_field { /// Defines field accesor functions for a write-only CSR type. #[macro_export] macro_rules! write_only_csr_field { - ($ty:ident, $field_doc:expr, $field:ident: $bit:literal$(,)?) => { + ($ty:ident, + $(#[$field_doc:meta])* + $field:ident: $bit:literal$(,)?) => { impl $ty { - #[doc = $field_doc] + $(#[$field_doc])* #[inline] pub fn $field(&mut self, $field: bool) { self.bits = $crate::bits::bf_insert(self.bits, $bit, 1, $field as usize); @@ -1219,9 +1414,11 @@ macro_rules! write_only_csr_field { } }; - ($ty:ident, $field_doc:expr, $field:ident: $bit_start:literal..=$bit_end:literal$(,)?) => { + ($ty:ident, + $(#[$field_doc:meta])* + $field:ident: $bit_start:literal..=$bit_end:literal$(,)?) => { impl $ty { - #[doc = $field_doc] + $(#[$field_doc])* #[inline] pub fn $field(&mut self, index: usize, $field: bool) { assert!(($bit_start..=$bit_end).contains(&index)); @@ -1230,9 +1427,11 @@ macro_rules! write_only_csr_field { } }; - ($ty:ident, $field_doc:expr, $field:ident: [$bit_start:literal : $bit_end:literal]$(,)?) => { + ($ty:ident, + $(#[$field_doc:meta])* + $field:ident: [$bit_start:literal : $bit_end:literal]$(,)?) => { impl $ty { - #[doc = $field_doc] + $(#[$field_doc])* #[inline] pub fn $field(&mut self, $field: usize) { self.bits = $crate::bits::bf_insert( @@ -1246,9 +1445,9 @@ macro_rules! write_only_csr_field { }; ($ty:ident, - $field_doc:expr, + $(#[$field_doc:meta])* $field:ident, - $field_ty_doc:expr, + $(#[$field_ty_doc:meta])* $field_ty:ident { range: [$field_start:literal : $field_end:literal], default: $default_variant:ident, @@ -1256,7 +1455,7 @@ macro_rules! write_only_csr_field { }$(,)? ) => { $crate::csr_field_enum!( - $field_ty_doc, + $(#[$field_ty_doc])* $field_ty { range: [$field_start : $field_end], default: $default_variant, @@ -1265,7 +1464,7 @@ macro_rules! write_only_csr_field { ); impl $ty { - #[doc = $field_doc] + $(#[$field_doc])* #[inline] pub fn $field(&mut self, $field: $field_ty) { self.bits = $crate::bits::bf_insert( diff --git a/riscv/src/register/mcountinhibit.rs b/riscv/src/register/mcountinhibit.rs index d94e2b3a..b9e82ca5 100644 --- a/riscv/src/register/mcountinhibit.rs +++ b/riscv/src/register/mcountinhibit.rs @@ -1,27 +1,60 @@ //! `mcountinhibit` register use crate::read_write_csr; +use crate::result::{Error, Result}; read_write_csr! { - "`mcountinhibit` register", + /// `mcountinhibit` register Mcountinhibit: 0x320, 0xffff_fffd, - "Gets the `cycle[h]` inhibit field value.", + /// Gets the `cycle[h]` inhibit field value." cy: 0, - "Sets the `cycle[h]` inhibit field value.\n\n**NOTE**: only updates the in-memory value without touching the CSR.", + /// Attempts to get the `cycle[h]` inhibit field value." + try_cy: 0, + /// Sets the `cycle[h]` inhibit field value. + /// + /// **NOTE**: only updates the in-memory value without touching the CSR. set_cy: 0, - "Gets the `instret[h]` inhibit field value.", + /// Attempts to set the `cycle[h]` inhibit field value. + /// + /// **NOTE**: only updates the in-memory value without touching the CSR. + try_set_cy: 0, + /// Gets the `instret[h]` inhibit field value. ir: 2, - "Sets the `instret[h]` inhibit field value.\n\n**NOTE**: only updates the in-memory value without touching the CSR.", + /// Attempts to get the `instret[h]` inhibit field value. + try_ir: 2, + /// Sets the `instret[h]` inhibit field value. + /// + /// **NOTE**: only updates the in-memory value without touching the CSR. set_ir: 2, + /// Attempts to set the `instret[h]` inhibit field value. + /// + /// **NOTE**: only updates the in-memory value without touching the CSR. + try_set_ir: 2, } read_write_csr_field! { Mcountinhibit, - "Gets the `mhpmcounterX[h]` inhibit field value.\n\n**WARN**: `index` must be in the range `[31:3]`.", + /// Gets the `mhpmcounterX[h]` inhibit field value. + /// + /// **WARN**: `index` must be in the range `[31:3]`. hpm: 3..=31, - "Sets the `mhpmcounterX[h]` inhibit field value.\n\n**WARN**: `index` must be in the range `[31:3]`.\n\n**NOTE**: only updates the in-memory value without touching the CSR.", + /// Attempts to get the `mhpmcounterX[h]` inhibit field value. + /// + /// **WARN**: `index` must be in the range `[31:3]`. + try_hpm: 3..=31, + /// Sets the `mhpmcounterX[h]` inhibit field value. + /// + /// **WARN**: `index` must be in the range `[31:3]`. + /// + /// **NOTE**: only updates the in-memory value without touching the CSR. set_hpm: 3..=31, + /// Sets the `mhpmcounterX[h]` inhibit field value. + /// + /// **WARN**: `index` must be in the range `[31:3]`. + /// + /// **NOTE**: only updates the in-memory value without touching the CSR. + try_set_hpm: 3..=31, } set_clear_csr!( diff --git a/riscv/src/register/tests/read_only_csr.rs b/riscv/src/register/tests/read_only_csr.rs index 0633fb76..fecc3b62 100644 --- a/riscv/src/register/tests/read_only_csr.rs +++ b/riscv/src/register/tests/read_only_csr.rs @@ -1,28 +1,30 @@ +use crate::result::Result; + read_only_csr! { - "test CSR register type", + /// test CSR register type Mtest: 0x000, 0b1111_1111_1111, - "test single-bit field", + /// test single-bit field single: 0, } read_only_csr_field! { Mtest, - "multiple single-bit field range", + /// multiple single-bit field range multi_range: 1..=3, } read_only_csr_field!( Mtest, - "multi-bit field", + /// multi-bit field multi_field: [4:7], ); read_only_csr_field!( Mtest, - "multi-bit field", + /// multi-bit field field_enum, - "field enum type with valid field variants", + /// field enum type with valid field variants MtestFieldEnum { range: [7:11], default: Field1, @@ -39,6 +41,11 @@ pub fn _read_csr() -> Mtest { read() } +#[allow(unused)] +pub fn _try_read_csr() -> Result { + try_read() +} + #[test] fn test_mtest_read_only() { let mut mtest = Mtest::from_bits(0); diff --git a/riscv/src/register/tests/read_write_csr.rs b/riscv/src/register/tests/read_write_csr.rs index 26a864e3..f9a57fa3 100644 --- a/riscv/src/register/tests/read_write_csr.rs +++ b/riscv/src/register/tests/read_write_csr.rs @@ -1,36 +1,54 @@ +use crate::result::{Error, Result}; + read_write_csr! { - "test CSR register type", + /// test CSR register type Mtest: 0x000, 0b1111_1111_1111, - "test single-bit field", + /// test single-bit field single: 0, - "setter test single-bit field", + /// try-get test single-bit field + try_single: 0, + /// setter test single-bit field set_single: 0, + /// try-setter test single-bit field + try_set_single: 0, } read_write_csr_field! { Mtest, - "multiple single-bit field range", + /// multiple single-bit field range multi_range: 1..=3, - "setter multiple single-bit field range", + /// try-get multiple single-bit field range + try_multi_range: 1..=3, + /// setter multiple single-bit field range set_multi_range: 1..=3, + /// try-setter multiple single-bit field range + try_set_multi_range: 1..=3, } read_write_csr_field!( Mtest, - "multi-bit field", + /// multi-bit field multi_field: [4:7], - "setter multi-bit field", + /// try-get multi-bit field + try_multi_field: [4:7], + /// setter multi-bit field set_multi_field: [4:7], + /// try-setter multi-bit field + try_set_multi_field: [4:7], ); read_write_csr_field!( Mtest, - "multi-bit field", + /// multi-bit field field_enum, - "setter multi-bit field", + /// try-get multi-bit field + try_field_enum, + /// setter multi-bit field set_field_enum, - "field enum type with valid field variants", + /// try-setter multi-bit field + try_set_field_enum, + /// field enum type with valid field variants MtestFieldEnum { range: [7:11], default: Field1, @@ -38,7 +56,7 @@ read_write_csr_field!( Field2 = 2, Field3 = 3, Field4 = 15, - }, + } ); // we don't test the `read` and `write` functions, we are only testing in-memory functions. @@ -47,11 +65,21 @@ pub fn _read_csr() -> Mtest { read() } +#[allow(unused)] +pub fn _try_read_csr() -> Result { + try_read() +} + #[allow(unused)] pub fn _write_csr(csr: Mtest) { write(csr); } +#[allow(unused)] +pub fn _try_write_csr(csr: Mtest) { + try_write(csr); +} + #[test] fn test_mtest_read_write() { let mut mtest = Mtest::from_bits(0); @@ -96,7 +124,13 @@ fn test_mtest_read_write() { mtest.set_multi_field(0x0); assert_eq!(mtest.multi_field(), 0x0); - assert_eq!(mtest.field_enum(), None); + assert_eq!( + mtest.try_field_enum(), + Err(Error::InvalidFieldVariant { + field: "field_enum", + value: 0, + }) + ); [ MtestFieldEnum::Field1, @@ -107,10 +141,17 @@ fn test_mtest_read_write() { .into_iter() .for_each(|variant| { mtest.set_field_enum(variant); - assert_eq!(mtest.field_enum(), Some(variant)); + assert_eq!(mtest.field_enum(), variant); + assert_eq!(mtest.try_field_enum(), Ok(variant)); }); // check that setting an invalid variant returns `None` mtest = Mtest::from_bits(0xbad << 7); - assert_eq!(mtest.field_enum(), None); + assert_eq!( + mtest.try_field_enum(), + Err(Error::InvalidFieldVariant { + field: "field_enum", + value: 13, + }) + ); } diff --git a/riscv/src/register/tests/write_only_csr.rs b/riscv/src/register/tests/write_only_csr.rs index 5e02ed35..601325c2 100644 --- a/riscv/src/register/tests/write_only_csr.rs +++ b/riscv/src/register/tests/write_only_csr.rs @@ -1,28 +1,30 @@ +use crate::result::Result; + write_only_csr! { - "test CSR register type", + /// test CSR register type Mtest: 0x000, 0b1111_1111_1111, - "setter test single-bit field", + /// setter test single-bit field set_single: 0, } write_only_csr_field! { Mtest, - "setter multiple single-bit field range", + /// setter multiple single-bit field range set_multi_range: 1..=3, } write_only_csr_field!( Mtest, - "setter multi-bit field", + /// setter multi-bit field set_multi_field: [4:7], ); write_only_csr_field!( Mtest, - "setter multi-bit field", + /// setter multi-bit field set_field_enum, - "field enum type with valid field variants", + /// field enum type with valid field variants MtestFieldEnum { range: [7:11], default: Field1, @@ -39,6 +41,11 @@ pub fn _write_csr(csr: Mtest) { write(csr); } +#[allow(unused)] +pub fn _try_write_csr(csr: Mtest) -> Result<()> { + try_write(csr) +} + #[test] fn test_mtest_write_only() { let mut mtest = Mtest::from_bits(0); From a1c811980d595f994cc55e95dcca0254a88460e0 Mon Sep 17 00:00:00 2001 From: rmsyn Date: Sat, 14 Sep 2024 23:59:41 +0000 Subject: [PATCH 04/19] fixup: riscv: do not repeat macro field arguments Replaces repeated field bit and range arguments with a single `bit` or `range` argument. Intended to reduce copy-paste, prevent typo errors, and clarify intent. --- riscv/src/register/macros.rs | 127 +++++++++++---------- riscv/src/register/mcountinhibit.rs | 27 +++-- riscv/src/register/tests/read_write_csr.rs | 27 +++-- 3 files changed, 98 insertions(+), 83 deletions(-) diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index 55895f85..af6b4c5b 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -705,13 +705,14 @@ macro_rules! read_write_csr { $mask:tt, $( $(#[$field_doc:meta])* - $field:ident: $get_bit:literal, + $field:ident, $(#[$try_field_doc:meta])* - $try_field:ident: $try_get_bit:literal, + $try_field:ident, $(#[$set_field_doc:meta])* - $set_field:ident: $set_bit:literal, + $set_field:ident, $(#[$try_set_field_doc:meta])* - $try_set_field:ident: $try_set_bit:literal$(,)? + $try_set_field:ident, + bit: $bit:literal$(,)? )+) => { $crate::csr!($(#[$doc])* $ty: $csr, $mask); @@ -719,13 +720,14 @@ macro_rules! read_write_csr { $crate::read_write_csr_field!( $ty, $(#[$field_doc])* - $field: $get_bit, + $field, $(#[$try_field_doc])* - $try_field: $try_get_bit, + $try_field, $(#[$set_field_doc])* - $set_field: $set_bit, + $set_field, $(#[$try_set_field_doc])* - $try_set_field: $try_set_bit, + $try_set_field, + bit: $bit, ); )+ @@ -740,13 +742,14 @@ macro_rules! read_write_csr { $mask:tt, $( $(#[$field_doc:meta])* - $field:ident: $get_bit_start:literal ..= $get_bit_end:literal, + $field:ident, $(#[$try_field_doc:meta])* - $try_field:ident: $try_get_bit_start:literal ..= $try_get_bit_end:literal, + $try_field:ident, $(#[$set_field_doc:meta])* - $set_field:ident: $set_bit_start:literal ..= $set_bit_end:literal, + $set_field:ident, $(#[$try_set_field_doc:meta])* - $try_set_field:ident: $try_set_bit_start:literal ..= $try_set_bit_end:literal$(,)? + $try_set_field:ident, + range: $bit_start:literal ..= $bit_end:literal$(,)? )+) => { $crate::csr!($(#[$doc])*, $ty: $csr, $mask); @@ -754,13 +757,14 @@ macro_rules! read_write_csr { $crate::read_write_csr_field!( $ty, $(#[$field_doc])* - $field: $get_bit_start ..= $get_bit_end, + $field, $(#[$try_field_doc])* - $try_field: $try_get_bit_start ..= $try_get_bit_end, + $try_field, $(#[$set_field_doc])* - $set_field: $set_bit_start ..= $set_bit_end, + $set_field, $(#[$try_set_field_doc])* - $try_set_field: $try_set_bit_start ..= $try_set_bit_end, + $try_set_field, + range: $bit_start ..= $bit_end ); )+ @@ -775,13 +779,14 @@ macro_rules! read_write_csr { $mask:tt, $( $(#[$field_doc:meta])* - $field:ident: [$get_bit_start:literal : $get_bit_end:literal], + $field:ident, $(#[$try_field_doc:meta])* - $try_field:ident: [$try_get_bit_start:literal : $try_get_bit_end:literal], + $try_field:ident, $(#[$set_field_doc:meta])* - $set_field:ident: [$set_bit_start:literal : $set_bit_end:literal], + $set_field:ident, $(#[$try_set_field_doc:meta])* - $try_set_field:ident: [$try_set_bit_start:literal : $try_set_bit_end:literal]$(,)? + $try_set_field:ident, + range: [$bit_start:literal : $bit_end:literal]$(,)? )+) => { $crate::csr!($(#[$doc])*, $ty: $csr, $mask); @@ -789,13 +794,14 @@ macro_rules! read_write_csr { $crate::read_write_csr_field!( $ty, $(#[$field_doc])* - $field: [$get_bit_start : $get_bit_end], + $field, $(#[$try_field_doc])* - $try_field: [$try_get_bit_start : $try_get_bit_end], + $try_field, $(#[$set_field_doc])* - $set_field: [$set_bit_start : $set_bit_end], + $set_field, $(#[$try_set_field_doc])* - $try_set_field: [$try_set_bit_start : $try_set_bit_end], + $try_set_field, + range: [$bit_start : $bit_end], ); )+ @@ -1064,13 +1070,14 @@ macro_rules! write_only_csr { macro_rules! read_write_csr_field { ($ty:ident, $(#[$field_doc:meta])* - $field:ident: $get_bit:literal, + $field:ident, $(#[$try_field_doc:meta])* - $try_field:ident: $try_get_bit:literal, + $try_field:ident, $(#[$set_field_doc:meta])* - $set_field:ident: $set_bit:literal, + $set_field:ident, $(#[$try_set_field_doc:meta])* - $try_set_field:ident: $try_set_bit:literal$(,)? + $try_set_field:ident, + bit: $bit:literal$(,)? ) => { impl $ty { $(#[$field_doc])* @@ -1084,11 +1091,11 @@ macro_rules! read_write_csr_field { pub fn $try_field(&self) -> $crate::result::Result { let max_width = core::mem::size_of_val(&self.bits) * 8; - if $try_get_bit < max_width { - Ok($crate::bits::bf_extract(self.bits, $try_get_bit, 1) != 0) + if $bit < max_width { + Ok($crate::bits::bf_extract(self.bits, $bit, 1) != 0) } else { Err($crate::result::Error::IndexOutOfBounds { - index: $try_get_bit, + index: $bit, min: 0, max: max_width }) @@ -1106,12 +1113,12 @@ macro_rules! read_write_csr_field { pub fn $try_set_field(&mut self, $field: bool) -> $crate::result::Result<()> { let max_width = core::mem::size_of_val(&self.bits) * 8; - if $try_set_bit < max_width { - self.bits = $crate::bits::bf_insert(self.bits, $try_set_bit, 1, $field as usize); + if $bit < max_width { + self.bits = $crate::bits::bf_insert(self.bits, $bit, 1, $field as usize); Ok(()) } else { Err($crate::result::Error::IndexOutOfBounds { - index: $try_set_bit, + index: $bit, min: 0, max: max_width }) @@ -1122,13 +1129,14 @@ macro_rules! read_write_csr_field { ($ty:ident, $(#[$field_doc:meta])* - $field:ident: $get_bit_start:literal ..= $get_bit_end:literal, + $field:ident, $(#[$try_field_doc:meta])* - $try_field:ident: $try_get_bit_start:literal ..= $try_get_bit_end:literal, + $try_field:ident, $(#[$set_field_doc:meta])* - $set_field:ident: $set_bit_start:literal ..= $set_bit_end:literal, + $set_field:ident, $(#[$try_set_field_doc:meta])* - $try_set_field:ident: $try_set_bit_start:literal ..= $try_set_bit_end:literal$(,)? + $try_set_field:ident, + range: $bit_start:literal ..= $bit_end:literal$(,)? ) => { impl $ty { $(#[$field_doc])* @@ -1140,13 +1148,13 @@ macro_rules! read_write_csr_field { $(#[$field_doc])* #[inline] pub fn $try_field(&self, index: usize) -> $crate::result::Result { - if ($get_bit_start..=$get_bit_end).contains(&index) { + if ($bit_start..=$bit_end).contains(&index) { Ok($crate::bits::bf_extract(self.bits, index, 1) != 0) } else { Err($crate::result::Error::IndexOutOfBounds { index, - min: $try_get_bit_start, - max: $try_get_bit_end + min: $bit_start, + max: $bit_end }) } } @@ -1160,15 +1168,15 @@ macro_rules! read_write_csr_field { $(#[$try_set_field_doc])* #[inline] pub fn $try_set_field(&mut self, index: usize, $field: bool) -> $crate::result::Result<()> { - if ($try_set_bit_start..=$try_set_bit_end).contains(&index) { + if ($bit_start..=$bit_end).contains(&index) { self.bits = $crate::bits::bf_insert(self.bits, index, 1, $field as usize); Ok(()) } else { Err($crate::result::Error::IndexOutOfBounds { index, - min: $try_get_bit_start, - max: $try_get_bit_end + min: $bit_start, + max: $bit_end }) } } @@ -1177,13 +1185,14 @@ macro_rules! read_write_csr_field { ($ty:ident, $(#[$field_doc:meta])* - $field:ident: [$get_bit_start:literal : $get_bit_end:literal], + $field:ident, $(#[$try_field_doc:meta])* - $try_field:ident: [$try_get_bit_start:literal : $try_get_bit_end:literal], + $try_field:ident, $(#[$set_field_doc:meta])* - $set_field:ident: [$set_bit_start:literal : $set_bit_end:literal], + $set_field:ident, $(#[$try_set_field_doc:meta])* - $try_set_field:ident: [$try_set_bit_start:literal : $try_set_bit_end:literal]$(,)? + $try_set_field:ident, + range: [$bit_start:literal : $bit_end:literal]$(,)? ) => { impl $ty { $(#[$field_doc])* @@ -1195,17 +1204,17 @@ macro_rules! read_write_csr_field { $(#[$try_field_doc])* #[inline] pub fn $try_field(&self) -> $crate::result::Result { - if $try_get_bit_start <= $try_get_bit_end { + if $bit_start <= $bit_end { Ok($crate::bits::bf_extract( self.bits, - $try_get_bit_start, - $try_get_bit_end - $try_get_bit_start + 1, + $bit_start, + $bit_end - $bit_start + 1, )) } else { Err($crate::result::Error::IndexOutOfBounds { - index: $try_get_bit_start, - min: $try_get_bit_start, - max: $try_get_bit_end + index: $bit_start, + min: $bit_start, + max: $bit_end }) } } @@ -1219,11 +1228,11 @@ macro_rules! read_write_csr_field { $(#[$try_set_field_doc])* #[inline] pub fn $try_set_field(&mut self, $field: usize) -> $crate::result::Result<()> { - if $try_set_bit_start <= $try_set_bit_end { + if $bit_start <= $bit_end { self.bits = $crate::bits::bf_insert( self.bits, - $try_set_bit_start, - $try_set_bit_end - $try_set_bit_start + 1, + $bit_start, + $bit_end - $bit_start + 1, $field, ); @@ -1231,8 +1240,8 @@ macro_rules! read_write_csr_field { } else { Err($crate::result::Error::IndexOutOfBounds { index: $field, - min: $try_get_bit_start, - max: $try_get_bit_end + min: $bit_start, + max: $bit_end }) } } diff --git a/riscv/src/register/mcountinhibit.rs b/riscv/src/register/mcountinhibit.rs index b9e82ca5..6edacb00 100644 --- a/riscv/src/register/mcountinhibit.rs +++ b/riscv/src/register/mcountinhibit.rs @@ -8,29 +8,31 @@ read_write_csr! { Mcountinhibit: 0x320, 0xffff_fffd, /// Gets the `cycle[h]` inhibit field value." - cy: 0, + cy, /// Attempts to get the `cycle[h]` inhibit field value." - try_cy: 0, + try_cy, /// Sets the `cycle[h]` inhibit field value. /// /// **NOTE**: only updates the in-memory value without touching the CSR. - set_cy: 0, + set_cy, /// Attempts to set the `cycle[h]` inhibit field value. /// /// **NOTE**: only updates the in-memory value without touching the CSR. - try_set_cy: 0, + try_set_cy, + bit: 0, /// Gets the `instret[h]` inhibit field value. - ir: 2, + ir, /// Attempts to get the `instret[h]` inhibit field value. - try_ir: 2, + try_ir, /// Sets the `instret[h]` inhibit field value. /// /// **NOTE**: only updates the in-memory value without touching the CSR. - set_ir: 2, + set_ir, /// Attempts to set the `instret[h]` inhibit field value. /// /// **NOTE**: only updates the in-memory value without touching the CSR. - try_set_ir: 2, + try_set_ir, + bit: 2, } read_write_csr_field! { @@ -38,23 +40,24 @@ read_write_csr_field! { /// Gets the `mhpmcounterX[h]` inhibit field value. /// /// **WARN**: `index` must be in the range `[31:3]`. - hpm: 3..=31, + hpm, /// Attempts to get the `mhpmcounterX[h]` inhibit field value. /// /// **WARN**: `index` must be in the range `[31:3]`. - try_hpm: 3..=31, + try_hpm, /// Sets the `mhpmcounterX[h]` inhibit field value. /// /// **WARN**: `index` must be in the range `[31:3]`. /// /// **NOTE**: only updates the in-memory value without touching the CSR. - set_hpm: 3..=31, + set_hpm, /// Sets the `mhpmcounterX[h]` inhibit field value. /// /// **WARN**: `index` must be in the range `[31:3]`. /// /// **NOTE**: only updates the in-memory value without touching the CSR. - try_set_hpm: 3..=31, + try_set_hpm, + range: 3..=31, } set_clear_csr!( diff --git a/riscv/src/register/tests/read_write_csr.rs b/riscv/src/register/tests/read_write_csr.rs index f9a57fa3..7afc93e6 100644 --- a/riscv/src/register/tests/read_write_csr.rs +++ b/riscv/src/register/tests/read_write_csr.rs @@ -5,37 +5,40 @@ read_write_csr! { Mtest: 0x000, 0b1111_1111_1111, /// test single-bit field - single: 0, + single, /// try-get test single-bit field - try_single: 0, + try_single, /// setter test single-bit field - set_single: 0, + set_single, /// try-setter test single-bit field - try_set_single: 0, + try_set_single, + bit: 0, } read_write_csr_field! { Mtest, /// multiple single-bit field range - multi_range: 1..=3, + multi_range, /// try-get multiple single-bit field range - try_multi_range: 1..=3, + try_multi_range, /// setter multiple single-bit field range - set_multi_range: 1..=3, + set_multi_range, /// try-setter multiple single-bit field range - try_set_multi_range: 1..=3, + try_set_multi_range, + range: 1..=3, } read_write_csr_field!( Mtest, /// multi-bit field - multi_field: [4:7], + multi_field, /// try-get multi-bit field - try_multi_field: [4:7], + try_multi_field, /// setter multi-bit field - set_multi_field: [4:7], + set_multi_field, /// try-setter multi-bit field - try_set_multi_field: [4:7], + try_set_multi_field, + range: [4:7], ); read_write_csr_field!( From 49682f0f5df0ba6bcb17993e0a41657f4907b591 Mon Sep 17 00:00:00 2001 From: rmsyn Date: Sun, 15 Sep 2024 00:32:20 +0000 Subject: [PATCH 05/19] riscv: add try variants to read-only CSR macros Adds `try_*` variants for fallible getter functions on read-only CSR macros. --- riscv/src/register/macros.rs | 137 +++++++++++++++++++--- riscv/src/register/tests/read_only_csr.rs | 48 ++++++-- 2 files changed, 160 insertions(+), 25 deletions(-) diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index af6b4c5b..970bfcde 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -869,7 +869,10 @@ macro_rules! read_only_csr { $mask:tt, $( $(#[$field_doc:meta])* - $field:ident: $bit:literal$(,)? + $field:ident, + $(#[$try_field_doc:meta])* + $try_field:ident, + bit: $bit:literal$(,)? )+ ) => { $crate::csr! { $(#[$doc])* $ty: $csr, $mask } @@ -878,7 +881,10 @@ macro_rules! read_only_csr { $crate::read_only_csr_field! { $ty, $(#[$field_doc])* - $field: $bit, + $field, + $(#[$try_field_doc])* + $try_field, + bit: $bit, } )+ @@ -890,7 +896,10 @@ macro_rules! read_only_csr { $mask:tt, $( $(#[$field_doc:meta])* - $field:ident: $bit:literal ..= $bit_end:literal$(,)? + $field:ident, + $(#[$try_field_doc:meta])* + $try_field:ident, + range: $bit:literal ..= $bit_end:literal$(,)? )+) => { $crate::csr! { $(#[$doc])* $ty: $csr, $mask } @@ -898,7 +907,10 @@ macro_rules! read_only_csr { $crate::read_only_csr_field! { $ty, $(#[$field_doc])* - $field: $bit ..= $bit_end, + $field, + $(#[$try_field_doc])* + $try_field, + range: $bit ..= $bit_end, } )+ @@ -910,7 +922,10 @@ macro_rules! read_only_csr { $mask:literal, $( $(#[field_doc:meta])* - $field:ident: [$bit:tt : $bit_end:tt]$(,)? + $field:ident, + $(#[try_field_doc:meta])* + $try_field:ident, + range: [$bit:tt : $bit_end:tt]$(,)? )+) => { $crate::csr! { $(#[$doc])* $ty: $csr, $mask } @@ -918,7 +933,10 @@ macro_rules! read_only_csr { $crate::read_only_csr_field! { $ty, $(#[$field_doc])* - $field: [$bit : $bit_end], + $field, + $(#[$try_field_doc])* + $try_field, + range: [$bit : $bit_end], } )+ @@ -931,6 +949,8 @@ macro_rules! read_only_csr { $( $(#[$field_doc:meta])* $field:ident, + $(#[$try_field_doc:meta])* + $try_field:ident, $(#[$field_ty_doc:meta])* $field_ty:ident { range: [$field_start:literal : $field_end:literal], @@ -945,6 +965,8 @@ macro_rules! read_only_csr { $ty, $(#[$field_doc])* $field, + $(#[$try_field_doc])* + $try_field, $(#[$field_ty_doc])* $field_ty { range: [$field_start : $field_end], @@ -1340,44 +1362,102 @@ macro_rules! read_write_csr_field { macro_rules! read_only_csr_field { ($ty:ident, $(#[$field_doc:meta])* - $field:ident: $bit:literal$(,)?) => { + $field:ident, + $(#[$try_field_doc:meta])* + $try_field:ident, + bit: $bit:literal$(,)?) => { impl $ty { $(#[$field_doc])* #[inline] pub fn $field(&self) -> bool { - $crate::bits::bf_extract(self.bits, $bit, 1) != 0 + self.$try_field().unwrap() + } + + $(#[$try_field_doc])* + #[inline] + pub fn $try_field(&self) -> $crate::result::Result { + let max_width = core::mem::size_of_val(&self.bits) * 8; + + if $bit < max_width { + Ok($crate::bits::bf_extract(self.bits, $bit, 1) != 0) + } else { + Err($crate::result::Error::IndexOutOfBounds { + index: $bit, + min: 0, + max: max_width, + }) + } } } }; ($ty:ident, $(#[$field_doc:meta])* - $field:ident: $bit_start:literal..=$bit_end:literal$(,)?) => { + $field:ident, + $(#[$try_field_doc:meta])* + $try_field:ident, + range: $bit_start:literal..=$bit_end:literal$(,)?) => { impl $ty { $(#[$field_doc])* #[inline] pub fn $field(&self, index: usize) -> bool { - assert!(($bit_start..=$bit_end).contains(&index)); - $crate::bits::bf_extract(self.bits, index, 1) != 0 + self.$try_field(index).unwrap() + } + + $(#[$try_field_doc])* + #[inline] + pub fn $try_field(&self, index: usize) -> $crate::result::Result { + let max_width = core::mem::size_of_val(&self.bits) * 8; + + if $bit_end < max_width && ($bit_start..=$bit_end).contains(&index) { + Ok($crate::bits::bf_extract(self.bits, index, 1) != 0) + } else { + Err($crate::result::Error::IndexOutOfBounds { + index, + min: $bit_start, + max: $bit_end, + }) + } } } }; ($ty:ident, $(#[$field_doc:meta])* - $field:ident: [$bit_start:literal : $bit_end:literal]$(,)?) => { + $field:ident, + $(#[$try_field_doc:meta])* + $try_field:ident, + range: [$bit_start:literal : $bit_end:literal]$(,)?) => { impl $ty { $(#[$field_doc])* #[inline] pub fn $field(&self) -> usize { $crate::bits::bf_extract(self.bits, $bit_start, $bit_end - $bit_start + 1) } + + $(#[$try_field_doc])* + #[inline] + pub fn $try_field(&self) -> $crate::result::Result { + let max_width = core::mem::size_of_val(&self.bits) * 8; + + if $bit_end < max_width && $bit_start <= $bit_end { + Ok($crate::bits::bf_extract(self.bits, $bit_start, $bit_end - $bit_start + 1)) + } else { + Err($crate::result::Error::IndexOutOfBounds { + index: $bit_start, + min: $bit_start, + max: $bit_end, + }) + } + } } }; ($ty:ident, $(#[$field_doc:meta])* $field:ident, + $(#[$try_field_doc:meta])* + $try_field:ident, $(#[$field_ty_doc:meta])* $field_ty:ident { range: [$field_start:literal : $field_end:literal], @@ -1397,12 +1477,33 @@ macro_rules! read_only_csr_field { impl $ty { $(#[$field_doc])* #[inline] - pub fn $field(&self) -> Option<$field_ty> { - $field_ty::from_usize($crate::bits::bf_extract( - self.bits, - $field_start, - $field_end - $field_start + 1, - )) + pub fn $field(&self) -> $field_ty { + self.$try_field().unwrap() + } + + $(#[$try_field_doc])* + #[inline] + pub fn $try_field(&self) -> $crate::result::Result<$field_ty> { + let max_width = core::mem::size_of_val(&self.bits) * 8; + + if $field_end < max_width && $field_start < $field_end { + let value = $crate::bits::bf_extract( + self.bits, + $field_start, + $field_end - $field_start + 1, + ); + + $field_ty::from_usize(value).ok_or($crate::result::Error::InvalidFieldVariant { + field: stringify!($field), + value, + }) + } else { + Err($crate::result::Error::IndexOutOfBounds { + index: $field_start, + min: $field_start, + max: $field_end, + }) + } } } }; diff --git a/riscv/src/register/tests/read_only_csr.rs b/riscv/src/register/tests/read_only_csr.rs index fecc3b62..b379340b 100644 --- a/riscv/src/register/tests/read_only_csr.rs +++ b/riscv/src/register/tests/read_only_csr.rs @@ -1,29 +1,40 @@ -use crate::result::Result; +use crate::result::{Error, Result}; read_only_csr! { /// test CSR register type Mtest: 0x000, 0b1111_1111_1111, /// test single-bit field - single: 0, + single, + /// try-getter test single-bit field + try_single, + bit: 0, } read_only_csr_field! { Mtest, /// multiple single-bit field range - multi_range: 1..=3, + multi_range, + /// try-getter multiple single-bit field range + try_multi_range, + range: 1..=3, } read_only_csr_field!( Mtest, /// multi-bit field - multi_field: [4:7], + multi_field, + /// try-getter multi-bit field + try_multi_field, + range: [4:7], ); read_only_csr_field!( Mtest, /// multi-bit field field_enum, + /// try-getter multi-bit field + try_field_enum, /// field enum type with valid field variants MtestFieldEnum { range: [7:11], @@ -55,41 +66,57 @@ fn test_mtest_read_only() { // check that single bit field getter/setters work. assert_eq!(mtest.single(), false); + assert_eq!(mtest.try_single(), Ok(false)); mtest = Mtest::from_bits(1); assert_eq!(mtest.single(), true); + assert_eq!(mtest.try_single(), Ok(true)); mtest = Mtest::from_bits(0); // check that single bit range field getter/setters work. for i in 1..=3 { assert_eq!(mtest.multi_range(i), false); + assert_eq!(mtest.try_multi_range(i), Ok(false)); mtest = Mtest::from_bits(1 << i); assert_eq!(mtest.multi_range(i), true); + assert_eq!(mtest.try_multi_range(i), Ok(true)); mtest = Mtest::from_bits(0 << i); assert_eq!(mtest.multi_range(i), false); + assert_eq!(mtest.try_multi_range(i), Ok(false)); } // check that multi-bit field getter/setters work. assert_eq!(mtest.multi_field(), 0); + assert_eq!(mtest.try_multi_field(), Ok(0)); mtest = Mtest::from_bits(0xf << 4); assert_eq!(mtest.multi_field(), 0xf); + assert_eq!(mtest.try_multi_field(), Ok(0xf)); mtest = Mtest::from_bits(0x3 << 4); assert_eq!(mtest.multi_field(), 0x3); + assert_eq!(mtest.try_multi_field(), Ok(0x3)); // check that only bits in the field are set. mtest = Mtest::from_bits(0xff << 4); assert_eq!(mtest.multi_field(), 0xf); + assert_eq!(mtest.try_multi_field(), Ok(0xf)); assert_eq!(mtest.bits(), 0xff << 4); mtest = Mtest::from_bits(0x0 << 4); assert_eq!(mtest.multi_field(), 0x0); + assert_eq!(mtest.try_multi_field(), Ok(0x0)); - assert_eq!(mtest.field_enum(), None); + assert_eq!( + mtest.try_field_enum(), + Err(Error::InvalidFieldVariant { + field: "field_enum", + value: 0, + }) + ); [ MtestFieldEnum::Field1, @@ -100,10 +127,17 @@ fn test_mtest_read_only() { .into_iter() .for_each(|variant| { mtest = Mtest::from_bits(variant.into_usize() << 7); - assert_eq!(mtest.field_enum(), Some(variant)); + assert_eq!(mtest.field_enum(), variant); + assert_eq!(mtest.try_field_enum(), Ok(variant)); }); // check that setting an invalid variant returns `None` mtest = Mtest::from_bits(0xbad << 7); - assert_eq!(mtest.field_enum(), None); + assert_eq!( + mtest.try_field_enum(), + Err(Error::InvalidFieldVariant { + field: "field_enum", + value: 13, + }) + ); } From 6cf867d39c1c0244b71e5163424fe3a76d2a43f7 Mon Sep 17 00:00:00 2001 From: rmsyn Date: Sun, 15 Sep 2024 01:13:58 +0000 Subject: [PATCH 06/19] riscv: add try variants to write-only CSR macros Adds `try_*` variants for fallible getter functions on write-only CSR macros. --- riscv/src/register/macros.rs | 152 +++++++++++++++++---- riscv/src/register/tests/write_only_csr.rs | 32 +++-- 2 files changed, 151 insertions(+), 33 deletions(-) diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index 970bfcde..397ffbcb 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -990,7 +990,10 @@ macro_rules! write_only_csr { $mask:literal, $( $(#[$field_doc:meta])* - $field:ident: $bit:literal$(,)? + $field:ident, + $(#[$try_field_doc:meta])* + $try_field:ident, + bit: $bit:literal$(,)? )+) => { $crate::csr! { $(#[$doc])* $ty: $csr, $mask } @@ -998,7 +1001,10 @@ macro_rules! write_only_csr { $crate::write_only_csr_field! { $ty, $(#[$field_doc])* - $field: $bit, + $field, + $(#[$try_field_doc])* + $try_field, + bit: $bit, } )+ @@ -1012,7 +1018,10 @@ macro_rules! write_only_csr { $mask:literal, $( $(#[field_doc:meta])* - $field:ident: $bit_start:literal ..= $bit_end:literal$(,)? + $field:ident, + $(#[try_field_doc:meta])* + $try_field:ident, + range: $bit_start:literal ..= $bit_end:literal$(,)? )+) => { $crate::csr! { $(#[$doc])* $ty: $csr, $mask } @@ -1020,7 +1029,10 @@ macro_rules! write_only_csr { $crate::write_only_csr_field! { $ty, $(#[$field_doc])* - $field: $bit_start..=$bit_end, + $field, + $(#[$try_field_doc])* + $try_field, + range: $bit_start..=$bit_end, } )+ @@ -1034,15 +1046,21 @@ macro_rules! write_only_csr { $mask:literal, $( $(#[field_doc:meta])* - $field:ident: [$bit_start:literal : $bit_end:literal]$(,)? + $field:ident, + $(#[try_field_doc:meta])* + $try_field:ident, + range: [$bit_start:literal : $bit_end:literal]$(,)? )+) => { $crate::csr! { $(#[doc])*, $ty: $csr, $mask } $( $crate::write_only_csr_field! { $ty, - $(#[$field_doc])*, - $field: [$bit_start:$bit_end], + $(#[$field_doc])* + $field, + $(#[$try_field_doc])* + $try_field, + range: [$bit_start:$bit_end], } )+ @@ -1057,6 +1075,8 @@ macro_rules! write_only_csr { $( $(#[$field_doc:meta])* $field:ident, + $(#[$try_field_doc:meta])* + $try_field:ident, $(#[$field_ty_doc:meta])* $field_ty:ident { range: [$field_start:literal : $field_end:literal], @@ -1071,6 +1091,8 @@ macro_rules! write_only_csr { $ty, $(#[$field_doc])* $field, + $(#[$try_field_doc])* + $try_field, $(#[$field_ty_doc])* $field_ty { range: [$field_start : $field_end], @@ -1514,42 +1536,102 @@ macro_rules! read_only_csr_field { macro_rules! write_only_csr_field { ($ty:ident, $(#[$field_doc:meta])* - $field:ident: $bit:literal$(,)?) => { + $field:ident, + $(#[$try_field_doc:meta])* + $try_field:ident, + bit: $bit:literal$(,)?) => { impl $ty { $(#[$field_doc])* #[inline] pub fn $field(&mut self, $field: bool) { - self.bits = $crate::bits::bf_insert(self.bits, $bit, 1, $field as usize); + self.$try_field($field).unwrap(); + } + + $(#[$try_field_doc])* + #[inline] + pub fn $try_field(&mut self, $field: bool) -> $crate::result::Result<()> { + let max_width = core::mem::size_of_val(&self.bits) * 8; + + if $bit < max_width { + self.bits = $crate::bits::bf_insert(self.bits, $bit, 1, $field as usize); + Ok(()) + } else { + Err($crate::result::Error::IndexOutOfBounds { + index: $bit, + min: 0, + max: max_width, + }) + } } } }; ($ty:ident, $(#[$field_doc:meta])* - $field:ident: $bit_start:literal..=$bit_end:literal$(,)?) => { + $field:ident, + $(#[$try_field_doc:meta])* + $try_field:ident, + range: $bit_start:literal..=$bit_end:literal$(,)?) => { impl $ty { $(#[$field_doc])* #[inline] pub fn $field(&mut self, index: usize, $field: bool) { - assert!(($bit_start..=$bit_end).contains(&index)); - self.bits = $crate::bits::bf_insert(self.bits, index, 1, $field as usize); + self.$try_field(index, $field).unwrap(); + } + + $(#[$try_field_doc])* + #[inline] + pub fn $try_field(&mut self, index: usize, $field: bool) -> $crate::result::Result<()> { + let max_width = core::mem::size_of_val(&self.bits) * 8; + + if index < max_width && ($bit_start..=$bit_end).contains(&index) { + self.bits = $crate::bits::bf_insert(self.bits, index, 1, $field as usize); + Ok(()) + } else { + Err($crate::result::Error::IndexOutOfBounds { + index, + min: $bit_start, + max: $bit_end, + }) + } } } }; ($ty:ident, $(#[$field_doc:meta])* - $field:ident: [$bit_start:literal : $bit_end:literal]$(,)?) => { + $field:ident, + $(#[$try_field_doc:meta])* + $try_field:ident, + range: [$bit_start:literal : $bit_end:literal]$(,)?) => { impl $ty { $(#[$field_doc])* #[inline] pub fn $field(&mut self, $field: usize) { - self.bits = $crate::bits::bf_insert( - self.bits, - $bit_start, - $bit_end - $bit_start + 1, - $field, - ); + self.$try_field($field).unwrap(); + } + + $(#[$try_field_doc])* + #[inline] + pub fn $try_field(&mut self, $field: usize) -> $crate::result::Result<()> { + let max_width = core::mem::size_of_val(&self.bits) * 8; + + if $bit_start < max_width && $bit_start <= $bit_end { + self.bits = $crate::bits::bf_insert( + self.bits, + $bit_start, + $bit_end - $bit_start + 1, + $field, + ); + + Ok(()) + } else { + Err($crate::result::Error::IndexOutOfBounds { + index: $bit_start, + min: $bit_start, + max: $bit_end, + }) + } } } }; @@ -1557,6 +1639,8 @@ macro_rules! write_only_csr_field { ($ty:ident, $(#[$field_doc:meta])* $field:ident, + $(#[$try_field_doc:meta])* + $try_field:ident, $(#[$field_ty_doc:meta])* $field_ty:ident { range: [$field_start:literal : $field_end:literal], @@ -1577,12 +1661,30 @@ macro_rules! write_only_csr_field { $(#[$field_doc])* #[inline] pub fn $field(&mut self, $field: $field_ty) { - self.bits = $crate::bits::bf_insert( - self.bits, - $field_start, - $field_end - $field_start + 1, - $field.into(), - ); + self.$try_field($field).unwrap(); + } + + $(#[$try_field_doc])* + #[inline] + pub fn $try_field(&mut self, $field: $field_ty) -> $crate::result::Result<()> { + let max_width = core::mem::size_of_val(&self.bits) * 8; + + if $field_end < max_width && $field_start <= $field_end { + self.bits = $crate::bits::bf_insert( + self.bits, + $field_start, + $field_end - $field_start + 1, + $field.into(), + ); + + Ok(()) + } else { + Err($crate::result::Error::IndexOutOfBounds { + index: $field_start, + min: $field_start, + max: $field_end, + }) + } } } }; diff --git a/riscv/src/register/tests/write_only_csr.rs b/riscv/src/register/tests/write_only_csr.rs index 601325c2..1205ca33 100644 --- a/riscv/src/register/tests/write_only_csr.rs +++ b/riscv/src/register/tests/write_only_csr.rs @@ -5,28 +5,39 @@ write_only_csr! { Mtest: 0x000, 0b1111_1111_1111, /// setter test single-bit field - set_single: 0, + set_single, + /// try-setter test single-bit field + try_set_single, + bit: 0, } write_only_csr_field! { Mtest, /// setter multiple single-bit field range - set_multi_range: 1..=3, + set_multi_range, + /// try-setter multiple single-bit field range + try_set_multi_range, + range: 1..=3, } write_only_csr_field!( Mtest, /// setter multi-bit field - set_multi_field: [4:7], + set_multi_field, + /// try-setter multi-bit field + try_set_multi_field, + range: [4:7], ); write_only_csr_field!( Mtest, /// setter multi-bit field set_field_enum, + /// try-setter multi-bit field + try_set_field_enum, /// field enum type with valid field variants MtestFieldEnum { - range: [7:11], + range: [8:11], default: Field1, Field1 = 1, Field2 = 2, @@ -85,7 +96,7 @@ fn test_mtest_write_only() { mtest = Mtest::from_bits(0); - assert_eq!(MtestFieldEnum::from_usize(mtest.bits() >> 7), None); + assert_eq!(MtestFieldEnum::from_usize(mtest.bits() >> 8), None); [ MtestFieldEnum::Field1, @@ -95,11 +106,16 @@ fn test_mtest_write_only() { ] .into_iter() .for_each(|variant| { + assert_eq!( + mtest.try_set_field_enum(variant), + Ok(()), + "field value: {variant:?}" + ); mtest.set_field_enum(variant); - assert_eq!(MtestFieldEnum::from_usize(mtest.bits() >> 7), Some(variant)); + assert_eq!(MtestFieldEnum::from_usize(mtest.bits() >> 8), Some(variant)); }); // check that setting an invalid variant returns `None` - mtest = Mtest::from_bits(0xbad << 7); - assert_eq!(MtestFieldEnum::from_usize(mtest.bits() >> 7), None); + mtest = Mtest::from_bits(0xbad << 8); + assert_eq!(MtestFieldEnum::from_usize(mtest.bits() >> 8), None); } From 3084b6cc3bb3fb6549aaa60ff79f60f1760970c1 Mon Sep 17 00:00:00 2001 From: rmsyn Date: Sun, 15 Sep 2024 02:18:56 +0000 Subject: [PATCH 07/19] riscv: modularize CSR macro field helpers Modularizes the `read_only_csr_field` and `write_only_csr_field` macro helpers for re-use in `read_write_only_csr_field`. --- riscv/src/register/macros.rs | 598 +++++++++------------ riscv/src/register/tests/read_write_csr.rs | 4 + 2 files changed, 257 insertions(+), 345 deletions(-) diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index 397ffbcb..542ab5bd 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -700,32 +700,32 @@ macro_rules! csr_field_enum { /// The user can then write the entire bitfield value back into the CSR with a single write. #[macro_export] macro_rules! read_write_csr { - ($(#[$doc:meta])* + ($(#[$doc:meta])+ $ty:ident: $csr:tt, $mask:tt, $( - $(#[$field_doc:meta])* + $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])* + $(#[$try_field_doc:meta])+ $try_field:ident, - $(#[$set_field_doc:meta])* + $(#[$set_field_doc:meta])+ $set_field:ident, - $(#[$try_set_field_doc:meta])* + $(#[$try_set_field_doc:meta])+ $try_set_field:ident, bit: $bit:literal$(,)? )+) => { - $crate::csr!($(#[$doc])* $ty: $csr, $mask); + $crate::csr!($(#[$doc])+ $ty: $csr, $mask); $( $crate::read_write_csr_field!( $ty, - $(#[$field_doc])* + $(#[$field_doc])+ $field, - $(#[$try_field_doc])* + $(#[$try_field_doc])+ $try_field, - $(#[$set_field_doc])* + $(#[$set_field_doc])+ $set_field, - $(#[$try_set_field_doc])* + $(#[$try_set_field_doc])+ $try_set_field, bit: $bit, ); @@ -737,17 +737,17 @@ macro_rules! read_write_csr { $crate::clear!($csr); }; - ($(#[$doc:meta])* + ($(#[$doc:meta])+ $ty:ident: $csr:tt, $mask:tt, $( - $(#[$field_doc:meta])* + $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])* + $(#[$try_field_doc:meta])+ $try_field:ident, - $(#[$set_field_doc:meta])* + $(#[$set_field_doc:meta])+ $set_field:ident, - $(#[$try_set_field_doc:meta])* + $(#[$try_set_field_doc:meta])+ $try_set_field:ident, range: $bit_start:literal ..= $bit_end:literal$(,)? )+) => { @@ -756,13 +756,13 @@ macro_rules! read_write_csr { $( $crate::read_write_csr_field!( $ty, - $(#[$field_doc])* + $(#[$field_doc])+ $field, - $(#[$try_field_doc])* + $(#[$try_field_doc])+ $try_field, - $(#[$set_field_doc])* + $(#[$set_field_doc])+ $set_field, - $(#[$try_set_field_doc])* + $(#[$try_set_field_doc])+ $try_set_field, range: $bit_start ..= $bit_end ); @@ -774,32 +774,32 @@ macro_rules! read_write_csr { $crate::clear!($csr); }; - ($(#[$doc:meta])* + ($(#[$doc:meta])+ $ty:ident: $csr:tt, $mask:tt, $( - $(#[$field_doc:meta])* + $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])* + $(#[$try_field_doc:meta])+ $try_field:ident, - $(#[$set_field_doc:meta])* + $(#[$set_field_doc:meta])+ $set_field:ident, - $(#[$try_set_field_doc:meta])* + $(#[$try_set_field_doc:meta])+ $try_set_field:ident, range: [$bit_start:literal : $bit_end:literal]$(,)? )+) => { - $crate::csr!($(#[$doc])*, $ty: $csr, $mask); + $crate::csr!($(#[$doc])+, $ty: $csr, $mask); $( $crate::read_write_csr_field!( $ty, - $(#[$field_doc])* + $(#[$field_doc])+ $field, - $(#[$try_field_doc])* + $(#[$try_field_doc])+ $try_field, - $(#[$set_field_doc])* + $(#[$set_field_doc])+ $set_field, - $(#[$try_set_field_doc])* + $(#[$try_set_field_doc])+ $try_set_field, range: [$bit_start : $bit_end], ); @@ -811,39 +811,39 @@ macro_rules! read_write_csr { $crate::clear!($csr); }; - ($(#[$doc:meta])* + ($(#[$doc:meta])+ $ty:ident: $csr:tt, $mask:tt, $( - $(#[$field_doc:meta])* + $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])* + $(#[$try_field_doc:meta])+ $try_field:ident, - $(#[$set_field_doc:meta])* + $(#[$set_field_doc:meta])+ $set_field:ident, - $(#[$try_set_field_doc:meta])* + $(#[$try_set_field_doc:meta])+ $try_set_field:ident, - $(#[$field_ty_doc:meta])* + $(#[$field_ty_doc:meta])+ $field_ty:ident { range: [$field_start:literal : $field_end:literal], default: $default_variant:ident, $($variant:ident = $value:expr$(,)?)+ }$(,)? )+) => { - $crate::csr!($(#[$doc])* $ty: $csr, $mask); + $crate::csr!($(#[$doc])+ $ty: $csr, $mask); $( $crate::read_write_csr_field!( $ty, - $(#[$field_doc])* + $(#[$field_doc])+ $field, - $(#[$try_field_doc])* + $(#[$try_field_doc])+ $try_field, - $(#[$set_field_doc])* + $(#[$set_field_doc])+ $set_field, - $(#[$try_set_field_doc])* + $(#[$try_set_field_doc])+ $try_set_field, - $(#[$field_ty_doc])* + $(#[$field_ty_doc])+ $field_ty { range: [$field_start : $field_end], default: $field_default, @@ -864,25 +864,25 @@ macro_rules! read_write_csr { /// The type allows to read the CSR value into memory. #[macro_export] macro_rules! read_only_csr { - ($(#[$doc:meta])* + ($(#[$doc:meta])+ $ty:ident: $csr:tt, $mask:tt, $( - $(#[$field_doc:meta])* + $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])* + $(#[$try_field_doc:meta])+ $try_field:ident, bit: $bit:literal$(,)? )+ ) => { - $crate::csr! { $(#[$doc])* $ty: $csr, $mask } + $crate::csr! { $(#[$doc])+ $ty: $csr, $mask } $( $crate::read_only_csr_field! { $ty, - $(#[$field_doc])* + $(#[$field_doc])+ $field, - $(#[$try_field_doc])* + $(#[$try_field_doc])+ $try_field, bit: $bit, } @@ -891,24 +891,24 @@ macro_rules! read_only_csr { $crate::read_csr_as!($ty, $csr); }; - ($(#[doc:meta])* + ($(#[doc:meta])+ $ty:ident: $csr:tt, $mask:tt, $( - $(#[$field_doc:meta])* + $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])* + $(#[$try_field_doc:meta])+ $try_field:ident, range: $bit:literal ..= $bit_end:literal$(,)? )+) => { - $crate::csr! { $(#[$doc])* $ty: $csr, $mask } + $crate::csr! { $(#[$doc])+ $ty: $csr, $mask } $( $crate::read_only_csr_field! { $ty, - $(#[$field_doc])* + $(#[$field_doc])+ $field, - $(#[$try_field_doc])* + $(#[$try_field_doc])+ $try_field, range: $bit ..= $bit_end, } @@ -917,24 +917,24 @@ macro_rules! read_only_csr { $crate::read_csr_as!($ty, $csr); }; - ($(#[doc:meta])* + ($(#[doc:meta])+ $ty:ident: $csr:literal, $mask:literal, $( - $(#[field_doc:meta])* + $(#[field_doc:meta])+ $field:ident, - $(#[try_field_doc:meta])* + $(#[try_field_doc:meta])+ $try_field:ident, range: [$bit:tt : $bit_end:tt]$(,)? )+) => { - $crate::csr! { $(#[$doc])* $ty: $csr, $mask } + $crate::csr! { $(#[$doc])+ $ty: $csr, $mask } $( $crate::read_only_csr_field! { $ty, - $(#[$field_doc])* + $(#[$field_doc])+ $field, - $(#[$try_field_doc])* + $(#[$try_field_doc])+ $try_field, range: [$bit : $bit_end], } @@ -943,31 +943,31 @@ macro_rules! read_only_csr { $crate::read_csr_as!($ty, $csr); }; - ($(#[$doc:meta])* + ($(#[$doc:meta])+ $ty:ident: $csr:tt, $mask:tt, $( - $(#[$field_doc:meta])* + $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])* + $(#[$try_field_doc:meta])+ $try_field:ident, - $(#[$field_ty_doc:meta])* + $(#[$field_ty_doc:meta])+ $field_ty:ident { range: [$field_start:literal : $field_end:literal], default: $default_variant:ident, $($variant:ident = $value:expr$(,)?)+ }$(,)? )+) => { - $crate::csr!($(#[$doc])* $ty: $csr, $mask); + $crate::csr!($(#[$doc])+ $ty: $csr, $mask); $( $crate::read_only_csr_field!( $ty, - $(#[$field_doc])* + $(#[$field_doc])+ $field, - $(#[$try_field_doc])* + $(#[$try_field_doc])+ $try_field, - $(#[$field_ty_doc])* + $(#[$field_ty_doc])+ $field_ty { range: [$field_start : $field_end], default: $field_default, @@ -985,24 +985,24 @@ macro_rules! read_only_csr { /// The type allows to read the CSR value into memory. #[macro_export] macro_rules! write_only_csr { - ($(#[$doc:meta])* + ($(#[$doc:meta])+ $ty:ident: $csr:literal, $mask:literal, $( - $(#[$field_doc:meta])* + $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])* + $(#[$try_field_doc:meta])+ $try_field:ident, bit: $bit:literal$(,)? )+) => { - $crate::csr! { $(#[$doc])* $ty: $csr, $mask } + $crate::csr! { $(#[$doc])+ $ty: $csr, $mask } $( $crate::write_only_csr_field! { $ty, - $(#[$field_doc])* + $(#[$field_doc])+ $field, - $(#[$try_field_doc])* + $(#[$try_field_doc])+ $try_field, bit: $bit, } @@ -1013,24 +1013,24 @@ macro_rules! write_only_csr { $crate::clear!($csr); }; - ($(#[$doc:meta])* + ($(#[$doc:meta])+ $ty:ident: $csr:literal, $mask:literal, $( - $(#[field_doc:meta])* + $(#[field_doc:meta])+ $field:ident, - $(#[try_field_doc:meta])* + $(#[try_field_doc:meta])+ $try_field:ident, range: $bit_start:literal ..= $bit_end:literal$(,)? )+) => { - $crate::csr! { $(#[$doc])* $ty: $csr, $mask } + $crate::csr! { $(#[$doc])+ $ty: $csr, $mask } $( $crate::write_only_csr_field! { $ty, - $(#[$field_doc])* + $(#[$field_doc])+ $field, - $(#[$try_field_doc])* + $(#[$try_field_doc])+ $try_field, range: $bit_start..=$bit_end, } @@ -1041,24 +1041,24 @@ macro_rules! write_only_csr { $crate::clear!($csr); }; - ($(#[doc:meta])* + ($(#[doc:meta])+ $ty:ident: $csr:literal, $mask:literal, $( - $(#[field_doc:meta])* + $(#[field_doc:meta])+ $field:ident, - $(#[try_field_doc:meta])* + $(#[try_field_doc:meta])+ $try_field:ident, range: [$bit_start:literal : $bit_end:literal]$(,)? )+) => { - $crate::csr! { $(#[doc])*, $ty: $csr, $mask } + $crate::csr! { $(#[doc])+, $ty: $csr, $mask } $( $crate::write_only_csr_field! { $ty, - $(#[$field_doc])* + $(#[$field_doc])+ $field, - $(#[$try_field_doc])* + $(#[$try_field_doc])+ $try_field, range: [$bit_start:$bit_end], } @@ -1069,31 +1069,31 @@ macro_rules! write_only_csr { $crate::clear!($csr); }; - ($(#[$doc:meta])* + ($(#[$doc:meta])+ $ty:ident: $csr:tt, $mask:tt, $( - $(#[$field_doc:meta])* + $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])* + $(#[$try_field_doc:meta])+ $try_field:ident, - $(#[$field_ty_doc:meta])* + $(#[$field_ty_doc:meta])+ $field_ty:ident { range: [$field_start:literal : $field_end:literal], default: $default_variant:ident, $($variant:ident = $value:expr$(,)?)+ }$(,)? )+) => { - $crate::csr!($(#[$doc])* $ty: $csr, $mask); + $crate::csr!($(#[$doc])+ $ty: $csr, $mask); $( $crate::write_only_csr_field!( $ty, - $(#[$field_doc])* + $(#[$field_doc])+ $field, - $(#[$try_field_doc])* + $(#[$try_field_doc])+ $try_field, - $(#[$field_ty_doc])* + $(#[$field_ty_doc])+ $field_ty { range: [$field_start : $field_end], default: $field_default, @@ -1113,195 +1113,105 @@ macro_rules! write_only_csr { #[macro_export] macro_rules! read_write_csr_field { ($ty:ident, - $(#[$field_doc:meta])* + $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])* + $(#[$try_field_doc:meta])+ $try_field:ident, - $(#[$set_field_doc:meta])* + $(#[$set_field_doc:meta])+ $set_field:ident, - $(#[$try_set_field_doc:meta])* + $(#[$try_set_field_doc:meta])+ $try_set_field:ident, bit: $bit:literal$(,)? ) => { - impl $ty { - $(#[$field_doc])* - #[inline] - pub fn $field(&self) -> bool { - self.$try_field().unwrap() - } - - $(#[$try_field_doc])* - #[inline] - pub fn $try_field(&self) -> $crate::result::Result { - let max_width = core::mem::size_of_val(&self.bits) * 8; - - if $bit < max_width { - Ok($crate::bits::bf_extract(self.bits, $bit, 1) != 0) - } else { - Err($crate::result::Error::IndexOutOfBounds { - index: $bit, - min: 0, - max: max_width - }) - } - } - - $(#[$set_field_doc])* - #[inline] - pub fn $set_field(&mut self, $field: bool) { - self.$try_set_field($field).unwrap(); - } - - $(#[$try_set_field_doc])* - #[inline] - pub fn $try_set_field(&mut self, $field: bool) -> $crate::result::Result<()> { - let max_width = core::mem::size_of_val(&self.bits) * 8; + $crate::read_only_csr_field!( + $ty, + $(#[$field_doc])+ + $field, + $(#[$try_field_doc])+ + $try_field, + bit: $bit, + ); - if $bit < max_width { - self.bits = $crate::bits::bf_insert(self.bits, $bit, 1, $field as usize); - Ok(()) - } else { - Err($crate::result::Error::IndexOutOfBounds { - index: $bit, - min: 0, - max: max_width - }) - } - } - } + $crate::write_only_csr_field!( + $ty, + $(#[$set_field_doc])+ + $set_field, + $(#[$try_set_field_doc])+ + $try_set_field, + bit: $bit, + ); }; ($ty:ident, - $(#[$field_doc:meta])* + $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])* + $(#[$try_field_doc:meta])+ $try_field:ident, - $(#[$set_field_doc:meta])* + $(#[$set_field_doc:meta])+ $set_field:ident, - $(#[$try_set_field_doc:meta])* + $(#[$try_set_field_doc:meta])+ $try_set_field:ident, range: $bit_start:literal ..= $bit_end:literal$(,)? ) => { - impl $ty { - $(#[$field_doc])* - #[inline] - pub fn $field(&self, index: usize) -> bool { - self.$try_field(index).unwrap() - } - - $(#[$field_doc])* - #[inline] - pub fn $try_field(&self, index: usize) -> $crate::result::Result { - if ($bit_start..=$bit_end).contains(&index) { - Ok($crate::bits::bf_extract(self.bits, index, 1) != 0) - } else { - Err($crate::result::Error::IndexOutOfBounds { - index, - min: $bit_start, - max: $bit_end - }) - } - } - - $(#[$set_field_doc])* - #[inline] - pub fn $set_field(&mut self, index: usize, $field: bool) { - self.$try_set_field(index, $field).unwrap(); - } - - $(#[$try_set_field_doc])* - #[inline] - pub fn $try_set_field(&mut self, index: usize, $field: bool) -> $crate::result::Result<()> { - if ($bit_start..=$bit_end).contains(&index) { - self.bits = $crate::bits::bf_insert(self.bits, index, 1, $field as usize); + $crate::read_only_csr_field!( + $ty, + $(#[$field_doc])+ + $field, + $(#[$try_field_doc])+ + $try_field, + range: $bit_start ..= $bit_end, + ); - Ok(()) - } else { - Err($crate::result::Error::IndexOutOfBounds { - index, - min: $bit_start, - max: $bit_end - }) - } - } - } + $crate::write_only_csr_field!( + $ty, + $(#[$set_field_doc])+ + $set_field, + $(#[$try_set_field_doc])+ + $try_set_field, + range: $bit_start ..= $bit_end, + ); }; ($ty:ident, - $(#[$field_doc:meta])* + $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])* + $(#[$try_field_doc:meta])+ $try_field:ident, - $(#[$set_field_doc:meta])* + $(#[$set_field_doc:meta])+ $set_field:ident, - $(#[$try_set_field_doc:meta])* + $(#[$try_set_field_doc:meta])+ $try_set_field:ident, range: [$bit_start:literal : $bit_end:literal]$(,)? ) => { - impl $ty { - $(#[$field_doc])* - #[inline] - pub fn $field(&self) -> usize { - self.$try_field().unwrap() - } - - $(#[$try_field_doc])* - #[inline] - pub fn $try_field(&self) -> $crate::result::Result { - if $bit_start <= $bit_end { - Ok($crate::bits::bf_extract( - self.bits, - $bit_start, - $bit_end - $bit_start + 1, - )) - } else { - Err($crate::result::Error::IndexOutOfBounds { - index: $bit_start, - min: $bit_start, - max: $bit_end - }) - } - } - - $(#[$set_field_doc])* - #[inline] - pub fn $set_field(&mut self, $field: usize) { - self.$try_set_field($field).unwrap(); - } - - $(#[$try_set_field_doc])* - #[inline] - pub fn $try_set_field(&mut self, $field: usize) -> $crate::result::Result<()> { - if $bit_start <= $bit_end { - self.bits = $crate::bits::bf_insert( - self.bits, - $bit_start, - $bit_end - $bit_start + 1, - $field, - ); - - Ok(()) - } else { - Err($crate::result::Error::IndexOutOfBounds { - index: $field, - min: $bit_start, - max: $bit_end - }) - } - } - } + $crate::read_only_csr_field!( + $ty, + $(#[$field_doc])+ + $field, + $(#[$try_field_doc])+ + $try_field, + range: [$bit_start : $bit_end], + ); + + $crate::write_only_csr_field!( + $ty, + $(#[$set_field_doc])+ + $set_field, + $(#[$try_set_field_doc])+ + $try_set_field, + range: [$bit_start : $bit_end], + ); }; ($ty:ident, - $(#[$field_doc:meta])* + $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])* + $(#[$try_field_doc:meta])+ $try_field:ident, - $(#[$set_field_doc:meta])* + $(#[$set_field_doc:meta])+ $set_field:ident, - $(#[$try_set_field_doc:meta])* + $(#[$try_set_field_doc:meta])+ $try_set_field:ident, - $(#[$field_ty_doc:meta])* + $(#[$field_ty_doc:meta])+ $field_ty:ident { range: [$field_start:literal : $field_end:literal], default: $default_variant:ident, @@ -1309,7 +1219,7 @@ macro_rules! read_write_csr_field { }$(,)? ) => { $crate::csr_field_enum!( - $(#[$field_ty_doc])* + $(#[$field_ty_doc])+ $field_ty { range: [$field_start : $field_end], default: $default_variant, @@ -1317,65 +1227,25 @@ macro_rules! read_write_csr_field { }, ); - impl $ty { - $(#[$field_doc])* - #[inline] - pub fn $field(&self) -> $field_ty { - self.$try_field().unwrap() - } - - $(#[$field_doc])* - #[inline] - pub fn $try_field(&self) -> $crate::result::Result<$field_ty> { - if $field_start <= $field_end { - let value = $crate::bits::bf_extract( - self.bits, - $field_start, - $field_end - $field_start + 1, - ); - - $field_ty::from_usize(value).ok_or( - $crate::result::Error::InvalidFieldVariant { - field: stringify!($field), - value, - } - ) - } else { - Err($crate::result::Error::IndexOutOfBounds { - index: $field_start, - min: $field_start, - max: $field_end - }) - } - } - - $(#[$set_field_doc])* - #[inline] - pub fn $set_field(&mut self, $field: $field_ty) { - self.$try_set_field($field).unwrap() - } - - $(#[$try_set_field_doc])* - #[inline] - pub fn $try_set_field(&mut self, $field: $field_ty) -> $crate::result::Result<()> { - if $field_start <= $field_end { - self.bits = $crate::bits::bf_insert( - self.bits, - $field_start, - $field_end - $field_start + 1, - $field.into(), - ); + $crate::read_only_csr_field!( + $ty, + $(#[$field_doc])+ + $field, + $(#[$try_field_doc])+ + $try_field, + $field_ty, + range: [$field_start : $field_end], + ); - Ok(()) - } else { - Err($crate::result::Error::IndexOutOfBounds { - index: $field_start, - min: $field_start, - max: $field_end - }) - } - } - } + $crate::write_only_csr_field!( + $ty, + $(#[$set_field_doc])+ + $set_field, + $(#[$try_set_field_doc])+ + $try_set_field, + $field_ty, + range: [$field_start : $field_end], + ); }; } @@ -1383,19 +1253,19 @@ macro_rules! read_write_csr_field { #[macro_export] macro_rules! read_only_csr_field { ($ty:ident, - $(#[$field_doc:meta])* + $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])* + $(#[$try_field_doc:meta])+ $try_field:ident, bit: $bit:literal$(,)?) => { impl $ty { - $(#[$field_doc])* + $(#[$field_doc])+ #[inline] pub fn $field(&self) -> bool { self.$try_field().unwrap() } - $(#[$try_field_doc])* + $(#[$try_field_doc])+ #[inline] pub fn $try_field(&self) -> $crate::result::Result { let max_width = core::mem::size_of_val(&self.bits) * 8; @@ -1414,19 +1284,19 @@ macro_rules! read_only_csr_field { }; ($ty:ident, - $(#[$field_doc:meta])* + $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])* + $(#[$try_field_doc:meta])+ $try_field:ident, range: $bit_start:literal..=$bit_end:literal$(,)?) => { impl $ty { - $(#[$field_doc])* + $(#[$field_doc])+ #[inline] pub fn $field(&self, index: usize) -> bool { self.$try_field(index).unwrap() } - $(#[$try_field_doc])* + $(#[$try_field_doc])+ #[inline] pub fn $try_field(&self, index: usize) -> $crate::result::Result { let max_width = core::mem::size_of_val(&self.bits) * 8; @@ -1445,19 +1315,19 @@ macro_rules! read_only_csr_field { }; ($ty:ident, - $(#[$field_doc:meta])* + $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])* + $(#[$try_field_doc:meta])+ $try_field:ident, range: [$bit_start:literal : $bit_end:literal]$(,)?) => { impl $ty { - $(#[$field_doc])* + $(#[$field_doc])+ #[inline] pub fn $field(&self) -> usize { $crate::bits::bf_extract(self.bits, $bit_start, $bit_end - $bit_start + 1) } - $(#[$try_field_doc])* + $(#[$try_field_doc])+ #[inline] pub fn $try_field(&self) -> $crate::result::Result { let max_width = core::mem::size_of_val(&self.bits) * 8; @@ -1476,11 +1346,11 @@ macro_rules! read_only_csr_field { }; ($ty:ident, - $(#[$field_doc:meta])* + $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])* + $(#[$try_field_doc:meta])+ $try_field:ident, - $(#[$field_ty_doc:meta])* + $(#[$field_ty_doc:meta])+ $field_ty:ident { range: [$field_start:literal : $field_end:literal], default: $default_variant:ident, @@ -1488,22 +1358,41 @@ macro_rules! read_only_csr_field { }$(,)? ) => { $crate::csr_field_enum!( - $(#[$field_ty_doc])* + $(#[$field_ty_doc])+ $field_ty { range: [$field_start : $field_end], default: $default_variant, $($variant = $value,)+ }, - ); + ); + + $crate::read_only_csr_field!( + $ty, + $(#[$field_doc])* + $field, + $(#[$try_field_doc])* + $try_field, + $field_ty, + range: [$field_start : $field_end], + ); + }; + ($ty:ident, + $(#[$field_doc:meta])+ + $field:ident, + $(#[$try_field_doc:meta])+ + $try_field:ident, + $field_ty:ident, + range: [$field_start:literal : $field_end:literal]$(,)? + ) => { impl $ty { - $(#[$field_doc])* + $(#[$field_doc])+ #[inline] pub fn $field(&self) -> $field_ty { self.$try_field().unwrap() } - $(#[$try_field_doc])* + $(#[$try_field_doc])+ #[inline] pub fn $try_field(&self) -> $crate::result::Result<$field_ty> { let max_width = core::mem::size_of_val(&self.bits) * 8; @@ -1535,19 +1424,19 @@ macro_rules! read_only_csr_field { #[macro_export] macro_rules! write_only_csr_field { ($ty:ident, - $(#[$field_doc:meta])* + $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])* + $(#[$try_field_doc:meta])+ $try_field:ident, bit: $bit:literal$(,)?) => { impl $ty { - $(#[$field_doc])* + $(#[$field_doc])+ #[inline] pub fn $field(&mut self, $field: bool) { self.$try_field($field).unwrap(); } - $(#[$try_field_doc])* + $(#[$try_field_doc])+ #[inline] pub fn $try_field(&mut self, $field: bool) -> $crate::result::Result<()> { let max_width = core::mem::size_of_val(&self.bits) * 8; @@ -1567,19 +1456,19 @@ macro_rules! write_only_csr_field { }; ($ty:ident, - $(#[$field_doc:meta])* + $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])* + $(#[$try_field_doc:meta])+ $try_field:ident, range: $bit_start:literal..=$bit_end:literal$(,)?) => { impl $ty { - $(#[$field_doc])* + $(#[$field_doc])+ #[inline] pub fn $field(&mut self, index: usize, $field: bool) { self.$try_field(index, $field).unwrap(); } - $(#[$try_field_doc])* + $(#[$try_field_doc])+ #[inline] pub fn $try_field(&mut self, index: usize, $field: bool) -> $crate::result::Result<()> { let max_width = core::mem::size_of_val(&self.bits) * 8; @@ -1599,19 +1488,19 @@ macro_rules! write_only_csr_field { }; ($ty:ident, - $(#[$field_doc:meta])* + $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])* + $(#[$try_field_doc:meta])+ $try_field:ident, range: [$bit_start:literal : $bit_end:literal]$(,)?) => { impl $ty { - $(#[$field_doc])* + $(#[$field_doc])+ #[inline] pub fn $field(&mut self, $field: usize) { self.$try_field($field).unwrap(); } - $(#[$try_field_doc])* + $(#[$try_field_doc])+ #[inline] pub fn $try_field(&mut self, $field: usize) -> $crate::result::Result<()> { let max_width = core::mem::size_of_val(&self.bits) * 8; @@ -1637,11 +1526,11 @@ macro_rules! write_only_csr_field { }; ($ty:ident, - $(#[$field_doc:meta])* + $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])* + $(#[$try_field_doc:meta])+ $try_field:ident, - $(#[$field_ty_doc:meta])* + $(#[$field_ty_doc:meta])+ $field_ty:ident { range: [$field_start:literal : $field_end:literal], default: $default_variant:ident, @@ -1649,7 +1538,7 @@ macro_rules! write_only_csr_field { }$(,)? ) => { $crate::csr_field_enum!( - $(#[$field_ty_doc])* + $(#[$field_ty_doc])+ $field_ty { range: [$field_start : $field_end], default: $default_variant, @@ -1657,14 +1546,33 @@ macro_rules! write_only_csr_field { }, ); + $crate::write_only_csr_field!( + $ty, + $(#[$field_doc])+ + $field, + $(#[$try_field_doc])+ + $try_field, + $field_ty, + range: [$field_start : $field_end], + ); + }; + + ($ty:ident, + $(#[$field_doc:meta])+ + $field:ident, + $(#[$try_field_doc:meta])+ + $try_field:ident, + $field_ty:ident, + range: [$field_start:literal : $field_end:literal]$(,)? + ) => { impl $ty { - $(#[$field_doc])* + $(#[$field_doc])+ #[inline] pub fn $field(&mut self, $field: $field_ty) { self.$try_field($field).unwrap(); } - $(#[$try_field_doc])* + $(#[$try_field_doc])+ #[inline] pub fn $try_field(&mut self, $field: $field_ty) -> $crate::result::Result<()> { let max_width = core::mem::size_of_val(&self.bits) * 8; diff --git a/riscv/src/register/tests/read_write_csr.rs b/riscv/src/register/tests/read_write_csr.rs index 7afc93e6..79d5aab8 100644 --- a/riscv/src/register/tests/read_write_csr.rs +++ b/riscv/src/register/tests/read_write_csr.rs @@ -115,17 +115,21 @@ fn test_mtest_read_write() { mtest.set_multi_field(0xf); assert_eq!(mtest.multi_field(), 0xf); + assert_eq!(mtest.try_multi_field(), Ok(0xf)); mtest.set_multi_field(0x3); assert_eq!(mtest.multi_field(), 0x3); + assert_eq!(mtest.try_multi_field(), Ok(0x3)); // check that only bits in the field are set. mtest.set_multi_field(0xff); assert_eq!(mtest.multi_field(), 0xf); + assert_eq!(mtest.try_multi_field(), Ok(0xf)); assert_eq!(mtest.bits(), 0xf << 4); mtest.set_multi_field(0x0); assert_eq!(mtest.multi_field(), 0x0); + assert_eq!(mtest.try_multi_field(), Ok(0x0)); assert_eq!( mtest.try_field_enum(), From 03676016b2e66c73742edf2e847e6cd7a2218fac Mon Sep 17 00:00:00 2001 From: rmsyn Date: Sun, 15 Sep 2024 02:29:17 +0000 Subject: [PATCH 08/19] riscv: add explicit mask field to CSR macros Adds the explicit `mask:` field name to CSR helper macros to clarify intent. --- riscv/src/register/macros.rs | 24 +++++++++++----------- riscv/src/register/mcountinhibit.rs | 6 +++--- riscv/src/register/tests/read_only_csr.rs | 2 +- riscv/src/register/tests/read_write_csr.rs | 2 +- riscv/src/register/tests/write_only_csr.rs | 2 +- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index 542ab5bd..5b9e03e5 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -702,7 +702,7 @@ macro_rules! csr_field_enum { macro_rules! read_write_csr { ($(#[$doc:meta])+ $ty:ident: $csr:tt, - $mask:tt, + mask: $mask:tt, $( $(#[$field_doc:meta])+ $field:ident, @@ -739,7 +739,7 @@ macro_rules! read_write_csr { ($(#[$doc:meta])+ $ty:ident: $csr:tt, - $mask:tt, + mask: $mask:tt, $( $(#[$field_doc:meta])+ $field:ident, @@ -776,7 +776,7 @@ macro_rules! read_write_csr { ($(#[$doc:meta])+ $ty:ident: $csr:tt, - $mask:tt, + mask: $mask:tt, $( $(#[$field_doc:meta])+ $field:ident, @@ -813,7 +813,7 @@ macro_rules! read_write_csr { ($(#[$doc:meta])+ $ty:ident: $csr:tt, - $mask:tt, + mask: $mask:tt, $( $(#[$field_doc:meta])+ $field:ident, @@ -866,7 +866,7 @@ macro_rules! read_write_csr { macro_rules! read_only_csr { ($(#[$doc:meta])+ $ty:ident: $csr:tt, - $mask:tt, + mask: $mask:tt, $( $(#[$field_doc:meta])+ $field:ident, @@ -893,7 +893,7 @@ macro_rules! read_only_csr { ($(#[doc:meta])+ $ty:ident: $csr:tt, - $mask:tt, + mask: $mask:tt, $( $(#[$field_doc:meta])+ $field:ident, @@ -919,7 +919,7 @@ macro_rules! read_only_csr { ($(#[doc:meta])+ $ty:ident: $csr:literal, - $mask:literal, + mask: $mask:literal, $( $(#[field_doc:meta])+ $field:ident, @@ -945,7 +945,7 @@ macro_rules! read_only_csr { ($(#[$doc:meta])+ $ty:ident: $csr:tt, - $mask:tt, + mask: $mask:tt, $( $(#[$field_doc:meta])+ $field:ident, @@ -987,7 +987,7 @@ macro_rules! read_only_csr { macro_rules! write_only_csr { ($(#[$doc:meta])+ $ty:ident: $csr:literal, - $mask:literal, + mask: $mask:literal, $( $(#[$field_doc:meta])+ $field:ident, @@ -1015,7 +1015,7 @@ macro_rules! write_only_csr { ($(#[$doc:meta])+ $ty:ident: $csr:literal, - $mask:literal, + mask: $mask:literal, $( $(#[field_doc:meta])+ $field:ident, @@ -1043,7 +1043,7 @@ macro_rules! write_only_csr { ($(#[doc:meta])+ $ty:ident: $csr:literal, - $mask:literal, + mask: $mask:literal, $( $(#[field_doc:meta])+ $field:ident, @@ -1071,7 +1071,7 @@ macro_rules! write_only_csr { ($(#[$doc:meta])+ $ty:ident: $csr:tt, - $mask:tt, + mask: $mask:tt, $( $(#[$field_doc:meta])+ $field:ident, diff --git a/riscv/src/register/mcountinhibit.rs b/riscv/src/register/mcountinhibit.rs index 6edacb00..969a705c 100644 --- a/riscv/src/register/mcountinhibit.rs +++ b/riscv/src/register/mcountinhibit.rs @@ -6,10 +6,10 @@ use crate::result::{Error, Result}; read_write_csr! { /// `mcountinhibit` register Mcountinhibit: 0x320, - 0xffff_fffd, - /// Gets the `cycle[h]` inhibit field value." + mask: 0xffff_fffd, + /// Gets the `cycle[h]` inhibit field value. cy, - /// Attempts to get the `cycle[h]` inhibit field value." + /// Attempts to get the `cycle[h]` inhibit field value. try_cy, /// Sets the `cycle[h]` inhibit field value. /// diff --git a/riscv/src/register/tests/read_only_csr.rs b/riscv/src/register/tests/read_only_csr.rs index b379340b..0b11805c 100644 --- a/riscv/src/register/tests/read_only_csr.rs +++ b/riscv/src/register/tests/read_only_csr.rs @@ -3,7 +3,7 @@ use crate::result::{Error, Result}; read_only_csr! { /// test CSR register type Mtest: 0x000, - 0b1111_1111_1111, + mask: 0b1111_1111_1111, /// test single-bit field single, /// try-getter test single-bit field diff --git a/riscv/src/register/tests/read_write_csr.rs b/riscv/src/register/tests/read_write_csr.rs index 79d5aab8..7386ba70 100644 --- a/riscv/src/register/tests/read_write_csr.rs +++ b/riscv/src/register/tests/read_write_csr.rs @@ -3,7 +3,7 @@ use crate::result::{Error, Result}; read_write_csr! { /// test CSR register type Mtest: 0x000, - 0b1111_1111_1111, + mask: 0b1111_1111_1111, /// test single-bit field single, /// try-get test single-bit field diff --git a/riscv/src/register/tests/write_only_csr.rs b/riscv/src/register/tests/write_only_csr.rs index 1205ca33..677e661f 100644 --- a/riscv/src/register/tests/write_only_csr.rs +++ b/riscv/src/register/tests/write_only_csr.rs @@ -3,7 +3,7 @@ use crate::result::Result; write_only_csr! { /// test CSR register type Mtest: 0x000, - 0b1111_1111_1111, + mask: 0b1111_1111_1111, /// setter test single-bit field set_single, /// try-setter test single-bit field From db53e901bb3d1763163422e201b90d83308b492a Mon Sep 17 00:00:00 2001 From: rmsyn Date: Sun, 15 Sep 2024 02:38:57 +0000 Subject: [PATCH 09/19] riscv: add field label to CSR macros Adds the `field` macro argument label to CSR helper macros to clarify intent. --- riscv/src/register/macros.rs | 200 ++++++++++++--------- riscv/src/register/mcountinhibit.rs | 56 +++--- riscv/src/register/tests/read_only_csr.rs | 12 +- riscv/src/register/tests/read_write_csr.rs | 20 ++- riscv/src/register/tests/write_only_csr.rs | 12 +- 5 files changed, 167 insertions(+), 133 deletions(-) diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index 5b9e03e5..034a51c3 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -704,15 +704,17 @@ macro_rules! read_write_csr { $ty:ident: $csr:tt, mask: $mask:tt, $( - $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - $(#[$set_field_doc:meta])+ - $set_field:ident, - $(#[$try_set_field_doc:meta])+ - $try_set_field:ident, - bit: $bit:literal$(,)? + field: { + $(#[$field_doc:meta])+ + $field:ident, + $(#[$try_field_doc:meta])+ + $try_field:ident, + $(#[$set_field_doc:meta])+ + $set_field:ident, + $(#[$try_set_field_doc:meta])+ + $try_set_field:ident, + bit: $bit:literal$(,)? + }$(,)? )+) => { $crate::csr!($(#[$doc])+ $ty: $csr, $mask); @@ -741,15 +743,17 @@ macro_rules! read_write_csr { $ty:ident: $csr:tt, mask: $mask:tt, $( - $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - $(#[$set_field_doc:meta])+ - $set_field:ident, - $(#[$try_set_field_doc:meta])+ - $try_set_field:ident, - range: $bit_start:literal ..= $bit_end:literal$(,)? + field: { + $(#[$field_doc:meta])+ + $field:ident, + $(#[$try_field_doc:meta])+ + $try_field:ident, + $(#[$set_field_doc:meta])+ + $set_field:ident, + $(#[$try_set_field_doc:meta])+ + $try_set_field:ident, + range: $bit_start:literal ..= $bit_end:literal$(,)? + }$(,)? )+) => { $crate::csr!($(#[$doc])*, $ty: $csr, $mask); @@ -778,15 +782,17 @@ macro_rules! read_write_csr { $ty:ident: $csr:tt, mask: $mask:tt, $( - $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - $(#[$set_field_doc:meta])+ - $set_field:ident, - $(#[$try_set_field_doc:meta])+ - $try_set_field:ident, - range: [$bit_start:literal : $bit_end:literal]$(,)? + field: { + $(#[$field_doc:meta])+ + $field:ident, + $(#[$try_field_doc:meta])+ + $try_field:ident, + $(#[$set_field_doc:meta])+ + $set_field:ident, + $(#[$try_set_field_doc:meta])+ + $try_set_field:ident, + range: [$bit_start:literal : $bit_end:literal]$(,)? + }$(,)? )+) => { $crate::csr!($(#[$doc])+, $ty: $csr, $mask); @@ -815,19 +821,21 @@ macro_rules! read_write_csr { $ty:ident: $csr:tt, mask: $mask:tt, $( - $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - $(#[$set_field_doc:meta])+ - $set_field:ident, - $(#[$try_set_field_doc:meta])+ - $try_set_field:ident, - $(#[$field_ty_doc:meta])+ - $field_ty:ident { - range: [$field_start:literal : $field_end:literal], - default: $default_variant:ident, - $($variant:ident = $value:expr$(,)?)+ + field: { + $(#[$field_doc:meta])+ + $field:ident, + $(#[$try_field_doc:meta])+ + $try_field:ident, + $(#[$set_field_doc:meta])+ + $set_field:ident, + $(#[$try_set_field_doc:meta])+ + $try_set_field:ident, + $(#[$field_ty_doc:meta])+ + $field_ty:ident { + range: [$field_start:literal : $field_end:literal], + default: $default_variant:ident, + $($variant:ident = $value:expr$(,)?)+ + }$(,)? }$(,)? )+) => { $crate::csr!($(#[$doc])+ $ty: $csr, $mask); @@ -868,11 +876,13 @@ macro_rules! read_only_csr { $ty:ident: $csr:tt, mask: $mask:tt, $( - $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - bit: $bit:literal$(,)? + field: { + $(#[$field_doc:meta])+ + $field:ident, + $(#[$try_field_doc:meta])+ + $try_field:ident, + bit: $bit:literal$(,)? + }$(,)? )+ ) => { $crate::csr! { $(#[$doc])+ $ty: $csr, $mask } @@ -895,11 +905,13 @@ macro_rules! read_only_csr { $ty:ident: $csr:tt, mask: $mask:tt, $( - $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - range: $bit:literal ..= $bit_end:literal$(,)? + field: { + $(#[$field_doc:meta])+ + $field:ident, + $(#[$try_field_doc:meta])+ + $try_field:ident, + range: $bit:literal ..= $bit_end:literal$(,)? + }$(,)? )+) => { $crate::csr! { $(#[$doc])+ $ty: $csr, $mask } @@ -921,11 +933,13 @@ macro_rules! read_only_csr { $ty:ident: $csr:literal, mask: $mask:literal, $( - $(#[field_doc:meta])+ - $field:ident, - $(#[try_field_doc:meta])+ - $try_field:ident, - range: [$bit:tt : $bit_end:tt]$(,)? + field: { + $(#[field_doc:meta])+ + $field:ident, + $(#[try_field_doc:meta])+ + $try_field:ident, + range: [$bit:tt : $bit_end:tt]$(,)? + }$(,)? )+) => { $crate::csr! { $(#[$doc])+ $ty: $csr, $mask } @@ -947,15 +961,17 @@ macro_rules! read_only_csr { $ty:ident: $csr:tt, mask: $mask:tt, $( - $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - $(#[$field_ty_doc:meta])+ - $field_ty:ident { - range: [$field_start:literal : $field_end:literal], - default: $default_variant:ident, - $($variant:ident = $value:expr$(,)?)+ + field: { + $(#[$field_doc:meta])+ + $field:ident, + $(#[$try_field_doc:meta])+ + $try_field:ident, + $(#[$field_ty_doc:meta])+ + $field_ty:ident { + range: [$field_start:literal : $field_end:literal], + default: $default_variant:ident, + $($variant:ident = $value:expr$(,)?)+ + }$(,)? }$(,)? )+) => { $crate::csr!($(#[$doc])+ $ty: $csr, $mask); @@ -989,11 +1005,13 @@ macro_rules! write_only_csr { $ty:ident: $csr:literal, mask: $mask:literal, $( - $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - bit: $bit:literal$(,)? + field: { + $(#[$field_doc:meta])+ + $field:ident, + $(#[$try_field_doc:meta])+ + $try_field:ident, + bit: $bit:literal$(,)? + }$(,)? )+) => { $crate::csr! { $(#[$doc])+ $ty: $csr, $mask } @@ -1017,11 +1035,13 @@ macro_rules! write_only_csr { $ty:ident: $csr:literal, mask: $mask:literal, $( - $(#[field_doc:meta])+ - $field:ident, - $(#[try_field_doc:meta])+ - $try_field:ident, - range: $bit_start:literal ..= $bit_end:literal$(,)? + field: { + $(#[field_doc:meta])+ + $field:ident, + $(#[try_field_doc:meta])+ + $try_field:ident, + range: $bit_start:literal ..= $bit_end:literal$(,)? + }$(,)? )+) => { $crate::csr! { $(#[$doc])+ $ty: $csr, $mask } @@ -1045,11 +1065,13 @@ macro_rules! write_only_csr { $ty:ident: $csr:literal, mask: $mask:literal, $( - $(#[field_doc:meta])+ - $field:ident, - $(#[try_field_doc:meta])+ - $try_field:ident, - range: [$bit_start:literal : $bit_end:literal]$(,)? + field: { + $(#[field_doc:meta])+ + $field:ident, + $(#[try_field_doc:meta])+ + $try_field:ident, + range: [$bit_start:literal : $bit_end:literal]$(,)? + }$(,)? )+) => { $crate::csr! { $(#[doc])+, $ty: $csr, $mask } @@ -1073,15 +1095,17 @@ macro_rules! write_only_csr { $ty:ident: $csr:tt, mask: $mask:tt, $( - $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - $(#[$field_ty_doc:meta])+ - $field_ty:ident { - range: [$field_start:literal : $field_end:literal], - default: $default_variant:ident, - $($variant:ident = $value:expr$(,)?)+ + field: { + $(#[$field_doc:meta])+ + $field:ident, + $(#[$try_field_doc:meta])+ + $try_field:ident, + $(#[$field_ty_doc:meta])+ + $field_ty:ident { + range: [$field_start:literal : $field_end:literal], + default: $default_variant:ident, + $($variant:ident = $value:expr$(,)?)+ + }$(,)? }$(,)? )+) => { $crate::csr!($(#[$doc])+ $ty: $csr, $mask); diff --git a/riscv/src/register/mcountinhibit.rs b/riscv/src/register/mcountinhibit.rs index 969a705c..6a5222ea 100644 --- a/riscv/src/register/mcountinhibit.rs +++ b/riscv/src/register/mcountinhibit.rs @@ -7,32 +7,36 @@ read_write_csr! { /// `mcountinhibit` register Mcountinhibit: 0x320, mask: 0xffff_fffd, - /// Gets the `cycle[h]` inhibit field value. - cy, - /// Attempts to get the `cycle[h]` inhibit field value. - try_cy, - /// Sets the `cycle[h]` inhibit field value. - /// - /// **NOTE**: only updates the in-memory value without touching the CSR. - set_cy, - /// Attempts to set the `cycle[h]` inhibit field value. - /// - /// **NOTE**: only updates the in-memory value without touching the CSR. - try_set_cy, - bit: 0, - /// Gets the `instret[h]` inhibit field value. - ir, - /// Attempts to get the `instret[h]` inhibit field value. - try_ir, - /// Sets the `instret[h]` inhibit field value. - /// - /// **NOTE**: only updates the in-memory value without touching the CSR. - set_ir, - /// Attempts to set the `instret[h]` inhibit field value. - /// - /// **NOTE**: only updates the in-memory value without touching the CSR. - try_set_ir, - bit: 2, + field: { + /// Gets the `cycle[h]` inhibit field value. + cy, + /// Attempts to get the `cycle[h]` inhibit field value. + try_cy, + /// Sets the `cycle[h]` inhibit field value. + /// + /// **NOTE**: only updates the in-memory value without touching the CSR. + set_cy, + /// Attempts to set the `cycle[h]` inhibit field value. + /// + /// **NOTE**: only updates the in-memory value without touching the CSR. + try_set_cy, + bit: 0, + }, + field: { + /// Gets the `instret[h]` inhibit field value. + ir, + /// Attempts to get the `instret[h]` inhibit field value. + try_ir, + /// Sets the `instret[h]` inhibit field value. + /// + /// **NOTE**: only updates the in-memory value without touching the CSR. + set_ir, + /// Attempts to set the `instret[h]` inhibit field value. + /// + /// **NOTE**: only updates the in-memory value without touching the CSR. + try_set_ir, + bit: 2, + } } read_write_csr_field! { diff --git a/riscv/src/register/tests/read_only_csr.rs b/riscv/src/register/tests/read_only_csr.rs index 0b11805c..c770f028 100644 --- a/riscv/src/register/tests/read_only_csr.rs +++ b/riscv/src/register/tests/read_only_csr.rs @@ -4,11 +4,13 @@ read_only_csr! { /// test CSR register type Mtest: 0x000, mask: 0b1111_1111_1111, - /// test single-bit field - single, - /// try-getter test single-bit field - try_single, - bit: 0, + field: { + /// test single-bit field + single, + /// try-getter test single-bit field + try_single, + bit: 0, + } } read_only_csr_field! { diff --git a/riscv/src/register/tests/read_write_csr.rs b/riscv/src/register/tests/read_write_csr.rs index 7386ba70..95bb7a90 100644 --- a/riscv/src/register/tests/read_write_csr.rs +++ b/riscv/src/register/tests/read_write_csr.rs @@ -4,15 +4,17 @@ read_write_csr! { /// test CSR register type Mtest: 0x000, mask: 0b1111_1111_1111, - /// test single-bit field - single, - /// try-get test single-bit field - try_single, - /// setter test single-bit field - set_single, - /// try-setter test single-bit field - try_set_single, - bit: 0, + field: { + /// test single-bit field + single, + /// try-get test single-bit field + try_single, + /// setter test single-bit field + set_single, + /// try-setter test single-bit field + try_set_single, + bit: 0, + } } read_write_csr_field! { diff --git a/riscv/src/register/tests/write_only_csr.rs b/riscv/src/register/tests/write_only_csr.rs index 677e661f..4309ee7a 100644 --- a/riscv/src/register/tests/write_only_csr.rs +++ b/riscv/src/register/tests/write_only_csr.rs @@ -4,11 +4,13 @@ write_only_csr! { /// test CSR register type Mtest: 0x000, mask: 0b1111_1111_1111, - /// setter test single-bit field - set_single, - /// try-setter test single-bit field - try_set_single, - bit: 0, + field: { + /// setter test single-bit field + set_single, + /// try-setter test single-bit field + try_set_single, + bit: 0, + } } write_only_csr_field! { From 6e41d3a24c74955a3389f448ab873513bb97569f Mon Sep 17 00:00:00 2001 From: rmsyn Date: Wed, 18 Sep 2024 23:35:47 +0000 Subject: [PATCH 10/19] fixup: riscv: remove field args from CSR macro Removes field arguments from CSR definition macros. --- riscv/src/register/macros.rs | 402 +-------------------- riscv/src/register/mcountinhibit.rs | 68 ++-- riscv/src/register/tests/read_only_csr.rs | 16 +- riscv/src/register/tests/read_write_csr.rs | 24 +- riscv/src/register/tests/write_only_csr.rs | 16 +- 5 files changed, 73 insertions(+), 453 deletions(-) diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index 034a51c3..1d9ce9b4 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -702,168 +702,12 @@ macro_rules! csr_field_enum { macro_rules! read_write_csr { ($(#[$doc:meta])+ $ty:ident: $csr:tt, - mask: $mask:tt, - $( - field: { - $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - $(#[$set_field_doc:meta])+ - $set_field:ident, - $(#[$try_set_field_doc:meta])+ - $try_set_field:ident, - bit: $bit:literal$(,)? - }$(,)? - )+) => { - $crate::csr!($(#[$doc])+ $ty: $csr, $mask); - - $( - $crate::read_write_csr_field!( - $ty, - $(#[$field_doc])+ - $field, - $(#[$try_field_doc])+ - $try_field, - $(#[$set_field_doc])+ - $set_field, - $(#[$try_set_field_doc])+ - $try_set_field, - bit: $bit, - ); - )+ - - $crate::read_csr_as!($ty, $csr); - $crate::write_csr_as!($ty, $csr); - $crate::set!($csr); - $crate::clear!($csr); - }; - - ($(#[$doc:meta])+ - $ty:ident: $csr:tt, - mask: $mask:tt, - $( - field: { - $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - $(#[$set_field_doc:meta])+ - $set_field:ident, - $(#[$try_set_field_doc:meta])+ - $try_set_field:ident, - range: $bit_start:literal ..= $bit_end:literal$(,)? - }$(,)? - )+) => { - $crate::csr!($(#[$doc])*, $ty: $csr, $mask); - - $( - $crate::read_write_csr_field!( - $ty, - $(#[$field_doc])+ - $field, - $(#[$try_field_doc])+ - $try_field, - $(#[$set_field_doc])+ - $set_field, - $(#[$try_set_field_doc])+ - $try_set_field, - range: $bit_start ..= $bit_end - ); - )+ - - $crate::read_csr_as!($ty, $csr); - $crate::write_csr_as!($ty, $csr); - $crate::set!($csr); - $crate::clear!($csr); - }; - - ($(#[$doc:meta])+ - $ty:ident: $csr:tt, - mask: $mask:tt, - $( - field: { - $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - $(#[$set_field_doc:meta])+ - $set_field:ident, - $(#[$try_set_field_doc:meta])+ - $try_set_field:ident, - range: [$bit_start:literal : $bit_end:literal]$(,)? - }$(,)? - )+) => { - $crate::csr!($(#[$doc])+, $ty: $csr, $mask); - - $( - $crate::read_write_csr_field!( - $ty, - $(#[$field_doc])+ - $field, - $(#[$try_field_doc])+ - $try_field, - $(#[$set_field_doc])+ - $set_field, - $(#[$try_set_field_doc])+ - $try_set_field, - range: [$bit_start : $bit_end], - ); - )+ - - $crate::read_csr_as!($ty, $csr); - $crate::write_csr_as!($ty, $csr); - $crate::set!($csr); - $crate::clear!($csr); - }; - - ($(#[$doc:meta])+ - $ty:ident: $csr:tt, - mask: $mask:tt, - $( - field: { - $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - $(#[$set_field_doc:meta])+ - $set_field:ident, - $(#[$try_set_field_doc:meta])+ - $try_set_field:ident, - $(#[$field_ty_doc:meta])+ - $field_ty:ident { - range: [$field_start:literal : $field_end:literal], - default: $default_variant:ident, - $($variant:ident = $value:expr$(,)?)+ - }$(,)? - }$(,)? - )+) => { + mask: $mask:tt$(,)? + ) => { $crate::csr!($(#[$doc])+ $ty: $csr, $mask); - $( - $crate::read_write_csr_field!( - $ty, - $(#[$field_doc])+ - $field, - $(#[$try_field_doc])+ - $try_field, - $(#[$set_field_doc])+ - $set_field, - $(#[$try_set_field_doc])+ - $try_set_field, - $(#[$field_ty_doc])+ - $field_ty { - range: [$field_start : $field_end], - default: $field_default, - $($variant = $value),+ - }, - ); - )+ - $crate::read_csr_as!($ty, $csr); $crate::write_csr_as!($ty, $csr); - $crate::set!($csr); - $crate::clear!($csr); }; } @@ -874,124 +718,10 @@ macro_rules! read_write_csr { macro_rules! read_only_csr { ($(#[$doc:meta])+ $ty:ident: $csr:tt, - mask: $mask:tt, - $( - field: { - $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - bit: $bit:literal$(,)? - }$(,)? - )+ + mask: $mask:tt$(,)? ) => { $crate::csr! { $(#[$doc])+ $ty: $csr, $mask } - $( - $crate::read_only_csr_field! { - $ty, - $(#[$field_doc])+ - $field, - $(#[$try_field_doc])+ - $try_field, - bit: $bit, - } - )+ - - $crate::read_csr_as!($ty, $csr); - }; - - ($(#[doc:meta])+ - $ty:ident: $csr:tt, - mask: $mask:tt, - $( - field: { - $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - range: $bit:literal ..= $bit_end:literal$(,)? - }$(,)? - )+) => { - $crate::csr! { $(#[$doc])+ $ty: $csr, $mask } - - $( - $crate::read_only_csr_field! { - $ty, - $(#[$field_doc])+ - $field, - $(#[$try_field_doc])+ - $try_field, - range: $bit ..= $bit_end, - } - )+ - - $crate::read_csr_as!($ty, $csr); - }; - - ($(#[doc:meta])+ - $ty:ident: $csr:literal, - mask: $mask:literal, - $( - field: { - $(#[field_doc:meta])+ - $field:ident, - $(#[try_field_doc:meta])+ - $try_field:ident, - range: [$bit:tt : $bit_end:tt]$(,)? - }$(,)? - )+) => { - $crate::csr! { $(#[$doc])+ $ty: $csr, $mask } - - $( - $crate::read_only_csr_field! { - $ty, - $(#[$field_doc])+ - $field, - $(#[$try_field_doc])+ - $try_field, - range: [$bit : $bit_end], - } - )+ - - $crate::read_csr_as!($ty, $csr); - }; - - ($(#[$doc:meta])+ - $ty:ident: $csr:tt, - mask: $mask:tt, - $( - field: { - $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - $(#[$field_ty_doc:meta])+ - $field_ty:ident { - range: [$field_start:literal : $field_end:literal], - default: $default_variant:ident, - $($variant:ident = $value:expr$(,)?)+ - }$(,)? - }$(,)? - )+) => { - $crate::csr!($(#[$doc])+ $ty: $csr, $mask); - - $( - $crate::read_only_csr_field!( - $ty, - $(#[$field_doc])+ - $field, - $(#[$try_field_doc])+ - $try_field, - $(#[$field_ty_doc])+ - $field_ty { - range: [$field_start : $field_end], - default: $field_default, - $($variant = $value),+ - }, - ); - )+ - $crate::read_csr_as!($ty, $csr); }; } @@ -1003,133 +733,11 @@ macro_rules! read_only_csr { macro_rules! write_only_csr { ($(#[$doc:meta])+ $ty:ident: $csr:literal, - mask: $mask:literal, - $( - field: { - $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - bit: $bit:literal$(,)? - }$(,)? - )+) => { - $crate::csr! { $(#[$doc])+ $ty: $csr, $mask } - - $( - $crate::write_only_csr_field! { - $ty, - $(#[$field_doc])+ - $field, - $(#[$try_field_doc])+ - $try_field, - bit: $bit, - } - )+ - - $crate::write_csr_as!($ty, $csr); - $crate::set!($csr); - $crate::clear!($csr); - }; - - ($(#[$doc:meta])+ - $ty:ident: $csr:literal, - mask: $mask:literal, - $( - field: { - $(#[field_doc:meta])+ - $field:ident, - $(#[try_field_doc:meta])+ - $try_field:ident, - range: $bit_start:literal ..= $bit_end:literal$(,)? - }$(,)? - )+) => { + mask: $mask:literal$(,)? + ) => { $crate::csr! { $(#[$doc])+ $ty: $csr, $mask } - $( - $crate::write_only_csr_field! { - $ty, - $(#[$field_doc])+ - $field, - $(#[$try_field_doc])+ - $try_field, - range: $bit_start..=$bit_end, - } - )+ - - $crate::write_csr_as!($ty, $csr); - $crate::set!($csr); - $crate::clear!($csr); - }; - - ($(#[doc:meta])+ - $ty:ident: $csr:literal, - mask: $mask:literal, - $( - field: { - $(#[field_doc:meta])+ - $field:ident, - $(#[try_field_doc:meta])+ - $try_field:ident, - range: [$bit_start:literal : $bit_end:literal]$(,)? - }$(,)? - )+) => { - $crate::csr! { $(#[doc])+, $ty: $csr, $mask } - - $( - $crate::write_only_csr_field! { - $ty, - $(#[$field_doc])+ - $field, - $(#[$try_field_doc])+ - $try_field, - range: [$bit_start:$bit_end], - } - )+ - - $crate::write_csr_as!($ty, $csr); - $crate::set!($csr); - $crate::clear!($csr); - }; - - ($(#[$doc:meta])+ - $ty:ident: $csr:tt, - mask: $mask:tt, - $( - field: { - $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - $(#[$field_ty_doc:meta])+ - $field_ty:ident { - range: [$field_start:literal : $field_end:literal], - default: $default_variant:ident, - $($variant:ident = $value:expr$(,)?)+ - }$(,)? - }$(,)? - )+) => { - $crate::csr!($(#[$doc])+ $ty: $csr, $mask); - - $( - $crate::write_only_csr_field!( - $ty, - $(#[$field_doc])+ - $field, - $(#[$try_field_doc])+ - $try_field, - $(#[$field_ty_doc])+ - $field_ty { - range: [$field_start : $field_end], - default: $field_default, - $($variant = $value),+ - }, - ); - )+ - - $crate::read_csr_as!($ty, $csr); $crate::write_csr_as!($ty, $csr); - $crate::set!($csr); - $crate::clear!($csr); }; } diff --git a/riscv/src/register/mcountinhibit.rs b/riscv/src/register/mcountinhibit.rs index 6a5222ea..7cca379d 100644 --- a/riscv/src/register/mcountinhibit.rs +++ b/riscv/src/register/mcountinhibit.rs @@ -1,42 +1,48 @@ //! `mcountinhibit` register -use crate::read_write_csr; use crate::result::{Error, Result}; read_write_csr! { /// `mcountinhibit` register Mcountinhibit: 0x320, mask: 0xffff_fffd, - field: { - /// Gets the `cycle[h]` inhibit field value. - cy, - /// Attempts to get the `cycle[h]` inhibit field value. - try_cy, - /// Sets the `cycle[h]` inhibit field value. - /// - /// **NOTE**: only updates the in-memory value without touching the CSR. - set_cy, - /// Attempts to set the `cycle[h]` inhibit field value. - /// - /// **NOTE**: only updates the in-memory value without touching the CSR. - try_set_cy, - bit: 0, - }, - field: { - /// Gets the `instret[h]` inhibit field value. - ir, - /// Attempts to get the `instret[h]` inhibit field value. - try_ir, - /// Sets the `instret[h]` inhibit field value. - /// - /// **NOTE**: only updates the in-memory value without touching the CSR. - set_ir, - /// Attempts to set the `instret[h]` inhibit field value. - /// - /// **NOTE**: only updates the in-memory value without touching the CSR. - try_set_ir, - bit: 2, - } +} + +set!(0x320); +clear!(0x320); + +read_write_csr_field! { + Mcountinhibit, + /// Gets the `cycle[h]` inhibit field value. + cy, + /// Attempts to get the `cycle[h]` inhibit field value. + try_cy, + /// Sets the `cycle[h]` inhibit field value. + /// + /// **NOTE**: only updates the in-memory value without touching the CSR. + set_cy, + /// Attempts to set the `cycle[h]` inhibit field value. + /// + /// **NOTE**: only updates the in-memory value without touching the CSR. + try_set_cy, + bit: 0, +} + +read_write_csr_field! { + Mcountinhibit, + /// Gets the `instret[h]` inhibit field value. + ir, + /// Attempts to get the `instret[h]` inhibit field value. + try_ir, + /// Sets the `instret[h]` inhibit field value. + /// + /// **NOTE**: only updates the in-memory value without touching the CSR. + set_ir, + /// Attempts to set the `instret[h]` inhibit field value. + /// + /// **NOTE**: only updates the in-memory value without touching the CSR. + try_set_ir, + bit: 2, } read_write_csr_field! { diff --git a/riscv/src/register/tests/read_only_csr.rs b/riscv/src/register/tests/read_only_csr.rs index c770f028..6f3fd97f 100644 --- a/riscv/src/register/tests/read_only_csr.rs +++ b/riscv/src/register/tests/read_only_csr.rs @@ -4,13 +4,15 @@ read_only_csr! { /// test CSR register type Mtest: 0x000, mask: 0b1111_1111_1111, - field: { - /// test single-bit field - single, - /// try-getter test single-bit field - try_single, - bit: 0, - } +} + +read_only_csr_field! { + Mtest, + /// test single-bit field + single, + /// try-getter test single-bit field + try_single, + bit: 0, } read_only_csr_field! { diff --git a/riscv/src/register/tests/read_write_csr.rs b/riscv/src/register/tests/read_write_csr.rs index 95bb7a90..77631ad5 100644 --- a/riscv/src/register/tests/read_write_csr.rs +++ b/riscv/src/register/tests/read_write_csr.rs @@ -4,17 +4,19 @@ read_write_csr! { /// test CSR register type Mtest: 0x000, mask: 0b1111_1111_1111, - field: { - /// test single-bit field - single, - /// try-get test single-bit field - try_single, - /// setter test single-bit field - set_single, - /// try-setter test single-bit field - try_set_single, - bit: 0, - } +} + +read_write_csr_field! { + Mtest, + /// test single-bit field + single, + /// try-get test single-bit field + try_single, + /// setter test single-bit field + set_single, + /// try-setter test single-bit field + try_set_single, + bit: 0, } read_write_csr_field! { diff --git a/riscv/src/register/tests/write_only_csr.rs b/riscv/src/register/tests/write_only_csr.rs index 4309ee7a..8e9d20b2 100644 --- a/riscv/src/register/tests/write_only_csr.rs +++ b/riscv/src/register/tests/write_only_csr.rs @@ -4,13 +4,15 @@ write_only_csr! { /// test CSR register type Mtest: 0x000, mask: 0b1111_1111_1111, - field: { - /// setter test single-bit field - set_single, - /// try-setter test single-bit field - try_set_single, - bit: 0, - } +} + +write_only_csr_field! { + Mtest, + /// setter test single-bit field + set_single, + /// try-setter test single-bit field + try_set_single, + bit: 0, } write_only_csr_field! { From ec6ef2b41ff47a89b7a6ca2d212a74d06b2a7997 Mon Sep 17 00:00:00 2001 From: rmsyn Date: Wed, 18 Sep 2024 23:38:32 +0000 Subject: [PATCH 11/19] fixup: riscv: remove CSR number from csr macro Removes the unused `csr` number argument from the `csr` macro. --- riscv/src/register/macros.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index 1d9ce9b4..9bc851bb 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -610,7 +610,7 @@ macro_rules! clear_pmp { #[macro_export] macro_rules! csr { ($(#[$doc:meta])* - $ty:ident: $csr:literal, + $ty:ident, $mask:literal) => { #[repr(C)] $(#[$doc])* @@ -704,7 +704,7 @@ macro_rules! read_write_csr { $ty:ident: $csr:tt, mask: $mask:tt$(,)? ) => { - $crate::csr!($(#[$doc])+ $ty: $csr, $mask); + $crate::csr!($(#[$doc])+ $ty, $mask); $crate::read_csr_as!($ty, $csr); $crate::write_csr_as!($ty, $csr); @@ -720,7 +720,7 @@ macro_rules! read_only_csr { $ty:ident: $csr:tt, mask: $mask:tt$(,)? ) => { - $crate::csr! { $(#[$doc])+ $ty: $csr, $mask } + $crate::csr! { $(#[$doc])+ $ty, $mask } $crate::read_csr_as!($ty, $csr); }; @@ -735,7 +735,7 @@ macro_rules! write_only_csr { $ty:ident: $csr:literal, mask: $mask:literal$(,)? ) => { - $crate::csr! { $(#[$doc])+ $ty: $csr, $mask } + $crate::csr! { $(#[$doc])+ $ty, $mask } $crate::write_csr_as!($ty, $csr); }; From ac99986e6915fc4631b66e7490a362c72109c57a Mon Sep 17 00:00:00 2001 From: rmsyn Date: Wed, 18 Sep 2024 23:53:15 +0000 Subject: [PATCH 12/19] fixup: riscv: use result for CSR enum conversion Uses the crate result type for converting a CSR enum type from a `usize`. --- riscv/src/register/macros.rs | 11 ++++------- riscv/src/register/tests/read_only_csr.rs | 16 ++-------------- riscv/src/register/tests/read_write_csr.rs | 16 ++-------------- riscv/src/register/tests/write_only_csr.rs | 14 ++++++++++---- 4 files changed, 18 insertions(+), 39 deletions(-) diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index 9bc851bb..32aaacec 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -666,10 +666,10 @@ macro_rules! csr_field_enum { } /// Attempts to convert a [`usize`] into a valid variant. - pub const fn from_usize(val: usize) -> Option { + pub const fn from_usize(val: usize) -> $crate::result::Result { match val { - $($value => Some(Self::$variant),)+ - _ => None, + $($value => Ok(Self::$variant),)+ + _ => Err($crate::result::Error::InvalidVariant(val)), } } @@ -1036,10 +1036,7 @@ macro_rules! read_only_csr_field { $field_end - $field_start + 1, ); - $field_ty::from_usize(value).ok_or($crate::result::Error::InvalidFieldVariant { - field: stringify!($field), - value, - }) + $field_ty::from_usize(value) } else { Err($crate::result::Error::IndexOutOfBounds { index: $field_start, diff --git a/riscv/src/register/tests/read_only_csr.rs b/riscv/src/register/tests/read_only_csr.rs index 6f3fd97f..6925dcd1 100644 --- a/riscv/src/register/tests/read_only_csr.rs +++ b/riscv/src/register/tests/read_only_csr.rs @@ -114,13 +114,7 @@ fn test_mtest_read_only() { assert_eq!(mtest.multi_field(), 0x0); assert_eq!(mtest.try_multi_field(), Ok(0x0)); - assert_eq!( - mtest.try_field_enum(), - Err(Error::InvalidFieldVariant { - field: "field_enum", - value: 0, - }) - ); + assert_eq!(mtest.try_field_enum(), Err(Error::InvalidVariant(0)),); [ MtestFieldEnum::Field1, @@ -137,11 +131,5 @@ fn test_mtest_read_only() { // check that setting an invalid variant returns `None` mtest = Mtest::from_bits(0xbad << 7); - assert_eq!( - mtest.try_field_enum(), - Err(Error::InvalidFieldVariant { - field: "field_enum", - value: 13, - }) - ); + assert_eq!(mtest.try_field_enum(), Err(Error::InvalidVariant(13)),); } diff --git a/riscv/src/register/tests/read_write_csr.rs b/riscv/src/register/tests/read_write_csr.rs index 77631ad5..3fb39012 100644 --- a/riscv/src/register/tests/read_write_csr.rs +++ b/riscv/src/register/tests/read_write_csr.rs @@ -135,13 +135,7 @@ fn test_mtest_read_write() { assert_eq!(mtest.multi_field(), 0x0); assert_eq!(mtest.try_multi_field(), Ok(0x0)); - assert_eq!( - mtest.try_field_enum(), - Err(Error::InvalidFieldVariant { - field: "field_enum", - value: 0, - }) - ); + assert_eq!(mtest.try_field_enum(), Err(Error::InvalidVariant(0)),); [ MtestFieldEnum::Field1, @@ -158,11 +152,5 @@ fn test_mtest_read_write() { // check that setting an invalid variant returns `None` mtest = Mtest::from_bits(0xbad << 7); - assert_eq!( - mtest.try_field_enum(), - Err(Error::InvalidFieldVariant { - field: "field_enum", - value: 13, - }) - ); + assert_eq!(mtest.try_field_enum(), Err(Error::InvalidVariant(13)),); } diff --git a/riscv/src/register/tests/write_only_csr.rs b/riscv/src/register/tests/write_only_csr.rs index 8e9d20b2..2e7da165 100644 --- a/riscv/src/register/tests/write_only_csr.rs +++ b/riscv/src/register/tests/write_only_csr.rs @@ -1,4 +1,4 @@ -use crate::result::Result; +use crate::result::{Error, Result}; write_only_csr! { /// test CSR register type @@ -100,7 +100,10 @@ fn test_mtest_write_only() { mtest = Mtest::from_bits(0); - assert_eq!(MtestFieldEnum::from_usize(mtest.bits() >> 8), None); + assert_eq!( + MtestFieldEnum::from_usize(mtest.bits() >> 8), + Err(Error::InvalidVariant(0)) + ); [ MtestFieldEnum::Field1, @@ -116,10 +119,13 @@ fn test_mtest_write_only() { "field value: {variant:?}" ); mtest.set_field_enum(variant); - assert_eq!(MtestFieldEnum::from_usize(mtest.bits() >> 8), Some(variant)); + assert_eq!(MtestFieldEnum::from_usize(mtest.bits() >> 8), Ok(variant)); }); // check that setting an invalid variant returns `None` mtest = Mtest::from_bits(0xbad << 8); - assert_eq!(MtestFieldEnum::from_usize(mtest.bits() >> 8), None); + assert_eq!( + MtestFieldEnum::from_usize(mtest.bits() >> 8), + Err(Error::InvalidVariant(13)) + ); } From cc061bdd9c911050fcb6c33912ef277984aa3913 Mon Sep 17 00:00:00 2001 From: rmsyn Date: Fri, 20 Sep 2024 01:59:17 +0000 Subject: [PATCH 13/19] fixup: riscv: read-only CSR compile-time asserts Applies compile-time checks in read-only CSR macros. Authored-by: rmsyn Co-authored-by: romancardenas --- riscv/src/register/macros.rs | 117 ++++++--------------- riscv/src/register/mcountinhibit.rs | 4 - riscv/src/register/tests/read_only_csr.rs | 23 +--- riscv/src/register/tests/read_write_csr.rs | 8 -- 4 files changed, 39 insertions(+), 113 deletions(-) diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index 32aaacec..293fd525 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -747,8 +747,6 @@ macro_rules! read_write_csr_field { ($ty:ident, $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, $(#[$set_field_doc:meta])+ $set_field:ident, $(#[$try_set_field_doc:meta])+ @@ -758,10 +756,7 @@ macro_rules! read_write_csr_field { $crate::read_only_csr_field!( $ty, $(#[$field_doc])+ - $field, - $(#[$try_field_doc])+ - $try_field, - bit: $bit, + $field: $bit, ); $crate::write_only_csr_field!( @@ -807,8 +802,6 @@ macro_rules! read_write_csr_field { ($ty:ident, $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, $(#[$set_field_doc:meta])+ $set_field:ident, $(#[$try_set_field_doc:meta])+ @@ -818,10 +811,7 @@ macro_rules! read_write_csr_field { $crate::read_only_csr_field!( $ty, $(#[$field_doc])+ - $field, - $(#[$try_field_doc])+ - $try_field, - range: [$bit_start : $bit_end], + $field: [$bit_start : $bit_end], ); $crate::write_only_csr_field!( @@ -886,31 +876,14 @@ macro_rules! read_write_csr_field { macro_rules! read_only_csr_field { ($ty:ident, $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - bit: $bit:literal$(,)?) => { + $field:ident: $bit:literal$(,)?) => { + const _: () = assert!($bit < usize::BITS); + impl $ty { $(#[$field_doc])+ #[inline] pub fn $field(&self) -> bool { - self.$try_field().unwrap() - } - - $(#[$try_field_doc])+ - #[inline] - pub fn $try_field(&self) -> $crate::result::Result { - let max_width = core::mem::size_of_val(&self.bits) * 8; - - if $bit < max_width { - Ok($crate::bits::bf_extract(self.bits, $bit, 1) != 0) - } else { - Err($crate::result::Error::IndexOutOfBounds { - index: $bit, - min: 0, - max: max_width, - }) - } + $crate::bits::bf_extract(self.bits, $bit, 1) != 0 } } }; @@ -921,6 +894,9 @@ macro_rules! read_only_csr_field { $(#[$try_field_doc:meta])+ $try_field:ident, range: $bit_start:literal..=$bit_end:literal$(,)?) => { + const _: () = assert!($bit_end < usize::BITS); + const _: () = assert!($bit_start <= $bit_end); + impl $ty { $(#[$field_doc])+ #[inline] @@ -931,9 +907,7 @@ macro_rules! read_only_csr_field { $(#[$try_field_doc])+ #[inline] pub fn $try_field(&self, index: usize) -> $crate::result::Result { - let max_width = core::mem::size_of_val(&self.bits) * 8; - - if $bit_end < max_width && ($bit_start..=$bit_end).contains(&index) { + if ($bit_start..=$bit_end).contains(&index) { Ok($crate::bits::bf_extract(self.bits, index, 1) != 0) } else { Err($crate::result::Error::IndexOutOfBounds { @@ -948,32 +922,16 @@ macro_rules! read_only_csr_field { ($ty:ident, $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - range: [$bit_start:literal : $bit_end:literal]$(,)?) => { + $field:ident: [$bit_start:literal : $bit_end:literal]$(,)?) => { + const _: () = assert!($bit_end < usize::BITS); + const _: () = assert!($bit_start <= $bit_end); + impl $ty { $(#[$field_doc])+ #[inline] pub fn $field(&self) -> usize { $crate::bits::bf_extract(self.bits, $bit_start, $bit_end - $bit_start + 1) } - - $(#[$try_field_doc])+ - #[inline] - pub fn $try_field(&self) -> $crate::result::Result { - let max_width = core::mem::size_of_val(&self.bits) * 8; - - if $bit_end < max_width && $bit_start <= $bit_end { - Ok($crate::bits::bf_extract(self.bits, $bit_start, $bit_end - $bit_start + 1)) - } else { - Err($crate::result::Error::IndexOutOfBounds { - index: $bit_start, - min: $bit_start, - max: $bit_end, - }) - } - } } }; @@ -1017,35 +975,28 @@ macro_rules! read_only_csr_field { $field_ty:ident, range: [$field_start:literal : $field_end:literal]$(,)? ) => { - impl $ty { - $(#[$field_doc])+ - #[inline] - pub fn $field(&self) -> $field_ty { - self.$try_field().unwrap() - } + const _: () = assert!($field_end < usize::BITS); + const _: () = assert!($field_start <= $field_end); - $(#[$try_field_doc])+ - #[inline] - pub fn $try_field(&self) -> $crate::result::Result<$field_ty> { - let max_width = core::mem::size_of_val(&self.bits) * 8; - - if $field_end < max_width && $field_start < $field_end { - let value = $crate::bits::bf_extract( - self.bits, - $field_start, - $field_end - $field_start + 1, - ); + impl $ty { + $(#[$field_doc])+ + #[inline] + pub fn $field(&self) -> $field_ty { + self.$try_field().unwrap() + } - $field_ty::from_usize(value) - } else { - Err($crate::result::Error::IndexOutOfBounds { - index: $field_start, - min: $field_start, - max: $field_end, - }) - } - } - } + $(#[$try_field_doc])+ + #[inline] + pub fn $try_field(&self) -> $crate::result::Result<$field_ty> { + let value = $crate::bits::bf_extract( + self.bits, + $field_start, + $field_end - $field_start + 1, + ); + + $field_ty::from_usize(value) + } + } }; } diff --git a/riscv/src/register/mcountinhibit.rs b/riscv/src/register/mcountinhibit.rs index 7cca379d..4ad8d0e0 100644 --- a/riscv/src/register/mcountinhibit.rs +++ b/riscv/src/register/mcountinhibit.rs @@ -15,8 +15,6 @@ read_write_csr_field! { Mcountinhibit, /// Gets the `cycle[h]` inhibit field value. cy, - /// Attempts to get the `cycle[h]` inhibit field value. - try_cy, /// Sets the `cycle[h]` inhibit field value. /// /// **NOTE**: only updates the in-memory value without touching the CSR. @@ -32,8 +30,6 @@ read_write_csr_field! { Mcountinhibit, /// Gets the `instret[h]` inhibit field value. ir, - /// Attempts to get the `instret[h]` inhibit field value. - try_ir, /// Sets the `instret[h]` inhibit field value. /// /// **NOTE**: only updates the in-memory value without touching the CSR. diff --git a/riscv/src/register/tests/read_only_csr.rs b/riscv/src/register/tests/read_only_csr.rs index 6925dcd1..f9ec1278 100644 --- a/riscv/src/register/tests/read_only_csr.rs +++ b/riscv/src/register/tests/read_only_csr.rs @@ -9,10 +9,7 @@ read_only_csr! { read_only_csr_field! { Mtest, /// test single-bit field - single, - /// try-getter test single-bit field - try_single, - bit: 0, + single: 0, } read_only_csr_field! { @@ -27,10 +24,7 @@ read_only_csr_field! { read_only_csr_field!( Mtest, /// multi-bit field - multi_field, - /// try-getter multi-bit field - try_multi_field, - range: [4:7], + multi_field: [4:7], ); read_only_csr_field!( @@ -41,7 +35,7 @@ read_only_csr_field!( try_field_enum, /// field enum type with valid field variants MtestFieldEnum { - range: [7:11], + range: [8:11], default: Field1, Field1 = 1, Field2 = 2, @@ -70,11 +64,9 @@ fn test_mtest_read_only() { // check that single bit field getter/setters work. assert_eq!(mtest.single(), false); - assert_eq!(mtest.try_single(), Ok(false)); mtest = Mtest::from_bits(1); assert_eq!(mtest.single(), true); - assert_eq!(mtest.try_single(), Ok(true)); mtest = Mtest::from_bits(0); @@ -94,25 +86,20 @@ fn test_mtest_read_only() { // check that multi-bit field getter/setters work. assert_eq!(mtest.multi_field(), 0); - assert_eq!(mtest.try_multi_field(), Ok(0)); mtest = Mtest::from_bits(0xf << 4); assert_eq!(mtest.multi_field(), 0xf); - assert_eq!(mtest.try_multi_field(), Ok(0xf)); mtest = Mtest::from_bits(0x3 << 4); assert_eq!(mtest.multi_field(), 0x3); - assert_eq!(mtest.try_multi_field(), Ok(0x3)); // check that only bits in the field are set. mtest = Mtest::from_bits(0xff << 4); assert_eq!(mtest.multi_field(), 0xf); - assert_eq!(mtest.try_multi_field(), Ok(0xf)); assert_eq!(mtest.bits(), 0xff << 4); mtest = Mtest::from_bits(0x0 << 4); assert_eq!(mtest.multi_field(), 0x0); - assert_eq!(mtest.try_multi_field(), Ok(0x0)); assert_eq!(mtest.try_field_enum(), Err(Error::InvalidVariant(0)),); @@ -124,12 +111,12 @@ fn test_mtest_read_only() { ] .into_iter() .for_each(|variant| { - mtest = Mtest::from_bits(variant.into_usize() << 7); + mtest = Mtest::from_bits(variant.into_usize() << 8); assert_eq!(mtest.field_enum(), variant); assert_eq!(mtest.try_field_enum(), Ok(variant)); }); // check that setting an invalid variant returns `None` - mtest = Mtest::from_bits(0xbad << 7); + mtest = Mtest::from_bits(0xbad << 8); assert_eq!(mtest.try_field_enum(), Err(Error::InvalidVariant(13)),); } diff --git a/riscv/src/register/tests/read_write_csr.rs b/riscv/src/register/tests/read_write_csr.rs index 3fb39012..e8b2fe56 100644 --- a/riscv/src/register/tests/read_write_csr.rs +++ b/riscv/src/register/tests/read_write_csr.rs @@ -10,8 +10,6 @@ read_write_csr_field! { Mtest, /// test single-bit field single, - /// try-get test single-bit field - try_single, /// setter test single-bit field set_single, /// try-setter test single-bit field @@ -36,8 +34,6 @@ read_write_csr_field!( Mtest, /// multi-bit field multi_field, - /// try-get multi-bit field - try_multi_field, /// setter multi-bit field set_multi_field, /// try-setter multi-bit field @@ -119,21 +115,17 @@ fn test_mtest_read_write() { mtest.set_multi_field(0xf); assert_eq!(mtest.multi_field(), 0xf); - assert_eq!(mtest.try_multi_field(), Ok(0xf)); mtest.set_multi_field(0x3); assert_eq!(mtest.multi_field(), 0x3); - assert_eq!(mtest.try_multi_field(), Ok(0x3)); // check that only bits in the field are set. mtest.set_multi_field(0xff); assert_eq!(mtest.multi_field(), 0xf); - assert_eq!(mtest.try_multi_field(), Ok(0xf)); assert_eq!(mtest.bits(), 0xf << 4); mtest.set_multi_field(0x0); assert_eq!(mtest.multi_field(), 0x0); - assert_eq!(mtest.try_multi_field(), Ok(0x0)); assert_eq!(mtest.try_field_enum(), Err(Error::InvalidVariant(0)),); From cb9310b99f169f5aa991357b335dca12d325e896 Mon Sep 17 00:00:00 2001 From: rmsyn Date: Fri, 20 Sep 2024 02:01:00 +0000 Subject: [PATCH 14/19] fixup: riscv: write-only CSR compile-time asserts Applies compile-time checks in write-only CSR macros. Authored-by: rmsyn Co-authored-by: romancardenas --- riscv/src/register/macros.rs | 138 +++++---------------- riscv/src/register/mcountinhibit.rs | 8 -- riscv/src/register/tests/read_write_csr.rs | 14 +-- riscv/src/register/tests/write_only_csr.rs | 17 +-- 4 files changed, 40 insertions(+), 137 deletions(-) diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index 293fd525..ff005c26 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -749,8 +749,6 @@ macro_rules! read_write_csr_field { $field:ident, $(#[$set_field_doc:meta])+ $set_field:ident, - $(#[$try_set_field_doc:meta])+ - $try_set_field:ident, bit: $bit:literal$(,)? ) => { $crate::read_only_csr_field!( @@ -762,10 +760,7 @@ macro_rules! read_write_csr_field { $crate::write_only_csr_field!( $ty, $(#[$set_field_doc])+ - $set_field, - $(#[$try_set_field_doc])+ - $try_set_field, - bit: $bit, + $set_field: $bit, ); }; @@ -804,8 +799,6 @@ macro_rules! read_write_csr_field { $field:ident, $(#[$set_field_doc:meta])+ $set_field:ident, - $(#[$try_set_field_doc:meta])+ - $try_set_field:ident, range: [$bit_start:literal : $bit_end:literal]$(,)? ) => { $crate::read_only_csr_field!( @@ -817,10 +810,7 @@ macro_rules! read_write_csr_field { $crate::write_only_csr_field!( $ty, $(#[$set_field_doc])+ - $set_field, - $(#[$try_set_field_doc])+ - $try_set_field, - range: [$bit_start : $bit_end], + $set_field: [$bit_start : $bit_end], ); }; @@ -831,8 +821,6 @@ macro_rules! read_write_csr_field { $try_field:ident, $(#[$set_field_doc:meta])+ $set_field:ident, - $(#[$try_set_field_doc:meta])+ - $try_set_field:ident, $(#[$field_ty_doc:meta])+ $field_ty:ident { range: [$field_start:literal : $field_end:literal], @@ -863,8 +851,6 @@ macro_rules! read_write_csr_field { $ty, $(#[$set_field_doc])+ $set_field, - $(#[$try_set_field_doc])+ - $try_set_field, $field_ty, range: [$field_start : $field_end], ); @@ -1005,32 +991,14 @@ macro_rules! read_only_csr_field { macro_rules! write_only_csr_field { ($ty:ident, $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - bit: $bit:literal$(,)?) => { + $field:ident: $bit:literal$(,)?) => { + const _: () = assert!($bit < usize::BITS); + impl $ty { $(#[$field_doc])+ #[inline] pub fn $field(&mut self, $field: bool) { - self.$try_field($field).unwrap(); - } - - $(#[$try_field_doc])+ - #[inline] - pub fn $try_field(&mut self, $field: bool) -> $crate::result::Result<()> { - let max_width = core::mem::size_of_val(&self.bits) * 8; - - if $bit < max_width { - self.bits = $crate::bits::bf_insert(self.bits, $bit, 1, $field as usize); - Ok(()) - } else { - Err($crate::result::Error::IndexOutOfBounds { - index: $bit, - min: 0, - max: max_width, - }) - } + self.bits = $crate::bits::bf_insert(self.bits, $bit, 1, $field as usize); } } }; @@ -1041,6 +1009,9 @@ macro_rules! write_only_csr_field { $(#[$try_field_doc:meta])+ $try_field:ident, range: $bit_start:literal..=$bit_end:literal$(,)?) => { + const _: () = assert!($bit_end < usize::BITS); + const _: () = assert!($bit_start <= $bit_end); + impl $ty { $(#[$field_doc])+ #[inline] @@ -1051,9 +1022,7 @@ macro_rules! write_only_csr_field { $(#[$try_field_doc])+ #[inline] pub fn $try_field(&mut self, index: usize, $field: bool) -> $crate::result::Result<()> { - let max_width = core::mem::size_of_val(&self.bits) * 8; - - if index < max_width && ($bit_start..=$bit_end).contains(&index) { + if ($bit_start..=$bit_end).contains(&index) { self.bits = $crate::bits::bf_insert(self.bits, index, 1, $field as usize); Ok(()) } else { @@ -1069,38 +1038,20 @@ macro_rules! write_only_csr_field { ($ty:ident, $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - range: [$bit_start:literal : $bit_end:literal]$(,)?) => { + $field:ident: [$bit_start:literal : $bit_end:literal]$(,)?) => { + const _: () = assert!($bit_end < usize::BITS); + const _: () = assert!($bit_start <= $bit_end); + impl $ty { $(#[$field_doc])+ #[inline] pub fn $field(&mut self, $field: usize) { - self.$try_field($field).unwrap(); - } - - $(#[$try_field_doc])+ - #[inline] - pub fn $try_field(&mut self, $field: usize) -> $crate::result::Result<()> { - let max_width = core::mem::size_of_val(&self.bits) * 8; - - if $bit_start < max_width && $bit_start <= $bit_end { - self.bits = $crate::bits::bf_insert( - self.bits, - $bit_start, - $bit_end - $bit_start + 1, - $field, - ); - - Ok(()) - } else { - Err($crate::result::Error::IndexOutOfBounds { - index: $bit_start, - min: $bit_start, - max: $bit_end, - }) - } + self.bits = $crate::bits::bf_insert( + self.bits, + $bit_start, + $bit_end - $bit_start + 1, + $field, + ); } } }; @@ -1108,8 +1059,6 @@ macro_rules! write_only_csr_field { ($ty:ident, $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, $(#[$field_ty_doc:meta])+ $field_ty:ident { range: [$field_start:literal : $field_end:literal], @@ -1130,8 +1079,6 @@ macro_rules! write_only_csr_field { $ty, $(#[$field_doc])+ $field, - $(#[$try_field_doc])+ - $try_field, $field_ty, range: [$field_start : $field_end], ); @@ -1140,40 +1087,23 @@ macro_rules! write_only_csr_field { ($ty:ident, $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, $field_ty:ident, range: [$field_start:literal : $field_end:literal]$(,)? ) => { - impl $ty { - $(#[$field_doc])+ - #[inline] - pub fn $field(&mut self, $field: $field_ty) { - self.$try_field($field).unwrap(); - } - - $(#[$try_field_doc])+ - #[inline] - pub fn $try_field(&mut self, $field: $field_ty) -> $crate::result::Result<()> { - let max_width = core::mem::size_of_val(&self.bits) * 8; - - if $field_end < max_width && $field_start <= $field_end { - self.bits = $crate::bits::bf_insert( - self.bits, - $field_start, - $field_end - $field_start + 1, - $field.into(), - ); + const _: () = assert!($field_end < usize::BITS); + const _: () = assert!($field_start <= $field_end); - Ok(()) - } else { - Err($crate::result::Error::IndexOutOfBounds { - index: $field_start, - min: $field_start, - max: $field_end, - }) - } - } - } + impl $ty { + $(#[$field_doc])+ + #[inline] + pub fn $field(&mut self, $field: $field_ty) { + self.bits = $crate::bits::bf_insert( + self.bits, + $field_start, + $field_end - $field_start + 1, + $field.into(), + ); + } + } }; } diff --git a/riscv/src/register/mcountinhibit.rs b/riscv/src/register/mcountinhibit.rs index 4ad8d0e0..1ec86285 100644 --- a/riscv/src/register/mcountinhibit.rs +++ b/riscv/src/register/mcountinhibit.rs @@ -19,10 +19,6 @@ read_write_csr_field! { /// /// **NOTE**: only updates the in-memory value without touching the CSR. set_cy, - /// Attempts to set the `cycle[h]` inhibit field value. - /// - /// **NOTE**: only updates the in-memory value without touching the CSR. - try_set_cy, bit: 0, } @@ -34,10 +30,6 @@ read_write_csr_field! { /// /// **NOTE**: only updates the in-memory value without touching the CSR. set_ir, - /// Attempts to set the `instret[h]` inhibit field value. - /// - /// **NOTE**: only updates the in-memory value without touching the CSR. - try_set_ir, bit: 2, } diff --git a/riscv/src/register/tests/read_write_csr.rs b/riscv/src/register/tests/read_write_csr.rs index e8b2fe56..c3981afa 100644 --- a/riscv/src/register/tests/read_write_csr.rs +++ b/riscv/src/register/tests/read_write_csr.rs @@ -12,8 +12,6 @@ read_write_csr_field! { single, /// setter test single-bit field set_single, - /// try-setter test single-bit field - try_set_single, bit: 0, } @@ -36,8 +34,6 @@ read_write_csr_field!( multi_field, /// setter multi-bit field set_multi_field, - /// try-setter multi-bit field - try_set_multi_field, range: [4:7], ); @@ -49,11 +45,9 @@ read_write_csr_field!( try_field_enum, /// setter multi-bit field set_field_enum, - /// try-setter multi-bit field - try_set_field_enum, /// field enum type with valid field variants MtestFieldEnum { - range: [7:11], + range: [8:11], default: Field1, Field1 = 1, Field2 = 2, @@ -127,7 +121,7 @@ fn test_mtest_read_write() { mtest.set_multi_field(0x0); assert_eq!(mtest.multi_field(), 0x0); - assert_eq!(mtest.try_field_enum(), Err(Error::InvalidVariant(0)),); + assert_eq!(mtest.try_field_enum(), Err(Error::InvalidVariant(0))); [ MtestFieldEnum::Field1, @@ -143,6 +137,6 @@ fn test_mtest_read_write() { }); // check that setting an invalid variant returns `None` - mtest = Mtest::from_bits(0xbad << 7); - assert_eq!(mtest.try_field_enum(), Err(Error::InvalidVariant(13)),); + mtest = Mtest::from_bits(0xbad << 8); + assert_eq!(mtest.try_field_enum(), Err(Error::InvalidVariant(13))); } diff --git a/riscv/src/register/tests/write_only_csr.rs b/riscv/src/register/tests/write_only_csr.rs index 2e7da165..73de0d0a 100644 --- a/riscv/src/register/tests/write_only_csr.rs +++ b/riscv/src/register/tests/write_only_csr.rs @@ -9,10 +9,7 @@ write_only_csr! { write_only_csr_field! { Mtest, /// setter test single-bit field - set_single, - /// try-setter test single-bit field - try_set_single, - bit: 0, + set_single: 0, } write_only_csr_field! { @@ -27,18 +24,13 @@ write_only_csr_field! { write_only_csr_field!( Mtest, /// setter multi-bit field - set_multi_field, - /// try-setter multi-bit field - try_set_multi_field, - range: [4:7], + set_multi_field: [4:7], ); write_only_csr_field!( Mtest, /// setter multi-bit field set_field_enum, - /// try-setter multi-bit field - try_set_field_enum, /// field enum type with valid field variants MtestFieldEnum { range: [8:11], @@ -113,11 +105,6 @@ fn test_mtest_write_only() { ] .into_iter() .for_each(|variant| { - assert_eq!( - mtest.try_set_field_enum(variant), - Ok(()), - "field value: {variant:?}" - ); mtest.set_field_enum(variant); assert_eq!(MtestFieldEnum::from_usize(mtest.bits() >> 8), Ok(variant)); }); From 87ebf67da1fd4f33a1ab485055416269f11cf078 Mon Sep 17 00:00:00 2001 From: rmsyn Date: Tue, 24 Sep 2024 02:20:21 +0000 Subject: [PATCH 15/19] fixup: riscv: remove equality check in CSR macros Removes the equality check for range branches in CSR helper macros. Users who want a single-bit field, i.e. `start == end`, should use the single-bit branch variants. Authored-by: rmsyn Co-authored-by: romancardenas --- riscv/src/register/macros.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index ff005c26..42f4d277 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -881,7 +881,7 @@ macro_rules! read_only_csr_field { $try_field:ident, range: $bit_start:literal..=$bit_end:literal$(,)?) => { const _: () = assert!($bit_end < usize::BITS); - const _: () = assert!($bit_start <= $bit_end); + const _: () = assert!($bit_start < $bit_end); impl $ty { $(#[$field_doc])+ @@ -910,7 +910,7 @@ macro_rules! read_only_csr_field { $(#[$field_doc:meta])+ $field:ident: [$bit_start:literal : $bit_end:literal]$(,)?) => { const _: () = assert!($bit_end < usize::BITS); - const _: () = assert!($bit_start <= $bit_end); + const _: () = assert!($bit_start < $bit_end); impl $ty { $(#[$field_doc])+ @@ -1010,7 +1010,7 @@ macro_rules! write_only_csr_field { $try_field:ident, range: $bit_start:literal..=$bit_end:literal$(,)?) => { const _: () = assert!($bit_end < usize::BITS); - const _: () = assert!($bit_start <= $bit_end); + const _: () = assert!($bit_start < $bit_end); impl $ty { $(#[$field_doc])+ @@ -1040,7 +1040,7 @@ macro_rules! write_only_csr_field { $(#[$field_doc:meta])+ $field:ident: [$bit_start:literal : $bit_end:literal]$(,)?) => { const _: () = assert!($bit_end < usize::BITS); - const _: () = assert!($bit_start <= $bit_end); + const _: () = assert!($bit_start < $bit_end); impl $ty { $(#[$field_doc])+ From b7c3049a7b85f0377a76b43ef0ae781727ffe53f Mon Sep 17 00:00:00 2001 From: rmsyn Date: Tue, 24 Sep 2024 02:15:14 +0000 Subject: [PATCH 16/19] fixup: riscv: remove CSR macro enum creation branch Removes CSR helper macro branches that include field enum type creation. Leaves the creation of the field enum to the separate `csr_field_enum` macro, or manual definition of the field enum. Authored-by: rmsyn Co-authored-by: romancardenas --- riscv/src/register/macros.rs | 85 +++------------------- riscv/src/register/tests/read_only_csr.rs | 25 ++++--- riscv/src/register/tests/read_write_csr.rs | 27 ++++--- riscv/src/register/tests/write_only_csr.rs | 21 ++++-- 4 files changed, 54 insertions(+), 104 deletions(-) diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index 42f4d277..d62327d7 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -690,6 +690,14 @@ macro_rules! csr_field_enum { val.into_usize() } } + + impl TryFrom for $field_ty { + type Error = $crate::result::Error; + + fn try_from(val: usize) -> $crate::result::Result { + Self::from_usize(val) + } + } }; } @@ -821,22 +829,9 @@ macro_rules! read_write_csr_field { $try_field:ident, $(#[$set_field_doc:meta])+ $set_field:ident, - $(#[$field_ty_doc:meta])+ - $field_ty:ident { - range: [$field_start:literal : $field_end:literal], - default: $default_variant:ident, - $($variant:ident = $value:expr$(,)?)+ - }$(,)? + $field_ty:ident, + range: [$field_start:literal : $field_end:literal], ) => { - $crate::csr_field_enum!( - $(#[$field_ty_doc])+ - $field_ty { - range: [$field_start : $field_end], - default: $default_variant, - $($variant = $value,)+ - }, - ); - $crate::read_only_csr_field!( $ty, $(#[$field_doc])+ @@ -921,38 +916,6 @@ macro_rules! read_only_csr_field { } }; - ($ty:ident, - $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - $(#[$field_ty_doc:meta])+ - $field_ty:ident { - range: [$field_start:literal : $field_end:literal], - default: $default_variant:ident, - $($variant:ident = $value:expr$(,)?)+ - }$(,)? - ) => { - $crate::csr_field_enum!( - $(#[$field_ty_doc])+ - $field_ty { - range: [$field_start : $field_end], - default: $default_variant, - $($variant = $value,)+ - }, - ); - - $crate::read_only_csr_field!( - $ty, - $(#[$field_doc])* - $field, - $(#[$try_field_doc])* - $try_field, - $field_ty, - range: [$field_start : $field_end], - ); - }; - ($ty:ident, $(#[$field_doc:meta])+ $field:ident, @@ -1056,34 +1019,6 @@ macro_rules! write_only_csr_field { } }; - ($ty:ident, - $(#[$field_doc:meta])+ - $field:ident, - $(#[$field_ty_doc:meta])+ - $field_ty:ident { - range: [$field_start:literal : $field_end:literal], - default: $default_variant:ident, - $($variant:ident = $value:expr$(,)?)+ - }$(,)? - ) => { - $crate::csr_field_enum!( - $(#[$field_ty_doc])+ - $field_ty { - range: [$field_start : $field_end], - default: $default_variant, - $($variant = $value,)+ - }, - ); - - $crate::write_only_csr_field!( - $ty, - $(#[$field_doc])+ - $field, - $field_ty, - range: [$field_start : $field_end], - ); - }; - ($ty:ident, $(#[$field_doc:meta])+ $field:ident, diff --git a/riscv/src/register/tests/read_only_csr.rs b/riscv/src/register/tests/read_only_csr.rs index f9ec1278..e61d2e49 100644 --- a/riscv/src/register/tests/read_only_csr.rs +++ b/riscv/src/register/tests/read_only_csr.rs @@ -21,18 +21,13 @@ read_only_csr_field! { range: 1..=3, } -read_only_csr_field!( +read_only_csr_field! { Mtest, /// multi-bit field multi_field: [4:7], -); +} -read_only_csr_field!( - Mtest, - /// multi-bit field - field_enum, - /// try-getter multi-bit field - try_field_enum, +csr_field_enum! { /// field enum type with valid field variants MtestFieldEnum { range: [8:11], @@ -41,8 +36,18 @@ read_only_csr_field!( Field2 = 2, Field3 = 3, Field4 = 15, - }, -); + } +} + +read_only_csr_field! { + Mtest, + /// multi-bit field + field_enum, + /// try-getter multi-bit field + try_field_enum, + MtestFieldEnum, + range: [8:11], +} // we don't test the `read` function, we are only testing in-memory functions. #[allow(unused)] diff --git a/riscv/src/register/tests/read_write_csr.rs b/riscv/src/register/tests/read_write_csr.rs index c3981afa..6712096d 100644 --- a/riscv/src/register/tests/read_write_csr.rs +++ b/riscv/src/register/tests/read_write_csr.rs @@ -28,23 +28,16 @@ read_write_csr_field! { range: 1..=3, } -read_write_csr_field!( +read_write_csr_field! { Mtest, /// multi-bit field multi_field, /// setter multi-bit field set_multi_field, range: [4:7], -); +} -read_write_csr_field!( - Mtest, - /// multi-bit field - field_enum, - /// try-get multi-bit field - try_field_enum, - /// setter multi-bit field - set_field_enum, +csr_field_enum! { /// field enum type with valid field variants MtestFieldEnum { range: [8:11], @@ -54,7 +47,19 @@ read_write_csr_field!( Field3 = 3, Field4 = 15, } -); +} + +read_write_csr_field! { + Mtest, + /// multi-bit field + field_enum, + /// try-get multi-bit field + try_field_enum, + /// setter multi-bit field + set_field_enum, + MtestFieldEnum, + range: [8:11], +} // we don't test the `read` and `write` functions, we are only testing in-memory functions. #[allow(unused)] diff --git a/riscv/src/register/tests/write_only_csr.rs b/riscv/src/register/tests/write_only_csr.rs index 73de0d0a..cfae8300 100644 --- a/riscv/src/register/tests/write_only_csr.rs +++ b/riscv/src/register/tests/write_only_csr.rs @@ -21,16 +21,13 @@ write_only_csr_field! { range: 1..=3, } -write_only_csr_field!( +write_only_csr_field! { Mtest, /// setter multi-bit field set_multi_field: [4:7], -); +} -write_only_csr_field!( - Mtest, - /// setter multi-bit field - set_field_enum, +csr_field_enum! { /// field enum type with valid field variants MtestFieldEnum { range: [8:11], @@ -39,8 +36,16 @@ write_only_csr_field!( Field2 = 2, Field3 = 3, Field4 = 15, - }, -); + } +} + +write_only_csr_field! { + Mtest, + /// setter multi-bit field + set_field_enum, + MtestFieldEnum, + range: [8:11], +} // we don't test the `write` function, we are only testing in-memory functions. #[allow(unused)] From c7f6e75ff2af3c9ee48c090d86fa2e07520302e7 Mon Sep 17 00:00:00 2001 From: rmsyn Date: Wed, 25 Sep 2024 04:54:34 +0000 Subject: [PATCH 17/19] riscv: use paste for CSR helper macros Uses the [`paste`](https://docs.rs/paste) dependency for concatenating idents in CSR helper macros. --- riscv/Cargo.toml | 1 + riscv/src/register/macros.rs | 270 ++++++++++----------- riscv/src/register/mcountinhibit.rs | 33 +-- riscv/src/register/tests/read_only_csr.rs | 10 +- riscv/src/register/tests/read_write_csr.rs | 26 +- riscv/src/register/tests/write_only_csr.rs | 8 +- 6 files changed, 140 insertions(+), 208 deletions(-) diff --git a/riscv/Cargo.toml b/riscv/Cargo.toml index 35bc7fd8..ccde8ed3 100644 --- a/riscv/Cargo.toml +++ b/riscv/Cargo.toml @@ -29,3 +29,4 @@ critical-section = "1.1.2" embedded-hal = "1.0.0" riscv-pac = { path = "../riscv-pac", version = "0.2.0" } riscv-macros = { path = "macros", version = "0.1.0", optional = true } +paste = "1.0.15" diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index d62327d7..c1151ea9 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -754,101 +754,81 @@ macro_rules! write_only_csr { macro_rules! read_write_csr_field { ($ty:ident, $(#[$field_doc:meta])+ - $field:ident, - $(#[$set_field_doc:meta])+ - $set_field:ident, - bit: $bit:literal$(,)? + $field:ident: $bit:literal$(,)? ) => { - $crate::read_only_csr_field!( - $ty, - $(#[$field_doc])+ - $field: $bit, - ); - - $crate::write_only_csr_field!( - $ty, - $(#[$set_field_doc])+ - $set_field: $bit, - ); + paste::paste! { + $crate::read_only_csr_field!( + $ty, + $(#[$field_doc])+ + $field: $bit, + ); + + $crate::write_only_csr_field!( + $ty, + $(#[$field_doc])+ + []: $bit, + ); + } }; ($ty:ident, $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - $(#[$set_field_doc:meta])+ - $set_field:ident, - $(#[$try_set_field_doc:meta])+ - $try_set_field:ident, - range: $bit_start:literal ..= $bit_end:literal$(,)? + $field:ident: $bit_start:literal ..= $bit_end:literal$(,)? ) => { - $crate::read_only_csr_field!( - $ty, - $(#[$field_doc])+ - $field, - $(#[$try_field_doc])+ - $try_field, - range: $bit_start ..= $bit_end, - ); - - $crate::write_only_csr_field!( - $ty, - $(#[$set_field_doc])+ - $set_field, - $(#[$try_set_field_doc])+ - $try_set_field, - range: $bit_start ..= $bit_end, - ); + paste::paste! { + $crate::read_only_csr_field!( + $ty, + $(#[$field_doc])+ + $field: $bit_start ..= $bit_end, + ); + + $crate::write_only_csr_field!( + $ty, + $(#[$field_doc])+ + []: $bit_start ..= $bit_end, + ); + } }; ($ty:ident, $(#[$field_doc:meta])+ - $field:ident, - $(#[$set_field_doc:meta])+ - $set_field:ident, - range: [$bit_start:literal : $bit_end:literal]$(,)? + $field:ident: [$bit_start:literal : $bit_end:literal]$(,)? ) => { - $crate::read_only_csr_field!( - $ty, - $(#[$field_doc])+ - $field: [$bit_start : $bit_end], - ); - - $crate::write_only_csr_field!( - $ty, - $(#[$set_field_doc])+ - $set_field: [$bit_start : $bit_end], - ); + paste::paste! { + $crate::read_only_csr_field!( + $ty, + $(#[$field_doc])+ + $field: [$bit_start : $bit_end], + ); + + $crate::write_only_csr_field!( + $ty, + $(#[$field_doc])+ + []: [$bit_start : $bit_end], + ); + } }; ($ty:ident, $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - $(#[$set_field_doc:meta])+ - $set_field:ident, - $field_ty:ident, - range: [$field_start:literal : $field_end:literal], + $field_ty:ident: [$field_start:literal : $field_end:literal], ) => { - $crate::read_only_csr_field!( - $ty, - $(#[$field_doc])+ - $field, - $(#[$try_field_doc])+ - $try_field, - $field_ty, - range: [$field_start : $field_end], - ); - - $crate::write_only_csr_field!( - $ty, - $(#[$set_field_doc])+ - $set_field, - $field_ty, - range: [$field_start : $field_end], - ); + paste::paste! { + $crate::read_only_csr_field!( + $ty, + $(#[$field_doc])+ + $field, + $field_ty: [$field_start : $field_end], + ); + + $crate::write_only_csr_field!( + $ty, + $(#[$field_doc])+ + [], + $field_ty: [$field_start : $field_end], + ); + } }; } @@ -871,31 +851,30 @@ macro_rules! read_only_csr_field { ($ty:ident, $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - range: $bit_start:literal..=$bit_end:literal$(,)?) => { + $field:ident: $bit_start:literal..=$bit_end:literal$(,)?) => { const _: () = assert!($bit_end < usize::BITS); const _: () = assert!($bit_start < $bit_end); - impl $ty { - $(#[$field_doc])+ - #[inline] - pub fn $field(&self, index: usize) -> bool { - self.$try_field(index).unwrap() - } + paste::paste! { + impl $ty { + $(#[$field_doc])+ + #[inline] + pub fn $field(&self, index: usize) -> bool { + self.[](index).unwrap() + } - $(#[$try_field_doc])+ - #[inline] - pub fn $try_field(&self, index: usize) -> $crate::result::Result { - if ($bit_start..=$bit_end).contains(&index) { - Ok($crate::bits::bf_extract(self.bits, index, 1) != 0) - } else { - Err($crate::result::Error::IndexOutOfBounds { - index, - min: $bit_start, - max: $bit_end, - }) + $(#[$field_doc])+ + #[inline] + pub fn [](&self, index: usize) -> $crate::result::Result { + if ($bit_start..=$bit_end).contains(&index) { + Ok($crate::bits::bf_extract(self.bits, index, 1) != 0) + } else { + Err($crate::result::Error::IndexOutOfBounds { + index, + min: $bit_start, + max: $bit_end, + }) + } } } } @@ -919,31 +898,30 @@ macro_rules! read_only_csr_field { ($ty:ident, $(#[$field_doc:meta])+ $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - $field_ty:ident, - range: [$field_start:literal : $field_end:literal]$(,)? + $field_ty:ident: [$field_start:literal : $field_end:literal]$(,)? ) => { const _: () = assert!($field_end < usize::BITS); const _: () = assert!($field_start <= $field_end); - impl $ty { - $(#[$field_doc])+ - #[inline] - pub fn $field(&self) -> $field_ty { - self.$try_field().unwrap() - } + paste::paste! { + impl $ty { + $(#[$field_doc])+ + #[inline] + pub fn $field(&self) -> $field_ty { + self.[]().unwrap() + } - $(#[$try_field_doc])+ - #[inline] - pub fn $try_field(&self) -> $crate::result::Result<$field_ty> { - let value = $crate::bits::bf_extract( - self.bits, - $field_start, - $field_end - $field_start + 1, - ); + $(#[$field_doc])+ + #[inline] + pub fn [](&self) -> $crate::result::Result<$field_ty> { + let value = $crate::bits::bf_extract( + self.bits, + $field_start, + $field_end - $field_start + 1, + ); - $field_ty::from_usize(value) + $field_ty::from_usize(value) + } } } }; @@ -959,6 +937,8 @@ macro_rules! write_only_csr_field { impl $ty { $(#[$field_doc])+ + #[doc = ""] + #[doc = "**NOTE**: only updates in-memory values, does not write to CSR."] #[inline] pub fn $field(&mut self, $field: bool) { self.bits = $crate::bits::bf_insert(self.bits, $bit, 1, $field as usize); @@ -968,32 +948,35 @@ macro_rules! write_only_csr_field { ($ty:ident, $(#[$field_doc:meta])+ - $field:ident, - $(#[$try_field_doc:meta])+ - $try_field:ident, - range: $bit_start:literal..=$bit_end:literal$(,)?) => { + $field:ident: $bit_start:literal..=$bit_end:literal$(,)?) => { const _: () = assert!($bit_end < usize::BITS); const _: () = assert!($bit_start < $bit_end); - impl $ty { - $(#[$field_doc])+ - #[inline] - pub fn $field(&mut self, index: usize, $field: bool) { - self.$try_field(index, $field).unwrap(); - } + paste::paste! { + impl $ty { + $(#[$field_doc])+ + #[doc = ""] + #[doc = "**NOTE**: only updates in-memory values, does not write to CSR."] + #[inline] + pub fn $field(&mut self, index: usize, $field: bool) { + self.[](index, $field).unwrap(); + } - $(#[$try_field_doc])+ - #[inline] - pub fn $try_field(&mut self, index: usize, $field: bool) -> $crate::result::Result<()> { - if ($bit_start..=$bit_end).contains(&index) { - self.bits = $crate::bits::bf_insert(self.bits, index, 1, $field as usize); - Ok(()) - } else { - Err($crate::result::Error::IndexOutOfBounds { - index, - min: $bit_start, - max: $bit_end, - }) + $(#[$field_doc])+ + #[doc = ""] + #[doc = "**NOTE**: only updates in-memory values, does not write to CSR."] + #[inline] + pub fn [](&mut self, index: usize, $field: bool) -> $crate::result::Result<()> { + if ($bit_start..=$bit_end).contains(&index) { + self.bits = $crate::bits::bf_insert(self.bits, index, 1, $field as usize); + Ok(()) + } else { + Err($crate::result::Error::IndexOutOfBounds { + index, + min: $bit_start, + max: $bit_end, + }) + } } } } @@ -1007,6 +990,8 @@ macro_rules! write_only_csr_field { impl $ty { $(#[$field_doc])+ + #[doc = ""] + #[doc = "**NOTE**: only updates in-memory values, does not write to CSR."] #[inline] pub fn $field(&mut self, $field: usize) { self.bits = $crate::bits::bf_insert( @@ -1022,14 +1007,15 @@ macro_rules! write_only_csr_field { ($ty:ident, $(#[$field_doc:meta])+ $field:ident, - $field_ty:ident, - range: [$field_start:literal : $field_end:literal]$(,)? + $field_ty:ident: [$field_start:literal : $field_end:literal]$(,)? ) => { const _: () = assert!($field_end < usize::BITS); const _: () = assert!($field_start <= $field_end); impl $ty { $(#[$field_doc])+ + #[doc = ""] + #[doc = "**NOTE**: only updates in-memory values, does not write to CSR."] #[inline] pub fn $field(&mut self, $field: $field_ty) { self.bits = $crate::bits::bf_insert( diff --git a/riscv/src/register/mcountinhibit.rs b/riscv/src/register/mcountinhibit.rs index 1ec86285..daa71c67 100644 --- a/riscv/src/register/mcountinhibit.rs +++ b/riscv/src/register/mcountinhibit.rs @@ -14,23 +14,13 @@ clear!(0x320); read_write_csr_field! { Mcountinhibit, /// Gets the `cycle[h]` inhibit field value. - cy, - /// Sets the `cycle[h]` inhibit field value. - /// - /// **NOTE**: only updates the in-memory value without touching the CSR. - set_cy, - bit: 0, + cy: 0, } read_write_csr_field! { Mcountinhibit, /// Gets the `instret[h]` inhibit field value. - ir, - /// Sets the `instret[h]` inhibit field value. - /// - /// **NOTE**: only updates the in-memory value without touching the CSR. - set_ir, - bit: 2, + ir: 2, } read_write_csr_field! { @@ -38,24 +28,7 @@ read_write_csr_field! { /// Gets the `mhpmcounterX[h]` inhibit field value. /// /// **WARN**: `index` must be in the range `[31:3]`. - hpm, - /// Attempts to get the `mhpmcounterX[h]` inhibit field value. - /// - /// **WARN**: `index` must be in the range `[31:3]`. - try_hpm, - /// Sets the `mhpmcounterX[h]` inhibit field value. - /// - /// **WARN**: `index` must be in the range `[31:3]`. - /// - /// **NOTE**: only updates the in-memory value without touching the CSR. - set_hpm, - /// Sets the `mhpmcounterX[h]` inhibit field value. - /// - /// **WARN**: `index` must be in the range `[31:3]`. - /// - /// **NOTE**: only updates the in-memory value without touching the CSR. - try_set_hpm, - range: 3..=31, + hpm: 3..=31, } set_clear_csr!( diff --git a/riscv/src/register/tests/read_only_csr.rs b/riscv/src/register/tests/read_only_csr.rs index e61d2e49..7c0d2598 100644 --- a/riscv/src/register/tests/read_only_csr.rs +++ b/riscv/src/register/tests/read_only_csr.rs @@ -15,10 +15,7 @@ read_only_csr_field! { read_only_csr_field! { Mtest, /// multiple single-bit field range - multi_range, - /// try-getter multiple single-bit field range - try_multi_range, - range: 1..=3, + multi_range: 1..=3, } read_only_csr_field! { @@ -43,10 +40,7 @@ read_only_csr_field! { Mtest, /// multi-bit field field_enum, - /// try-getter multi-bit field - try_field_enum, - MtestFieldEnum, - range: [8:11], + MtestFieldEnum: [8:11], } // we don't test the `read` function, we are only testing in-memory functions. diff --git a/riscv/src/register/tests/read_write_csr.rs b/riscv/src/register/tests/read_write_csr.rs index 6712096d..269ee852 100644 --- a/riscv/src/register/tests/read_write_csr.rs +++ b/riscv/src/register/tests/read_write_csr.rs @@ -9,32 +9,19 @@ read_write_csr! { read_write_csr_field! { Mtest, /// test single-bit field - single, - /// setter test single-bit field - set_single, - bit: 0, + single: 0, } read_write_csr_field! { Mtest, /// multiple single-bit field range - multi_range, - /// try-get multiple single-bit field range - try_multi_range, - /// setter multiple single-bit field range - set_multi_range, - /// try-setter multiple single-bit field range - try_set_multi_range, - range: 1..=3, + multi_range: 1..=3, } read_write_csr_field! { Mtest, /// multi-bit field - multi_field, - /// setter multi-bit field - set_multi_field, - range: [4:7], + multi_field: [4:7], } csr_field_enum! { @@ -53,12 +40,7 @@ read_write_csr_field! { Mtest, /// multi-bit field field_enum, - /// try-get multi-bit field - try_field_enum, - /// setter multi-bit field - set_field_enum, - MtestFieldEnum, - range: [8:11], + MtestFieldEnum: [8:11], } // we don't test the `read` and `write` functions, we are only testing in-memory functions. diff --git a/riscv/src/register/tests/write_only_csr.rs b/riscv/src/register/tests/write_only_csr.rs index cfae8300..4c550f55 100644 --- a/riscv/src/register/tests/write_only_csr.rs +++ b/riscv/src/register/tests/write_only_csr.rs @@ -15,10 +15,7 @@ write_only_csr_field! { write_only_csr_field! { Mtest, /// setter multiple single-bit field range - set_multi_range, - /// try-setter multiple single-bit field range - try_set_multi_range, - range: 1..=3, + set_multi_range: 1..=3, } write_only_csr_field! { @@ -43,8 +40,7 @@ write_only_csr_field! { Mtest, /// setter multi-bit field set_field_enum, - MtestFieldEnum, - range: [8:11], + MtestFieldEnum: [8:11], } // we don't test the `write` function, we are only testing in-memory functions. From 00dc02bb9c80cbe402f60c686763141489ed92f7 Mon Sep 17 00:00:00 2001 From: rmsyn Date: Wed, 25 Sep 2024 05:01:33 +0000 Subject: [PATCH 18/19] fixup: riscv: clippy fixes for CSR test assertions --- riscv/src/register/tests/read_only_csr.rs | 10 +++++----- riscv/src/register/tests/read_write_csr.rs | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/riscv/src/register/tests/read_only_csr.rs b/riscv/src/register/tests/read_only_csr.rs index 7c0d2598..477e884e 100644 --- a/riscv/src/register/tests/read_only_csr.rs +++ b/riscv/src/register/tests/read_only_csr.rs @@ -62,24 +62,24 @@ fn test_mtest_read_only() { assert_eq!(mtest.bits(), 0); // check that single bit field getter/setters work. - assert_eq!(mtest.single(), false); + assert!(!mtest.single()); mtest = Mtest::from_bits(1); - assert_eq!(mtest.single(), true); + assert!(mtest.single()); mtest = Mtest::from_bits(0); // check that single bit range field getter/setters work. for i in 1..=3 { - assert_eq!(mtest.multi_range(i), false); + assert!(!mtest.multi_range(i)); assert_eq!(mtest.try_multi_range(i), Ok(false)); mtest = Mtest::from_bits(1 << i); - assert_eq!(mtest.multi_range(i), true); + assert!(mtest.multi_range(i)); assert_eq!(mtest.try_multi_range(i), Ok(true)); mtest = Mtest::from_bits(0 << i); - assert_eq!(mtest.multi_range(i), false); + assert!(!mtest.multi_range(i)); assert_eq!(mtest.try_multi_range(i), Ok(false)); } diff --git a/riscv/src/register/tests/read_write_csr.rs b/riscv/src/register/tests/read_write_csr.rs index 269ee852..bcad6478 100644 --- a/riscv/src/register/tests/read_write_csr.rs +++ b/riscv/src/register/tests/read_write_csr.rs @@ -72,23 +72,23 @@ fn test_mtest_read_write() { assert_eq!(mtest.bits(), 0); // check that single bit field getter/setters work. - assert_eq!(mtest.single(), false); + assert!(!mtest.single()); mtest.set_single(true); - assert_eq!(mtest.single(), true); + assert!(mtest.single()); mtest.set_single(false); - assert_eq!(mtest.single(), false); + assert!(!mtest.single()); // check that single bit range field getter/setters work. for i in 1..=3 { - assert_eq!(mtest.multi_range(i), false); + assert!(!mtest.multi_range(i)); mtest.set_multi_range(i, true); - assert_eq!(mtest.multi_range(i), true); + assert!(mtest.multi_range(i)); mtest.set_multi_range(i, false); - assert_eq!(mtest.multi_range(i), false); + assert!(!mtest.multi_range(i)); } // check that multi-bit field getter/setters work. From b568220677ec09f5ff38d33a2fbdbae0776b7542 Mon Sep 17 00:00:00 2001 From: rmsyn Date: Fri, 27 Sep 2024 00:47:25 +0000 Subject: [PATCH 19/19] riscv: re-export paste macro Re-exports the `paste` macro to allow using CSR helper macros in external crates. Authored-by: rmsyn Co-authored-by: romancardenas --- riscv/src/lib.rs | 2 ++ riscv/src/register/macros.rs | 14 +++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/riscv/src/lib.rs b/riscv/src/lib.rs index 9408c8fe..9f44cb73 100644 --- a/riscv/src/lib.rs +++ b/riscv/src/lib.rs @@ -35,6 +35,8 @@ #![no_std] #![allow(clippy::missing_safety_doc)] +pub use paste::paste; + pub mod asm; pub mod bits; pub mod delay; diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index c1151ea9..1aeb082d 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -756,7 +756,7 @@ macro_rules! read_write_csr_field { $(#[$field_doc:meta])+ $field:ident: $bit:literal$(,)? ) => { - paste::paste! { + $crate::paste! { $crate::read_only_csr_field!( $ty, $(#[$field_doc])+ @@ -775,7 +775,7 @@ macro_rules! read_write_csr_field { $(#[$field_doc:meta])+ $field:ident: $bit_start:literal ..= $bit_end:literal$(,)? ) => { - paste::paste! { + $crate::paste! { $crate::read_only_csr_field!( $ty, $(#[$field_doc])+ @@ -794,7 +794,7 @@ macro_rules! read_write_csr_field { $(#[$field_doc:meta])+ $field:ident: [$bit_start:literal : $bit_end:literal]$(,)? ) => { - paste::paste! { + $crate::paste! { $crate::read_only_csr_field!( $ty, $(#[$field_doc])+ @@ -814,7 +814,7 @@ macro_rules! read_write_csr_field { $field:ident, $field_ty:ident: [$field_start:literal : $field_end:literal], ) => { - paste::paste! { + $crate::paste! { $crate::read_only_csr_field!( $ty, $(#[$field_doc])+ @@ -855,7 +855,7 @@ macro_rules! read_only_csr_field { const _: () = assert!($bit_end < usize::BITS); const _: () = assert!($bit_start < $bit_end); - paste::paste! { + $crate::paste! { impl $ty { $(#[$field_doc])+ #[inline] @@ -903,7 +903,7 @@ macro_rules! read_only_csr_field { const _: () = assert!($field_end < usize::BITS); const _: () = assert!($field_start <= $field_end); - paste::paste! { + $crate::paste! { impl $ty { $(#[$field_doc])+ #[inline] @@ -952,7 +952,7 @@ macro_rules! write_only_csr_field { const _: () = assert!($bit_end < usize::BITS); const _: () = assert!($bit_start < $bit_end); - paste::paste! { + $crate::paste! { impl $ty { $(#[$field_doc])+ #[doc = ""]