Skip to content

Commit b584859

Browse files
Merge pull request #261 from rmsyn/riscv/scause-csr-macro
riscv: define `scause` CSR with macro helpers
2 parents c5a8b24 + b2b533e commit b584859

File tree

2 files changed

+94
-25
lines changed

2 files changed

+94
-25
lines changed

riscv/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
3333
- Use CSR helper macros to define `mtvendorid` register
3434
- Use CSR helper macros to define `satp` register
3535
- Use CSR helper macros to define `pmpcfgx` field types
36+
- Use CSR helper macros to define `scause` field types
3637

3738
## [v0.12.1] - 2024-10-20
3839

riscv/src/register/scause.rs

Lines changed: 93 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,47 @@
33
pub use crate::interrupt::Trap;
44
pub use riscv_pac::{CoreInterruptNumber, ExceptionNumber, InterruptNumber}; // re-export useful riscv-pac traits
55

6-
/// scause register
7-
#[derive(Clone, Copy)]
8-
pub struct Scause {
9-
bits: usize,
6+
read_write_csr! {
7+
/// scause register
8+
Scause: 0x142,
9+
mask: usize::MAX,
1010
}
1111

12-
impl Scause {
13-
/// Returns the contents of the register as raw bits
14-
#[inline]
15-
pub fn bits(&self) -> usize {
16-
self.bits
17-
}
12+
#[cfg(target_arch = "riscv32")]
13+
read_write_csr_field! {
14+
Scause,
15+
/// Returns the type of the trap:
16+
///
17+
/// - `true`: an interrupt caused the trap
18+
/// - `false`: an exception caused the trap
19+
interrupt: 31,
20+
}
21+
22+
#[cfg(not(target_arch = "riscv32"))]
23+
read_write_csr_field! {
24+
Scause,
25+
/// Returns the type of the trap:
26+
///
27+
/// - `true`: an interrupt caused the trap
28+
/// - `false`: an exception caused the trap
29+
interrupt: 63,
30+
}
1831

32+
#[cfg(target_arch = "riscv32")]
33+
read_write_csr_field! {
34+
Scause,
1935
/// Returns the code field
20-
#[inline]
21-
pub fn code(&self) -> usize {
22-
self.bits & !(1 << (usize::BITS as usize - 1))
23-
}
36+
code: [0:30],
37+
}
38+
39+
#[cfg(not(target_arch = "riscv32"))]
40+
read_write_csr_field! {
41+
Scause,
42+
/// Returns the code field
43+
code: [0:62],
44+
}
2445

46+
impl Scause {
2547
/// Returns the trap cause represented by this register.
2648
///
2749
/// # Note
@@ -40,25 +62,16 @@ impl Scause {
4062
/// Is trap cause an interrupt.
4163
#[inline]
4264
pub fn is_interrupt(&self) -> bool {
43-
self.bits & (1 << (usize::BITS as usize - 1)) != 0
65+
self.interrupt()
4466
}
4567

4668
/// Is trap cause an exception.
4769
#[inline]
4870
pub fn is_exception(&self) -> bool {
49-
!self.is_interrupt()
71+
!self.interrupt()
5072
}
5173
}
5274

53-
read_csr_as!(Scause, 0x142);
54-
write_csr!(0x142);
55-
56-
/// Writes the CSR
57-
#[inline]
58-
pub unsafe fn write(bits: usize) {
59-
_write(bits)
60-
}
61-
6275
/// Set supervisor cause register to corresponding cause.
6376
#[inline]
6477
pub unsafe fn set<I: CoreInterruptNumber, E: ExceptionNumber>(cause: Trap<I, E>) {
@@ -70,3 +83,58 @@ pub unsafe fn set<I: CoreInterruptNumber, E: ExceptionNumber>(cause: Trap<I, E>)
7083
};
7184
_write(bits);
7285
}
86+
87+
#[cfg(test)]
88+
mod tests {
89+
use super::*;
90+
91+
#[test]
92+
fn test_scause() {
93+
let new_code = 0;
94+
(1usize..=usize::BITS as usize)
95+
.map(|r| ((1u128 << r) - 1) as usize)
96+
.for_each(|raw| {
97+
let exp_interrupt = (raw >> (usize::BITS - 1)) != 0;
98+
let exp_code = raw & ((1usize << (usize::BITS - 1)) - 1);
99+
let exp_cause = if exp_interrupt {
100+
Trap::Interrupt(exp_code)
101+
} else {
102+
Trap::Exception(exp_code)
103+
};
104+
105+
let mut scause = Scause::from_bits(raw);
106+
107+
assert_eq!(scause.interrupt(), exp_interrupt);
108+
assert_eq!(scause.is_interrupt(), exp_interrupt);
109+
assert_eq!(scause.is_exception(), !exp_interrupt);
110+
111+
assert_eq!(scause.code(), exp_code);
112+
assert_eq!(scause.cause(), exp_cause);
113+
114+
scause.set_interrupt(!exp_interrupt);
115+
116+
assert_eq!(scause.is_interrupt(), !exp_interrupt);
117+
assert_eq!(scause.is_exception(), exp_interrupt);
118+
119+
scause.set_code(new_code);
120+
let new_cause = if scause.interrupt() {
121+
Trap::Interrupt(new_code)
122+
} else {
123+
Trap::Exception(new_code)
124+
};
125+
126+
assert_eq!(scause.code(), new_code);
127+
assert_eq!(scause.cause(), new_cause);
128+
129+
scause.set_code(exp_code);
130+
let exp_cause = if scause.interrupt() {
131+
Trap::Interrupt(exp_code)
132+
} else {
133+
Trap::Exception(exp_code)
134+
};
135+
136+
assert_eq!(scause.code(), exp_code);
137+
assert_eq!(scause.cause(), exp_cause);
138+
});
139+
}
140+
}

0 commit comments

Comments
 (0)