diff --git a/.gitignore b/.gitignore index b8d1054c..cb60d8be 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ Cargo.lock target/ +.idea/ .vscode/ .DS_Store diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 9c206869..de9def68 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -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 @@ -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 diff --git a/riscv/src/interrupt/machine.rs b/riscv/src/interrupt/machine.rs index 52212f1d..b8a54fb8 100644 --- a/riscv/src/interrupt/machine.rs +++ b/riscv/src/interrupt/machine.rs @@ -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}, @@ -123,6 +123,12 @@ pub unsafe fn enable_interrupt(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(interrupt: I) -> bool { + mip::read().is_pending(interrupt) +} + /// Disables interrupts globally in the current hart (machine mode). #[inline] pub fn disable() { diff --git a/riscv/src/interrupt/supervisor.rs b/riscv/src/interrupt/supervisor.rs index 8db43f98..33266f2c 100644 --- a/riscv/src/interrupt/supervisor.rs +++ b/riscv/src/interrupt/supervisor.rs @@ -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}, @@ -116,6 +116,12 @@ pub unsafe fn enable_interrupt(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(interrupt: I) -> bool { + sip::read().is_pending(interrupt) +} + /// Disables interrupts globally in the current hart (supervisor mode). #[inline] pub fn disable() { diff --git a/riscv/src/register/mip.rs b/riscv/src/register/mip.rs index bfcb8936..47985a5b 100644 --- a/riscv/src/register/mip.rs +++ b/riscv/src/register/mip.rs @@ -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, @@ -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, @@ -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, @@ -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(&self, interrupt: I) -> bool { + bf_extract(self.bits, interrupt.number(), 1) != 0 + } +} + set!(0x344); clear!(0x344); @@ -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(interrupt: I) { + _clear(1 << interrupt.number()); +} + #[cfg(test)] mod tests { use super::*; diff --git a/riscv/src/register/sip.rs b/riscv/src/register/sip.rs index 4b8d7795..31fc4852 100644 --- a/riscv/src/register/sip.rs +++ b/riscv/src/register/sip.rs @@ -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, @@ -24,6 +27,14 @@ read_only_csr_field! { sext: 9, } +impl Sip { + /// Returns true when a given interrupt is pending. + #[inline] + pub fn is_pending(&self, interrupt: I) -> bool { + bf_extract(self.bits, interrupt.number(), 1) != 0 + } +} + set!(0x144); clear!(0x144); @@ -31,6 +42,18 @@ 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(interrupt: I) { + _clear(1 << interrupt.number()); +} + #[cfg(test)] mod tests { use super::*;