@@ -312,3 +312,136 @@ pub fn loop_global_asm(input: TokenStream) -> TokenStream {
312312    let  res = format ! ( "core::arch::global_asm!(\n \" {}\" \n );" ,  instructions) ; 
313313    res. parse ( ) . unwrap ( ) 
314314} 
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