Skip to content

Commit decd797

Browse files
committed
works for custom enums
1 parent 458e921 commit decd797

File tree

2 files changed

+119
-23
lines changed

2 files changed

+119
-23
lines changed

riscv/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,4 @@ riscv-macros = { path = "macros", version = "0.1.0", optional = true }
3232

3333
[dev-dependencies]
3434
trybuild = "1.0"
35+
riscv-rt = { path = "../riscv-rt", version = "0.13.0" }

riscv/macros/src/lib.rs

Lines changed: 118 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -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
1473
enum 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

53142
impl 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

Comments
 (0)