Skip to content

Commit 55578c3

Browse files
Merge pull request #331 from rust-embedded/riscv-interrupts
`riscv`: Use `riscv_pac::CoreInterruptNumber` in `xip` registers
2 parents ca86c48 + 335f3a7 commit 55578c3

File tree

6 files changed

+78
-11
lines changed

6 files changed

+78
-11
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
Cargo.lock
22
target/
33

4+
.idea/
45
.vscode/
56
.DS_Store

riscv/CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1111

1212
- New convenience `try_new` and `new` associated functions for `Mtvec` and `Stvec`.
1313
- New methods and functions for enabling core interrupts in the `mie` and `sie` registers
14-
using the `riscv_pac::CoreInterrupt` trait.
14+
using the `riscv_pac::CoreInterruptNumber` trait.
1515
- New `riscv::interrupt::{is_interrupt_enabled, disable_interrupt, enable_interrupt}` functions.
16+
- New methods and functions for dealing with pending interrupts in `mip` and `sip` registers
17+
using the `riscv_pac::CoreInterruptNumber` trait.
18+
- New `riscv::interrupt::is_interrupt_pending` function.
19+
- New `riscv::register::xip::clear_pending` atomic function for `mip` and `sip` registers.
20+
This function is marked as `unsafe`, as its availability depends both on the target chip
21+
and the target interrupt source.
1622

1723
### Changed
1824

@@ -24,6 +30,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
2430
### Removed
2531

2632
- Removed custom build script, as `cfg(riscv)` is no longer necessary.
33+
- All the fields of `Mip` and `Sip` CSR proxies are now read-only. This change is motivated
34+
to avoid clearing unwanted interrupts triggered between CSR reads and CSR writes.
2735

2836
## [v0.14.0] - 2025-06-10
2937

riscv/src/interrupt/machine.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
22
interrupt::Trap,
3-
register::{mcause, mepc, mie, mstatus},
3+
register::{mcause, mepc, mie, mip, mstatus},
44
};
55
use riscv_pac::{
66
result::{Error, Result},
@@ -123,6 +123,12 @@ pub unsafe fn enable_interrupt<I: CoreInterruptNumber>(interrupt: I) {
123123
mie::enable(interrupt);
124124
}
125125

126+
/// Checks if a specific core interrupt source is pending in the current hart (machine mode).
127+
#[inline]
128+
pub fn is_interrupt_pending<I: CoreInterruptNumber>(interrupt: I) -> bool {
129+
mip::read().is_pending(interrupt)
130+
}
131+
126132
/// Disables interrupts globally in the current hart (machine mode).
127133
#[inline]
128134
pub fn disable() {

riscv/src/interrupt/supervisor.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
22
interrupt::Trap,
3-
register::{scause, sepc, sie, sstatus},
3+
register::{scause, sepc, sie, sip, sstatus},
44
};
55
use riscv_pac::{
66
result::{Error, Result},
@@ -116,6 +116,12 @@ pub unsafe fn enable_interrupt<I: CoreInterruptNumber>(interrupt: I) {
116116
sie::enable(interrupt);
117117
}
118118

119+
/// Checks if a specific core interrupt source is pending in the current hart (supervisor mode).
120+
#[inline]
121+
pub fn is_interrupt_pending<I: CoreInterruptNumber>(interrupt: I) -> bool {
122+
sip::read().is_pending(interrupt)
123+
}
124+
119125
/// Disables interrupts globally in the current hart (supervisor mode).
120126
#[inline]
121127
pub fn disable() {

riscv/src/register/mip.rs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
//! mip register
22
3-
read_write_csr! {
3+
use crate::bits::bf_extract;
4+
use riscv_pac::CoreInterruptNumber;
5+
6+
read_only_csr! {
47
/// `mip` register
58
Mip: 0x344,
6-
mask: 0xaaa,
9+
mask: usize::MAX,
710
}
811

9-
read_write_csr_field! {
12+
read_only_csr_field! {
1013
Mip,
1114
/// Supervisor Software Interrupt Pending
1215
ssoft: 1,
@@ -18,7 +21,7 @@ read_only_csr_field! {
1821
msoft: 3,
1922
}
2023

21-
read_write_csr_field! {
24+
read_only_csr_field! {
2225
Mip,
2326
/// Supervisor Timer Interrupt Pending
2427
stimer: 5,
@@ -30,7 +33,7 @@ read_only_csr_field! {
3033
mtimer: 7,
3134
}
3235

33-
read_write_csr_field! {
36+
read_only_csr_field! {
3437
Mip,
3538
/// Supervisor External Interrupt Pending
3639
sext: 9,
@@ -42,6 +45,14 @@ read_only_csr_field! {
4245
mext: 11,
4346
}
4447

48+
impl Mip {
49+
/// Returns true when a given interrupt is pending.
50+
#[inline]
51+
pub fn is_pending<I: CoreInterruptNumber>(&self, interrupt: I) -> bool {
52+
bf_extract(self.bits, interrupt.number(), 1) != 0
53+
}
54+
}
55+
4556
set!(0x344);
4657
clear!(0x344);
4758

@@ -55,6 +66,18 @@ set_clear_csr!(
5566
/// Supervisor External Interrupt Pending
5667
, set_sext, clear_sext, 1 << 9);
5768

69+
/// Clear the pending state of a specific core interrupt source.
70+
///
71+
/// # Safety
72+
///
73+
/// Not all interrupt sources allow clearing of pending interrupts via the `mip` register.
74+
/// Instead, it may be necessary to perform an alternative action to clear the interrupt.
75+
/// Check the specification of your target chip for details.
76+
#[inline]
77+
pub unsafe fn clear_pending<I: CoreInterruptNumber>(interrupt: I) {
78+
_clear(1 << interrupt.number());
79+
}
80+
5881
#[cfg(test)]
5982
mod tests {
6083
use super::*;

riscv/src/register/sip.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
//! sip register
22
3-
read_write_csr! {
3+
use crate::bits::bf_extract;
4+
use riscv_pac::CoreInterruptNumber;
5+
6+
read_only_csr! {
47
/// sip register
58
Sip: 0x144,
6-
mask: 0x222,
9+
mask: usize::MAX,
710
}
811

9-
read_write_csr_field! {
12+
read_only_csr_field! {
1013
Sip,
1114
/// Supervisor Software Interrupt Pending
1215
ssoft: 1,
@@ -24,13 +27,33 @@ read_only_csr_field! {
2427
sext: 9,
2528
}
2629

30+
impl Sip {
31+
/// Returns true when a given interrupt is pending.
32+
#[inline]
33+
pub fn is_pending<I: CoreInterruptNumber>(&self, interrupt: I) -> bool {
34+
bf_extract(self.bits, interrupt.number(), 1) != 0
35+
}
36+
}
37+
2738
set!(0x144);
2839
clear!(0x144);
2940

3041
set_clear_csr!(
3142
/// Supervisor Software Interrupt Pending
3243
, set_ssoft, clear_ssoft, 1 << 1);
3344

45+
/// Clear the pending state of a specific core interrupt source.
46+
///
47+
/// # Safety
48+
///
49+
/// Not all interrupt sources allow clearing of pending interrupts via the `sip` register.
50+
/// Instead, it may be necessary to perform an alternative action to clear the interrupt.
51+
/// Check the specification of your specific core for details.
52+
#[inline]
53+
pub unsafe fn clear_pending<I: CoreInterruptNumber>(interrupt: I) {
54+
_clear(1 << interrupt.number());
55+
}
56+
3457
#[cfg(test)]
3558
mod tests {
3659
use super::*;

0 commit comments

Comments
 (0)