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/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; 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)] diff --git a/riscv/src/register/mtvec.rs b/riscv/src/register/mtvec.rs index cc77011e..8fa599ac 100644 --- a/riscv/src/register/mtvec.rs +++ b/riscv/src/register/mtvec.rs @@ -1,50 +1,103 @@ //! 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); +#[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); -write_csr!(0x305); + assert_eq!(m.try_set_address(address), Ok(())); + assert_eq!(m.address(), address); + }); -/// Writes the CSR -#[inline] -pub unsafe fn write(addr: usize, mode: TrapMode) { - let bits = addr + mode as usize; - _write(bits); + (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); + } } 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) } }