From 6304be46c43b788b8e1887f63b7c7ad7bf49d197 Mon Sep 17 00:00:00 2001 From: rmsyn Date: Sat, 25 May 2024 05:15:26 +0000 Subject: [PATCH] riscv: add `mcounteren` in-memory update functions Adds functions for updating the in-memory `Mcounteren` structure without touching the CSR. Allows manipulating all bitfields in-memory, and writing the entire value back to the CSR at once. --- riscv/CHANGELOG.md | 1 + riscv/src/register/mcounteren.rs | 81 +++++++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 6f2b963a..2a56518a 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). the CSR - Export `riscv::register::macros` module macros for external use - Add `riscv::register::mcountinhibit` module for `mcountinhibit` CSR +- Add `Mcounteren` in-memory update functions ### Fixed diff --git a/riscv/src/register/mcounteren.rs b/riscv/src/register/mcounteren.rs index 9501d126..da9df7a5 100644 --- a/riscv/src/register/mcounteren.rs +++ b/riscv/src/register/mcounteren.rs @@ -1,6 +1,6 @@ //! mcounteren register -use crate::bits::bf_extract; +use crate::bits::{bf_extract, bf_insert}; /// mcounteren register #[derive(Clone, Copy, Debug)] @@ -15,28 +15,61 @@ impl Mcounteren { 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); + } + /// 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); + } + /// 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); + } + /// Supervisor "hpm\[x\]" Enable (bits 3-31) #[inline] pub fn hpm(&self, index: usize) -> bool { assert!((3..32).contains(&index)); bf_extract(self.bits, index, 1) != 0 } + + /// Sets whether to enable the "hpm\[X\]" counter. + /// + /// Only updates the in-memory value, does not modify the `mcounteren` 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); + } } read_csr_as!(Mcounteren, 0x306); -write_csr!(0x306); +write_csr_as!(Mcounteren, 0x306); set!(0x306); clear!(0x306); @@ -63,3 +96,47 @@ pub unsafe fn clear_hpm(index: usize) { assert!((3..32).contains(&index)); _clear(1 << index); } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + 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)); + + m.set_hpm(i, true); + assert!(m.hpm(i)); + + m.set_hpm(i, false); + assert!(!m.hpm(i)); + }); + } +}