diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index c09ef787..30bf8d6f 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Use CSR helper macros to define `mstatush` register - Use CSR helper macros to define `mtvec` register - Use CSR helper macros to define `mtvendorid` register +- Use CSR helper macros to define `satp` register ## [v0.12.1] - 2024-10-20 diff --git a/riscv/src/register/macros.rs b/riscv/src/register/macros.rs index 48776bb0..46457ac3 100644 --- a/riscv/src/register/macros.rs +++ b/riscv/src/register/macros.rs @@ -601,8 +601,8 @@ macro_rules! csr_field_enum { #[macro_export] macro_rules! read_write_csr { ($(#[$doc:meta])+ - $ty:ident: $csr:tt, - mask: $mask:tt$(,)? + $ty:ident: $csr:expr, + mask: $mask:expr$(,)? ) => { $crate::csr!($(#[$doc])+ $ty, $mask); @@ -617,8 +617,8 @@ macro_rules! read_write_csr { #[macro_export] macro_rules! read_only_csr { ($(#[$doc:meta])+ - $ty:ident: $csr:tt, - mask: $mask:tt$(,)? + $ty:ident: $csr:expr, + mask: $mask:expr$(,)? ) => { $crate::csr! { $(#[$doc])+ $ty, $mask } @@ -626,8 +626,8 @@ macro_rules! read_only_csr { }; ($(#[$doc:meta])+ - $ty:ident: $csr:tt, - mask: $mask:tt, + $ty:ident: $csr:expr, + mask: $mask:expr, sentinel: $sentinel:tt$(,)?, ) => { $crate::csr! { $(#[$doc])+ $ty, $mask } @@ -642,8 +642,8 @@ macro_rules! read_only_csr { #[macro_export] macro_rules! write_only_csr { ($(#[$doc:meta])+ - $ty:ident: $csr:literal, - mask: $mask:literal$(,)? + $ty:ident: $csr:expr, + mask: $mask:expr$(,)? ) => { $crate::csr! { $(#[$doc])+ $ty, $mask } diff --git a/riscv/src/register/satp.rs b/riscv/src/register/satp.rs index d321bf9c..48c9cd9f 100644 --- a/riscv/src/register/satp.rs +++ b/riscv/src/register/satp.rs @@ -2,144 +2,86 @@ use crate::result::{Error, Result}; -/// satp register -#[derive(Clone, Copy, Debug)] -pub struct Satp { - bits: usize, +read_write_csr! { + /// `satp` register + Satp: 0x180, + mask: usize::MAX, } -impl Satp { - /// Returns the contents of the register as raw bits - #[inline] - pub fn bits(&self) -> usize { - self.bits - } - - /// Current address-translation scheme - /// - /// **WARNING**: panics if the field has an invalid variant. - #[inline] - #[cfg(target_pointer_width = "32")] - pub fn mode(&self) -> Mode { - self.try_mode().unwrap() - } - - /// Attempts to get the current address-translation scheme. - #[inline] - #[cfg(target_pointer_width = "32")] - pub fn try_mode(&self) -> Result { - ((self.bits >> 31) as u8).try_into() - } - - /// Current address-translation scheme - /// - /// **WARNING**: panics if the field has an invalid variant. - #[inline] - #[cfg(target_pointer_width = "64")] - pub fn mode(&self) -> Mode { - self.try_mode().unwrap() - } - - /// Attempts to get the current address-translation scheme. - #[inline] - #[cfg(target_pointer_width = "64")] - pub fn try_mode(&self) -> Result { - ((self.bits >> 60) as u8).try_into() - } - - /// Address space identifier - #[inline] - #[cfg(target_pointer_width = "32")] - pub fn asid(&self) -> usize { - (self.bits >> 22) & 0x1FF // bits 22-30 +#[cfg(target_pointer_width = "32")] +csr_field_enum! { + /// 32-bit satp mode + Mode { + default: Bare, + /// No translation or protection + Bare = 0, + /// Page-based 32-bit virtual addressing + Sv32 = 1, } +} - /// Address space identifier - #[inline] - #[cfg(target_pointer_width = "64")] - pub fn asid(&self) -> usize { - (self.bits >> 44) & 0xFFFF // bits 44-59 +#[cfg(target_pointer_width = "64")] +csr_field_enum! { + /// 64-bit satp mode + Mode { + default: Bare, + /// No translation or protection + Bare = 0, + /// Page-based 39-bit virtual addressing + Sv39 = 8, + /// Page-based 48-bit virtual addressing + Sv48 = 9, + /// Page-based 57-bit virtual addressing + Sv57 = 10, + /// Page-based 64-bit virtual addressing + Sv64 = 11, } +} +#[cfg(target_pointer_width = "32")] +read_write_csr_field! { + Satp, /// Physical page number - #[inline] - #[cfg(target_pointer_width = "32")] - pub fn ppn(&self) -> usize { - self.bits & 0x3F_FFFF // bits 0-21 - } + ppn: [0:21], +} +#[cfg(target_pointer_width = "64")] +read_write_csr_field! { + Satp, /// Physical page number - #[inline] - #[cfg(target_pointer_width = "64")] - pub fn ppn(&self) -> usize { - self.bits & 0xFFF_FFFF_FFFF // bits 0-43 - } + ppn: [0:43], } -/// 32-bit satp mode #[cfg(target_pointer_width = "32")] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum Mode { - /// No translation or protection - Bare = 0, - /// Page-based 32-bit virtual addressing - Sv32 = 1, +read_write_csr_field! { + Satp, + /// Address space identifier + asid: [22:30], } -/// 64-bit satp mode #[cfg(target_pointer_width = "64")] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum Mode { - /// No translation or protection - Bare = 0, - /// Page-based 39-bit virtual addressing - Sv39 = 8, - /// Page-based 48-bit virtual addressing - Sv48 = 9, - /// Page-based 57-bit virtual addressing - Sv57 = 10, - /// Page-based 64-bit virtual addressing - Sv64 = 11, +read_write_csr_field! { + Satp, + /// Address space identifier + asid: [44:59], } #[cfg(target_pointer_width = "32")] -impl TryFrom for Mode { - type Error = Error; - - fn try_from(val: u8) -> Result { - match val { - 0 => Ok(Mode::Bare), - 1 => Ok(Mode::Sv32), - _ => Err(Error::InvalidFieldVariant { - field: "mode", - value: val as usize, - }), - } - } +read_write_csr_field! { + Satp, + /// Current address-translation scheme. + mode, + Mode: [31:31], } #[cfg(target_pointer_width = "64")] -impl TryFrom for Mode { - type Error = Error; - - fn try_from(val: u8) -> Result { - match val { - 0 => Ok(Mode::Bare), - 8 => Ok(Mode::Sv39), - 9 => Ok(Mode::Sv48), - 10 => Ok(Mode::Sv57), - 11 => Ok(Mode::Sv64), - _ => Err(Error::InvalidFieldVariant { - field: "mode", - value: val as usize, - }), - } - } +read_write_csr_field! { + Satp, + /// Current address-translation scheme. + mode, + Mode: [60:63], } -read_csr_as!(Satp, 0x180); -write_csr_as_usize!(0x180); - /// Sets the register to corresponding page table mode, physical page number and address space id. /// /// **WARNING**: panics on: @@ -207,3 +149,77 @@ pub unsafe fn try_set(mode: Mode, asid: usize, ppn: usize) -> Result<()> { _try_write(bits) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[cfg(target_pointer_width = "32")] + const ASID_START: usize = 22; + #[cfg(target_pointer_width = "64")] + const ASID_START: usize = 44; + #[cfg(target_pointer_width = "32")] + const MODE_START: usize = 31; + #[cfg(target_pointer_width = "64")] + const MODE_START: usize = 60; + + #[cfg(target_pointer_width = "32")] + const MODES: [Mode; 2] = [Mode::Bare, Mode::Sv32]; + #[cfg(target_pointer_width = "64")] + const MODES: [Mode; 5] = [Mode::Bare, Mode::Sv39, Mode::Sv48, Mode::Sv57, Mode::Sv64]; + + #[test] + fn test_satp() { + let new_mode = Mode::new(); + + (1..=usize::BITS) + .map(|r| ((1u128 << r) - 1) as usize) + .for_each(|raw| { + let mut satp = Satp::from_bits(raw); + + let exp_ppn = raw & ((1usize << ASID_START) - 1); + let exp_asid = (raw & ((1usize << MODE_START) - 1)) >> ASID_START; + + assert_eq!(satp.ppn(), exp_ppn); + + satp.set_ppn(0); + assert_eq!(satp.ppn(), 0); + + satp.set_ppn(exp_ppn); + assert_eq!(satp.ppn(), exp_ppn); + + assert_eq!(satp.asid(), exp_asid); + + satp.set_asid(0); + assert_eq!(satp.asid(), 0); + + satp.set_asid(exp_asid); + assert_eq!(satp.asid(), exp_asid); + + match Mode::from_usize(raw >> 60) { + Ok(exp_mode) => { + assert_eq!(satp.try_mode(), Ok(exp_mode)); + assert_eq!(satp.mode(), exp_mode); + + satp.set_mode(new_mode); + + assert_eq!(satp.try_mode(), Ok(new_mode)); + assert_eq!(satp.mode(), new_mode); + + satp.set_mode(exp_mode); + + assert_eq!(satp.try_mode(), Ok(exp_mode)); + assert_eq!(satp.mode(), exp_mode); + } + Err(exp_err) => { + assert_eq!(satp.try_mode(), Err(exp_err)); + } + } + }); + + let mut satp = Satp::from_bits(0); + MODES + .into_iter() + .for_each(|mode| test_csr_field!(satp, mode: mode)); + } +}