added argument trampoline to hardware tasks to allow exception "masking"

Co-authored-by: Salon <salon64@users.noreply.github.com>
This commit is contained in:
Olle Ronstad 2025-10-02 17:02:43 +02:00
parent 300ad99b74
commit 11d2ca9f2b
4 changed files with 79 additions and 26 deletions

View file

@ -319,13 +319,13 @@ pub fn architecture_specific_analysis(app: &App, _: &SyntaxAnalysis) -> parse::R
.filter(|prio| *prio > 0)
.collect::<HashSet<_>>();
let need = priorities.len();
let need_software = priorities.len();
let given = app.args.dispatchers.len();
if need > given {
if need_software > given {
let s = {
format!(
"not enough interrupts to dispatch \
all software tasks (need: {need}; given: {given})"
all software tasks (need: {need_software}; given: {given})"
)
};

View file

@ -24,26 +24,62 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 {
let exit_stmts = interrupt_exit(app, analysis);
let config = handler_config(app, analysis, symbol.clone());
mod_app.push(quote!(
#[allow(non_snake_case)]
#[no_mangle]
#(#attrs)*
#(#cfgs)*
#(#config)*
unsafe fn #symbol() {
#(#entry_stmts)*
if let Some(trampoline) = &task.args.trampoline {
let trampoline_symbol = trampoline.clone();
mod_app.push(quote!(
const PRIORITY: u8 = #priority;
#[allow(non_snake_case)]
#[no_mangle]
#(#attrs)*
#(#cfgs)*
#(#config)*
unsafe fn #symbol() {
rtic::export::pend(rtic::export::Interrupt::#trampoline_symbol);
}
rtic::export::run(PRIORITY, || {
#name(
#name::Context::new()
)
});
#[allow(non_snake_case)]
#[no_mangle]
#(#attrs)*
#(#cfgs)*
#(#config)*
unsafe fn #trampoline_symbol() {
#(#entry_stmts)*
#(#exit_stmts)*
}
));
const PRIORITY: u8 = #priority;
rtic::export::run(PRIORITY, || {
#name(
#name::Context::new()
)
});
#(#exit_stmts)*
}
));
} else {
mod_app.push(quote!(
#[allow(non_snake_case)]
#[no_mangle]
#(#attrs)*
#(#cfgs)*
#(#config)*
unsafe fn #symbol() {
#(#entry_stmts)*
const PRIORITY: u8 = #priority;
rtic::export::run(PRIORITY, || {
#name(
#name::Context::new()
)
});
#(#exit_stmts)*
}
));
}
// `${task}Locals`
if !task.args.local_resources.is_empty() {
@ -51,7 +87,6 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 {
local_resources_struct::codegen(Context::HardwareTask(name), app);
root.push(item);
mod_app.push(constructor);
}
@ -61,7 +96,6 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 {
shared_resources_struct::codegen(Context::HardwareTask(name), app);
root.push(item);
mod_app.push(constructor);
}

View file

@ -298,6 +298,9 @@ pub struct HardwareTaskArgs {
/// The interrupt or exception that this task is bound to
pub binds: Ident,
/// if set the bind would trampoline with the given interrupt handler
pub trampoline: Option<Ident>,
/// The priority of this task
pub priority: u8,

View file

@ -193,6 +193,7 @@ fn task_args(tokens: TokenStream2) -> parse::Result<Either<HardwareTaskArgs, Sof
}
let mut binds = None;
let mut trampoline = None;
let mut priority = None;
let mut shared_resources = None;
let mut local_resources = None;
@ -223,7 +224,21 @@ fn task_args(tokens: TokenStream2) -> parse::Result<Either<HardwareTaskArgs, Sof
let ident = input.parse()?;
binds = Some(ident);
}
},
"trampoline" => {
if trampoline.is_some() {
return Err(parse::Error::new(
ident.span(),
"argument appears more than once",
));
}
// Parse identifier name
let ident: Ident = input.parse()?;
trampoline = Some(ident);
},
"priority" => {
if priority.is_some() {
@ -277,8 +292,8 @@ fn task_args(tokens: TokenStream2) -> parse::Result<Either<HardwareTaskArgs, Sof
local_resources = Some(util::parse_local_resources(input)?);
}
_ => {
return Err(parse::Error::new(ident.span(), "unexpected argument"));
a => {
return Err(parse::Error::new(ident.span(), format!("unexpected argument {}", a)));
}
}
@ -308,6 +323,7 @@ fn task_args(tokens: TokenStream2) -> parse::Result<Either<HardwareTaskArgs, Sof
priority,
shared_resources,
local_resources,
trampoline,
})
} else {
// Software tasks start at idle priority