@@ -10,6 +10,65 @@ use syn::{
10
10
Data , DeriveInput , Ident , Token ,
11
11
} ;
12
12
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
+
13
72
/// Traits that can be implemented using the `pac_enum` macro
14
73
enum PacTrait {
15
74
Exception ,
@@ -29,6 +88,14 @@ impl PacTrait {
29
88
}
30
89
}
31
90
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
+
32
99
/// Returns a token stream representing the data type used to represent the number
33
100
fn num_type ( & self ) -> TokenStream2 {
34
101
match self {
@@ -48,6 +115,28 @@ impl PacTrait {
48
115
Self :: HartId => quote ! ( MAX_HART_ID_NUMBER ) ,
49
116
}
50
117
}
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
+ }
51
140
}
52
141
53
142
impl Parse for PacTrait {
@@ -165,19 +254,20 @@ impl PacEnumItem {
165
254
}
166
255
167
256
/// 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 ( ) ;
169
259
self . numbers
170
260
. values ( )
171
261
. map ( |ident| {
172
- quote ! { fn #ident ( ) }
262
+ quote ! { fn #ident ( # ( #signature ) , * ) }
173
263
} )
174
264
. collect ( )
175
265
}
176
266
177
267
/// Returns a sorted vector of token streams representing all the elements of the interrupt array.
178
268
/// If an interrupt number is not present in the enum, the corresponding element is `None`.
179
269
/// Otherwise, it is `Some(<interrupt_handler>)`.
180
- fn interrupt_array ( & self ) -> Vec < TokenStream2 > {
270
+ fn handlers_array ( & self ) -> Vec < TokenStream2 > {
181
271
let mut vectors = vec ! [ ] ;
182
272
for i in 0 ..=self . max_number {
183
273
if let Some ( ident) = self . numbers . get ( & i) {
@@ -261,46 +351,51 @@ core::arch::global_asm!("
261
351
}
262
352
} ) ;
263
353
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 ( ) {
272
355
res. push ( quote ! { unsafe impl riscv:: #marker_trait_name for #name { } } ) ;
356
+ }
273
357
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 ( ) ;
276
369
277
370
// Push the interrupt handler functions and the interrupt array
278
371
res. push ( quote ! {
279
372
extern "C" {
280
- #( #interrupt_handlers ; ) *
373
+ #( #handlers ; ) *
281
374
}
282
375
376
+ #[ doc( hidden) ]
283
377
#[ 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 ] = [
285
379
#( #interrupt_array) , *
286
380
] ;
287
381
382
+ #[ inline]
288
383
#[ no_mangle]
289
- unsafe extern "C" fn #dispatch_fn_name( code : usize ) {
384
+ unsafe extern "C" fn #dispatch_fn_name( # ( #dispatch_fn_args ) , * ) {
290
385
extern "C" {
291
- fn DefaultHandler ( ) ;
386
+ fn #default_handler ( # ( #extern_signature ) , * ) ;
292
387
}
293
388
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 ) , * ) ,
297
392
}
298
393
}
299
394
} ) ;
395
+ }
300
396
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 ( ) ) ;
304
399
}
305
400
306
401
res
0 commit comments