diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index f40a3202..7b2aa2fb 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Add `riscv::register::mcountinhibit` module for `mcountinhibit` CSR - Add `Mcounteren` in-memory update functions - Add `Mstatus` vector extension support +- Add fallible counterparts to all functions that `panic` ### Fixed diff --git a/riscv/src/register/mcountinhibit.rs b/riscv/src/register/mcountinhibit.rs index fca8cce7..60d32af3 100644 --- a/riscv/src/register/mcountinhibit.rs +++ b/riscv/src/register/mcountinhibit.rs @@ -1,6 +1,7 @@ //! `mcountinhibit` register use crate::bits::{bf_extract, bf_insert}; +use crate::result::{Error, Result}; /// `mcountinhibit` register #[derive(Clone, Copy, Debug)] @@ -44,6 +45,22 @@ impl Mcountinhibit { 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. @@ -52,6 +69,25 @@ impl Mcountinhibit { 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_csr_as!(Mcountinhibit, 0x320); @@ -73,12 +109,38 @@ pub unsafe fn set_hpm(index: usize) { _set(1 << index); } +#[inline] +pub unsafe fn try_set_hpm(index: usize) -> Result<()> { + if (3..32).contains(&index) { + _try_set(1 << index) + } else { + Err(Error::IndexOutOfBounds { + index, + min: 3, + max: 31, + }) + } +} + #[inline] pub unsafe fn clear_hpm(index: usize) { assert!((3..32).contains(&index)); _clear(1 << index); } +#[inline] +pub unsafe fn try_clear_hpm(index: usize) -> Result<()> { + if (3..32).contains(&index) { + _try_clear(1 << index) + } else { + Err(Error::IndexOutOfBounds { + index, + min: 3, + max: 31, + }) + } +} + #[cfg(test)] mod tests { use super::*; @@ -105,12 +167,33 @@ mod tests { (3..32).for_each(|i| { assert!(!m.hpm(i)); + assert_eq!(m.try_hpm(i), Ok(false)); m.set_hpm(i, true); assert!(m.hpm(i)); + assert_eq!(m.try_hpm(i), Ok(true)); - m.set_hpm(i, false); - assert!(!m.hpm(i)); + assert_eq!(m.try_set_hpm(i, false), Ok(())); + assert_eq!(m.try_hpm(i), Ok(false)); + }); + + (0..2).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 { + index, + min: 3, + max: 31 + }) + ); }); } }