Skip to content

Commit

Permalink
Merge pull request #234 from rmsyn/riscv/mcounteren-csr-macro
Browse files Browse the repository at this point in the history
riscv: use CSR macros for mcounteren
  • Loading branch information
romancardenas authored Nov 4, 2024
2 parents b7e9117 + 783906a commit 29dd75d
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 144 deletions.
1 change: 1 addition & 0 deletions riscv/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Use CSR helper macros to define `mcause` register
- Use CSR helper macros to define `medeleg` register
- Use CSR helper macros to define `mideleg` register
- Use CSR helper macros to define `mcounteren` register

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

Expand Down
25 changes: 25 additions & 0 deletions riscv/src/register/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1063,6 +1063,7 @@ macro_rules! write_only_csr_field {
#[cfg(test)]
#[macro_export]
macro_rules! test_csr_field {
// test a single bit field
($reg:ident, $field:ident) => {{
$crate::paste! {
assert!(!$reg.$field());
Expand All @@ -1074,4 +1075,28 @@ macro_rules! test_csr_field {
assert!(!$reg.$field());
}
}};

// test a range bit field (valid)
($reg:ident, $field:ident, $index:expr) => {{
$crate::paste! {
assert!(!$reg.$field($index));
assert_eq!($reg.[<try_ $field>]($index), Ok(false));

$reg.[<set_ $field>]($index, true);
assert!($reg.$field($index));

assert_eq!($reg.[<try_set_ $field>]($index, false), Ok(()));
assert_eq!($reg.[<try_ $field>]($index), Ok(false));

assert!(!$reg.$field($index));
}
}};

// test a range bit field (invalid)
($reg:ident, $field:ident, $index:expr, $err:expr) => {{
$crate::paste! {
assert_eq!($reg.[<try_ $field>]($index), Err($err));
assert_eq!($reg.[<try_set_ $field>]($index, false), Err($err));
}
}};
}
175 changes: 31 additions & 144 deletions riscv/src/register/mcounteren.rs
Original file line number Diff line number Diff line change
@@ -1,113 +1,37 @@
//! mcounteren register
use crate::bits::{bf_extract, bf_insert};
use crate::result::{Error, Result};

/// mcounteren register
#[derive(Clone, Copy, Debug)]
pub struct Mcounteren {
bits: usize,
read_write_csr! {
/// `mcounteren` register
Mcounteren: 0x306,
mask: 0xffff_ffff,
}

impl Mcounteren {
read_write_csr_field! {
Mcounteren,
/// Supervisor "cycle\[h\]" Enable
#[inline]
pub fn cy(&self) -> bool {
bf_extract(self.bits, 0, 1) != 0
}

/// Sets whether to enable the "cycle\[h\]" counter.
///
/// Only updates the in-memory value, does not modify the `mcounteren` register.
#[inline]
pub fn set_cy(&mut self, cy: bool) {
self.bits = bf_insert(self.bits, 0, 1, cy as usize);
}
cy: 0,
}

read_write_csr_field! {
Mcounteren,
/// Supervisor "time\[h\]" Enable
#[inline]
pub fn tm(&self) -> bool {
bf_extract(self.bits, 1, 1) != 0
}

/// Sets whether to enable "time\[h\]".
///
/// Only updates the in-memory value, does not modify the `mcounteren` register.
#[inline]
pub fn set_tm(&mut self, tm: bool) {
self.bits = bf_insert(self.bits, 1, 1, tm as usize);
}
tm: 1,
}

read_write_csr_field! {
Mcounteren,
/// Supervisor "instret\[h\]" Enable
#[inline]
pub fn ir(&self) -> bool {
bf_extract(self.bits, 2, 1) != 0
}

/// Sets whether to enable the "instret\[h\]" counter.
///
/// Only updates the in-memory value, does not modify the `mcounteren` register.
#[inline]
pub fn set_ir(&mut self, ir: bool) {
self.bits = bf_insert(self.bits, 2, 1, ir as usize);
}
ir: 2,
}

read_write_csr_field! {
Mcounteren,
/// Supervisor "hpm\[x\]" Enable (bits 3-31)
///
/// **WARNING**: panics on `index` out-of-bounds
#[inline]
pub fn hpm(&self, index: usize) -> bool {
self.try_hpm(index).unwrap()
}

/// Fallible Supervisor "hpm\[x\]" Enable (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<bool> {
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 enable the "hpm\[X\]" counter.
///
/// Only updates the in-memory value, does not modify the `mcounteren` register.
///
/// **WARNING**: panics on `index` out-of-bounds
#[inline]
pub fn set_hpm(&mut self, index: usize, hpm: bool) {
self.try_set_hpm(index, hpm).unwrap()
}

/// Sets whether to enable the "hpm\[X\]" counter.
///
/// Only updates the in-memory value, does not modify the `mcounteren` 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,
})
}
}
hpm: 3..=31,
}

read_csr_as!(Mcounteren, 0x306);
write_csr_as!(Mcounteren, 0x306);
set!(0x306);
clear!(0x306);

Expand Down Expand Up @@ -189,60 +113,23 @@ mod tests {
fn test_mcounteren() {
let mut m = Mcounteren { bits: 0 };

assert!(!m.cy());

m.set_cy(true);
assert!(m.cy());

m.set_cy(false);
assert!(!m.cy());

assert!(!m.tm());

m.set_tm(true);
assert!(m.tm());

m.set_tm(false);
assert!(!m.tm());

assert!(!m.ir());

m.set_ir(true);
assert!(m.ir());

m.set_ir(false);
assert!(!m.ir());

(3..32).for_each(|i| {
assert!(!m.hpm(i));
assert_eq!(m.try_hpm(i), Ok(false));
test_csr_field!(m, cy);
test_csr_field!(m, tm);
test_csr_field!(m, ir);

m.set_hpm(i, true);
assert!(m.hpm(i));

assert_eq!(m.try_set_hpm(i, false), Ok(()));
assert_eq!(m.try_hpm(i), Ok(false));

assert!(!m.hpm(i));
});
(3..32).for_each(|i| test_csr_field!(m, hpm, i));

(0..3).chain(32..64).for_each(|index| {
assert_eq!(
m.try_hpm(index),
Err(Error::IndexOutOfBounds {
index,
min: 3,
max: 31
})
);
assert_eq!(
m.try_set_hpm(index, false),
Err(Error::IndexOutOfBounds {
test_csr_field!(
m,
hpm,
index,
Error::IndexOutOfBounds {
index,
min: 3,
max: 31
})
);
})
}
)
});
}
}

0 comments on commit 29dd75d

Please sign in to comment.