Skip to content

Commit 66fabc4

Browse files
0xllx0romancardenas
andcommitted
riscv: add the mvien + mvienh CSR
Adds the `mvien` + `mvienh` CSR to represent the `Machine Virtual Interrupt Enable` registers. Authored-by: Elle Rhumsaa <elle@weathered-steel.dev> Co-authored-by: Román Cárdenas Rodríguez <rcardenas.rod@gmail.com>
1 parent bedbc41 commit 66fabc4

File tree

5 files changed

+280
-1
lines changed

5 files changed

+280
-1
lines changed

riscv/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1313
- Add `miselect` CSR
1414
- Improved assembly macro handling in asm.rs
1515
- New `rt` and `rt-v-trap` features to opt-in `riscv-rt`-related code in `riscv::pac_enum` macro.
16+
- Add `mvien` + `mvienh` CSR
1617

1718
# Changed
1819

riscv/src/register.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ pub mod mscratch;
9191
pub mod mtinst;
9292
pub mod mtval;
9393
pub mod mtval2;
94+
pub mod mvien;
95+
#[cfg(any(test, target_arch = "riscv32"))]
96+
pub mod mvienh;
9497

9598
// Machine Protection and Translation
9699
mod pmpcfgx;

riscv/src/register/mvien.rs

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
//! mvien register
2+
3+
use crate::bits::{bf_extract, bf_insert};
4+
use riscv_pac::result::{Error, Result};
5+
use riscv_pac::InterruptNumber;
6+
7+
#[cfg(target_arch = "riscv32")]
8+
const MASK: usize = 0xffff_e222;
9+
#[cfg(not(target_arch = "riscv32"))]
10+
const MASK: usize = 0xffff_ffff_ffff_e222;
11+
12+
read_write_csr! {
13+
/// `mvien` register
14+
Mvien: 0x308,
15+
mask: MASK,
16+
}
17+
18+
read_write_csr_field! {
19+
Mvien,
20+
/// Alias of `mie.SSIE`
21+
ssoft: 1,
22+
}
23+
24+
read_write_csr_field! {
25+
Mvien,
26+
/// Alias of `mie.STIE`
27+
stimer: 5,
28+
}
29+
30+
read_write_csr_field! {
31+
Mvien,
32+
/// Alias of `mie.SEIE`
33+
sext: 9,
34+
}
35+
36+
impl Mvien {
37+
/// Represents the minimum interrupt of the unlabelled virtual interrupt range.
38+
pub const MIN_INTERRUPT: usize = 13;
39+
/// Represents the maximum interrupt of the unlabelled virtual interrupt range.
40+
#[cfg(target_arch = "riscv32")]
41+
pub const MAX_INTERRUPT: usize = 31;
42+
/// Represents the maximum interrupt of the unlabelled virtual interrupt range.
43+
#[cfg(not(target_arch = "riscv32"))]
44+
pub const MAX_INTERRUPT: usize = 63;
45+
46+
/// Gets whether the interrupt number is a valid virtual interrupt.
47+
#[inline]
48+
pub const fn is_valid_interrupt(int: usize) -> bool {
49+
matches!(int, 1 | 5 | 9 | Self::MIN_INTERRUPT..=Self::MAX_INTERRUPT)
50+
}
51+
52+
/// Check if a specific core interrupt source is enabled.
53+
///
54+
/// Returns `Error` if the interrupt number is invalid.
55+
#[inline]
56+
pub fn is_enabled<I: InterruptNumber>(&self, interrupt: I) -> bool {
57+
let n = interrupt.number();
58+
59+
Self::is_valid_interrupt(n) && bf_extract(self.bits, n, 1) != 0
60+
}
61+
62+
/// Enable a specific core interrupt source.
63+
///
64+
/// Returns `Error` if the interrupt number is invalid.
65+
#[inline]
66+
pub fn enable<I: InterruptNumber>(&mut self, interrupt: I) -> Result<()> {
67+
let n = interrupt.number();
68+
69+
if Self::is_valid_interrupt(n) {
70+
self.bits = bf_insert(self.bits, n, 1, 1);
71+
Ok(())
72+
} else {
73+
Err(Error::InvalidVariant(n))
74+
}
75+
}
76+
77+
/// Disable a specific core interrupt source.
78+
///
79+
/// Returns `Error` if the interrupt number is invalid.
80+
#[inline]
81+
pub fn disable<I: InterruptNumber>(&mut self, interrupt: I) -> Result<()> {
82+
let n = interrupt.number();
83+
84+
if Self::is_valid_interrupt(n) {
85+
self.bits = bf_insert(self.bits, n, 1, 0);
86+
Ok(())
87+
} else {
88+
Err(Error::InvalidVariant(n))
89+
}
90+
}
91+
}
92+
93+
set!(0x308);
94+
clear!(0x308);
95+
96+
set_clear_csr!(
97+
/// Supervisor Software Interrupt Enable
98+
, set_ssoft, clear_ssoft, 1 << 1);
99+
set_clear_csr!(
100+
/// Supervisor Timer Interrupt Enable
101+
, set_stimer, clear_stimer, 1 << 5);
102+
set_clear_csr!(
103+
/// Supervisor External Interrupt Enable
104+
, set_sext, clear_sext, 1 << 9);
105+
106+
read_composite_csr!(super::mvienh::read().bits(), read().bits());
107+
108+
#[cfg(test)]
109+
mod tests {
110+
use super::*;
111+
112+
/// Represents a custom set of virtual interrupts.
113+
///
114+
/// NOTE: a real implementation may want to enumerate the valid virtual interrupt variants.
115+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
116+
pub struct VirtualInterrupt(usize);
117+
118+
/// SAFETY: `VirtualInterrupt` represents the virtual RISC-V interrupts
119+
unsafe impl InterruptNumber for VirtualInterrupt {
120+
const MAX_INTERRUPT_NUMBER: usize = Mvien::MAX_INTERRUPT;
121+
122+
#[inline]
123+
fn number(self) -> usize {
124+
self.0
125+
}
126+
127+
#[inline]
128+
fn from_number(value: usize) -> Result<Self> {
129+
if Mvien::is_valid_interrupt(value) {
130+
Ok(Self(value))
131+
} else {
132+
Err(Error::InvalidVariant(value))
133+
}
134+
}
135+
}
136+
137+
#[test]
138+
fn test_mvien() {
139+
let mut m = Mvien::from_bits(0);
140+
141+
test_csr_field!(m, ssoft);
142+
test_csr_field!(m, stimer);
143+
test_csr_field!(m, sext);
144+
145+
(0..=VirtualInterrupt::MAX_INTERRUPT_NUMBER)
146+
.filter_map(|n| VirtualInterrupt::from_number(n).ok())
147+
.for_each(|int| {
148+
assert!(!m.is_enabled(int));
149+
150+
assert!(m.enable(int).is_ok());
151+
assert!(m.is_enabled(int));
152+
153+
assert!(m.disable(int).is_ok());
154+
assert!(!m.is_enabled(int));
155+
});
156+
}
157+
}

riscv/src/register/mvienh.rs

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
//! mvienh register
2+
3+
use crate::bits::{bf_extract, bf_insert};
4+
use riscv_pac::result::{Error, Result};
5+
use riscv_pac::InterruptNumber;
6+
7+
read_write_csr! {
8+
/// `mvienh` register
9+
Mvienh: 0x318,
10+
mask: 0xffff_ffff,
11+
}
12+
13+
set!(0x318);
14+
clear!(0x318);
15+
16+
impl Mvienh {
17+
/// Represents the value to shift interrupt numbers to their relative value.
18+
pub const INTERRUPT_SHIFT: usize = 32;
19+
/// Represents the minimum interrupt of the unlabelled virtual interrupt range.
20+
pub const MIN_INTERRUPT: usize = 32;
21+
/// Represents the maximum interrupt of the unlabelled virtual interrupt range.
22+
pub const MAX_INTERRUPT: usize = 63;
23+
24+
/// Gets whether the interrupt number is a valid virtual interrupt.
25+
#[inline]
26+
pub const fn is_valid_interrupt(int: usize) -> bool {
27+
matches!(int, Self::MIN_INTERRUPT..=Self::MAX_INTERRUPT)
28+
}
29+
30+
/// Shifts the high-order interrupt number bits down to their relative value.
31+
#[inline]
32+
pub const fn shift_interrupt(int: usize) -> usize {
33+
int.saturating_sub(Self::INTERRUPT_SHIFT)
34+
}
35+
36+
/// Check if a specific core interrupt source is enabled.
37+
///
38+
/// Returns `Error` if the interrupt number is invalid.
39+
#[inline]
40+
pub fn is_enabled<I: InterruptNumber>(&self, interrupt: I) -> bool {
41+
let n = interrupt.number();
42+
43+
Self::is_valid_interrupt(n) && bf_extract(self.bits, Self::shift_interrupt(n), 1) != 0
44+
}
45+
46+
/// Enable a specific core interrupt source.
47+
#[inline]
48+
pub fn enable<I: InterruptNumber>(&mut self, interrupt: I) -> Result<()> {
49+
let n = interrupt.number();
50+
51+
if Self::is_valid_interrupt(n) {
52+
self.bits = bf_insert(self.bits, Self::shift_interrupt(n), 1, 1);
53+
Ok(())
54+
} else {
55+
Err(Error::InvalidVariant(n))
56+
}
57+
}
58+
59+
/// Disable a specific core interrupt source.
60+
#[inline]
61+
pub fn disable<I: InterruptNumber>(&mut self, interrupt: I) -> Result<()> {
62+
let n = interrupt.number();
63+
64+
if Self::is_valid_interrupt(n) {
65+
self.bits = bf_insert(self.bits, Self::shift_interrupt(n), 1, 0);
66+
Ok(())
67+
} else {
68+
Err(Error::InvalidVariant(n))
69+
}
70+
}
71+
}
72+
73+
#[cfg(test)]
74+
mod tests {
75+
use super::*;
76+
77+
/// Represents a custom set of virtual interrupts.
78+
///
79+
/// NOTE: a real implementation may want to enumerate the valid virtual interrupt variants.
80+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
81+
pub struct VirtualInterrupt(usize);
82+
83+
/// SAFETY: `VirtualInterrupt` represents the virtual RISC-V interrupts
84+
unsafe impl InterruptNumber for VirtualInterrupt {
85+
const MAX_INTERRUPT_NUMBER: usize = Mvienh::MAX_INTERRUPT;
86+
87+
#[inline]
88+
fn number(self) -> usize {
89+
self.0
90+
}
91+
92+
#[inline]
93+
fn from_number(value: usize) -> Result<Self> {
94+
if Mvienh::is_valid_interrupt(value) {
95+
Ok(Self(value))
96+
} else {
97+
Err(Error::InvalidVariant(value))
98+
}
99+
}
100+
}
101+
102+
#[test]
103+
fn test_mvienh() {
104+
let mut m = Mvienh::from_bits(0);
105+
106+
(Mvienh::MIN_INTERRUPT..=Mvienh::MAX_INTERRUPT)
107+
.filter_map(|n| VirtualInterrupt::from_number(n).ok())
108+
.for_each(|int| {
109+
assert!(!m.is_enabled(int));
110+
111+
assert!(m.enable(int).is_ok());
112+
assert!(m.is_enabled(int));
113+
114+
assert!(m.disable(int).is_ok());
115+
assert!(!m.is_enabled(int));
116+
});
117+
}
118+
}

typos.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
[default]
2-
extend-ignore-re = ["[Ss][Ii][Ee]", "[Ss][Xx][Ll]", "[.]?useed[.,:]?"]
2+
extend-ignore-re = ["[Ss][Ii][Ee]", "[Ss][Xx][Ll]", "[.]?useed[.,:]?", "[Ss][Tt][Ii][Pp]"]

0 commit comments

Comments
 (0)