Skip to content

Commit 4246903

Browse files
Merge pull request #252 from rmsyn/riscv/mtvec-csr-macro
riscv: define mtvec CSR with macro helpers
2 parents fe6da17 + 9fd2f73 commit 4246903

File tree

4 files changed

+85
-30
lines changed

4 files changed

+85
-30
lines changed

riscv/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
2727
- Use CSR helper macros to define `mip` register
2828
- Use CSR helper macros to define `mstatus` register
2929
- Use CSR helper macros to define `mstatush` register
30+
- Use CSR helper macros to define `mtvec` register
3031

3132
## [v0.12.1] - 2024-10-20
3233

riscv/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#![no_std]
3636
#![allow(clippy::missing_safety_doc)]
3737
#![allow(clippy::eq_op)]
38+
#![allow(clippy::identity_op)]
3839

3940
pub use paste::paste;
4041

riscv/src/register/macros.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ macro_rules! clear_pmp {
498498
macro_rules! csr {
499499
($(#[$doc:meta])*
500500
$ty:ident,
501-
$mask:literal) => {
501+
$mask:expr) => {
502502
#[repr(C)]
503503
$(#[$doc])*
504504
#[derive(Clone, Copy, Debug, Eq, PartialEq)]

riscv/src/register/mtvec.rs

+82-29
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,103 @@
11
//! mtvec register
22
3-
/// mtvec register
4-
#[derive(Clone, Copy, Debug)]
5-
pub struct Mtvec {
6-
bits: usize,
3+
use crate::result::{Error, Result};
4+
5+
const MASK: usize = usize::MAX;
6+
const TRAP_MASK: usize = 0b11;
7+
8+
read_write_csr! {
9+
/// mtvec register
10+
Mtvec: 0x305,
11+
mask: MASK,
12+
}
13+
14+
csr_field_enum! {
15+
/// Trap mode
16+
TrapMode {
17+
default: Direct,
18+
Direct = 0,
19+
Vectored = 1,
20+
}
721
}
822

9-
/// Trap mode
10-
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
11-
pub enum TrapMode {
12-
Direct = 0,
13-
Vectored = 1,
23+
read_write_csr_field! {
24+
Mtvec,
25+
/// Accesses the trap-vector mode.
26+
trap_mode,
27+
TrapMode: [0:1],
1428
}
1529

1630
impl Mtvec {
17-
/// Returns the contents of the register as raw bits
31+
/// Returns the trap-vector base-address
1832
#[inline]
19-
pub fn bits(&self) -> usize {
20-
self.bits
33+
pub const fn address(&self) -> usize {
34+
self.bits & !TRAP_MASK
2135
}
2236

23-
/// Returns the trap-vector base-address
37+
/// Sets the trap-vector base-address.
38+
///
39+
/// # Note
40+
///
41+
/// Panics if the address is not aligned to 4-bytes.
2442
#[inline]
25-
pub fn address(&self) -> usize {
26-
self.bits - (self.bits & 0b11)
43+
pub fn set_address(&mut self, address: usize) {
44+
self.try_set_address(address).unwrap();
2745
}
2846

29-
/// Returns the trap-vector mode
47+
/// Attempts to set the trap-vector base-address.
48+
///
49+
/// # Note
50+
///
51+
/// Returns an error if the address is not aligned to 4-bytes.
3052
#[inline]
31-
pub fn trap_mode(&self) -> Option<TrapMode> {
32-
let mode = self.bits & 0b11;
33-
match mode {
34-
0 => Some(TrapMode::Direct),
35-
1 => Some(TrapMode::Vectored),
36-
_ => None,
53+
pub fn try_set_address(&mut self, address: usize) -> Result<()> {
54+
// check for four-byte alignment
55+
if (address & TRAP_MASK) != 0 {
56+
Err(Error::InvalidFieldVariant {
57+
field: "mtvec::address",
58+
value: address,
59+
})
60+
} else {
61+
self.bits = address | (self.bits & TRAP_MASK);
62+
Ok(())
3763
}
3864
}
3965
}
4066

41-
read_csr_as!(Mtvec, 0x305);
67+
#[cfg(test)]
68+
mod tests {
69+
use super::*;
70+
71+
#[test]
72+
fn test_mtvec() {
73+
let mut m = Mtvec::from_bits(0);
74+
75+
(1..=usize::BITS)
76+
.map(|r| (((1u128 << r) - 1) as usize) & !TRAP_MASK)
77+
.for_each(|address| {
78+
m.set_address(address);
79+
assert_eq!(m.address(), address);
4280

43-
write_csr!(0x305);
81+
assert_eq!(m.try_set_address(address), Ok(()));
82+
assert_eq!(m.address(), address);
83+
});
4484

45-
/// Writes the CSR
46-
#[inline]
47-
pub unsafe fn write(addr: usize, mode: TrapMode) {
48-
let bits = addr + mode as usize;
49-
_write(bits);
85+
(1..=usize::BITS)
86+
.filter_map(|r| match ((1u128 << r) - 1) as usize {
87+
addr if (addr & TRAP_MASK) != 0 => Some(addr),
88+
_ => None,
89+
})
90+
.for_each(|address| {
91+
assert_eq!(
92+
m.try_set_address(address),
93+
Err(Error::InvalidFieldVariant {
94+
field: "mtvec::address",
95+
value: address,
96+
})
97+
);
98+
});
99+
100+
test_csr_field!(m, trap_mode: TrapMode::Direct);
101+
test_csr_field!(m, trap_mode: TrapMode::Vectored);
102+
}
50103
}

0 commit comments

Comments
 (0)