Skip to content

Commit

Permalink
Merge pull request #259 from ia0/align
Browse files Browse the repository at this point in the history
riscv-rt: Add RISCV_MTVEC_ALIGN to control the alignment of the vector table
  • Loading branch information
romancardenas authored Jan 25, 2025
2 parents b391a48 + 3e499c0 commit b771540
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 93 deletions.
3 changes: 2 additions & 1 deletion riscv-rt/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Changed

- Ensure the `.heap` section is 4-byte aligned
- Use `RISCV_MTVEC_ALIGN` to control the alignment constraint of the vector table.
- Ensure the `.heap` section is 4-byte aligned.
- Limit rustc cfg flags to `riscvi`, `riscvm`, `riscvf`, and `riscvd`.
- Temporary use of `RISCV_RT_LLVM_ARCH_PATCH` environment variable to include the
temporary patch required for avoid LLVM spurious errors.
Expand Down
7 changes: 7 additions & 0 deletions riscv-rt/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ fn main() {
// make sure that these env variables are not changed without notice.
println!("cargo:rerun-if-env-changed=RISCV_RT_BASE_ISA");
println!("cargo:rerun-if-env-changed=RISCV_RT_LLVM_ARCH_PATCH");
if env::var_os("CARGO_FEATURE_V_TRAP").is_some()
&& env::var_os("CARGO_FEATURE_NO_INTERRUPTS").is_none()
{
// This environment variable is used by the `#[riscv::pac_enum()]` call in
// `src/interrupts.rs` (when `v-trap` is enabled and `no-interrupts` disabled).
println!("cargo:rerun-if-env-changed=RISCV_MTVEC_ALIGN");
}

for flag in target.rustc_flags() {
// Required until target_feature risc-v is stable and in-use
Expand Down
105 changes: 16 additions & 89 deletions riscv-rt/src/interrupts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,97 +7,24 @@
//!
//! In vectored mode (i.e., `v-trap` feature enabled), interrupt dispatching is handled by hardware.
//! To support this mode, we provide inline assembly code that defines the interrupt vector table.
//! Since the alignment constraint of this vector table is implementation-specific, it can be
//! changed by setting the `RISCV_MTVEC_ALIGN` environment variable (the default is 4).
//!
//! # Note
//!
//! If your target has custom core interrupt sources, the target PAC might provide equivalent
//! code to adapt for the target needs. In this case, you may need to opt out this module.
//! To do so, activate the `no-interrupts` feature of the `riscv-rt` crate.
#[cfg(not(feature = "v-trap"))]
extern "C" {
fn SupervisorSoft();
fn MachineSoft();
fn SupervisorTimer();
fn MachineTimer();
fn SupervisorExternal();
fn MachineExternal();
}

/// Array with all the core interrupt handlers sorted according to their interrupt source code.
///
/// # Note
///
/// This array is necessary only in direct mode (i.e., `v-trap` feature disabled).
#[cfg(not(feature = "v-trap"))]
#[no_mangle]
pub static __CORE_INTERRUPTS: [Option<unsafe extern "C" fn()>; 12] = [
None,
Some(SupervisorSoft),
None,
Some(MachineSoft),
None,
Some(SupervisorTimer),
None,
Some(MachineTimer),
None,
Some(SupervisorExternal),
None,
Some(MachineExternal),
];

/// It calls the corresponding interrupt handler depending on the interrupt source code.
///
/// # Note
///
/// This function is only required in direct mode (i.e., `v-trap` feature disabled).
/// In vectored mode, interrupt handler dispatching is performed directly by hardware.
///
/// # Safety
///
/// This function must be called only from the [`crate::start_trap_rust`] function.
/// Do **NOT** call this function directly.
#[cfg(not(feature = "v-trap"))]
#[inline]
#[no_mangle]
pub unsafe extern "C" fn _dispatch_core_interrupt(code: usize) {
extern "C" {
fn DefaultHandler();
}
match __CORE_INTERRUPTS.get(code) {
Some(Some(handler)) => handler(),
_ => DefaultHandler(),
}
}
//! If your target has custom core interrupt sources, the target PAC might provide equivalent code
//! to adapt for the target needs (and is responsible for any alignment constraint). In this case,
//! 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
#[cfg(all(
any(target_arch = "riscv32", target_arch = "riscv64"),
feature = "v-trap"
))]
core::arch::global_asm!(
r#" .section .trap, "ax"
.weak _vector_table
.type _vector_table, @function
.option push
.balign 0x4 // TODO check if this is the correct alignment
.option norelax
.option norvc
_vector_table:
j _start_trap // Interrupt 0 is used for exceptions
j _start_SupervisorSoft_trap
j _start_DefaultHandler_trap // Interrupt 2 is reserved
j _start_MachineSoft_trap
j _start_DefaultHandler_trap // Interrupt 4 is reserved
j _start_SupervisorTimer_trap
j _start_DefaultHandler_trap // Interrupt 6 is reserved
j _start_MachineTimer_trap
j _start_DefaultHandler_trap // Interrupt 8 is reserved
j _start_SupervisorExternal_trap
j _start_DefaultHandler_trap // Interrupt 10 is reserved
j _start_MachineExternal_trap
.option pop"#
);
#[riscv::pac_enum(unsafe CoreInterruptNumber)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum Interrupt {
SupervisorSoft = 1,
MachineSoft = 3,
SupervisorTimer = 5,
MachineTimer = 7,
SupervisorExternal = 9,
MachineExternal = 11,
}
1 change: 1 addition & 0 deletions riscv/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Changed

- Use `RISCV_MTVEC_ALIGN` to control the alignment constraint of the vector table
- Simplify register macros with `cfg` field
- Align assembly functions with `cortex-m`
- Use CSR helper macros to define `marchid` register
Expand Down
28 changes: 25 additions & 3 deletions riscv/macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,20 @@ impl PacEnumItem {
}

fn vector_table(&self) -> TokenStream2 {
let mut asm = String::from(
let align = match std::env::var("RISCV_MTVEC_ALIGN") {
Ok(x) => x.parse::<u32>().ok(),
Err(std::env::VarError::NotPresent) => Some(4),
Err(std::env::VarError::NotUnicode(_)) => None,
};
let align = match align {
Some(x) if x.is_power_of_two() && 4 <= x => x,
_ => {
return quote!(compile_error!(
"RISCV_MTVEC_ALIGN is not a power of 2 (minimum 4)"
))
}
};
let mut asm = format!(
r#"
#[cfg(all(feature = "v-trap", any(target_arch = "riscv32", target_arch = "riscv64")))]
core::arch::global_asm!("
Expand All @@ -274,7 +287,7 @@ core::arch::global_asm!("
.type _vector_table, @function
.option push
.balign 0x4 // TODO check if this is the correct alignment
.balign {align}
.option norelax
.option norvc
Expand Down Expand Up @@ -315,6 +328,8 @@ 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 Down Expand Up @@ -350,19 +365,26 @@ core::arch::global_asm!("

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;)*
}

#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),*) {
Expand All @@ -378,7 +400,7 @@ core::arch::global_asm!("
});
}

if let PacTrait::Interrupt(InterruptType::Core) = attr {
if is_core_interrupt {
res.push(self.vector_table());
}

Expand Down

0 comments on commit b771540

Please sign in to comment.