From b1881e4dd57795acec74c4093bc8a59d16312786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Tue, 22 Jul 2025 08:52:49 +0200 Subject: [PATCH 1/2] Use riscv_pac::CoreInterruptNumber in xip registers --- .gitignore | 1 + riscv/CHANGELOG.md | 5 ++++- riscv/src/interrupt/machine.rs | 8 ++++++- riscv/src/interrupt/supervisor.rs | 8 ++++++- riscv/src/register/mip.rs | 36 ++++++++++++++++++++++++++++++- riscv/src/register/sip.rs | 36 ++++++++++++++++++++++++++++++- 6 files changed, 89 insertions(+), 5 deletions(-) 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..0e680250 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -11,8 +11,11 @@ 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. ### Changed 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..8a9bc8f6 100644 --- a/riscv/src/register/mip.rs +++ b/riscv/src/register/mip.rs @@ -1,9 +1,12 @@ //! mip register +use crate::bits::{bf_extract, bf_insert}; +use riscv_pac::CoreInterruptNumber; + read_write_csr! { /// `mip` register Mip: 0x344, - mask: 0xaaa, + mask: usize::MAX, } read_write_csr_field! { @@ -42,6 +45,26 @@ 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 + } + + /// 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(&mut self, interrupt: I) { + self.bits = bf_insert(self.bits, interrupt.number(), 1, 0); + } +} + set!(0x344); clear!(0x344); @@ -55,6 +78,17 @@ 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. +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..491f059d 100644 --- a/riscv/src/register/sip.rs +++ b/riscv/src/register/sip.rs @@ -1,9 +1,12 @@ //! sip register +use crate::bits::{bf_extract, bf_insert}; +use riscv_pac::CoreInterruptNumber; + read_write_csr! { /// sip register Sip: 0x144, - mask: 0x222, + mask: usize::MAX, } read_write_csr_field! { @@ -24,6 +27,26 @@ 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 + } + + /// 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 target chip for details. + #[inline] + pub unsafe fn clear_pending(&mut self, interrupt: I) { + self.bits = bf_insert(self.bits, interrupt.number(), 1, 0); + } +} + set!(0x144); clear!(0x144); @@ -31,6 +54,17 @@ 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. +pub unsafe fn clear_pending(interrupt: I) { + _clear(1 << interrupt.number()); +} + #[cfg(test)] mod tests { use super::*; From 335f3a7b1c2f1114f666dccf0a252e600db00257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Fri, 25 Jul 2025 10:03:24 +0200 Subject: [PATCH 2/2] Make Xip fields read-only --- riscv/CHANGELOG.md | 5 +++++ riscv/src/register/mip.rs | 23 ++++++----------------- riscv/src/register/sip.rs | 19 ++++--------------- 3 files changed, 15 insertions(+), 32 deletions(-) diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 0e680250..de9def68 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -16,6 +16,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - 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 @@ -27,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/register/mip.rs b/riscv/src/register/mip.rs index 8a9bc8f6..47985a5b 100644 --- a/riscv/src/register/mip.rs +++ b/riscv/src/register/mip.rs @@ -1,15 +1,15 @@ //! mip register -use crate::bits::{bf_extract, bf_insert}; +use crate::bits::bf_extract; use riscv_pac::CoreInterruptNumber; -read_write_csr! { +read_only_csr! { /// `mip` register Mip: 0x344, mask: usize::MAX, } -read_write_csr_field! { +read_only_csr_field! { Mip, /// Supervisor Software Interrupt Pending ssoft: 1, @@ -21,7 +21,7 @@ read_only_csr_field! { msoft: 3, } -read_write_csr_field! { +read_only_csr_field! { Mip, /// Supervisor Timer Interrupt Pending stimer: 5, @@ -33,7 +33,7 @@ read_only_csr_field! { mtimer: 7, } -read_write_csr_field! { +read_only_csr_field! { Mip, /// Supervisor External Interrupt Pending sext: 9, @@ -51,18 +51,6 @@ impl Mip { pub fn is_pending(&self, interrupt: I) -> bool { bf_extract(self.bits, interrupt.number(), 1) != 0 } - - /// 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(&mut self, interrupt: I) { - self.bits = bf_insert(self.bits, interrupt.number(), 1, 0); - } } set!(0x344); @@ -85,6 +73,7 @@ set_clear_csr!( /// 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()); } diff --git a/riscv/src/register/sip.rs b/riscv/src/register/sip.rs index 491f059d..31fc4852 100644 --- a/riscv/src/register/sip.rs +++ b/riscv/src/register/sip.rs @@ -1,15 +1,15 @@ //! sip register -use crate::bits::{bf_extract, bf_insert}; +use crate::bits::bf_extract; use riscv_pac::CoreInterruptNumber; -read_write_csr! { +read_only_csr! { /// sip register Sip: 0x144, mask: usize::MAX, } -read_write_csr_field! { +read_only_csr_field! { Sip, /// Supervisor Software Interrupt Pending ssoft: 1, @@ -33,18 +33,6 @@ impl Sip { pub fn is_pending(&self, interrupt: I) -> bool { bf_extract(self.bits, interrupt.number(), 1) != 0 } - - /// 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 target chip for details. - #[inline] - pub unsafe fn clear_pending(&mut self, interrupt: I) { - self.bits = bf_insert(self.bits, interrupt.number(), 1, 0); - } } set!(0x144); @@ -61,6 +49,7 @@ set_clear_csr!( /// 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()); }