From 73e32c9f8c639da994b4bae219bc49f5224ef74b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Mon, 22 Sep 2025 16:05:05 +0200 Subject: [PATCH] Feature-gate trap-related code in riscv --- riscv-rt/CHANGELOG.md | 4 ++ riscv-rt/Cargo.toml | 4 +- riscv-rt/src/interrupts.rs | 2 +- riscv/CHANGELOG.md | 5 ++ riscv/Cargo.toml | 2 + riscv/macros/Cargo.toml | 4 ++ riscv/macros/src/lib.rs | 104 +++++++++++++++++++------------------ riscv/src/lib.rs | 11 ++++ 8 files changed, 83 insertions(+), 53 deletions(-) diff --git a/riscv-rt/CHANGELOG.md b/riscv-rt/CHANGELOG.md index 847d066b..920c9ae7 100644 --- a/riscv-rt/CHANGELOG.md +++ b/riscv-rt/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Changed + +- Adapted to new `riscv` version. + ## [v0.16.0] - 2025-09-08 ### Added diff --git a/riscv-rt/Cargo.toml b/riscv-rt/Cargo.toml index da9b550c..009227be 100644 --- a/riscv-rt/Cargo.toml +++ b/riscv-rt/Cargo.toml @@ -24,7 +24,7 @@ targets = [ riscv-target-parser = { path = "../riscv-target-parser", version = "0.1.2" } [dependencies] -riscv = { path = "../riscv", version = "0.15.0" } +riscv = { path = "../riscv", version = "0.15.0", features = ["rt"] } riscv-pac = { path = "../riscv-pac", version = "0.2.0" } riscv-rt-macros = { path = "macros", version = "0.6.0" } @@ -38,7 +38,7 @@ pre-init = [] post-init = [] s-mode = ["riscv-rt-macros/s-mode"] single-hart = [] -v-trap = ["riscv-rt-macros/v-trap"] +v-trap = ["riscv-rt-macros/v-trap", "riscv/rt-v-trap"] u-boot = ["riscv-rt-macros/u-boot", "single-hart"] no-interrupts = [] no-exceptions = [] diff --git a/riscv-rt/src/interrupts.rs b/riscv-rt/src/interrupts.rs index 44561f86..71b77014 100644 --- a/riscv-rt/src/interrupts.rs +++ b/riscv-rt/src/interrupts.rs @@ -17,10 +17,10 @@ //! you may need to opt out this module. To do so, activate the `no-interrupts` feature of the //! `riscv-rt` crate. -// In vectored mode, we also must provide a vector table #[riscv::pac_enum(unsafe CoreInterruptNumber)] #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[allow(dead_code)] // otherwise compiler complains about Interrupt not being used enum Interrupt { SupervisorSoft = 1, MachineSoft = 3, diff --git a/riscv/CHANGELOG.md b/riscv/CHANGELOG.md index 67a37179..2e2f3a93 100644 --- a/riscv/CHANGELOG.md +++ b/riscv/CHANGELOG.md @@ -11,6 +11,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Add `miselect` CSR - Improved assembly macro handling in asm.rs +- New `rt` and `rt-v-trap` features to opt-in `riscv-rt`-related code in `riscv::pac_enum` macro. + +# Changed + +- Now, `riscv::pac_enum` macro only includes trap-related code if `rt` or `rt-v-trap` features are enabled. ## [v0.15.0] - 2025-09-08 diff --git a/riscv/Cargo.toml b/riscv/Cargo.toml index 0cae7f10..945a1e94 100644 --- a/riscv/Cargo.toml +++ b/riscv/Cargo.toml @@ -23,6 +23,8 @@ targets = [ default = ["riscv-macros"] s-mode = [] critical-section-single-hart = ["critical-section/restore-state-bool"] +rt = ["riscv-macros/rt"] +rt-v-trap = ["rt", "riscv-macros/rt-v-trap"] [dependencies] critical-section = "1.2.0" diff --git a/riscv/macros/Cargo.toml b/riscv/macros/Cargo.toml index 43773c7a..749d8e5e 100644 --- a/riscv/macros/Cargo.toml +++ b/riscv/macros/Cargo.toml @@ -15,6 +15,10 @@ edition = "2021" [lib] proc-macro = true +[features] +rt = [] +rt-v-trap = ["rt"] + [dependencies] proc-macro2 = "1.0" quote = "1.0" diff --git a/riscv/macros/src/lib.rs b/riscv/macros/src/lib.rs index 5f4bf8f3..3192f1ad 100644 --- a/riscv/macros/src/lib.rs +++ b/riscv/macros/src/lib.rs @@ -11,6 +11,7 @@ use syn::{ }; /// Struct to represent a function parameter. +#[cfg(feature = "rt")] struct FunctionParam { /// Name of the parameter. param_name: TokenStream2, @@ -20,6 +21,7 @@ struct FunctionParam { /// Configuration parameters of a trap. It is useful to abstract the /// differences between exception handlers and core interrupt handlers. +#[cfg(feature = "rt")] struct TrapConfig { /// Name of the default handler (e.g., `DefaultHandler` for core interrupts). default_handler: TokenStream2, @@ -31,6 +33,7 @@ struct TrapConfig { handlers_array_name: TokenStream2, } +#[cfg(feature = "rt")] impl TrapConfig { /// Vector with all the input parameters expected when declaring extern handler functions fn extern_signature(&self) -> Vec { @@ -107,6 +110,7 @@ impl PacTrait { } /// For Exception or an Interrupt enums, it returns the trap configuration details. + #[cfg(feature = "rt")] fn trap_config(&self) -> Option { match self { Self::Exception => Some(TrapConfig { @@ -163,6 +167,7 @@ impl InterruptType { } /// Returns a token stream representing the name of the array of interrupt service routines + #[cfg(feature = "rt")] fn isr_array_name(&self) -> TokenStream2 { match self { Self::Core => quote!(__CORE_INTERRUPTS), @@ -171,6 +176,7 @@ impl InterruptType { } /// Returns a token stream representing the name of the interrupt dispatch function + #[cfg(feature = "rt")] fn dispatch_fn_name(&self) -> TokenStream2 { match self { Self::Core => quote!(_dispatch_core_interrupt), @@ -239,6 +245,7 @@ impl PacEnumItem { } /// Returns a vector of token streams representing the interrupt handler functions + #[cfg(feature = "rt")] fn handlers(&self, trap_config: &TrapConfig) -> Vec { let signature = trap_config.extern_signature(); self.numbers @@ -252,6 +259,7 @@ impl PacEnumItem { /// Returns a sorted vector of token streams representing all the elements of the interrupt array. /// If an interrupt number is not present in the enum, the corresponding element is `None`. /// Otherwise, it is `Some()`. + #[cfg(feature = "rt")] fn handlers_array(&self) -> Vec { let mut vectors = vec![]; for i in 0..=self.max_number { @@ -264,6 +272,7 @@ impl PacEnumItem { vectors } + #[cfg(feature = "rt-v-trap")] fn vector_table(&self) -> TokenStream2 { let align = match std::env::var("RISCV_MTVEC_ALIGN") { Ok(x) => x.parse::().ok(), @@ -280,7 +289,7 @@ impl PacEnumItem { }; let mut asm = format!( r#" -#[cfg(all(feature = "v-trap", any(target_arch = "riscv32", target_arch = "riscv64")))] +#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] core::arch::global_asm!(" .section .trap.vector, \"ax\" .global _vector_table @@ -328,8 +337,6 @@ core::arch::global_asm!(" let max_discriminant = self.max_number; let valid_matches = self.valid_matches(); - let is_core_interrupt = matches!(attr, PacTrait::Interrupt(InterruptType::Core)); - // Push the trait implementation res.push(quote! { unsafe impl riscv::#trait_name for #name { @@ -354,54 +361,51 @@ core::arch::global_asm!(" res.push(quote! { unsafe impl riscv::#marker_trait_name for #name {} }); } + #[cfg(feature = "rt")] if let Some(trap_config) = attr.trap_config() { - let default_handler = &trap_config.default_handler; - let extern_signature = trap_config.extern_signature(); - let handler_input = trap_config.handler_input(); - let array_signature = trap_config.array_signature(); - let dispatch_fn_name = &trap_config.dispatch_fn_name; - let dispatch_fn_args = &trap_config.dispatch_fn_signature(); - let vector_table = &trap_config.handlers_array_name; - - let handlers = self.handlers(&trap_config); - let interrupt_array = self.handlers_array(); - let cfg_v_trap = match is_core_interrupt { - true => Some(quote!(#[cfg(not(feature = "v-trap"))])), - false => None, - }; - - // Push the interrupt handler functions and the interrupt array - res.push(quote! { - #cfg_v_trap - extern "C" { - #(#handlers;)* + match attr { + #[cfg(feature = "rt-v-trap")] + PacTrait::Interrupt(InterruptType::Core) => { + res.push(self.vector_table()); } - - #cfg_v_trap - #[doc(hidden)] - #[no_mangle] - pub static #vector_table: [Option; #max_discriminant + 1] = [ - #(#interrupt_array),* - ]; - - #cfg_v_trap - #[inline] - #[no_mangle] - unsafe extern "C" fn #dispatch_fn_name(#(#dispatch_fn_args),*) { - extern "C" { - fn #default_handler(#(#extern_signature),*); - } - - match #vector_table.get(code) { - Some(Some(handler)) => handler(#(#handler_input),*), - _ => #default_handler(#(#handler_input),*), - } + _ => { + let default_handler = &trap_config.default_handler; + let extern_signature = trap_config.extern_signature(); + let handler_input = trap_config.handler_input(); + let array_signature = trap_config.array_signature(); + let dispatch_fn_name = &trap_config.dispatch_fn_name; + let dispatch_fn_args = &trap_config.dispatch_fn_signature(); + let vector_table = &trap_config.handlers_array_name; + + let handlers = self.handlers(&trap_config); + let interrupt_array = self.handlers_array(); + + res.push(quote! { + extern "C" { + #(#handlers;)* + } + + #[doc(hidden)] + #[no_mangle] + pub static #vector_table: [Option; #max_discriminant + 1] = [ + #(#interrupt_array),* + ]; + + #[inline] + #[no_mangle] + unsafe extern "C" fn #dispatch_fn_name(#(#dispatch_fn_args),*) { + extern "C" { + fn #default_handler(#(#extern_signature),*); + } + + match #vector_table.get(code) { + Some(Some(handler)) => handler(#(#handler_input),*), + _ => #default_handler(#(#handler_input),*), + } + } + }); } - }); - } - - if is_core_interrupt { - res.push(self.vector_table()); + } } res @@ -413,8 +417,8 @@ core::arch::global_asm!(" /// As these traits are unsafe, the macro must be called with the `unsafe` keyword followed by the trait name. /// In this way, we warn callers that they must comply with the requirements of the trait. /// -/// The trait name must be one of `ExceptionNumber`, `InterruptNumber`, `PriorityNumber`, or `HartIdNumber`. -/// Marker traits `CoreInterruptNumber` and `ExternalInterruptNumber` cannot be implemented using this macro. +/// The trait name must be one of `ExceptionNumber`, `CoreInterruptNumber`, `ExternalInterruptNumber`, +/// `PriorityNumber`, or `HartIdNumber`. /// /// # Safety /// diff --git a/riscv/src/lib.rs b/riscv/src/lib.rs index 838c7d9a..0704f75b 100644 --- a/riscv/src/lib.rs +++ b/riscv/src/lib.rs @@ -31,6 +31,17 @@ //! and may cause functional problems in systems where some interrupts must NOT be disabled //! or critical sections are managed as part of an RTOS. In these cases, you should use //! a target-specific implementation instead, typically provided by a HAL or RTOS crate. +//! +//! ## `rt` +//! +//! This feature enables code related to [`riscv-rt`](https://github.com/rust-embedded/riscv/tree/master/riscv-rt) +//! runtime support in the `riscv::pac_enum` macro. Namely, it enables the generation of +//! trap handler functions and dispatch functions. +//! +//! ## `rt-v-trap` +//! +//! This feature enables code related to vectored trap handling in addition to the `rt` feature. +//! Namely, it enables the generation of a vector table and the corresponding assembly code for core interrupts. #![no_std] #![allow(clippy::missing_safety_doc)]