@@ -6,6 +6,8 @@ extern crate proc_macro2;
66extern crate quote;
77extern crate syn;
88
9+ use std:: vec;
10+
911use proc_macro2:: { Span , TokenStream as TokenStream2 } ;
1012use quote:: quote;
1113use syn:: {
@@ -359,56 +361,60 @@ pub fn loop_global_asm(input: TokenStream) -> TokenStream {
359361
360362#[ derive( Clone , Copy , Debug ) ]
361363enum 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
366383impl 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] = [
421427fn 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
435441fn 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(
784817fn 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