@@ -10,6 +10,65 @@ use syn::{
1010 Data , DeriveInput , Ident , Token ,
1111} ;
1212
13+ /// Struct to represent a function parameter.
14+ struct FunctionParam {
15+ /// Name of the parameter.
16+ param_name : TokenStream2 ,
17+ /// Data type of the parameter.
18+ param_type : TokenStream2 ,
19+ }
20+
21+ /// Configuration parameters of a trap. It is useful to abstract the
22+ /// differences between exception handlers and core interrupt handlers.
23+ struct TrapConfig {
24+ /// Name of the default handler (e.g., `DefaultHandler` for core interrupts).
25+ default_handler : TokenStream2 ,
26+ /// Vector describing all the function parameters of these kind of trap handlers.
27+ handler_params : Vec < FunctionParam > ,
28+ /// Dispatch function name (e.g., `_dispatch_exception` or `_dispatch_core_interrupt`).
29+ dispatch_fn_name : TokenStream2 ,
30+ /// Name of the array that sorts all the trap handlers (e.g., `__CORE_INTERRUPTS`).
31+ handlers_array_name : TokenStream2 ,
32+ }
33+
34+ impl TrapConfig {
35+ /// Vector with all the input parameters expected when declaring extern handler functions
36+ fn extern_signature ( & self ) -> Vec < TokenStream2 > {
37+ let mut res = Vec :: new ( ) ;
38+ for param in self . handler_params . iter ( ) {
39+ let param_name = & param. param_name ;
40+ let param_type = & param. param_type ;
41+ res. push ( quote ! { #param_name: #param_type } ) ;
42+ }
43+ res
44+ }
45+
46+ /// Similar to [`Self::extern_signature`], but skipping the parameter names.
47+ fn array_signature ( & self ) -> Vec < TokenStream2 > {
48+ let mut res = Vec :: new ( ) ;
49+ for param in self . handler_params . iter ( ) {
50+ res. push ( param. param_type . clone ( ) )
51+ }
52+ res
53+ }
54+
55+ /// Similar to [`Self::extern_signature`], but skipping the parameter data types.
56+ fn handler_input ( & self ) -> Vec < TokenStream2 > {
57+ let mut res = Vec :: new ( ) ;
58+ for param in self . handler_params . iter ( ) {
59+ res. push ( param. param_name . clone ( ) )
60+ }
61+ res
62+ }
63+
64+ /// Similar to [`Self::extern_signature`], but pushing the trap `code` to the vector.
65+ fn dispatch_fn_signature ( & self ) -> Vec < TokenStream2 > {
66+ let mut res = self . extern_signature ( ) ;
67+ res. push ( quote ! { code: usize } ) ;
68+ res
69+ }
70+ }
71+
1372/// Traits that can be implemented using the `pac_enum` macro
1473enum PacTrait {
1574 Exception ,
@@ -29,6 +88,14 @@ impl PacTrait {
2988 }
3089 }
3190
91+ /// Returns a token stream representing an additional marker trait, if any.
92+ fn marker_trait_name ( & self ) -> Option < TokenStream2 > {
93+ match self {
94+ Self :: Interrupt ( interrupt_type) => Some ( interrupt_type. marker_trait_name ( ) ) ,
95+ _ => None ,
96+ }
97+ }
98+
3299 /// Returns a token stream representing the data type used to represent the number
33100 fn num_type ( & self ) -> TokenStream2 {
34101 match self {
@@ -48,6 +115,28 @@ impl PacTrait {
48115 Self :: HartId => quote ! ( MAX_HART_ID_NUMBER ) ,
49116 }
50117 }
118+
119+ /// For Exception or an Interrupt enums, it returns the trap configuration details.
120+ fn trap_config ( & self ) -> Option < TrapConfig > {
121+ match self {
122+ Self :: Exception => Some ( TrapConfig {
123+ default_handler : quote ! { ExceptionHandler } ,
124+ handler_params : vec ! [ FunctionParam {
125+ param_name: quote! { trap_frame } ,
126+ param_type: quote! { & riscv_rt:: TrapFrame } ,
127+ } ] ,
128+ dispatch_fn_name : quote ! { _dispatch_exception } ,
129+ handlers_array_name : quote ! { __EXCEPTIONS } ,
130+ } ) ,
131+ Self :: Interrupt ( interrupt_type) => Some ( TrapConfig {
132+ default_handler : quote ! { DefaultHandler } ,
133+ handler_params : Vec :: new ( ) ,
134+ dispatch_fn_name : interrupt_type. dispatch_fn_name ( ) ,
135+ handlers_array_name : interrupt_type. isr_array_name ( ) ,
136+ } ) ,
137+ _ => None ,
138+ }
139+ }
51140}
52141
53142impl Parse for PacTrait {
@@ -165,19 +254,20 @@ impl PacEnumItem {
165254 }
166255
167256 /// Returns a vector of token streams representing the interrupt handler functions
168- fn interrupt_handlers ( & self ) -> Vec < TokenStream2 > {
257+ fn handlers ( & self , trap_config : & TrapConfig ) -> Vec < TokenStream2 > {
258+ let signature = trap_config. extern_signature ( ) ;
169259 self . numbers
170260 . values ( )
171261 . map ( |ident| {
172- quote ! { fn #ident ( ) }
262+ quote ! { fn #ident ( # ( #signature ) , * ) }
173263 } )
174264 . collect ( )
175265 }
176266
177267 /// Returns a sorted vector of token streams representing all the elements of the interrupt array.
178268 /// If an interrupt number is not present in the enum, the corresponding element is `None`.
179269 /// Otherwise, it is `Some(<interrupt_handler>)`.
180- fn interrupt_array ( & self ) -> Vec < TokenStream2 > {
270+ fn handlers_array ( & self ) -> Vec < TokenStream2 > {
181271 let mut vectors = vec ! [ ] ;
182272 for i in 0 ..=self . max_number {
183273 if let Some ( ident) = self . numbers . get ( & i) {
@@ -261,46 +351,51 @@ core::arch::global_asm!("
261351 }
262352 } ) ;
263353
264- // Interrupt traits require additional code
265- if let PacTrait :: Interrupt ( interrupt_type) = attr {
266- let marker_trait_name = interrupt_type. marker_trait_name ( ) ;
267-
268- let isr_array_name = interrupt_type. isr_array_name ( ) ;
269- let dispatch_fn_name = interrupt_type. dispatch_fn_name ( ) ;
270-
271- // Push the marker trait implementation
354+ if let Some ( marker_trait_name) = attr. marker_trait_name ( ) {
272355 res. push ( quote ! { unsafe impl riscv:: #marker_trait_name for #name { } } ) ;
356+ }
273357
274- let interrupt_handlers = self . interrupt_handlers ( ) ;
275- let interrupt_array = self . interrupt_array ( ) ;
358+ if let Some ( trap_config) = attr. trap_config ( ) {
359+ let default_handler = & trap_config. default_handler ;
360+ let extern_signature = trap_config. extern_signature ( ) ;
361+ let handler_input = trap_config. handler_input ( ) ;
362+ let array_signature = trap_config. array_signature ( ) ;
363+ let dispatch_fn_name = & trap_config. dispatch_fn_name ;
364+ let dispatch_fn_args = & trap_config. dispatch_fn_signature ( ) ;
365+ let vector_table = & trap_config. handlers_array_name ;
366+
367+ let handlers = self . handlers ( & trap_config) ;
368+ let interrupt_array = self . handlers_array ( ) ;
276369
277370 // Push the interrupt handler functions and the interrupt array
278371 res. push ( quote ! {
279372 extern "C" {
280- #( #interrupt_handlers ; ) *
373+ #( #handlers ; ) *
281374 }
282375
376+ #[ doc( hidden) ]
283377 #[ no_mangle]
284- pub static #isr_array_name : [ Option <unsafe extern "C" fn ( ) >; #max_discriminant + 1 ] = [
378+ pub static #vector_table : [ Option <unsafe extern "C" fn ( # ( #array_signature ) , * ) >; #max_discriminant + 1 ] = [
285379 #( #interrupt_array) , *
286380 ] ;
287381
382+ #[ inline]
288383 #[ no_mangle]
289- unsafe extern "C" fn #dispatch_fn_name( code : usize ) {
384+ unsafe extern "C" fn #dispatch_fn_name( # ( #dispatch_fn_args ) , * ) {
290385 extern "C" {
291- fn DefaultHandler ( ) ;
386+ fn #default_handler ( # ( #extern_signature ) , * ) ;
292387 }
293388
294- match #isr_array_name . get( code) {
295- Some ( Some ( handler) ) => handler( ) ,
296- _ => DefaultHandler ( ) ,
389+ match #vector_table . get( code) {
390+ Some ( Some ( handler) ) => handler( # ( #handler_input ) , * ) ,
391+ _ => #default_handler ( # ( #handler_input ) , * ) ,
297392 }
298393 }
299394 } ) ;
395+ }
300396
301- if let InterruptType :: Core = interrupt_type {
302- res. push ( self . vector_table ( ) ) ;
303- }
397+ if let PacTrait :: Interrupt ( InterruptType :: Core ) = attr {
398+ res. push ( self . vector_table ( ) ) ;
304399 }
305400
306401 res
0 commit comments