Skip to content

Commit

Permalink
Merge pull request #258 from rmsyn/riscv/satp-csr-macro
Browse files Browse the repository at this point in the history
riscv: define satp CSR with macro helpers
  • Loading branch information
romancardenas authored Jan 25, 2025
2 parents b771540 + 3c665ee commit 2628fe4
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 123 deletions.
1 change: 1 addition & 0 deletions riscv/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,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

Expand Down
16 changes: 8 additions & 8 deletions riscv/src/register/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -617,17 +617,17 @@ 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 }

$crate::read_csr_as!($ty, $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 }
Expand All @@ -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 }

Expand Down
246 changes: 131 additions & 115 deletions riscv/src/register/satp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Mode> {
((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<Mode> {
((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<u8> for Mode {
type Error = Error;

fn try_from(val: u8) -> Result<Self> {
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<u8> for Mode {
type Error = Error;

fn try_from(val: u8) -> Result<Self> {
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:
Expand Down Expand Up @@ -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));
}
}

0 comments on commit 2628fe4

Please sign in to comment.