@@ -312,3 +312,136 @@ pub fn loop_global_asm(input: TokenStream) -> TokenStream {
312
312
let res = format ! ( "core::arch::global_asm!(\n \" {}\" \n );" , instructions) ;
313
313
res. parse ( ) . unwrap ( )
314
314
}
315
+
316
+ enum RiscvArch {
317
+ Rv32 ,
318
+ Rv64 ,
319
+ }
320
+
321
+ #[ proc_macro_attribute]
322
+ pub fn interrupt_riscv32 ( args : TokenStream , input : TokenStream ) -> TokenStream {
323
+ interrupt ( args, input, RiscvArch :: Rv32 )
324
+ }
325
+
326
+ #[ proc_macro_attribute]
327
+ pub fn interrupt_riscv64 ( args : TokenStream , input : TokenStream ) -> TokenStream {
328
+ interrupt ( args, input, RiscvArch :: Rv64 )
329
+ }
330
+
331
+ fn interrupt ( args : TokenStream , input : TokenStream , _arch : RiscvArch ) -> TokenStream {
332
+ let f = parse_macro_input ! ( input as ItemFn ) ;
333
+
334
+ // check the function signature
335
+ let valid_signature = f. sig . constness . is_none ( )
336
+ && f. sig . asyncness . is_none ( )
337
+ && f. vis == Visibility :: Inherited
338
+ && f. sig . abi . is_none ( )
339
+ && f. sig . generics . params . is_empty ( )
340
+ && f. sig . generics . where_clause . is_none ( )
341
+ && f. sig . variadic . is_none ( )
342
+ && match f. sig . output {
343
+ ReturnType :: Default => true ,
344
+ ReturnType :: Type ( _, ref ty) => matches ! ( * * ty, Type :: Never ( _) ) ,
345
+ } ;
346
+
347
+ if !valid_signature {
348
+ return parse:: Error :: new (
349
+ f. span ( ) ,
350
+ "`#[interrupt]` function must have signature `[unsafe] fn() [-> !]`" ,
351
+ )
352
+ . to_compile_error ( )
353
+ . into ( ) ;
354
+ }
355
+
356
+ if !args. is_empty ( ) {
357
+ return parse:: Error :: new ( Span :: call_site ( ) , "This attribute accepts no arguments" )
358
+ . to_compile_error ( )
359
+ . into ( ) ;
360
+ }
361
+
362
+ // XXX should we blacklist other attributes?
363
+ let attrs = f. attrs ;
364
+ let ident = f. sig . ident ;
365
+ let block = f. block ;
366
+
367
+ #[ cfg( not( feature = "v-trap" ) ) ]
368
+ let start_trap = proc_macro2:: TokenStream :: new ( ) ;
369
+ #[ cfg( feature = "v-trap" ) ]
370
+ let start_trap = v_trap:: start_interrupt_trap_asm ( & ident, _arch) ;
371
+
372
+ quote ! (
373
+ #start_trap
374
+ #[ export_name = #ident]
375
+ #( #attrs) *
376
+ pub unsafe fn #ident( ) #block
377
+ )
378
+ . into ( )
379
+ }
380
+
381
+ #[ cfg( feature = "v-trap" ) ]
382
+ mod v_trap {
383
+ use super :: * ;
384
+
385
+ const TRAP_SIZE : usize = 16 ;
386
+
387
+ #[ rustfmt:: skip]
388
+ const TRAP_FRAME : [ & str ; TRAP_SIZE ] = [
389
+ "ra" ,
390
+ "t0" ,
391
+ "t1" ,
392
+ "t2" ,
393
+ "t3" ,
394
+ "t4" ,
395
+ "t5" ,
396
+ "t6" ,
397
+ "a0" ,
398
+ "a1" ,
399
+ "a2" ,
400
+ "a3" ,
401
+ "a4" ,
402
+ "a5" ,
403
+ "a6" ,
404
+ "a7" ,
405
+ ] ;
406
+
407
+ pub fn start_interrupt_trap_asm (
408
+ ident : & syn:: Ident ,
409
+ arch : RiscvArch ,
410
+ ) -> proc_macro2:: TokenStream {
411
+ let function = ident. to_string ( ) ;
412
+ let ( width, store, load) = match arch {
413
+ RiscvArch :: Rv32 => ( 4 , "sw" , "lw" ) ,
414
+ RiscvArch :: Rv64 => ( 8 , "sd" , "ld" ) ,
415
+ } ;
416
+
417
+ let ( mut stores, mut loads) = ( Vec :: new ( ) , Vec :: new ( ) ) ;
418
+ for ( i, r) in TRAP_FRAME . iter ( ) . enumerate ( ) {
419
+ stores. push ( format ! ( " {store} {r}, {i}*{width}(sp)" ) ) ;
420
+ loads. push ( format ! ( " {load} {r}, {i}*{width}(sp)" ) ) ;
421
+ }
422
+ let store = stores. join ( "\n " ) ;
423
+ let load = loads. join ( "\n " ) ;
424
+
425
+ #[ cfg( feature = "s-mode" ) ]
426
+ let ret = "sret" ;
427
+ #[ cfg( not( feature = "s-mode" ) ) ]
428
+ let ret = "mret" ;
429
+
430
+ let instructions = format ! (
431
+ "
432
+ core::arch::global_asm!(
433
+ \" .section .trap, \\ \" ax\\ \"
434
+ .align {width}
435
+ _start_{function}_trap:
436
+ addi sp, sp, - {TRAP_SIZE} * {width}
437
+ {store}
438
+ call {function}
439
+ {load}
440
+ addi sp, sp, {TRAP_SIZE} * {width}
441
+ {ret}\"
442
+ );"
443
+ ) ;
444
+
445
+ instructions. parse ( ) . unwrap ( )
446
+ }
447
+ }
0 commit comments