Skip to content

Commit 1dac361

Browse files
Merge pull request #267 from rmsyn/riscv/stvec-csr-macro
riscv: define `stvec` CSR with macro helpers
2 parents abdce51 + 6ecf8a6 commit 1dac361

File tree

2 files changed

+78
-23
lines changed

2 files changed

+78
-23
lines changed

riscv/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
3838
- Use CSR helper macros to define `scounteren` field types
3939
- Use CSR helper macros to define `sip` register
4040
- Use CSR helper macros to define `sstatus` field types
41+
- Use CSR helper macros to define `stvec` field types
4142

4243
## [v0.12.1] - 2024-10-20
4344

riscv/src/register/stvec.rs

Lines changed: 77 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,97 @@
11
//! stvec register
22
33
pub use crate::register::mtvec::TrapMode;
4+
use crate::result::{Error, Result};
45

5-
/// stvec register
6-
#[derive(Clone, Copy, Debug)]
7-
pub struct Stvec {
8-
bits: usize,
6+
const TRAP_MASK: usize = 0b11;
7+
8+
read_write_csr! {
9+
/// stvec register
10+
Stvec: 0x105,
11+
mask: usize::MAX,
12+
}
13+
14+
read_write_csr_field! {
15+
Stvec,
16+
/// Returns the trap-vector mode
17+
trap_mode,
18+
TrapMode: [0:1],
919
}
1020

1121
impl Stvec {
12-
/// Returns the contents of the register as raw bits
22+
/// Returns the trap-vector base-address
1323
#[inline]
14-
pub fn bits(&self) -> usize {
15-
self.bits
24+
pub const fn address(&self) -> usize {
25+
self.bits & !TRAP_MASK
1626
}
1727

18-
/// Returns the trap-vector base-address
28+
/// Sets the trap-vector base-address.
29+
///
30+
/// # Note
31+
///
32+
/// Panics if the address is not aligned to 4-bytes.
1933
#[inline]
20-
pub fn address(&self) -> usize {
21-
self.bits - (self.bits & 0b11)
34+
pub fn set_address(&mut self, address: usize) {
35+
self.try_set_address(address).unwrap();
2236
}
2337

24-
/// Returns the trap-vector mode
38+
/// Attempts to set the trap-vector base-address.
39+
///
40+
/// # Note
41+
///
42+
/// Returns an error if the address is not aligned to 4-bytes.
2543
#[inline]
26-
pub fn trap_mode(&self) -> Option<TrapMode> {
27-
let mode = self.bits & 0b11;
28-
match mode {
29-
0 => Some(TrapMode::Direct),
30-
1 => Some(TrapMode::Vectored),
31-
_ => None,
44+
pub fn try_set_address(&mut self, address: usize) -> Result<()> {
45+
// check for four-byte alignment
46+
if (address & TRAP_MASK) != 0 {
47+
Err(Error::InvalidFieldVariant {
48+
field: "stvec::address",
49+
value: address,
50+
})
51+
} else {
52+
self.bits = address | (self.bits & TRAP_MASK);
53+
Ok(())
3254
}
3355
}
3456
}
3557

36-
read_csr_as!(Stvec, 0x105);
37-
write_csr!(0x105);
58+
#[cfg(test)]
59+
mod tests {
60+
use super::*;
61+
62+
#[test]
63+
fn test_stvec() {
64+
let mut stvec = Stvec::from_bits(0);
65+
66+
[TrapMode::Direct, TrapMode::Vectored]
67+
.into_iter()
68+
.for_each(|trap_mode| {
69+
test_csr_field!(stvec, trap_mode: trap_mode);
70+
});
3871

39-
/// Writes the CSR
40-
#[inline]
41-
pub unsafe fn write(addr: usize, mode: TrapMode) {
42-
_write(addr + mode as usize);
72+
(1..=usize::BITS)
73+
.map(|r| (((1u128 << r) - 1) as usize) & !TRAP_MASK)
74+
.for_each(|address| {
75+
stvec.set_address(address);
76+
assert_eq!(stvec.address(), address);
77+
78+
assert_eq!(stvec.try_set_address(address), Ok(()));
79+
assert_eq!(stvec.address(), address);
80+
});
81+
82+
(1..=usize::BITS)
83+
.filter_map(|r| match ((1u128 << r) - 1) as usize {
84+
addr if (addr & TRAP_MASK) != 0 => Some(addr),
85+
_ => None,
86+
})
87+
.for_each(|address| {
88+
assert_eq!(
89+
stvec.try_set_address(address),
90+
Err(Error::InvalidFieldVariant {
91+
field: "stvec::address",
92+
value: address,
93+
})
94+
);
95+
});
96+
}
4397
}

0 commit comments

Comments
 (0)