Skip to content
Open
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
4 changes: 4 additions & 0 deletions riscv-rt/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions riscv-rt/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }

Expand All @@ -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 = []
Expand Down
2 changes: 1 addition & 1 deletion riscv-rt/src/interrupts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
5 changes: 5 additions & 0 deletions riscv/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 2 additions & 0 deletions riscv/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions riscv/macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ edition = "2021"
[lib]
proc-macro = true

[features]
rt = []
rt-v-trap = ["rt"]

[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
Expand Down
104 changes: 54 additions & 50 deletions riscv/macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use syn::{
};

/// Struct to represent a function parameter.
#[cfg(feature = "rt")]
struct FunctionParam {
/// Name of the parameter.
param_name: TokenStream2,
Expand All @@ -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,
Expand All @@ -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<TokenStream2> {
Expand Down Expand Up @@ -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<TrapConfig> {
match self {
Self::Exception => Some(TrapConfig {
Expand Down Expand Up @@ -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),
Expand All @@ -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),
Expand Down Expand Up @@ -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<TokenStream2> {
let signature = trap_config.extern_signature();
self.numbers
Expand All @@ -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(<interrupt_handler>)`.
#[cfg(feature = "rt")]
fn handlers_array(&self) -> Vec<TokenStream2> {
let mut vectors = vec![];
for i in 0..=self.max_number {
Expand All @@ -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::<u32>().ok(),
Expand All @@ -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
Expand Down Expand Up @@ -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 {
Expand All @@ -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<unsafe extern "C" fn(#(#array_signature),*)>; #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<unsafe extern "C" fn(#(#array_signature),*)>; #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
Expand All @@ -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
///
Expand Down
11 changes: 11 additions & 0 deletions riscv/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
Loading