Skip to content

Commit fb14952

Browse files
committed
Use environment variables for finding out the base ISA on riscv_rt_macros
1 parent 1e71338 commit fb14952

File tree

4 files changed

+52
-145
lines changed

4 files changed

+52
-145
lines changed

riscv-rt/build.rs

+16-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// NOTE: Adapted from cortex-m/build.rs
22

3-
use riscv_target_parser::RiscvTarget;
3+
use riscv_target_parser::{Extension, RiscvTarget, Width};
44
use std::{env, fs, io, path::PathBuf};
55

66
fn add_linker_script(arch_width: u32) -> io::Result<()> {
@@ -28,11 +28,25 @@ 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+
let base = target.base_extension().expect("No base extension found");
33+
34+
// set environmet variable RISCV_RT_BASE_ISA to the width of the target
35+
// this is used in riscv_rt_macros to determine the base ISA
36+
let env_var = match (width, base) {
37+
(Width::W32, Extension::I) => "rv32i",
38+
(Width::W32, Extension::E) => "rv32e",
39+
(Width::W64, Extension::I) => "rv64i",
40+
(Width::W64, Extension::E) => "rv64e",
41+
_ => panic!("Unsupported target"),
42+
};
43+
println!("cargo:rustc-env=RISCV_RT_BASE_ISA={env_var}");
44+
3145
for flag in target.rustc_flags() {
3246
// Required until target_feature risc-v is stable and in-use
3347
println!("cargo:rustc-check-cfg=cfg({flag})");
3448
println!("cargo:rustc-cfg={flag}");
3549
}
36-
add_linker_script(target.width().into()).unwrap();
50+
add_linker_script(width.into()).unwrap();
3751
}
3852
}

riscv-rt/macros/src/lib.rs

+32-113
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
11
#![deny(warnings)]
22

3-
extern crate core;
4-
extern crate proc_macro;
5-
extern crate proc_macro2;
6-
extern crate quote;
7-
extern crate syn;
8-
9-
use std::vec;
10-
3+
use proc_macro::TokenStream;
114
use proc_macro2::{Span, TokenStream as TokenStream2};
125
use quote::quote;
136
use syn::{
@@ -18,8 +11,6 @@ use syn::{
1811
FnArg, ItemFn, LitInt, LitStr, PatType, Path, ReturnType, Token, Type, Visibility,
1912
};
2013

21-
use proc_macro::TokenStream;
22-
2314
/// Attribute to declare the entry point of the program
2415
///
2516
/// **IMPORTANT**: This attribute must appear exactly *once* in the dependency graph. Also, if you
@@ -367,7 +358,7 @@ enum RiscvArch {
367358
Rv64E,
368359
}
369360

370-
impl syn::parse::Parse for RiscvArch {
361+
impl Parse for RiscvArch {
371362
fn parse(input: parse::ParseStream) -> syn::Result<Self> {
372363
let ident: syn::Ident = input.parse()?;
373364
match ident.to_string().as_str() {
@@ -381,6 +372,17 @@ impl syn::parse::Parse for RiscvArch {
381372
}
382373

383374
impl RiscvArch {
375+
fn try_from_env() -> Option<Self> {
376+
let arch = std::env::var("RISCV_RT_BASE_ISA").ok()?;
377+
match arch.as_str() {
378+
"rv32i" => Some(Self::Rv32I),
379+
"rv32e" => Some(Self::Rv32E),
380+
"rv64i" => Some(Self::Rv64I),
381+
"rv64e" => Some(Self::Rv64E),
382+
_ => None,
383+
}
384+
}
385+
384386
fn width(&self) -> usize {
385387
match self {
386388
Self::Rv32I | Self::Rv32E => 4,
@@ -431,9 +433,9 @@ fn store_trap<T: FnMut(&str) -> bool>(arch: RiscvArch, mut filter: T) -> String
431433
.iter()
432434
.enumerate()
433435
.filter(|(_, &reg)| !reg.starts_with('_') && filter(reg))
434-
.map(|(i, reg)| format!(" {store} {reg}, {i}*{width}(sp)"))
436+
.map(|(i, reg)| format!("{store} {reg}, {i}*{width}(sp)"))
435437
.collect::<Vec<_>>()
436-
.join("\n")
438+
.join("\n ")
437439
}
438440

439441
/// Generate the assembly instructions to load the trap frame.
@@ -445,18 +447,18 @@ fn load_trap(arch: RiscvArch) -> String {
445447
.iter()
446448
.enumerate()
447449
.filter(|(_, &reg)| !reg.starts_with('_'))
448-
.map(|(i, reg)| format!(" {load} {reg}, {i}*{width}(sp)"))
450+
.map(|(i, reg)| format!("{load} {reg}, {i}*{width}(sp)"))
449451
.collect::<Vec<_>>()
450-
.join("\n")
452+
.join("\n ")
451453
}
452454

453455
/// Generates weak `_start_trap` function in assembly.
454456
///
455457
/// This implementation stores all registers in the trap frame and calls `_start_trap_rust`.
456458
/// The trap frame is allocated on the stack and deallocated after the call.
457459
#[proc_macro]
458-
pub fn weak_start_trap(input: TokenStream) -> TokenStream {
459-
let arch = parse_macro_input!(input as RiscvArch);
460+
pub fn weak_start_trap(_input: TokenStream) -> TokenStream {
461+
let arch = RiscvArch::try_from_env().unwrap();
460462

461463
let width = arch.width();
462464
let trap_size = arch.trap_frame().len();
@@ -482,10 +484,10 @@ core::arch::global_asm!(
482484
.weak _start_trap
483485
_start_trap:
484486
addi sp, sp, - {trap_size} * {width}
485-
{store}
487+
{store}
486488
add a0, sp, zero
487489
jal ra, _start_trap_rust
488-
{load}
490+
{load}
489491
addi sp, sp, {trap_size} * {width}
490492
{ret}
491493
");"#
@@ -500,8 +502,8 @@ _start_trap:
500502
/// The '_start_DefaultHandler_trap' function stores the trap frame partially (only register a0) and
501503
/// jumps to the interrupt handler. The '_continue_interrupt_trap' function stores the trap frame
502504
/// partially (all registers except a0), jumps to the interrupt handler, and restores the trap frame.
503-
pub fn vectored_interrupt_trap(input: TokenStream) -> TokenStream {
504-
let arch = parse_macro_input!(input as RiscvArch);
505+
pub fn vectored_interrupt_trap(_input: TokenStream) -> TokenStream {
506+
let arch = RiscvArch::try_from_env().unwrap();
505507
let width = arch.width();
506508
let trap_size = arch.trap_frame().len();
507509
let store_start = store_trap(arch, |reg| reg == "a0");
@@ -522,15 +524,15 @@ core::arch::global_asm!(
522524
.global _start_DefaultHandler_trap
523525
_start_DefaultHandler_trap:
524526
addi sp, sp, -{trap_size} * {width} // allocate space for trap frame
525-
{store_start} // store trap partially (only register a0)
527+
{store_start} // store trap partially (only register a0)
526528
la a0, DefaultHandler // load interrupt handler address into a0
527529
528530
.align 4
529531
.global _continue_interrupt_trap
530532
_continue_interrupt_trap:
531-
{store_continue} // store trap partially (all registers except a0)
533+
{store_continue} // store trap partially (all registers except a0)
532534
jalr ra, a0, 0 // jump to corresponding interrupt handler (address stored in a0)
533-
{load} // restore trap frame
535+
{load} // restore trap frame
534536
addi sp, sp, {trap_size} * {width} // deallocate space for trap frame
535537
{ret} // return from interrupt
536538
");"#
@@ -643,93 +645,11 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
643645
/// loop{};
644646
/// }
645647
/// ```
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 {
701-
let arch = match () {
702-
#[cfg(feature = "v-trap")]
703-
() => Some(RiscvArch::Rv64I),
704-
#[cfg(not(feature = "v-trap"))]
705-
() => None,
706-
};
707-
trap(args, input, RiscvPacItem::CoreInterrupt, arch)
708-
}
709-
710-
#[proc_macro_attribute]
711-
/// Attribute to declare a core interrupt handler.
712-
///
713-
/// The function must have the signature `[unsafe] fn() [-> !]`.
714-
///
715-
/// The argument of the macro must be a path to a variant of an enum that implements the `riscv_rt::CoreInterruptNumber` trait.
716-
///
717-
/// If the `v-trap` feature is enabled, this macro generates the corresponding interrupt trap handler in assembly.
718-
///
719-
/// # Example
720-
///
721-
/// ``` ignore,no_run
722-
/// #[riscv_rt::core_interrupt(riscv::interrupt::Interrupt::SupervisorSoft)]
723-
/// fn supervisor_soft() -> ! {
724-
/// loop{};
725-
/// }
726-
/// ```
727-
pub fn core_interrupt_rv64e(args: TokenStream, input: TokenStream) -> TokenStream {
728-
let arch = match () {
729-
#[cfg(feature = "v-trap")]
730-
() => Some(RiscvArch::Rv64E),
731-
#[cfg(not(feature = "v-trap"))]
732-
() => None,
648+
pub fn core_interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
649+
let arch = if cfg!(feature = "v-trap") {
650+
RiscvArch::try_from_env()
651+
} else {
652+
None
733653
};
734654
trap(args, input, RiscvPacItem::CoreInterrupt, arch)
735655
}
@@ -790,7 +710,6 @@ fn trap(
790710
Some(arch) => {
791711
let trap = start_interrupt_trap(int_ident, arch);
792712
quote! {
793-
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
794713
#trap
795714
}
796715
}
@@ -828,7 +747,7 @@ core::arch::global_asm!(
828747
.global _start_{interrupt}_trap
829748
_start_{interrupt}_trap:
830749
addi sp, sp, -{trap_size} * {width} // allocate space for trap frame
831-
{store} // store trap partially (only register a0)
750+
{store} // store trap partially (only register a0)
832751
la a0, {interrupt} // load interrupt handler address into a0
833752
j _continue_interrupt_trap // jump to common part of interrupt trap
834753
");"#

riscv-rt/src/asm.rs

+3-16
Original file line numberDiff line numberDiff line change
@@ -278,23 +278,10 @@ _pre_init_trap:
278278
j _pre_init_trap",
279279
);
280280

281-
#[cfg(all(target_arch = "riscv32", riscvi))]
282-
riscv_rt_macros::weak_start_trap!(rv32i);
283-
#[cfg(all(target_arch = "riscv32", riscve))]
284-
riscv_rt_macros::weak_start_trap!(rv32e);
285-
#[cfg(all(target_arch = "riscv64", riscvi))]
286-
riscv_rt_macros::weak_start_trap!(rv64i);
287-
#[cfg(all(target_arch = "riscv64", riscve))]
288-
riscv_rt_macros::weak_start_trap!(rv64e);
281+
riscv_rt_macros::weak_start_trap!();
289282

290-
#[cfg(all(target_arch = "riscv32", riscvi, feature = "v-trap"))]
291-
riscv_rt_macros::vectored_interrupt_trap!(rv32i);
292-
#[cfg(all(target_arch = "riscv32", riscve, feature = "v-trap"))]
293-
riscv_rt_macros::vectored_interrupt_trap!(rv32e);
294-
#[cfg(all(target_arch = "riscv64", riscvi, feature = "v-trap"))]
295-
riscv_rt_macros::vectored_interrupt_trap!(rv64i);
296-
#[cfg(all(target_arch = "riscv64", riscve, feature = "v-trap"))]
297-
riscv_rt_macros::vectored_interrupt_trap!(rv64e);
283+
#[cfg(feature = "v-trap")]
284+
riscv_rt_macros::vectored_interrupt_trap!();
298285

299286
#[rustfmt::skip]
300287
global_asm!(

riscv-rt/src/lib.rs

+1-14
Original file line numberDiff line numberDiff line change
@@ -547,21 +547,8 @@ use riscv::register::scause as xcause;
547547
#[cfg(not(feature = "s-mode"))]
548548
use riscv::register::mcause as xcause;
549549

550-
pub use riscv_rt_macros::{entry, exception, external_interrupt, pre_init};
551-
552550
pub use riscv_pac::*;
553-
554-
#[cfg(all(target_arch = "riscv32", riscve))]
555-
pub use riscv_rt_macros::core_interrupt_rv32e as core_interrupt;
556-
#[cfg(all(target_arch = "riscv32", riscvi))]
557-
pub use riscv_rt_macros::core_interrupt_rv32i as core_interrupt;
558-
#[cfg(all(target_arch = "riscv64", riscve))]
559-
pub use riscv_rt_macros::core_interrupt_rv64e as core_interrupt;
560-
#[cfg(any(
561-
all(target_arch = "riscv64", riscvi),
562-
not(any(target_arch = "riscv32", target_arch = "riscv64"))
563-
))]
564-
pub use riscv_rt_macros::core_interrupt_rv64i as core_interrupt;
551+
pub use riscv_rt_macros::{core_interrupt, entry, exception, external_interrupt, pre_init};
565552

566553
/// We export this static with an informative name so that if an application attempts to link
567554
/// two copies of riscv-rt together, linking will fail. We also declare a links key in

0 commit comments

Comments
 (0)