@@ -319,9 +319,11 @@ enum RiscvArch {
319
319
Rv64 ,
320
320
}
321
321
322
+ /// Size of the trap frame (in number of registers)
322
323
const TRAP_SIZE : usize = 16 ;
323
324
324
325
#[ rustfmt:: skip]
326
+ /// List of the register names to be stored in the trap frame
325
327
const TRAP_FRAME : [ & str ; TRAP_SIZE ] = [
326
328
"ra" ,
327
329
"t0" ,
@@ -341,6 +343,14 @@ const TRAP_FRAME: [&str; TRAP_SIZE] = [
341
343
"a7" ,
342
344
] ;
343
345
346
+ /// Generate the assembly instructions to store the trap frame.
347
+ ///
348
+ /// The `arch` parameter is used to determine the width of the registers.
349
+ ///
350
+ /// The `filter` function is used to filter which registers to store.
351
+ /// This is useful to optimize the binary size in vectored interrupt mode, which divides the trap
352
+ /// frame storage in two parts: the first part saves space in the stack and stores only the `a0` register,
353
+ /// while the second part stores the remaining registers.
344
354
fn store_trap < T : FnMut ( & str ) -> bool > ( arch : RiscvArch , mut filter : T ) -> String {
345
355
let ( width, store) = match arch {
346
356
RiscvArch :: Rv32 => ( 4 , "sw" ) ,
@@ -357,6 +367,8 @@ fn store_trap<T: FnMut(&str) -> bool>(arch: RiscvArch, mut filter: T) -> String
357
367
stores. join ( "\n " )
358
368
}
359
369
370
+ /// Generate the assembly instructions to load the trap frame.
371
+ /// The `arch` parameter is used to determine the width of the registers.
360
372
fn load_trap ( arch : RiscvArch ) -> String {
361
373
let ( width, load) = match arch {
362
374
RiscvArch :: Rv32 => ( 4 , "lw" ) ,
@@ -369,16 +381,31 @@ fn load_trap(arch: RiscvArch) -> String {
369
381
loads. join ( "\n " )
370
382
}
371
383
384
+ /// Generates weak `_start_trap` function in assembly for RISCV-32 targets.
385
+ ///
386
+ /// This implementation stores all registers in the trap frame and calls `_start_trap_rust`.
387
+ /// The trap frame is allocated on the stack and deallocated after the call.
372
388
#[ proc_macro]
373
389
pub fn weak_start_trap_riscv32 ( _input : TokenStream ) -> TokenStream {
374
390
weak_start_trap ( RiscvArch :: Rv32 )
375
391
}
376
392
393
+ /// Generates weak `_start_trap` function in assembly for RISCV-64 targets.
394
+ ///
395
+ /// This implementation stores all registers in the trap frame and calls `_start_trap_rust`.
396
+ /// The trap frame is allocated on the stack and deallocated after the call.
377
397
#[ proc_macro]
378
398
pub fn weak_start_trap_riscv64 ( _input : TokenStream ) -> TokenStream {
379
399
weak_start_trap ( RiscvArch :: Rv64 )
380
400
}
381
401
402
+ /// Generates weak `_start_trap` function in assembly.
403
+ ///
404
+ /// This implementation stores all registers in the trap frame and calls `_start_trap_rust`.
405
+ /// The trap frame is allocated on the stack and deallocated after the call.
406
+ ///
407
+ /// The `arch` parameter is used to determine the width of the registers.
408
+ /// The macro also ensures that the trap frame size is 16-byte aligned.
382
409
fn weak_start_trap ( arch : RiscvArch ) -> TokenStream {
383
410
let width = match arch {
384
411
RiscvArch :: Rv32 => 4 ,
@@ -398,7 +425,7 @@ fn weak_start_trap(arch: RiscvArch) -> TokenStream {
398
425
#[ cfg( not( feature = "s-mode" ) ) ]
399
426
let ret = "mret" ;
400
427
401
- let instructions : proc_macro2 :: TokenStream = format ! (
428
+ format ! (
402
429
"
403
430
core::arch::global_asm!(
404
431
\" .section .trap, \\ \" ax\\ \"
@@ -415,26 +442,76 @@ _start_trap:
415
442
\" );"
416
443
)
417
444
. parse ( )
418
- . unwrap ( ) ;
445
+ . unwrap ( )
446
+ }
419
447
420
- #[ cfg( feature = "v-trap" ) ]
421
- let v_trap = v_trap:: continue_interrupt_trap ( arch) ;
422
- #[ cfg( not( feature = "v-trap" ) ) ]
423
- let v_trap = proc_macro2:: TokenStream :: new ( ) ;
448
+ /// Generates vectored interrupt trap functions in assembly for RISCV-32 targets.
449
+ #[ cfg( feature = "v-trap" ) ]
450
+ #[ proc_macro]
451
+ pub fn vectored_interrupt_trap_riscv32 ( _input : TokenStream ) -> TokenStream {
452
+ vectored_interrupt_trap ( RiscvArch :: Rv32 )
453
+ }
424
454
425
- quote ! (
426
- #instructions
427
- #v_trap
428
- )
429
- . into ( )
455
+ /// Generates vectored interrupt trap functions in assembly for RISCV-64 targets.
456
+ #[ cfg( feature = "v-trap" ) ]
457
+ #[ proc_macro]
458
+ pub fn vectored_interrupt_trap_riscv64 ( _input : TokenStream ) -> TokenStream {
459
+ vectored_interrupt_trap ( RiscvArch :: Rv64 )
460
+ }
461
+
462
+ #[ cfg( feature = "v-trap" ) ]
463
+ /// Generates global '_start_DefaultHandler_trap' and '_continue_interrupt_trap' functions in assembly.
464
+ /// The '_start_DefaultHandler_trap' function stores the trap frame partially (only register a0) and
465
+ /// jumps to the interrupt handler. The '_continue_interrupt_trap' function stores the trap frame
466
+ /// partially (all registers except a0), jumps to the interrupt handler, and restores the trap frame.
467
+ fn vectored_interrupt_trap ( arch : RiscvArch ) -> TokenStream {
468
+ let width = match arch {
469
+ RiscvArch :: Rv32 => 4 ,
470
+ RiscvArch :: Rv64 => 8 ,
471
+ } ;
472
+ let store_start = store_trap ( arch, |reg| reg == "a0" ) ;
473
+ let store_continue = store_trap ( arch, |reg| reg != "a0" ) ;
474
+ let load = load_trap ( arch) ;
475
+
476
+ #[ cfg( feature = "s-mode" ) ]
477
+ let ret = "sret" ;
478
+ #[ cfg( not( feature = "s-mode" ) ) ]
479
+ let ret = "mret" ;
480
+
481
+ let instructions = format ! (
482
+ "
483
+ core::arch::global_asm!(
484
+ \" .section .trap, \\ \" ax\\ \"
485
+
486
+ .global _start_DefaultHandler_trap
487
+ _start_DefaultHandler_trap:
488
+ addi sp, sp, -{TRAP_SIZE} * {width} // allocate space for trap frame
489
+ {store_start} // store trap partially (only register a0)
490
+ la a0, DefaultHandler // load interrupt handler address into a0
491
+
492
+ .global _continue_interrupt_trap
493
+ _continue_interrupt_trap:
494
+ {store_continue} // store trap partially (all registers except a0)
495
+ jalr ra, a0, 0 // jump to corresponding interrupt handler (address stored in a0)
496
+ {load} // restore trap frame
497
+ addi sp, sp, {TRAP_SIZE} * {width} // deallocate space for trap frame
498
+ {ret} // return from interrupt
499
+ \" );"
500
+ ) ;
501
+
502
+ instructions. parse ( ) . unwrap ( )
430
503
}
431
504
432
505
#[ proc_macro_attribute]
506
+ /// Attribute to declare an interrupt handler. The function must have the signature `[unsafe] fn() [-> !]`.
507
+ /// If the `v-trap` feature is enabled, this macro generates the interrupt trap handler in assembly for RISCV-32 targets.
433
508
pub fn interrupt_riscv32 ( args : TokenStream , input : TokenStream ) -> TokenStream {
434
509
interrupt ( args, input, RiscvArch :: Rv32 )
435
510
}
436
511
437
512
#[ proc_macro_attribute]
513
+ /// Attribute to declare an interrupt handler. The function must have the signature `[unsafe] fn() [-> !]`.
514
+ /// If the `v-trap` feature is enabled, this macro generates the interrupt trap handler in assembly for RISCV-32 targets.
438
515
pub fn interrupt_riscv64 ( args : TokenStream , input : TokenStream ) -> TokenStream {
439
516
interrupt ( args, input, RiscvArch :: Rv64 )
440
517
}
@@ -487,7 +564,7 @@ fn interrupt(args: TokenStream, input: TokenStream, _arch: RiscvArch) -> TokenSt
487
564
#[ cfg( not( feature = "v-trap" ) ) ]
488
565
let start_trap = proc_macro2:: TokenStream :: new ( ) ;
489
566
#[ cfg( feature = "v-trap" ) ]
490
- let start_trap = v_trap :: start_interrupt_trap ( ident, _arch) ;
567
+ let start_trap = start_interrupt_trap ( ident, _arch) ;
491
568
492
569
quote ! (
493
570
#start_trap
@@ -498,65 +575,27 @@ fn interrupt(args: TokenStream, input: TokenStream, _arch: RiscvArch) -> TokenSt
498
575
}
499
576
500
577
#[ cfg( feature = "v-trap" ) ]
501
- mod v_trap {
502
- use super :: * ;
503
-
504
- pub ( crate ) fn start_interrupt_trap (
505
- ident : & syn:: Ident ,
506
- arch : RiscvArch ,
507
- ) -> proc_macro2:: TokenStream {
508
- let interrupt = ident. to_string ( ) ;
509
- let width = match arch {
510
- RiscvArch :: Rv32 => 4 ,
511
- RiscvArch :: Rv64 => 8 ,
512
- } ;
513
- let store = store_trap ( arch, |r| r == "a0" ) ;
578
+ fn start_interrupt_trap ( ident : & syn:: Ident , arch : RiscvArch ) -> proc_macro2:: TokenStream {
579
+ let interrupt = ident. to_string ( ) ;
580
+ let width = match arch {
581
+ RiscvArch :: Rv32 => 4 ,
582
+ RiscvArch :: Rv64 => 8 ,
583
+ } ;
584
+ let store = store_trap ( arch, |r| r == "a0" ) ;
514
585
515
- let instructions = format ! (
516
- "
586
+ let instructions = format ! (
587
+ "
517
588
core::arch::global_asm!(
518
589
\" .section .trap, \\ \" ax\\ \"
519
- .align {width}
590
+ .align 2
520
591
.global _start_{interrupt}_trap
521
592
_start_{interrupt}_trap:
522
593
addi sp, sp, -{TRAP_SIZE} * {width} // allocate space for trap frame
523
594
{store} // store trap partially (only register a0)
524
595
la a0, {interrupt} // load interrupt handler address into a0
525
596
j _continue_interrupt_trap // jump to common part of interrupt trap
526
597
\" );"
527
- ) ;
528
-
529
- instructions. parse ( ) . unwrap ( )
530
- }
531
-
532
- pub ( crate ) fn continue_interrupt_trap ( arch : RiscvArch ) -> proc_macro2:: TokenStream {
533
- let width = match arch {
534
- RiscvArch :: Rv32 => 4 ,
535
- RiscvArch :: Rv64 => 8 ,
536
- } ;
537
- let store = store_trap ( arch, |reg| reg != "a0" ) ;
538
- let load = load_trap ( arch) ;
598
+ ) ;
539
599
540
- #[ cfg( feature = "s-mode" ) ]
541
- let ret = "sret" ;
542
- #[ cfg( not( feature = "s-mode" ) ) ]
543
- let ret = "mret" ;
544
-
545
- let instructions = format ! (
546
- "
547
- core::arch::global_asm!(
548
- \" .section .trap, \\ \" ax\\ \"
549
- .align {width} // TODO is this necessary?
550
- .global _continue_interrupt_trap
551
- _continue_interrupt_trap:
552
- {store} // store trap partially (all registers except a0)
553
- 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
556
- {ret} // return from interrupt
557
- \" );"
558
- ) ;
559
-
560
- instructions. parse ( ) . unwrap ( )
561
- }
600
+ instructions. parse ( ) . unwrap ( )
562
601
}
0 commit comments