Skip to content

Commit 2628fe4

Browse files
Merge pull request #258 from rmsyn/riscv/satp-csr-macro
riscv: define satp CSR with macro helpers
2 parents b771540 + 3c665ee commit 2628fe4

File tree

3 files changed

+140
-123
lines changed

3 files changed

+140
-123
lines changed

riscv/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
3030
- Use CSR helper macros to define `mstatush` register
3131
- Use CSR helper macros to define `mtvec` register
3232
- Use CSR helper macros to define `mtvendorid` register
33+
- Use CSR helper macros to define `satp` register
3334

3435
## [v0.12.1] - 2024-10-20
3536

riscv/src/register/macros.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -601,8 +601,8 @@ macro_rules! csr_field_enum {
601601
#[macro_export]
602602
macro_rules! read_write_csr {
603603
($(#[$doc:meta])+
604-
$ty:ident: $csr:tt,
605-
mask: $mask:tt$(,)?
604+
$ty:ident: $csr:expr,
605+
mask: $mask:expr$(,)?
606606
) => {
607607
$crate::csr!($(#[$doc])+ $ty, $mask);
608608

@@ -617,17 +617,17 @@ macro_rules! read_write_csr {
617617
#[macro_export]
618618
macro_rules! read_only_csr {
619619
($(#[$doc:meta])+
620-
$ty:ident: $csr:tt,
621-
mask: $mask:tt$(,)?
620+
$ty:ident: $csr:expr,
621+
mask: $mask:expr$(,)?
622622
) => {
623623
$crate::csr! { $(#[$doc])+ $ty, $mask }
624624

625625
$crate::read_csr_as!($ty, $csr);
626626
};
627627

628628
($(#[$doc:meta])+
629-
$ty:ident: $csr:tt,
630-
mask: $mask:tt,
629+
$ty:ident: $csr:expr,
630+
mask: $mask:expr,
631631
sentinel: $sentinel:tt$(,)?,
632632
) => {
633633
$crate::csr! { $(#[$doc])+ $ty, $mask }
@@ -642,8 +642,8 @@ macro_rules! read_only_csr {
642642
#[macro_export]
643643
macro_rules! write_only_csr {
644644
($(#[$doc:meta])+
645-
$ty:ident: $csr:literal,
646-
mask: $mask:literal$(,)?
645+
$ty:ident: $csr:expr,
646+
mask: $mask:expr$(,)?
647647
) => {
648648
$crate::csr! { $(#[$doc])+ $ty, $mask }
649649

riscv/src/register/satp.rs

Lines changed: 131 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -2,144 +2,86 @@
22
33
use crate::result::{Error, Result};
44

5-
/// satp register
6-
#[derive(Clone, Copy, Debug)]
7-
pub struct Satp {
8-
bits: usize,
5+
read_write_csr! {
6+
/// `satp` register
7+
Satp: 0x180,
8+
mask: usize::MAX,
99
}
1010

11-
impl Satp {
12-
/// Returns the contents of the register as raw bits
13-
#[inline]
14-
pub fn bits(&self) -> usize {
15-
self.bits
16-
}
17-
18-
/// Current address-translation scheme
19-
///
20-
/// **WARNING**: panics if the field has an invalid variant.
21-
#[inline]
22-
#[cfg(target_pointer_width = "32")]
23-
pub fn mode(&self) -> Mode {
24-
self.try_mode().unwrap()
25-
}
26-
27-
/// Attempts to get the current address-translation scheme.
28-
#[inline]
29-
#[cfg(target_pointer_width = "32")]
30-
pub fn try_mode(&self) -> Result<Mode> {
31-
((self.bits >> 31) as u8).try_into()
32-
}
33-
34-
/// Current address-translation scheme
35-
///
36-
/// **WARNING**: panics if the field has an invalid variant.
37-
#[inline]
38-
#[cfg(target_pointer_width = "64")]
39-
pub fn mode(&self) -> Mode {
40-
self.try_mode().unwrap()
41-
}
42-
43-
/// Attempts to get the current address-translation scheme.
44-
#[inline]
45-
#[cfg(target_pointer_width = "64")]
46-
pub fn try_mode(&self) -> Result<Mode> {
47-
((self.bits >> 60) as u8).try_into()
48-
}
49-
50-
/// Address space identifier
51-
#[inline]
52-
#[cfg(target_pointer_width = "32")]
53-
pub fn asid(&self) -> usize {
54-
(self.bits >> 22) & 0x1FF // bits 22-30
11+
#[cfg(target_pointer_width = "32")]
12+
csr_field_enum! {
13+
/// 32-bit satp mode
14+
Mode {
15+
default: Bare,
16+
/// No translation or protection
17+
Bare = 0,
18+
/// Page-based 32-bit virtual addressing
19+
Sv32 = 1,
5520
}
21+
}
5622

57-
/// Address space identifier
58-
#[inline]
59-
#[cfg(target_pointer_width = "64")]
60-
pub fn asid(&self) -> usize {
61-
(self.bits >> 44) & 0xFFFF // bits 44-59
23+
#[cfg(target_pointer_width = "64")]
24+
csr_field_enum! {
25+
/// 64-bit satp mode
26+
Mode {
27+
default: Bare,
28+
/// No translation or protection
29+
Bare = 0,
30+
/// Page-based 39-bit virtual addressing
31+
Sv39 = 8,
32+
/// Page-based 48-bit virtual addressing
33+
Sv48 = 9,
34+
/// Page-based 57-bit virtual addressing
35+
Sv57 = 10,
36+
/// Page-based 64-bit virtual addressing
37+
Sv64 = 11,
6238
}
39+
}
6340

41+
#[cfg(target_pointer_width = "32")]
42+
read_write_csr_field! {
43+
Satp,
6444
/// Physical page number
65-
#[inline]
66-
#[cfg(target_pointer_width = "32")]
67-
pub fn ppn(&self) -> usize {
68-
self.bits & 0x3F_FFFF // bits 0-21
69-
}
45+
ppn: [0:21],
46+
}
7047

48+
#[cfg(target_pointer_width = "64")]
49+
read_write_csr_field! {
50+
Satp,
7151
/// Physical page number
72-
#[inline]
73-
#[cfg(target_pointer_width = "64")]
74-
pub fn ppn(&self) -> usize {
75-
self.bits & 0xFFF_FFFF_FFFF // bits 0-43
76-
}
52+
ppn: [0:43],
7753
}
7854

79-
/// 32-bit satp mode
8055
#[cfg(target_pointer_width = "32")]
81-
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
82-
pub enum Mode {
83-
/// No translation or protection
84-
Bare = 0,
85-
/// Page-based 32-bit virtual addressing
86-
Sv32 = 1,
56+
read_write_csr_field! {
57+
Satp,
58+
/// Address space identifier
59+
asid: [22:30],
8760
}
8861

89-
/// 64-bit satp mode
9062
#[cfg(target_pointer_width = "64")]
91-
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
92-
pub enum Mode {
93-
/// No translation or protection
94-
Bare = 0,
95-
/// Page-based 39-bit virtual addressing
96-
Sv39 = 8,
97-
/// Page-based 48-bit virtual addressing
98-
Sv48 = 9,
99-
/// Page-based 57-bit virtual addressing
100-
Sv57 = 10,
101-
/// Page-based 64-bit virtual addressing
102-
Sv64 = 11,
63+
read_write_csr_field! {
64+
Satp,
65+
/// Address space identifier
66+
asid: [44:59],
10367
}
10468

10569
#[cfg(target_pointer_width = "32")]
106-
impl TryFrom<u8> for Mode {
107-
type Error = Error;
108-
109-
fn try_from(val: u8) -> Result<Self> {
110-
match val {
111-
0 => Ok(Mode::Bare),
112-
1 => Ok(Mode::Sv32),
113-
_ => Err(Error::InvalidFieldVariant {
114-
field: "mode",
115-
value: val as usize,
116-
}),
117-
}
118-
}
70+
read_write_csr_field! {
71+
Satp,
72+
/// Current address-translation scheme.
73+
mode,
74+
Mode: [31:31],
11975
}
12076

12177
#[cfg(target_pointer_width = "64")]
122-
impl TryFrom<u8> for Mode {
123-
type Error = Error;
124-
125-
fn try_from(val: u8) -> Result<Self> {
126-
match val {
127-
0 => Ok(Mode::Bare),
128-
8 => Ok(Mode::Sv39),
129-
9 => Ok(Mode::Sv48),
130-
10 => Ok(Mode::Sv57),
131-
11 => Ok(Mode::Sv64),
132-
_ => Err(Error::InvalidFieldVariant {
133-
field: "mode",
134-
value: val as usize,
135-
}),
136-
}
137-
}
78+
read_write_csr_field! {
79+
Satp,
80+
/// Current address-translation scheme.
81+
mode,
82+
Mode: [60:63],
13883
}
13984

140-
read_csr_as!(Satp, 0x180);
141-
write_csr_as_usize!(0x180);
142-
14385
/// Sets the register to corresponding page table mode, physical page number and address space id.
14486
///
14587
/// **WARNING**: panics on:
@@ -207,3 +149,77 @@ pub unsafe fn try_set(mode: Mode, asid: usize, ppn: usize) -> Result<()> {
207149
_try_write(bits)
208150
}
209151
}
152+
153+
#[cfg(test)]
154+
mod tests {
155+
use super::*;
156+
157+
#[cfg(target_pointer_width = "32")]
158+
const ASID_START: usize = 22;
159+
#[cfg(target_pointer_width = "64")]
160+
const ASID_START: usize = 44;
161+
#[cfg(target_pointer_width = "32")]
162+
const MODE_START: usize = 31;
163+
#[cfg(target_pointer_width = "64")]
164+
const MODE_START: usize = 60;
165+
166+
#[cfg(target_pointer_width = "32")]
167+
const MODES: [Mode; 2] = [Mode::Bare, Mode::Sv32];
168+
#[cfg(target_pointer_width = "64")]
169+
const MODES: [Mode; 5] = [Mode::Bare, Mode::Sv39, Mode::Sv48, Mode::Sv57, Mode::Sv64];
170+
171+
#[test]
172+
fn test_satp() {
173+
let new_mode = Mode::new();
174+
175+
(1..=usize::BITS)
176+
.map(|r| ((1u128 << r) - 1) as usize)
177+
.for_each(|raw| {
178+
let mut satp = Satp::from_bits(raw);
179+
180+
let exp_ppn = raw & ((1usize << ASID_START) - 1);
181+
let exp_asid = (raw & ((1usize << MODE_START) - 1)) >> ASID_START;
182+
183+
assert_eq!(satp.ppn(), exp_ppn);
184+
185+
satp.set_ppn(0);
186+
assert_eq!(satp.ppn(), 0);
187+
188+
satp.set_ppn(exp_ppn);
189+
assert_eq!(satp.ppn(), exp_ppn);
190+
191+
assert_eq!(satp.asid(), exp_asid);
192+
193+
satp.set_asid(0);
194+
assert_eq!(satp.asid(), 0);
195+
196+
satp.set_asid(exp_asid);
197+
assert_eq!(satp.asid(), exp_asid);
198+
199+
match Mode::from_usize(raw >> 60) {
200+
Ok(exp_mode) => {
201+
assert_eq!(satp.try_mode(), Ok(exp_mode));
202+
assert_eq!(satp.mode(), exp_mode);
203+
204+
satp.set_mode(new_mode);
205+
206+
assert_eq!(satp.try_mode(), Ok(new_mode));
207+
assert_eq!(satp.mode(), new_mode);
208+
209+
satp.set_mode(exp_mode);
210+
211+
assert_eq!(satp.try_mode(), Ok(exp_mode));
212+
assert_eq!(satp.mode(), exp_mode);
213+
}
214+
Err(exp_err) => {
215+
assert_eq!(satp.try_mode(), Err(exp_err));
216+
}
217+
}
218+
});
219+
220+
let mut satp = Satp::from_bits(0);
221+
MODES
222+
.into_iter()
223+
.for_each(|mode| test_csr_field!(satp, mode: mode));
224+
}
225+
}

0 commit comments

Comments
 (0)