@@ -6,6 +6,8 @@ extern crate proc_macro2;
6
6
extern crate quote;
7
7
extern crate syn;
8
8
9
+ use std:: vec;
10
+
9
11
use proc_macro2:: { Span , TokenStream as TokenStream2 } ;
10
12
use quote:: quote;
11
13
use syn:: {
@@ -359,56 +361,60 @@ pub fn loop_global_asm(input: TokenStream) -> TokenStream {
359
361
360
362
#[ derive( Clone , Copy , Debug ) ]
361
363
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
+ }
364
381
}
365
382
366
383
impl RiscvArch {
367
384
fn width ( & self ) -> usize {
368
385
match self {
369
- Self :: Rv32 => 4 ,
370
- Self :: Rv64 => 8 ,
386
+ Self :: Rv32I | Self :: Rv32E => 4 ,
387
+ Self :: Rv64I | Self :: Rv64E => 8 ,
371
388
}
372
389
}
373
390
374
391
fn store ( & self ) -> & str {
375
392
match self {
376
- Self :: Rv32 => "sw" ,
377
- Self :: Rv64 => "sd" ,
393
+ Self :: Rv32I | Self :: Rv32E => "sw" ,
394
+ Self :: Rv64I | Self :: Rv64E => "sd" ,
378
395
}
379
396
}
380
397
381
398
fn load ( & self ) -> & str {
382
399
match self {
383
- Self :: Rv32 => "lw" ,
384
- Self :: Rv64 => "ld" ,
400
+ Self :: Rv32I | Self :: Rv32E => "lw" ,
401
+ Self :: Rv64I | Self :: Rv64E => "ld" ,
385
402
}
386
403
}
387
- }
388
404
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
+ }
412
418
413
419
/// Generate the assembly instructions to store the trap frame.
414
420
///
@@ -421,11 +427,11 @@ const TRAP_FRAME: [&str; TRAP_SIZE] = [
421
427
fn store_trap < T : FnMut ( & str ) -> bool > ( arch : RiscvArch , mut filter : T ) -> String {
422
428
let width = arch. width ( ) ;
423
429
let store = arch. store ( ) ;
424
- TRAP_FRAME
430
+ arch . trap_frame ( )
425
431
. iter ( )
426
432
. 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)" ) )
429
435
. collect :: < Vec < _ > > ( )
430
436
. join ( "\n " )
431
437
}
@@ -435,43 +441,27 @@ fn store_trap<T: FnMut(&str) -> bool>(arch: RiscvArch, mut filter: T) -> String
435
441
fn load_trap ( arch : RiscvArch ) -> String {
436
442
let width = arch. width ( ) ;
437
443
let load = arch. load ( ) ;
438
- TRAP_FRAME
444
+ arch . trap_frame ( )
439
445
. iter ( )
440
446
. 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)" ) )
442
449
. collect :: < Vec < _ > > ( )
443
450
. join ( "\n " )
444
451
}
445
452
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.
456
454
///
457
455
/// This implementation stores all registers in the trap frame and calls `_start_trap_rust`.
458
456
/// The trap frame is allocated on the stack and deallocated after the call.
459
457
#[ 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 ) ;
463
460
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 {
472
461
let width = arch. width ( ) ;
462
+ let trap_size = arch. trap_frame ( ) . len ( ) ;
473
463
// 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 {
475
465
return parse:: Error :: new ( Span :: call_site ( ) , "Trap frame size must be 16-byte aligned" )
476
466
. to_compile_error ( )
477
467
. into ( ) ;
@@ -491,40 +481,29 @@ core::arch::global_asm!(
491
481
.align {width}
492
482
.weak _start_trap
493
483
_start_trap:
494
- addi sp, sp, - {TRAP_SIZE } * {width}
495
- {store}
484
+ addi sp, sp, - {trap_size } * {width}
485
+ {store}
496
486
add a0, sp, zero
497
487
jal ra, _start_trap_rust
498
- {load}
499
- addi sp, sp, {TRAP_SIZE } * {width}
488
+ {load}
489
+ addi sp, sp, {trap_size } * {width}
500
490
{ret}
501
491
");"#
502
492
)
503
493
. parse ( )
504
494
. unwrap ( )
505
495
}
506
496
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.
515
497
#[ cfg( feature = "v-trap" ) ]
516
498
#[ 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" ) ]
522
499
/// Generates global '_start_DefaultHandler_trap' and '_continue_interrupt_trap' functions in assembly.
523
500
/// The '_start_DefaultHandler_trap' function stores the trap frame partially (only register a0) and
524
501
/// jumps to the interrupt handler. The '_continue_interrupt_trap' function stores the trap frame
525
502
/// 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 ) ;
527
505
let width = arch. width ( ) ;
506
+ let trap_size = arch. trap_frame ( ) . len ( ) ;
528
507
let store_start = store_trap ( arch, |reg| reg == "a0" ) ;
529
508
let store_continue = store_trap ( arch, |reg| reg != "a0" ) ;
530
509
let load = load_trap ( arch) ;
@@ -542,17 +521,17 @@ core::arch::global_asm!(
542
521
.align 4
543
522
.global _start_DefaultHandler_trap
544
523
_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)
547
526
la a0, DefaultHandler // load interrupt handler address into a0
548
527
549
528
.align 4
550
529
.global _continue_interrupt_trap
551
530
_continue_interrupt_trap:
552
- {store_continue} // store trap partially (all registers except a0)
531
+ {store_continue} // store trap partially (all registers except a0)
553
532
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
556
535
{ret} // return from interrupt
557
536
");"#
558
537
) ;
@@ -664,10 +643,64 @@ pub fn exception(args: TokenStream, input: TokenStream) -> TokenStream {
664
643
/// loop{};
665
644
/// }
666
645
/// ```
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 {
668
701
let arch = match ( ) {
669
702
#[ cfg( feature = "v-trap" ) ]
670
- ( ) => Some ( RiscvArch :: Rv32 ) ,
703
+ ( ) => Some ( RiscvArch :: Rv64I ) ,
671
704
#[ cfg( not( feature = "v-trap" ) ) ]
672
705
( ) => None ,
673
706
} ;
@@ -691,10 +724,10 @@ pub fn core_interrupt_riscv32(args: TokenStream, input: TokenStream) -> TokenStr
691
724
/// loop{};
692
725
/// }
693
726
/// ```
694
- pub fn core_interrupt_riscv64 ( args : TokenStream , input : TokenStream ) -> TokenStream {
727
+ pub fn core_interrupt_rv64e ( args : TokenStream , input : TokenStream ) -> TokenStream {
695
728
let arch = match ( ) {
696
729
#[ cfg( feature = "v-trap" ) ]
697
- ( ) => Some ( RiscvArch :: Rv64 ) ,
730
+ ( ) => Some ( RiscvArch :: Rv64E ) ,
698
731
#[ cfg( not( feature = "v-trap" ) ) ]
699
732
( ) => None ,
700
733
} ;
@@ -784,6 +817,7 @@ fn trap(
784
817
fn start_interrupt_trap ( ident : & syn:: Ident , arch : RiscvArch ) -> proc_macro2:: TokenStream {
785
818
let interrupt = ident. to_string ( ) ;
786
819
let width = arch. width ( ) ;
820
+ let trap_size = arch. trap_frame ( ) . len ( ) ;
787
821
let store = store_trap ( arch, |r| r == "a0" ) ;
788
822
789
823
let instructions = format ! (
@@ -793,8 +827,8 @@ core::arch::global_asm!(
793
827
.align 2
794
828
.global _start_{interrupt}_trap
795
829
_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)
798
832
la a0, {interrupt} // load interrupt handler address into a0
799
833
j _continue_interrupt_trap // jump to common part of interrupt trap
800
834
");"#
0 commit comments