Skip to content

riscv: Use riscv_pac::CoreInterruptNumber in xip registers #331

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
Cargo.lock
target/

.idea/
.vscode/
.DS_Store
10 changes: 9 additions & 1 deletion riscv/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

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

### Changed

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

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

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

Expand Down
8 changes: 7 additions & 1 deletion riscv/src/interrupt/machine.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
interrupt::Trap,
register::{mcause, mepc, mie, mstatus},
register::{mcause, mepc, mie, mip, mstatus},
};
use riscv_pac::{
result::{Error, Result},
Expand Down Expand Up @@ -123,6 +123,12 @@ pub unsafe fn enable_interrupt<I: CoreInterruptNumber>(interrupt: I) {
mie::enable(interrupt);
}

/// Checks if a specific core interrupt source is pending in the current hart (machine mode).
#[inline]
pub fn is_interrupt_pending<I: CoreInterruptNumber>(interrupt: I) -> bool {
mip::read().is_pending(interrupt)
}

/// Disables interrupts globally in the current hart (machine mode).
#[inline]
pub fn disable() {
Expand Down
8 changes: 7 additions & 1 deletion riscv/src/interrupt/supervisor.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
interrupt::Trap,
register::{scause, sepc, sie, sstatus},
register::{scause, sepc, sie, sip, sstatus},
};
use riscv_pac::{
result::{Error, Result},
Expand Down Expand Up @@ -116,6 +116,12 @@ pub unsafe fn enable_interrupt<I: CoreInterruptNumber>(interrupt: I) {
sie::enable(interrupt);
}

/// Checks if a specific core interrupt source is pending in the current hart (supervisor mode).
#[inline]
pub fn is_interrupt_pending<I: CoreInterruptNumber>(interrupt: I) -> bool {
sip::read().is_pending(interrupt)
}

/// Disables interrupts globally in the current hart (supervisor mode).
#[inline]
pub fn disable() {
Expand Down
33 changes: 28 additions & 5 deletions riscv/src/register/mip.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
//! mip register

read_write_csr! {
use crate::bits::bf_extract;
use riscv_pac::CoreInterruptNumber;

read_only_csr! {
/// `mip` register
Mip: 0x344,
mask: 0xaaa,
mask: usize::MAX,
}

read_write_csr_field! {
read_only_csr_field! {
Mip,
/// Supervisor Software Interrupt Pending
ssoft: 1,
Expand All @@ -18,7 +21,7 @@ read_only_csr_field! {
msoft: 3,
}

read_write_csr_field! {
read_only_csr_field! {
Mip,
/// Supervisor Timer Interrupt Pending
stimer: 5,
Expand All @@ -30,7 +33,7 @@ read_only_csr_field! {
mtimer: 7,
}

read_write_csr_field! {
read_only_csr_field! {
Mip,
/// Supervisor External Interrupt Pending
sext: 9,
Expand All @@ -42,6 +45,14 @@ read_only_csr_field! {
mext: 11,
}

impl Mip {
/// Returns true when a given interrupt is pending.
#[inline]
pub fn is_pending<I: CoreInterruptNumber>(&self, interrupt: I) -> bool {
bf_extract(self.bits, interrupt.number(), 1) != 0
}
}

set!(0x344);
clear!(0x344);

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

/// Clear the pending state of a specific core interrupt source.
///
/// # Safety
///
/// Not all interrupt sources allow clearing of pending interrupts via the `mip` register.
/// Instead, it may be necessary to perform an alternative action to clear the interrupt.
/// Check the specification of your target chip for details.
#[inline]
pub unsafe fn clear_pending<I: CoreInterruptNumber>(interrupt: I) {
_clear(1 << interrupt.number());
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
29 changes: 26 additions & 3 deletions riscv/src/register/sip.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
//! sip register

read_write_csr! {
use crate::bits::bf_extract;
use riscv_pac::CoreInterruptNumber;

read_only_csr! {
/// sip register
Sip: 0x144,
mask: 0x222,
mask: usize::MAX,
}

read_write_csr_field! {
read_only_csr_field! {
Sip,
/// Supervisor Software Interrupt Pending
ssoft: 1,
Expand All @@ -24,13 +27,33 @@ read_only_csr_field! {
sext: 9,
}

impl Sip {
/// Returns true when a given interrupt is pending.
#[inline]
pub fn is_pending<I: CoreInterruptNumber>(&self, interrupt: I) -> bool {
bf_extract(self.bits, interrupt.number(), 1) != 0
}
}

set!(0x144);
clear!(0x144);

set_clear_csr!(
/// Supervisor Software Interrupt Pending
, set_ssoft, clear_ssoft, 1 << 1);

/// Clear the pending state of a specific core interrupt source.
///
/// # Safety
///
/// Not all interrupt sources allow clearing of pending interrupts via the `sip` register.
/// Instead, it may be necessary to perform an alternative action to clear the interrupt.
/// Check the specification of your specific core for details.
#[inline]
pub unsafe fn clear_pending<I: CoreInterruptNumber>(interrupt: I) {
_clear(1 << interrupt.number());
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
Loading