diff options
Diffstat (limited to 'macros/src/codegen/dispatchers.rs')
-rw-r--r-- | macros/src/codegen/dispatchers.rs | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/macros/src/codegen/dispatchers.rs b/macros/src/codegen/dispatchers.rs new file mode 100644 index 00000000..65d25c78 --- /dev/null +++ b/macros/src/codegen/dispatchers.rs @@ -0,0 +1,178 @@ +use proc_macro2::TokenStream as TokenStream2; +use quote::quote; +use rtfm_syntax::ast::App; + +use crate::{analyze::Analysis, check::Extra, codegen::util}; + +/// Generates task dispatchers +pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> { + let mut items = vec![]; + + for (&receiver, dispatchers) in &analysis.channels { + let interrupts = &analysis.interrupts[&receiver]; + + for (&level, channels) in dispatchers { + let mut stmts = vec![]; + + for (&sender, channel) in channels { + let cfg_sender = util::cfg_core(sender, app.args.cores); + + let variants = channel + .tasks + .iter() + .map(|name| { + let cfgs = &app.software_tasks[name].cfgs; + + quote!( + #(#cfgs)* + #name + ) + }) + .collect::<Vec<_>>(); + + let doc = format!( + "Software tasks spawned from core #{} to be dispatched at priority level {} by core #{}", + sender, level, receiver, + ); + let t = util::spawn_t_ident(receiver, level, sender); + items.push(quote!( + #[allow(non_camel_case_types)] + #[derive(Clone, Copy)] + #[doc = #doc] + enum #t { + #(#variants,)* + } + )); + + let n = util::capacity_typenum(channel.capacity, true); + let rq = util::rq_ident(receiver, level, sender); + let (rq_attr, rq_ty, rq_expr) = if sender == receiver { + ( + cfg_sender.clone(), + quote!(rtfm::export::SCRQ<#t, #n>), + quote!(rtfm::export::Queue(unsafe { + rtfm::export::iQueue::u8_sc() + })), + ) + } else { + ( + Some(quote!(#[rtfm::export::shared])), + quote!(rtfm::export::MCRQ<#t, #n>), + quote!(rtfm::export::Queue(rtfm::export::iQueue::u8())), + ) + }; + + let doc = format!( + "Queue of tasks sent by core #{} ready to be dispatched by core #{} at priority level {}", + sender, + receiver, + level + ); + items.push(quote!( + #[doc = #doc] + #rq_attr + static mut #rq: #rq_ty = #rq_expr; + )); + + if let Some(ceiling) = channel.ceiling { + items.push(quote!( + #cfg_sender + struct #rq<'a> { + priority: &'a rtfm::export::Priority, + } + )); + + items.push(util::impl_mutex( + extra, + &[], + cfg_sender.as_ref(), + false, + &rq, + rq_ty, + ceiling, + quote!(&mut #rq), + )); + } + + let arms = channel + .tasks + .iter() + .map(|name| { + let task = &app.software_tasks[name]; + let cfgs = &task.cfgs; + let fq = util::fq_ident(name, sender); + let inputs = util::inputs_ident(name, sender); + let (_, tupled, pats, _) = util::regroup_inputs(&task.inputs); + + let (let_instant, instant) = if app.uses_schedule(receiver) { + let instants = util::instants_ident(name, sender); + + ( + quote!( + let instant = + #instants.get_unchecked(usize::from(index)).as_ptr().read(); + ), + quote!(, instant), + ) + } else { + (quote!(), quote!()) + }; + + let locals_new = if task.locals.is_empty() { + quote!() + } else { + quote!(#name::Locals::new(),) + }; + + quote!( + #(#cfgs)* + #t::#name => { + let #tupled = + #inputs.get_unchecked(usize::from(index)).as_ptr().read(); + #let_instant + #fq.split().0.enqueue_unchecked(index); + let priority = &rtfm::export::Priority::new(PRIORITY); + #name( + #locals_new + #name::Context::new(priority #instant) + #(,#pats)* + ) + } + ) + }) + .collect::<Vec<_>>(); + + stmts.push(quote!( + while let Some((task, index)) = #rq.split().1.dequeue() { + match task { + #(#arms)* + } + } + )); + } + + let doc = format!( + "Interrupt handler used by core #{} to dispatch tasks at priority {}", + receiver, level + ); + let cfg_receiver = util::cfg_core(receiver, app.args.cores); + let interrupt = &interrupts[&level]; + items.push(quote!( + #[allow(non_snake_case)] + #[doc = #doc] + #[no_mangle] + #cfg_receiver + unsafe fn #interrupt() { + /// The priority of this interrupt handler + const PRIORITY: u8 = #level; + + rtfm::export::run(PRIORITY, || { + #(#stmts)* + }); + } + )); + } + } + + items +} |