Skip to content

Commit 1e71338

Browse files
committed
Use conditional dependencies in riscv-rt depending on base extension
1 parent 289206a commit 1e71338

File tree

6 files changed

+154
-114
lines changed

6 files changed

+154
-114
lines changed

riscv-rt/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ riscv-target-parser = { path = "../riscv-target-parser", version = "0.1.0" }
2525
[dependencies]
2626
riscv = { path = "../riscv", version = "0.12.0" }
2727
riscv-pac = { path = "../riscv-pac", version = "0.2.0" }
28-
riscv-rt-macros = { path = "macros", version = "0.2.2" }
28+
riscv-rt-macros = { path = "macros", version = "0.3.0" }
2929

3030
[dev-dependencies]
3131
panic-halt = "1.0.0"

riscv-rt/build.rs

+1-8
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,11 @@ fn main() {
2828
let cargo_flags = env::var("CARGO_ENCODED_RUSTFLAGS").unwrap();
2929

3030
if let Ok(target) = RiscvTarget::build(&target, &cargo_flags) {
31-
let width = target.width();
32-
if matches!(width, riscv_target_parser::Width::W128) {
33-
panic!("Unsupported RISC-V target: {width}");
34-
}
35-
if target.base_extension().is_none() {
36-
panic!("Unsupported RISC-V target: no base extension");
37-
}
3831
for flag in target.rustc_flags() {
3932
// Required until target_feature risc-v is stable and in-use
4033
println!("cargo:rustc-check-cfg=cfg({flag})");
4134
println!("cargo:rustc-cfg={flag}");
4235
}
43-
add_linker_script(width.into()).unwrap();
36+
add_linker_script(target.width().into()).unwrap();
4437
}
4538
}

riscv-rt/macros/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ keywords = ["riscv", "runtime", "startup"]
1010
license = "MIT OR Apache-2.0"
1111
name = "riscv-rt-macros"
1212
repository = "https://github.com/rust-embedded/riscv"
13-
version = "0.2.2"
13+
version = "0.3.0"
1414
edition = "2021"
1515

1616
[lib]

riscv-rt/macros/src/lib.rs

+122-88
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ extern crate proc_macro2;
66
extern crate quote;
77
extern crate syn;
88

9+
use std::vec;
10+
911
use proc_macro2::{Span, TokenStream as TokenStream2};
1012
use quote::quote;
1113
use syn::{
@@ -359,56 +361,60 @@ pub fn loop_global_asm(input: TokenStream) -> TokenStream {
359361

360362
#[derive(Clone, Copy, Debug)]
361363
enum RiscvArch {
362-
Rv32,
363-
Rv64,
364+
Rv32I,
365+
Rv32E,
366+
Rv64I,
367+
Rv64E,
368+
}
369+
370+
impl syn::parse::Parse for RiscvArch {
371+
fn parse(input: parse::ParseStream) -> syn::Result<Self> {
372+
let ident: syn::Ident = input.parse()?;
373+
match ident.to_string().as_str() {
374+
"rv32i" => Ok(Self::Rv32I),
375+
"rv32e" => Ok(Self::Rv32E),
376+
"rv64i" => Ok(Self::Rv64I),
377+
"rv64e" => Ok(Self::Rv64E),
378+
_ => Err(syn::Error::new(ident.span(), "Invalid RISC-V architecture")),
379+
}
380+
}
364381
}
365382

366383
impl RiscvArch {
367384
fn width(&self) -> usize {
368385
match self {
369-
Self::Rv32 => 4,
370-
Self::Rv64 => 8,
386+
Self::Rv32I | Self::Rv32E => 4,
387+
Self::Rv64I | Self::Rv64E => 8,
371388
}
372389
}
373390

374391
fn store(&self) -> &str {
375392
match self {
376-
Self::Rv32 => "sw",
377-
Self::Rv64 => "sd",
393+
Self::Rv32I | Self::Rv32E => "sw",
394+
Self::Rv64I | Self::Rv64E => "sd",
378395
}
379396
}
380397

381398
fn load(&self) -> &str {
382399
match self {
383-
Self::Rv32 => "lw",
384-
Self::Rv64 => "ld",
400+
Self::Rv32I | Self::Rv32E => "lw",
401+
Self::Rv64I | Self::Rv64E => "ld",
385402
}
386403
}
387-
}
388404

389-
/// Size of the trap frame (in number of registers)
390-
const TRAP_SIZE: usize = 16;
391-
392-
#[rustfmt::skip]
393-
/// List of the register names to be stored in the trap frame
394-
const TRAP_FRAME: [&str; TRAP_SIZE] = [
395-
"ra",
396-
"t0",
397-
"t1",
398-
"t2",
399-
"t3",
400-
"t4",
401-
"t5",
402-
"t6",
403-
"a0",
404-
"a1",
405-
"a2",
406-
"a3",
407-
"a4",
408-
"a5",
409-
"a6",
410-
"a7",
411-
];
405+
fn trap_frame(&self) -> Vec<&str> {
406+
match self {
407+
Self::Rv32I | Self::Rv64I => vec![
408+
"ra", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "a0", "a1", "a2", "a3", "a4", "a5",
409+
"a6", "a7",
410+
],
411+
Self::Rv32E => vec![
412+
"ra", "t0", "t1", "t2", "a0", "a1", "a2", "a3", "a4", "a5", "_r0", "_r1",
413+
],
414+
Self::Rv64E => vec!["ra", "t0", "t1", "t2", "a0", "a1", "a2", "a3", "a4", "a5"],
415+
}
416+
}
417+
}
412418

413419
/// Generate the assembly instructions to store the trap frame.
414420
///
@@ -421,11 +427,11 @@ const TRAP_FRAME: [&str; TRAP_SIZE] = [
421427
fn store_trap<T: FnMut(&str) -> bool>(arch: RiscvArch, mut filter: T) -> String {
422428
let width = arch.width();
423429
let store = arch.store();
424-
TRAP_FRAME
430+
arch.trap_frame()
425431
.iter()
426432
.enumerate()
427-
.filter(|(_, &reg)| filter(reg))
428-
.map(|(i, reg)| format!("{store} {reg}, {i}*{width}(sp)"))
433+
.filter(|(_, &reg)| !reg.starts_with('_') && filter(reg))
434+
.map(|(i, reg)| format!(" {store} {reg}, {i}*{width}(sp)"))
429435
.collect::<Vec<_>>()
430436
.join("\n")
431437
}
@@ -435,43 +441,27 @@ fn store_trap<T: FnMut(&str) -> bool>(arch: RiscvArch, mut filter: T) -> String
435441
fn load_trap(arch: RiscvArch) -> String {
436442
let width = arch.width();
437443
let load = arch.load();
438-
TRAP_FRAME
444+
arch.trap_frame()
439445
.iter()
440446
.enumerate()
441-
.map(|(i, reg)| format!("{load} {reg}, {i}*{width}(sp)"))
447+
.filter(|(_, &reg)| !reg.starts_with('_'))
448+
.map(|(i, reg)| format!(" {load} {reg}, {i}*{width}(sp)"))
442449
.collect::<Vec<_>>()
443450
.join("\n")
444451
}
445452

446-
/// Generates weak `_start_trap` function in assembly for RISCV-32 targets.
447-
///
448-
/// This implementation stores all registers in the trap frame and calls `_start_trap_rust`.
449-
/// The trap frame is allocated on the stack and deallocated after the call.
450-
#[proc_macro]
451-
pub fn weak_start_trap_riscv32(_input: TokenStream) -> TokenStream {
452-
weak_start_trap(RiscvArch::Rv32)
453-
}
454-
455-
/// Generates weak `_start_trap` function in assembly for RISCV-64 targets.
453+
/// Generates weak `_start_trap` function in assembly.
456454
///
457455
/// This implementation stores all registers in the trap frame and calls `_start_trap_rust`.
458456
/// The trap frame is allocated on the stack and deallocated after the call.
459457
#[proc_macro]
460-
pub fn weak_start_trap_riscv64(_input: TokenStream) -> TokenStream {
461-
weak_start_trap(RiscvArch::Rv64)
462-
}
458+
pub fn weak_start_trap(input: TokenStream) -> TokenStream {
459+
let arch = parse_macro_input!(input as RiscvArch);
463460

464-
/// Generates weak `_start_trap` function in assembly.
465-
///
466-
/// This implementation stores all registers in the trap frame and calls `_start_trap_rust`.
467-
/// The trap frame is allocated on the stack and deallocated after the call.
468-
///
469-
/// The `arch` parameter is used to determine the width of the registers.
470-
/// The macro also ensures that the trap frame size is 16-byte aligned.
471-
fn weak_start_trap(arch: RiscvArch) -> TokenStream {
472461
let width = arch.width();
462+
let trap_size = arch.trap_frame().len();
473463
// ensure we do not break that sp is 16-byte aligned
474-
if (TRAP_SIZE * width) % 16 != 0 {
464+
if (trap_size * width) % 16 != 0 {
475465
return parse::Error::new(Span::call_site(), "Trap frame size must be 16-byte aligned")
476466
.to_compile_error()
477467
.into();
@@ -491,40 +481,29 @@ core::arch::global_asm!(
491481
.align {width}
492482
.weak _start_trap
493483
_start_trap:
494-
addi sp, sp, - {TRAP_SIZE} * {width}
495-
{store}
484+
addi sp, sp, - {trap_size} * {width}
485+
{store}
496486
add a0, sp, zero
497487
jal ra, _start_trap_rust
498-
{load}
499-
addi sp, sp, {TRAP_SIZE} * {width}
488+
{load}
489+
addi sp, sp, {trap_size} * {width}
500490
{ret}
501491
");"#
502492
)
503493
.parse()
504494
.unwrap()
505495
}
506496

507-
/// Generates vectored interrupt trap functions in assembly for RISCV-32 targets.
508-
#[cfg(feature = "v-trap")]
509-
#[proc_macro]
510-
pub fn vectored_interrupt_trap_riscv32(_input: TokenStream) -> TokenStream {
511-
vectored_interrupt_trap(RiscvArch::Rv32)
512-
}
513-
514-
/// Generates vectored interrupt trap functions in assembly for RISCV-64 targets.
515497
#[cfg(feature = "v-trap")]
516498
#[proc_macro]
517-
pub fn vectored_interrupt_trap_riscv64(_input: TokenStream) -> TokenStream {
518-
vectored_interrupt_trap(RiscvArch::Rv64)
519-
}
520-
521-
#[cfg(feature = "v-trap")]
522499
/// Generates global '_start_DefaultHandler_trap' and '_continue_interrupt_trap' functions in assembly.
523500
/// The '_start_DefaultHandler_trap' function stores the trap frame partially (only register a0) and
524501
/// jumps to the interrupt handler. The '_continue_interrupt_trap' function stores the trap frame
525502
/// partially (all registers except a0), jumps to the interrupt handler, and restores the trap frame.
526-
fn vectored_interrupt_trap(arch: RiscvArch) -> TokenStream {
503+
pub fn vectored_interrupt_trap(input: TokenStream) -> TokenStream {
504+
let arch = parse_macro_input!(input as RiscvArch);
527505
let width = arch.width();
506+
let trap_size = arch.trap_frame().len();
528507
let store_start = store_trap(arch, |reg| reg == "a0");
529508
let store_continue = store_trap(arch, |reg| reg != "a0");
530509
let load = load_trap(arch);
@@ -542,17 +521,17 @@ core::arch::global_asm!(
542521
.align 4
543522
.global _start_DefaultHandler_trap
544523
_start_DefaultHandler_trap:
545-
addi sp, sp, -{TRAP_SIZE} * {width} // allocate space for trap frame
546-
{store_start} // store trap partially (only register a0)
524+
addi sp, sp, -{trap_size} * {width} // allocate space for trap frame
525+
{store_start} // store trap partially (only register a0)
547526
la a0, DefaultHandler // load interrupt handler address into a0
548527
549528
.align 4
550529
.global _continue_interrupt_trap
551530
_continue_interrupt_trap:
552-
{store_continue} // store trap partially (all registers except a0)
531+
{store_continue} // store trap partially (all registers except a0)
553532
jalr ra, a0, 0 // jump to corresponding interrupt handler (address stored in a0)
554-
{load} // restore trap frame
555-
addi sp, sp, {TRAP_SIZE} * {width} // deallocate space for trap frame
533+
{load} // restore trap frame
534+
addi sp, sp, {trap_size} * {width} // deallocate space for trap frame
556535
{ret} // return from interrupt
557536
");"#
558537
);
@@ -664,10 +643,64 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
664643
/// loop{};
665644
/// }
666645
/// ```
667-
pub fn core_interrupt_riscv32(args: TokenStream, input: TokenStream) -> TokenStream {
646+
pub fn core_interrupt_rv32i(args: TokenStream, input: TokenStream) -> TokenStream {
647+
let arch = match () {
648+
#[cfg(feature = "v-trap")]
649+
() => Some(RiscvArch::Rv32I),
650+
#[cfg(not(feature = "v-trap"))]
651+
() => None,
652+
};
653+
trap(args, input, RiscvPacItem::CoreInterrupt, arch)
654+
}
655+
656+
#[proc_macro_attribute]
657+
/// Attribute to declare a core interrupt handler.
658+
///
659+
/// The function must have the signature `[unsafe] fn() [-> !]`.
660+
///
661+
/// The argument of the macro must be a path to a variant of an enum that implements the `riscv_rt::CoreInterruptNumber` trait.
662+
///
663+
/// If the `v-trap` feature is enabled, this macro generates the corresponding interrupt trap handler in assembly.
664+
///
665+
/// # Example
666+
///
667+
/// ``` ignore,no_run
668+
/// #[riscv_rt::core_interrupt(riscv::interrupt::Interrupt::SupervisorSoft)]
669+
/// fn supervisor_soft() -> ! {
670+
/// loop{};
671+
/// }
672+
/// ```
673+
pub fn core_interrupt_rv32e(args: TokenStream, input: TokenStream) -> TokenStream {
674+
let arch = match () {
675+
#[cfg(feature = "v-trap")]
676+
() => Some(RiscvArch::Rv32E),
677+
#[cfg(not(feature = "v-trap"))]
678+
() => None,
679+
};
680+
trap(args, input, RiscvPacItem::CoreInterrupt, arch)
681+
}
682+
683+
#[proc_macro_attribute]
684+
/// Attribute to declare a core interrupt handler.
685+
///
686+
/// The function must have the signature `[unsafe] fn() [-> !]`.
687+
///
688+
/// The argument of the macro must be a path to a variant of an enum that implements the `riscv_rt::CoreInterruptNumber` trait.
689+
///
690+
/// If the `v-trap` feature is enabled, this macro generates the corresponding interrupt trap handler in assembly.
691+
///
692+
/// # Example
693+
///
694+
/// ``` ignore,no_run
695+
/// #[riscv_rt::core_interrupt(riscv::interrupt::Interrupt::SupervisorSoft)]
696+
/// fn supervisor_soft() -> ! {
697+
/// loop{};
698+
/// }
699+
/// ```
700+
pub fn core_interrupt_rv64i(args: TokenStream, input: TokenStream) -> TokenStream {
668701
let arch = match () {
669702
#[cfg(feature = "v-trap")]
670-
() => Some(RiscvArch::Rv32),
703+
() => Some(RiscvArch::Rv64I),
671704
#[cfg(not(feature = "v-trap"))]
672705
() => None,
673706
};
@@ -691,10 +724,10 @@ pub fn core_interrupt_riscv32(args: TokenStream, input: TokenStream) -> TokenStr
691724
/// loop{};
692725
/// }
693726
/// ```
694-
pub fn core_interrupt_riscv64(args: TokenStream, input: TokenStream) -> TokenStream {
727+
pub fn core_interrupt_rv64e(args: TokenStream, input: TokenStream) -> TokenStream {
695728
let arch = match () {
696729
#[cfg(feature = "v-trap")]
697-
() => Some(RiscvArch::Rv64),
730+
() => Some(RiscvArch::Rv64E),
698731
#[cfg(not(feature = "v-trap"))]
699732
() => None,
700733
};
@@ -784,6 +817,7 @@ fn trap(
784817
fn start_interrupt_trap(ident: &syn::Ident, arch: RiscvArch) -> proc_macro2::TokenStream {
785818
let interrupt = ident.to_string();
786819
let width = arch.width();
820+
let trap_size = arch.trap_frame().len();
787821
let store = store_trap(arch, |r| r == "a0");
788822

789823
let instructions = format!(
@@ -793,8 +827,8 @@ core::arch::global_asm!(
793827
.align 2
794828
.global _start_{interrupt}_trap
795829
_start_{interrupt}_trap:
796-
addi sp, sp, -{TRAP_SIZE} * {width} // allocate space for trap frame
797-
{store} // store trap partially (only register a0)
830+
addi sp, sp, -{trap_size} * {width} // allocate space for trap frame
831+
{store} // store trap partially (only register a0)
798832
la a0, {interrupt} // load interrupt handler address into a0
799833
j _continue_interrupt_trap // jump to common part of interrupt trap
800834
");"#

0 commit comments

Comments
 (0)