From d85beafa7908349a2857fb3f42d338e6b21824cf Mon Sep 17 00:00:00 2001 From: rmsyn Date: Sat, 21 Dec 2024 20:56:59 +0000 Subject: [PATCH 1/5] macros: change CSR mask to an `expr` type Changes the macro argument type to `expr` to allow using constants, expressions, and other initializers for CSR mask values. --- riscv/src/register/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index ac89c0d8..48776bb0 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -498,7 +498,7 @@ macro_rules! clear_pmp { macro_rules! csr { ($(#[$doc:meta])* $ty:ident, - $mask:literal) => { + $mask:expr) => { #[repr(C)] $(#[$doc])* #[derive(Clone, Copy, Debug, Eq, PartialEq)] From 6e911349c063d87e7a68a20e52b76c664b45442f Mon Sep 17 00:00:00 2001 From: rmsyn Date: Sat, 21 Dec 2024 20:58:40 +0000 Subject: [PATCH 2/5] lint: allow the `identity-op` warning Ignores the warning for the `clippy::identity_op` to allow using ranged bitfield CSR macro arguments with a leading `0`. --- riscv/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/riscv/src/lib.rs b/riscv/src/lib.rs index 93e019d4..3d139f60 100644 --- a/riscv/src/lib.rs +++ b/riscv/src/lib.rs @@ -35,6 +35,7 @@ #![no_std] #![allow(clippy::missing_safety_doc)] #![allow(clippy::eq_op)] +#![allow(clippy::identity_op)] pub use paste::paste; From b343fbeb1ddc4a007599e4c900e184806ed61703 Mon Sep 17 00:00:00 2001 From: rmsyn Date: Sat, 21 Dec 2024 21:02:31 +0000 Subject: [PATCH 3/5] riscv: define mtvec CSR with macro helpers Uses the CSR macro helpers to define the `mtvec` CSR register. Authored-by: rmsyn Reviewed-by: romancardenas --- riscv/src/register/mtvec.rs | 81 ++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 33 deletions(-) diff --git a/riscv/src/register/mtvec.rs b/riscv/src/register/mtvec.rs index cc77011e..c4fc7375 100644 --- a/riscv/src/register/mtvec.rs +++ b/riscv/src/register/mtvec.rs @@ -1,50 +1,65 @@ //! mtvec register -/// mtvec register -#[derive(Clone, Copy, Debug)] -pub struct Mtvec { - bits: usize, +use crate::result::{Error, Result}; + +const MASK: usize = usize::MAX; +const TRAP_MASK: usize = 0b11; + +read_write_csr! { + /// mtvec register + Mtvec: 0x305, + mask: MASK, +} + +csr_field_enum! { + /// Trap mode + TrapMode { + default: Direct, + Direct = 0, + Vectored = 1, + } } -/// Trap mode -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum TrapMode { - Direct = 0, - Vectored = 1, +read_write_csr_field! { + Mtvec, + /// Accesses the trap-vector mode. + trap_mode, + TrapMode: [0:1], } impl Mtvec { - /// Returns the contents of the register as raw bits + /// Returns the trap-vector base-address #[inline] - pub fn bits(&self) -> usize { - self.bits + pub const fn address(&self) -> usize { + self.bits & !TRAP_MASK } - /// Returns the trap-vector base-address + /// Sets the trap-vector base-address. + /// + /// # Note + /// + /// Panics if the address is not aligned to 4-bytes. #[inline] - pub fn address(&self) -> usize { - self.bits - (self.bits & 0b11) + pub fn set_address(&mut self, address: usize) { + self.try_set_address(address).unwrap(); } - /// Returns the trap-vector mode + /// Attempts to set the trap-vector base-address. + /// + /// # Note + /// + /// Returns an error if the address is not aligned to 4-bytes. #[inline] - pub fn trap_mode(&self) -> Option { - let mode = self.bits & 0b11; - match mode { - 0 => Some(TrapMode::Direct), - 1 => Some(TrapMode::Vectored), - _ => None, + pub fn try_set_address(&mut self, address: usize) -> Result<()> { + // check for four-byte alignment + if (address & TRAP_MASK) != 0 { + Err(Error::InvalidFieldVariant { + field: "mtvec::address", + value: address, + }) + } else { + self.bits = address | (self.bits & TRAP_MASK); + Ok(()) } } } - -read_csr_as!(Mtvec, 0x305); - -write_csr!(0x305); - -/// Writes the CSR -#[inline] -pub unsafe fn write(addr: usize, mode: TrapMode) { - let bits = addr + mode as usize; - _write(bits); -} From 9fd2f73ac75ff774672e700618cbbdbe72d0b6be Mon Sep 17 00:00:00 2001 From: rmsyn Date: Sat, 21 Dec 2024 21:12:09 +0000 Subject: [PATCH 4/5] riscv: add mtvec unit-tests Adds basic unit-tests for the `mtvec` CSR. --- riscv/CHANGELOG.md | 1 + riscv/src/register/mtvec.rs | 38 +++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index d94ca726..3894d740 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Use CSR helper macros to define `mip` register - Use CSR helper macros to define `mstatus` register - Use CSR helper macros to define `mstatush` register +- Use CSR helper macros to define `mtvec` register ## [v0.12.1] - 2024-10-20 diff --git a/riscv/src/register/mtvec.rs b/riscv/src/register/mtvec.rs index c4fc7375..8fa599ac 100644 --- a/riscv/src/register/mtvec.rs +++ b/riscv/src/register/mtvec.rs @@ -63,3 +63,41 @@ impl Mtvec { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_mtvec() { + let mut m = Mtvec::from_bits(0); + + (1..=usize::BITS) + .map(|r| (((1u128 << r) - 1) as usize) & !TRAP_MASK) + .for_each(|address| { + m.set_address(address); + assert_eq!(m.address(), address); + + assert_eq!(m.try_set_address(address), Ok(())); + assert_eq!(m.address(), address); + }); + + (1..=usize::BITS) + .filter_map(|r| match ((1u128 << r) - 1) as usize { + addr if (addr & TRAP_MASK) != 0 => Some(addr), + _ => None, + }) + .for_each(|address| { + assert_eq!( + m.try_set_address(address), + Err(Error::InvalidFieldVariant { + field: "mtvec::address", + value: address, + }) + ); + }); + + test_csr_field!(m, trap_mode: TrapMode::Direct); + test_csr_field!(m, trap_mode: TrapMode::Vectored); + } +} From e9ff3ada685f44c2fd1c9cc02cd92a36c8d60212 Mon Sep 17 00:00:00 2001 From: rmsyn Date: Tue, 7 Jan 2025 14:32:24 +0000 Subject: [PATCH 5/5] fixup: riscv: lint fixes --- riscv/src/register/satp.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/riscv/src/register/satp.rs b/riscv/src/register/satp.rs index 16f3aeb2..d321bf9c 100644 --- a/riscv/src/register/satp.rs +++ b/riscv/src/register/satp.rs @@ -58,7 +58,7 @@ impl Satp { #[inline] #[cfg(target_pointer_width = "64")] pub fn asid(&self) -> usize { - self.bits >> 44 & 0xFFFF // bits 44-59 + (self.bits >> 44) & 0xFFFF // bits 44-59 } /// Physical page number @@ -203,7 +203,7 @@ pub unsafe fn try_set(mode: Mode, asid: usize, ppn: usize) -> Result<()> { bitmask: 0xFFF_FFFF_FFFF, }) } else { - let bits = (mode as usize) << 60 | (asid << 44) | ppn; + let bits = ((mode as usize) << 60) | (asid << 44) | ppn; _try_write(bits) } }