diff options
Diffstat (limited to 'macros/src/codegen')
-rw-r--r-- | macros/src/codegen/assertions.rs | 26 | ||||
-rw-r--r-- | macros/src/codegen/dispatchers.rs | 290 | ||||
-rw-r--r-- | macros/src/codegen/hardware_tasks.rs | 50 | ||||
-rw-r--r-- | macros/src/codegen/idle.rs | 45 | ||||
-rw-r--r-- | macros/src/codegen/init.rs | 102 | ||||
-rw-r--r-- | macros/src/codegen/locals.rs | 9 | ||||
-rw-r--r-- | macros/src/codegen/module.rs | 48 | ||||
-rw-r--r-- | macros/src/codegen/post_init.rs | 149 | ||||
-rw-r--r-- | macros/src/codegen/pre_init.rs | 109 | ||||
-rw-r--r-- | macros/src/codegen/resources.rs | 67 | ||||
-rw-r--r-- | macros/src/codegen/resources_struct.rs | 19 | ||||
-rw-r--r-- | macros/src/codegen/schedule.rs | 23 | ||||
-rw-r--r-- | macros/src/codegen/schedule_body.rs | 14 | ||||
-rw-r--r-- | macros/src/codegen/software_tasks.rs | 181 | ||||
-rw-r--r-- | macros/src/codegen/spawn.rs | 28 | ||||
-rw-r--r-- | macros/src/codegen/spawn_body.rs | 24 | ||||
-rw-r--r-- | macros/src/codegen/timer_queue.rs | 40 | ||||
-rw-r--r-- | macros/src/codegen/util.rs | 148 |
18 files changed, 490 insertions, 882 deletions
diff --git a/macros/src/codegen/assertions.rs b/macros/src/codegen/assertions.rs index 51bbdbff..4d9aae47 100644 --- a/macros/src/codegen/assertions.rs +++ b/macros/src/codegen/assertions.rs @@ -1,32 +1,18 @@ use proc_macro2::TokenStream as TokenStream2; use quote::quote; -use crate::{analyze::Analysis, check::Extra}; +use crate::analyze::Analysis; /// Generates compile-time assertions that check that types implement the `Send` / `Sync` traits -pub fn codegen(core: u8, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> { +pub fn codegen(analysis: &Analysis) -> Vec<TokenStream2> { let mut stmts = vec![]; - // we don't generate *all* assertions on all cores because the user could conditionally import a - // type only on some core (e.g. `#[cfg(core = "0")] use some::Type;`) - - if let Some(types) = analysis.send_types.get(&core) { - for ty in types { - stmts.push(quote!(rtic::export::assert_send::<#ty>();)); - } - } - - if let Some(types) = analysis.sync_types.get(&core) { - for ty in types { - stmts.push(quote!(rtic::export::assert_sync::<#ty>();)); - } + for ty in &analysis.send_types { + stmts.push(quote!(rtic::export::assert_send::<#ty>();)); } - // if the `schedule` API is used in more than one core then we need to check that the - // `monotonic` timer can be used in multi-core context - if analysis.timer_queues.len() > 1 && analysis.timer_queues.contains_key(&core) { - let monotonic = extra.monotonic(); - stmts.push(quote!(rtic::export::assert_multicore::<#monotonic>();)); + for ty in &analysis.sync_types { + stmts.push(quote!(rtic::export::assert_sync::<#ty>();)); } stmts diff --git a/macros/src/codegen/dispatchers.rs b/macros/src/codegen/dispatchers.rs index 60b8626e..300aa996 100644 --- a/macros/src/codegen/dispatchers.rs +++ b/macros/src/codegen/dispatchers.rs @@ -8,181 +8,147 @@ use crate::{analyze::Analysis, check::Extra, codegen::util}; 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]; + let interrupts = &analysis.interrupts; + + for (&level, channel) in &analysis.channels { + let mut stmts = vec![]; + + let variants = channel + .tasks + .iter() + .map(|name| { + let cfgs = &app.software_tasks[name].cfgs; + + quote!( + #(#cfgs)* + #name + ) + }) + .collect::<Vec<_>>(); + + let doc = format!( + "Software tasks to be dispatched at priority level {}", + level, + ); + let t = util::spawn_t_ident(level); + 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(level); + let (rq_ty, rq_expr) = { + ( + quote!(rtic::export::SCRQ<#t, #n>), + quote!(rtic::export::Queue(unsafe { + rtic::export::iQueue::u8_sc() + })), + ) + }; + + let doc = format!( + "Queue of tasks ready to be dispatched at priority level {}", + level + ); + items.push(quote!( + #[doc = #doc] + static mut #rq: #rq_ty = #rq_expr; + )); + + if let Some(ceiling) = channel.ceiling { + items.push(quote!( + struct #rq<'a> { + priority: &'a rtic::export::Priority, + } + )); - for (&level, channels) in dispatchers { - let mut stmts = vec![]; + items.push(util::impl_mutex( + extra, + &[], + false, + &rq, + rq_ty, + ceiling, + quote!(&mut #rq), + )); + } - for (&sender, channel) in channels { - let cfg_sender = util::cfg_core(sender, app.args.cores); + let arms = channel + .tasks + .iter() + .map(|name| { + let task = &app.software_tasks[name]; + let cfgs = &task.cfgs; + let fq = util::fq_ident(name); + let inputs = util::inputs_ident(name); + let (_, tupled, pats, _) = util::regroup_inputs(&task.inputs); - let variants = channel - .tasks - .iter() - .map(|name| { - let cfgs = &app.software_tasks[name].cfgs; + let (let_instant, instant) = if app.uses_schedule() { + let instants = util::instants_ident(name); - 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, section) = if sender == receiver { ( - cfg_sender.clone(), - quote!(rtic::export::SCRQ<#t, #n>), - quote!(rtic::export::Queue(unsafe { - rtic::export::iQueue::u8_sc() - })), - util::link_section("bss", sender), + quote!( + let instant = + #instants.get_unchecked(usize::from(index)).as_ptr().read(); + ), + quote!(, instant), ) } else { - let shared = if cfg!(feature = "heterogeneous") { - Some(quote!(#[rtic::export::shared])) - } else { - None - }; - - ( - shared, - quote!(rtic::export::MCRQ<#t, #n>), - quote!(rtic::export::Queue(rtic::export::iQueue::u8())), - None, - ) + (quote!(), quote!()) }; - 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 - #section - static mut #rq: #rq_ty = #rq_expr; - )); - - if let Some(ceiling) = channel.ceiling { - items.push(quote!( - #cfg_sender - struct #rq<'a> { - priority: &'a rtic::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(),) - }; + 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 = &rtic::export::Priority::new(PRIORITY); - crate::#name( - #locals_new - #name::Context::new(priority #instant) - #(,#pats)* - ) - } + 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 = &rtic::export::Priority::new(PRIORITY); + crate::#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 section = util::link_section("text", receiver); - let interrupt = util::suffixed(&interrupts[&level].to_string(), receiver); - items.push(quote!( - #[allow(non_snake_case)] - #[doc = #doc] - #[no_mangle] - #cfg_receiver - #section - unsafe fn #interrupt() { - /// The priority of this interrupt handler - const PRIORITY: u8 = #level; - - rtic::export::run(PRIORITY, || { - #(#stmts)* - }); + ) + }) + .collect::<Vec<_>>(); + + stmts.push(quote!( + while let Some((task, index)) = #rq.split().1.dequeue() { + match task { + #(#arms)* } - )); - } + } + )); + + let doc = format!("Interrupt handler to dispatch tasks at priority {}", level); + let interrupt = util::suffixed(&interrupts[&level].to_string()); + items.push(quote!( + #[allow(non_snake_case)] + #[doc = #doc] + #[no_mangle] + unsafe fn #interrupt() { + /// The priority of this interrupt handler + const PRIORITY: u8 = #level; + + rtic::export::run(PRIORITY, || { + #(#stmts)* + }); + } + )); } items diff --git a/macros/src/codegen/hardware_tasks.rs b/macros/src/codegen/hardware_tasks.rs index 453dbccb..25f1df41 100644 --- a/macros/src/codegen/hardware_tasks.rs +++ b/macros/src/codegen/hardware_tasks.rs @@ -1,11 +1,11 @@ use proc_macro2::TokenStream as TokenStream2; -use quote::quote; +use quote::{format_ident, quote}; use rtic_syntax::{ast::App, Context}; use crate::{ analyze::Analysis, check::Extra, - codegen::{locals, module, resources_struct, util}, + codegen::{locals, module, resources_struct}, }; /// Generate support code for hardware tasks (`#[exception]`s and `#[interrupt]`s) @@ -14,7 +14,7 @@ pub fn codegen( analysis: &Analysis, extra: &Extra, ) -> ( - // const_app_hardware_tasks -- interrupt handlers and `${task}Resources` constructors + // mod_app_hardware_tasks -- interrupt handlers and `${task}Resources` constructors Vec<TokenStream2>, // root_hardware_tasks -- items that must be placed in the root of the crate: // - `${task}Locals` structs @@ -23,16 +23,16 @@ pub fn codegen( Vec<TokenStream2>, // user_hardware_tasks -- the `#[task]` functions written by the user Vec<TokenStream2>, + // user_hardware_tasks_imports -- the imports for `#[task]` functions written by the user + Vec<TokenStream2>, ) { - let mut const_app = vec![]; + let mut mod_app = vec![]; let mut root = vec![]; let mut user_tasks = vec![]; + let mut hardware_tasks_imports = vec![]; for (name, task) in &app.hardware_tasks { - let core = task.args.core; - let cfg_core = util::cfg_core(core, app.args.cores); - - let (let_instant, instant) = if app.uses_schedule(core) { + let (let_instant, instant) = if app.uses_schedule() { let m = extra.monotonic(); ( @@ -49,19 +49,12 @@ pub fn codegen( quote!(#name::Locals::new(),) }; - let symbol = if cfg!(feature = "homogeneous") { - util::suffixed(&task.args.binds.to_string(), core) - } else { - task.args.binds.clone() - }; + let symbol = task.args.binds.clone(); let priority = task.args.priority; - let section = util::link_section("text", core); - const_app.push(quote!( + mod_app.push(quote!( #[allow(non_snake_case)] #[no_mangle] - #section - #cfg_core unsafe fn #symbol() { const PRIORITY: u8 = #priority; @@ -88,9 +81,16 @@ pub fn codegen( analysis, ); + // Add resources to imports + let name_res = format_ident!("{}Resources", name); + hardware_tasks_imports.push(quote!( + #[allow(non_snake_case)] + use super::#name_res; + )); + root.push(item); - const_app.push(constructor); + mod_app.push(constructor); } root.push(module::codegen( @@ -103,8 +103,7 @@ pub fn codegen( // `${task}Locals` let mut locals_pat = None; if !task.locals.is_empty() { - let (struct_, pat) = - locals::codegen(Context::HardwareTask(name), &task.locals, core, app); + let (struct_, pat) = locals::codegen(Context::HardwareTask(name), &task.locals, app); root.push(struct_); locals_pat = Some(pat); @@ -113,20 +112,23 @@ pub fn codegen( let attrs = &task.attrs; let context = &task.context; let stmts = &task.stmts; - let section = util::link_section("text", core); - // XXX shouldn't this have a cfg_core? let locals_pat = locals_pat.iter(); user_tasks.push(quote!( #(#attrs)* #[allow(non_snake_case)] - #section fn #name(#(#locals_pat,)* #context: #name::Context) { use rtic::Mutex as _; #(#stmts)* } )); + + hardware_tasks_imports.push(quote!( + #(#attrs)* + #[allow(non_snake_case)] + use super::#name; + )); } - (const_app, root, user_tasks) + (mod_app, root, user_tasks, hardware_tasks_imports) } diff --git a/macros/src/codegen/idle.rs b/macros/src/codegen/idle.rs index 032c8ade..2e2932d7 100644 --- a/macros/src/codegen/idle.rs +++ b/macros/src/codegen/idle.rs @@ -1,21 +1,20 @@ use proc_macro2::TokenStream as TokenStream2; -use quote::quote; +use quote::{format_ident, quote}; use rtic_syntax::{ast::App, Context}; use crate::{ analyze::Analysis, check::Extra, - codegen::{locals, module, resources_struct, util}, + codegen::{locals, module, resources_struct}, }; /// Generates support code for `#[idle]` functions pub fn codegen( - core: u8, app: &App, analysis: &Analysis, extra: &Extra, ) -> ( - // const_app_idle -- the `${idle}Resources` constructor + // mod_app_idle -- the `${idle}Resources` constructor Option<TokenStream2>, // root_idle -- items that must be placed in the root of the crate: // - the `${idle}Locals` struct @@ -24,52 +23,65 @@ pub fn codegen( Vec<TokenStream2>, // user_idle Option<TokenStream2>, + // user_idle_imports + Vec<TokenStream2>, // call_idle TokenStream2, ) { - if let Some(idle) = app.idles.get(&core) { + if app.idles.len() > 0 { + let idle = &app.idles.first().unwrap(); let mut needs_lt = false; - let mut const_app = None; + let mut mod_app = None; let mut root_idle = vec![]; let mut locals_pat = None; let mut locals_new = None; + let mut user_idle_imports = vec![]; + + let name = &idle.name; + if !idle.args.resources.is_empty() { let (item, constructor) = - resources_struct::codegen(Context::Idle(core), 0, &mut needs_lt, app, analysis); + resources_struct::codegen(Context::Idle, 0, &mut needs_lt, app, analysis); root_idle.push(item); - const_app = Some(constructor); + mod_app = Some(constructor); + + let name_resource = format_ident!("{}Resources", name); + user_idle_imports.push(quote!( + #[allow(non_snake_case)] + use super::#name_resource; + )); } - let name = &idle.name; if !idle.locals.is_empty() { - let (locals, pat) = locals::codegen(Context::Idle(core), &idle.locals, core, app); + let (locals, pat) = locals::codegen(Context::Idle, &idle.locals, app); locals_new = Some(quote!(#name::Locals::new())); locals_pat = Some(pat); root_idle.push(locals); } - root_idle.push(module::codegen(Context::Idle(core), needs_lt, app, extra)); + root_idle.push(module::codegen(Context::Idle, needs_lt, app, extra)); - let cfg_core = util::cfg_core(core, app.args.cores); let attrs = &idle.attrs; let context = &idle.context; let stmts = &idle.stmts; - let section = util::link_section("text", core); let locals_pat = locals_pat.iter(); let user_idle = Some(quote!( #(#attrs)* #[allow(non_snake_case)] - #cfg_core - #section fn #name(#(#locals_pat,)* #context: #name::Context) -> ! { use rtic::Mutex as _; #(#stmts)* } )); + user_idle_imports.push(quote!( + #(#attrs)* + #[allow(non_snake_case)] + use super::#name; + )); let locals_new = locals_new.iter(); let call_idle = quote!(crate::#name( @@ -77,12 +89,13 @@ pub fn codegen( #name::Context::new(&rtic::export::Priority::new(0)) )); - (const_app, root_idle, user_idle, call_idle) + (mod_app, root_idle, user_idle, user_idle_imports, call_idle) } else { ( None, vec![], None, + vec![], quote!(loop { rtic::export::wfi() }), diff --git a/macros/src/codegen/init.rs b/macros/src/codegen/init.rs index fa273fee..8942439b 100644 --- a/macros/src/codegen/init.rs +++ b/macros/src/codegen/init.rs @@ -1,5 +1,5 @@ use proc_macro2::TokenStream as TokenStream2; -use quote::quote; +use quote::{format_ident, quote}; use rtic_syntax::{ast::App, Context}; use crate::{ @@ -10,12 +10,11 @@ use crate::{ /// Generates support code for `#[init]` functions pub fn codegen( - core: u8, app: &App, analysis: &Analysis, extra: &Extra, ) -> ( - // const_app_idle -- the `${init}Resources` constructor + // mod_app_idle -- the `${init}Resources` constructor Option<TokenStream2>, // root_init -- items that must be placed in the root of the crate: // - the `${init}Locals` struct @@ -25,58 +24,55 @@ pub fn codegen( Vec<TokenStream2>, // user_init -- the `#[init]` function written by the user Option<TokenStream2>, + // user_init_imports -- the imports for `#[init]` functio written by the user + Vec<TokenStream2>, // call_init -- the call to the user `#[init]` if there's one Option<TokenStream2>, ) { - if let Some(init) = app.inits.get(&core) { - let cfg_core = util::cfg_core(core, app.args.cores); + if app.inits.len() > 0 { + let init = &app.inits.first().unwrap(); let mut needs_lt = false; let name = &init.name; let mut root_init = vec![]; - let ret = { - let late_fields = analysis - .late_resources - .get(&core) - .map(|resources| { - resources - .iter() - .map(|name| { - let ty = &app.late_resources[name].ty; - let cfgs = &app.late_resources[name].cfgs; - - quote!( - #(#cfgs)* - pub #name: #ty - ) - }) - .collect::<Vec<_>>() + let late_fields = analysis + .late_resources + .iter() + .flat_map(|resources| { + resources.iter().map(|name| { + let ty = &app.late_resources[name].ty; + let cfgs = &app.late_resources[name].cfgs; + + quote!( + #(#cfgs)* + pub #name: #ty + ) }) - .unwrap_or(vec![]); + }) + .collect::<Vec<_>>(); - if !late_fields.is_empty() { - let late_resources = util::late_resources_ident(&name); + let mut user_init_imports = vec![]; + let late_resources = util::late_resources_ident(&name); - root_init.push(quote!( - /// Resources initialized at runtime - #cfg_core - #[allow(non_snake_case)] - pub struct #late_resources { - #(#late_fields),* - } - )); - - Some(quote!(-> #name::LateResources)) - } else { - None + root_init.push(quote!( + /// Resources initialized at runtime + #[allow(non_snake_case)] + pub struct #late_resources { + #(#late_fields),* } - }; + )); + + let name_late = format_ident!("{}LateResources", name); + user_init_imports.push(quote!( + #[allow(non_snake_case)] + use super::#name_late; + )); let mut locals_pat = None; let mut locals_new = None; if !init.locals.is_empty() { - let (struct_, pat) = locals::codegen(Context::Init(core), &init.locals, core, app); + let (struct_, pat) = locals::codegen(Context::Init, &init.locals, app); locals_new = Some(quote!(#name::Locals::new())); locals_pat = Some(pat); @@ -86,25 +82,33 @@ pub fn codegen( let context = &init.context; let attrs = &init.attrs; let stmts = &init.stmts; - let section = util::link_section("text", core); let locals_pat = locals_pat.iter(); let user_init = Some(quote!( #(#attrs)* - #cfg_core #[allow(non_snake_case)] - #section - fn #name(#(#locals_pat,)* #context: #name::Context) #ret { + fn #name(#(#locals_pat,)* #context: #name::Context) -> #name::LateResources { #(#stmts)* } )); + user_init_imports.push(quote!( + #(#attrs)* + #[allow(non_snake_case)] + use super::#name; + )); - let mut const_app = None; + let mut mod_app = None; if !init.args.resources.is_empty() { let (item, constructor) = - resources_struct::codegen(Context::Init(core), 0, &mut needs_lt, app, analysis); + resources_struct::codegen(Context::Init, 0, &mut needs_lt, app, analysis); root_init.push(item); - const_app = Some(constructor); + mod_app = Some(constructor); + + let name_late = format_ident!("{}Resources", name); + user_init_imports.push(quote!( + #[allow(non_snake_case)] + use super::#name_late; + )); } let locals_new = locals_new.iter(); @@ -112,10 +116,10 @@ pub fn codegen( quote!(let late = crate::#name(#(#locals_new,)* #name::Context::new(core.into()));), ); - root_init.push(module::codegen(Context::Init(core), needs_lt, app, extra)); + root_init.push(module::codegen(Context::Init, needs_lt, app, extra)); - (const_app, root_init, user_init, call_init) + (mod_app, root_init, user_init, user_init_imports, call_init) } else { - (None, vec![], None, None) + (None, vec![], None, vec![], None) } } diff --git a/macros/src/codegen/locals.rs b/macros/src/codegen/locals.rs index 127f4b09..336c0b21 100644 --- a/macros/src/codegen/locals.rs +++ b/macros/src/codegen/locals.rs @@ -2,7 +2,7 @@ use proc_macro2::TokenStream as TokenStream2; use quote::quote; use rtic_syntax::{ ast::{App, Local}, - Context, Core, Map, + Context, Map, }; use crate::codegen::util; @@ -10,7 +10,6 @@ use crate::codegen::util; pub fn codegen( ctxt: Context, locals: &Map<Local>, - core: Core, app: &App, ) -> ( // locals @@ -42,11 +41,6 @@ pub fn codegen( let cfgs = &local.cfgs; has_cfgs |= !cfgs.is_empty(); - let section = if local.shared && cfg!(feature = "heterogeneous") { - Some(quote!(#[rtic::export::shared])) - } else { - util::link_section("data", core) - }; let expr = &local.expr; let ty = &local.ty; fields.push(quote!( @@ -55,7 +49,6 @@ pub fn codegen( )); items.push(quote!( #(#cfgs)* - #section static mut #name: #ty = #expr )); values.push(quote!( diff --git a/macros/src/codegen/module.rs b/macros/src/codegen/module.rs index 1b21209f..2e51e7db 100644 --- a/macros/src/codegen/module.rs +++ b/macros/src/codegen/module.rs @@ -11,12 +11,11 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) -> let name = ctxt.ident(app); - let core = ctxt.core(app); let mut needs_instant = false; let mut lt = None; match ctxt { - Context::Init(core) => { - if app.uses_schedule(core) { + Context::Init => { + if app.uses_schedule() { let m = extra.monotonic(); fields.push(quote!( @@ -37,7 +36,7 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) -> )); } - if extra.peripherals == Some(core) { + if extra.peripherals { let device = extra.device; fields.push(quote!( @@ -48,13 +47,21 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) -> values.push(quote!(device: #device::Peripherals::steal())); } + lt = Some(quote!('a)); + fields.push(quote!( + /// Critical section token for init + pub cs: rtic::export::CriticalSection<#lt> + )); + + values.push(quote!(cs: rtic::export::CriticalSection::new())); + values.push(quote!(core)); } - Context::Idle(..) => {} + Context::Idle => {} Context::HardwareTask(..) => { - if app.uses_schedule(core) { + if app.uses_schedule() { let m = extra.monotonic(); fields.push(quote!( @@ -69,7 +76,7 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) -> } Context::SoftwareTask(..) => { - if app.uses_schedule(core) { + if app.uses_schedule() { let m = extra.monotonic(); fields.push(quote!( @@ -205,7 +212,7 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) -> values.push(quote!(spawn: Spawn { priority })); } else { - let instant_field = if app.uses_schedule(core) { + let instant_field = if app.uses_schedule() { let m = extra.monotonic(); needs_instant = true; @@ -252,27 +259,25 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) -> } } - if let Context::Init(core) = ctxt { - let init = &app.inits[&core]; - if init.returns_late_resources { - let late_resources = util::late_resources_ident(&init.name); + if let Context::Init = ctxt { + let init = &app.inits.first().unwrap(); + let late_resources = util::late_resources_ident(&init.name); - items.push(quote!( - #[doc(inline)] - pub use super::#late_resources as LateResources; - )); - } + items.push(quote!( + #[doc(inline)] + pub use super::#late_resources as LateResources; + )); } let doc = match ctxt { - Context::Idle(_) => "Idle loop", - Context::Init(_) => "Initialization function", + Context::Idle => "Idle loop", + Context::Init => "Initialization function", Context::HardwareTask(_) => "Hardware task", Context::SoftwareTask(_) => "Software task", }; let core = if ctxt.is_init() { - if app.uses_schedule(core) { + if app.uses_schedule() { Some(quote!(core: rtic::Peripherals,)) } else { Some(quote!(core: rtic::export::Peripherals,)) @@ -312,12 +317,9 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) -> )); if !items.is_empty() { - let cfg_core = util::cfg_core(ctxt.core(app), app.args.cores); - quote!( #[allow(non_snake_case)] #[doc = #doc] - #cfg_core pub mod #name { #(#items)* } diff --git a/macros/src/codegen/post_init.rs b/macros/src/codegen/post_init.rs index 0c740e85..c35c6976 100644 --- a/macros/src/codegen/post_init.rs +++ b/macros/src/codegen/post_init.rs @@ -2,22 +2,17 @@ use proc_macro2::TokenStream as TokenStream2; use quote::quote; use rtic_syntax::ast::App; -use crate::{analyze::Analysis, check::Extra, codegen::util}; +use crate::analyze::Analysis; /// Generates code that runs after `#[init]` returns -pub fn codegen( - core: u8, - app: &App, - analysis: &Analysis, - extra: &Extra, -) -> (Vec<TokenStream2>, Vec<TokenStream2>) { - let mut const_app = vec![]; +pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> { let mut stmts = vec![]; - // initialize late resources - if let Some(late_resources) = analysis.late_resources.get(&core) { - for name in late_resources { - // if it's live + // Initialize late resources + if analysis.late_resources.len() > 0 { + // BTreeSet wrapped in a vector + for name in analysis.late_resources.first().unwrap() { + // If it's live let cfgs = app.late_resources[name].cfgs.clone(); if analysis.locations.get(name).is_some() { // Need to also include the cfgs @@ -29,134 +24,8 @@ pub fn codegen( } } - if analysis.timer_queues.is_empty() { - // cross-initialization barriers -- notify *other* cores that their resources have been - // initialized - for (user, initializers) in &analysis.initialization_barriers { - if !initializers.contains(&core) { - continue; - } - - let ib = util::init_barrier(*user); - let shared = if cfg!(feature = "heterogeneous") { - Some(quote!( - #[rtic::export::shared] - )) - } else { - None - }; - - const_app.push(quote!( - #shared - static #ib: rtic::export::Barrier = rtic::export::Barrier::new(); - )); - - stmts.push(quote!( - #ib.release(); - )); - } - - // then wait until the other cores have initialized *our* resources - if analysis.initialization_barriers.contains_key(&core) { - let ib = util::init_barrier(core); - - stmts.push(quote!( - #ib.wait(); - )); - } - - // cross-spawn barriers: wait until other cores are ready to receive messages - for (&receiver, senders) in &analysis.spawn_barriers { - if senders.get(&core) == Some(&false) { - let sb = util::spawn_barrier(receiver); - - stmts.push(quote!( - #sb.wait(); - )); - } - } - } else { - // if the `schedule` API is used then we'll synchronize all cores to leave the - // `init`-ialization phase at the same time. In this case the rendezvous barrier makes the - // cross-initialization and spawn barriers unnecessary - - let m = extra.monotonic(); - - if analysis.timer_queues.len() == 1 { - // reset the monotonic timer / counter - stmts.push(quote!( - <#m as rtic::Monotonic>::reset(); - )); - } else { - // in the multi-core case we need a rendezvous (RV) barrier between *all* the cores that - // use the `schedule` API; otherwise one of the cores could observe the before-reset - // value of the monotonic counter - // (this may be easier to implement with `AtomicU8.fetch_sub` but that API is not - // available on ARMv6-M) - - // this core will reset the monotonic counter - const FIRST: u8 = 0; - - if core == FIRST { - for &i in analysis.timer_queues.keys() { - let rv = util::rendezvous_ident(i); - let shared = if cfg!(feature = "heterogeneous") { - Some(quote!( - #[rtic::export::shared] - )) - } else { - None - }; - - const_app.push(quote!( - #shared - static #rv: rtic::export::Barrier = rtic::export::Barrier::new(); - )); - - // wait until all the other cores have reached the RV point - if i != FIRST { - stmts.push(quote!( - #rv.wait(); - )); - } - } - - let rv = util::rendezvous_ident(core); - stmts.push(quote!( - // the compiler fences are used to prevent `reset` from being re-ordering wrt to - // the atomic operations -- we don't know if `reset` contains load or store - // operations - - core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst); - - // reset the counter - <#m as rtic::Monotonic>::reset(); - - core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst); - - // now unblock all the other cores - #rv.release(); - )); - } else { - let rv = util::rendezvous_ident(core); - - // let the first core know that we have reached the RV point - stmts.push(quote!( - #rv.release(); - )); - - let rv = util::rendezvous_ident(FIRST); - - // wait until the first core has reset the monotonic timer - stmts.push(quote!( - #rv.wait(); - )); - } - } - } - - // enable the interrupts -- this completes the `init`-ialization phase + // Enable the interrupts -- this completes the `init`-ialization phase stmts.push(quote!(rtic::export::interrupt::enable();)); - (const_app, stmts) + stmts } diff --git a/macros/src/codegen/pre_init.rs b/macros/src/codegen/pre_init.rs index 8aae5998..9c5f35ec 100644 --- a/macros/src/codegen/pre_init.rs +++ b/macros/src/codegen/pre_init.rs @@ -5,76 +5,52 @@ use rtic_syntax::ast::App; use crate::{analyze::Analysis, check::Extra, codegen::util}; /// Generates code that runs before `#[init]` -pub fn codegen( - core: u8, - app: &App, - analysis: &Analysis, - extra: &Extra, -) -> ( - // `const_app_pre_init` -- `static` variables for barriers - Vec<TokenStream2>, - // `pre_init_stmts` - Vec<TokenStream2>, -) { - let mut const_app = vec![]; +pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> { let mut stmts = vec![]; - // disable interrupts -- `init` must run with interrupts disabled + // Disable interrupts -- `init` must run with interrupts disabled stmts.push(quote!(rtic::export::interrupt::disable();)); - // populate this core `FreeQueue`s - for (name, senders) in &analysis.free_queues { + // Populate the FreeQueue + for fq in &analysis.free_queues { + // Get the task name + let name = fq.0; let task = &app.software_tasks[name]; let cap = task.args.capacity; - for &sender in senders.keys() { - if sender == core { - let fq = util::fq_ident(name, sender); + let fq_ident = util::fq_ident(name); - stmts.push(quote!( - (0..#cap).for_each(|i| #fq.enqueue_unchecked(i)); - )); - } - } - } - - if app.args.cores == 1 { - stmts.push(quote!( - // To set the variable in cortex_m so the peripherals cannot be taken multiple times - let peripherals = cortex_m::Peripherals::steal(); - let mut core: rtic::export::Peripherals = peripherals.into(); - )); - } else { stmts.push(quote!( - // NOTE(transmute) to avoid debug_assertion in multi-core mode - // (This code will go away when we drop multi-core mode) - let mut core: rtic::export::Peripherals = core::mem::transmute(()); + (0..#cap).for_each(|i| #fq_ident.enqueue_unchecked(i)); )); } + stmts.push(quote!( + // To set the variable in cortex_m so the peripherals cannot be taken multiple times + let mut core: rtic::export::Peripherals = rtic::export::Peripherals::steal().into(); + )); + let device = extra.device; let nvic_prio_bits = quote!(#device::NVIC_PRIO_BITS); - // unmask interrupts and set their priorities + // Unmask interrupts and set their priorities for (&priority, name) in analysis .interrupts - .get(&core) .iter() - .flat_map(|interrupts| *interrupts) .chain(app.hardware_tasks.values().flat_map(|task| { if !util::is_exception(&task.args.binds) { Some((&task.args.priority, &task.args.binds)) } else { - // we do exceptions in another pass + // We do exceptions in another pass None } })) { - // compile time assert that this priority is supported by the device + // Compile time assert that this priority is supported by the device stmts.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];)); // NOTE this also checks that the interrupt exists in the `Interrupt` enumeration - let interrupt = util::interrupt_ident(core, app.args.cores); + let interrupt = util::interrupt_ident(); stmts.push(quote!( core.NVIC.set_priority( #device::#interrupt::#name, @@ -87,30 +63,7 @@ pub fn codegen( stmts.push(quote!(rtic::export::NVIC::unmask(#device::#interrupt::#name);)); } - // cross-spawn barriers: now that priorities have been set and the interrupts have been unmasked - // we are ready to receive messages from *other* cores - if analysis.spawn_barriers.contains_key(&core) { - let sb = util::spawn_barrier(core); - let shared = if cfg!(feature = "heterogeneous") { - Some(quote!( - #[rtic::export::shared] - )) - } else { - None - }; - - const_app.push(quote!( - #shared - static #sb: rtic::export::Barrier = rtic::export::Barrier::new(); - )); - - // unblock cores that may send us a message - stmts.push(quote!( - #sb.release(); - )); - } - - // set exception priorities + // Set exception priorities for (name, priority) in app.hardware_tasks.values().filter_map(|task| { if util::is_exception(&task.args.binds) { Some((&task.args.binds, task.args.priority)) @@ -118,7 +71,7 @@ pub fn codegen( None } }) { - // compile time assert that this priority is supported by the device + // Compile time assert that this priority is supported by the device stmts.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];)); stmts.push(quote!(core.SCB.set_priority( @@ -127,11 +80,11 @@ pub fn codegen( );)); } - // initialize the SysTick - if let Some(tq) = analysis.timer_queues.get(&core) { + // Initialize the SysTick if there exist a TimerQueue + if let Some(tq) = analysis.timer_queues.first() { let priority = tq.priority; - // compile time assert that this priority is supported by the device + // Compile time assert that this priority is supported by the device stmts.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];)); stmts.push(quote!(core.SCB.set_priority( @@ -146,23 +99,11 @@ pub fn codegen( )); } - // if there's no user `#[idle]` then optimize returning from interrupt handlers - if app.idles.get(&core).is_none() { + // If there's no user `#[idle]` then optimize returning from interrupt handlers + if app.idles.is_empty() { // Set SLEEPONEXIT bit to enter sleep mode when returning from ISR stmts.push(quote!(core.SCB.scr.modify(|r| r | 1 << 1);)); } - // cross-spawn barriers: wait until other cores are ready to receive messages - for (&receiver, senders) in &analysis.spawn_barriers { - // only block here if `init` can send messages to `receiver` - if senders.get(&core) == Some(&true) { - let sb = util::spawn_barrier(receiver); - - stmts.push(quote!( - #sb.wait(); - )); - } - } - - (const_app, stmts) + stmts } diff --git a/macros/src/codegen/resources.rs b/macros/src/codegen/resources.rs index 0bec3e5a..38ea5245 100644 --- a/macros/src/codegen/resources.rs +++ b/macros/src/codegen/resources.rs @@ -1,9 +1,6 @@ use proc_macro2::TokenStream as TokenStream2; use quote::quote; -use rtic_syntax::{ - analyze::{Location, Ownership}, - ast::App, -}; +use rtic_syntax::{analyze::Ownership, ast::App}; use crate::{analyze::Analysis, check::Extra, codegen::util}; @@ -13,45 +10,26 @@ pub fn codegen( analysis: &Analysis, extra: &Extra, ) -> ( - // const_app -- the `static [mut]` variables behind the proxies + // mod_app -- the `static [mut]` variables behind the proxies Vec<TokenStream2>, // mod_resources -- the `resources` module TokenStream2, + // mod_resources_imports -- the `resources` module imports + Vec<TokenStream2>, ) { - let mut const_app = vec![]; + let mut mod_app = vec![]; let mut mod_resources = vec![]; + let mut mod_resources_imports = vec![]; - for (name, res, expr, loc) in app.resources(analysis) { + for (name, res, expr, _) in app.resources(analysis) { let cfgs = &res.cfgs; let ty = &res.ty; { - let (loc_attr, section) = match loc { - Location::Owned { - core, - cross_initialized: false, - } => ( - util::cfg_core(*core, app.args.cores), - if expr.is_none() { - util::link_section_uninit(Some(*core)) - } else { - util::link_section("data", *core) - }, - ), - - // shared `static`s and cross-initialized resources need to be in `.shared` memory - _ => ( - if cfg!(feature = "heterogeneous") { - Some(quote!(#[rtic::export::shared])) - } else { - None - }, - if expr.is_none() { - util::link_section_uninit(None) - } else { - None - }, - ), + let section = if expr.is_none() { + util::link_section_uninit(true) + } else { + None }; let (ty, expr) = if let Some(expr) = expr { @@ -64,29 +42,24 @@ pub fn codegen( }; let attrs = &res.attrs; - const_app.push(quote!( + mod_app.push(quote!( #[allow(non_upper_case_globals)] #(#attrs)* #(#cfgs)* - #loc_attr #section static mut #name: #ty = #expr; )); } if let Some(Ownership::Contended { ceiling }) = analysis.ownerships.get(name) { - let cfg_core = util::cfg_core(loc.core().expect("UNREACHABLE"), app.args.cores); - mod_resources.push(quote!( #[allow(non_camel_case_types)] #(#cfgs)* - #cfg_core pub struct #name<'a> { priority: &'a Priority, } #(#cfgs)* - #cfg_core impl<'a> #name<'a> { #[inline(always)] pub unsafe fn new(priority: &'a Priority) -> Self { @@ -112,10 +85,15 @@ pub fn codegen( ) }; - const_app.push(util::impl_mutex( + mod_resources_imports.push(quote!( + #[allow(non_camel_case_types)] + #(#cfgs)* + use super::resources::#name; + )); + + mod_app.push(util::impl_mutex( extra, cfgs, - cfg_core.as_ref(), true, name, quote!(#ty), @@ -128,6 +106,11 @@ pub fn codegen( let mod_resources = if mod_resources.is_empty() { quote!() } else { + // Also import the resource module + mod_resources_imports.push(quote!( + use super::resources; + )); + quote!(mod resources { use rtic::export::Priority; @@ -135,5 +118,5 @@ pub fn codegen( }) }; - (const_app, mod_resources) + (mod_app, mod_resources, mod_resources_imports) } diff --git a/macros/src/codegen/resources_struct.rs b/macros/src/codegen/resources_struct.rs index 994e751c..92d5b666 100644 --- a/macros/src/codegen/resources_struct.rs +++ b/macros/src/codegen/resources_struct.rs @@ -14,8 +14,8 @@ pub fn codegen( let mut lt = None; let resources = match ctxt { - Context::Init(core) => &app.inits[&core].args.resources, - Context::Idle(core) => &app.idles[&core].args.resources, + Context::Init => &app.inits.first().unwrap().args.resources, + Context::Idle => &app.idles.first().unwrap().args.resources, Context::HardwareTask(name) => &app.hardware_tasks[name].args.resources, Context::SoftwareTask(name) => &app.software_tasks[name].args.resources, }; @@ -39,7 +39,7 @@ pub fn codegen( if ctxt.is_init() { if !analysis.ownerships.contains_key(name) { - // owned by `init` + // Owned by `init` fields.push(quote!( #(#cfgs)* pub #name: &'static #mut_ #ty @@ -50,7 +50,7 @@ pub fn codegen( #name: &#mut_ #name )); } else { - // owned by someone else + // Owned by someone else lt = Some(quote!('a)); fields.push(quote!( @@ -75,7 +75,7 @@ pub fn codegen( pub #name: &'a #ty )); } else { - // resource proxy + // Resource proxy lt = Some(quote!('a)); fields.push(quote!( @@ -136,7 +136,7 @@ pub fn codegen( if lt.is_some() { *needs_lt = true; - // the struct could end up empty due to `cfg`s leading to an error due to `'a` being unused + // The struct could end up empty due to `cfg`s leading to an error due to `'a` being unused if has_cfgs { fields.push(quote!( #[doc(hidden)] @@ -147,13 +147,9 @@ pub fn codegen( } } - let core = ctxt.core(app); - let cores = app.args.cores; - let cfg_core = util::cfg_core(core, cores); let doc = format!("Resources `{}` has access to", ctxt.ident(app)); let ident = util::resources_ident(ctxt, app); let item = quote!( - #cfg_core #[allow(non_snake_case)] #[doc = #doc] pub struct #ident<#lt> { @@ -167,10 +163,9 @@ pub fn codegen( Some(quote!(priority: &#lt rtic::export::Priority)) }; let constructor = quote!( - #cfg_core impl<#lt> #ident<#lt> { #[inline(always)] - unsafe fn new(#arg) -> Self { + pub unsafe fn new(#arg) -> Self { #ident { #(#values,)* } diff --git a/macros/src/codegen/schedule.rs b/macros/src/codegen/schedule.rs index 728d3a09..5a887496 100644 --- a/macros/src/codegen/schedule.rs +++ b/macros/src/codegen/schedule.rs @@ -1,4 +1,4 @@ -use std::collections::{BTreeMap, HashSet}; +use std::collections::HashSet; use proc_macro2::TokenStream as TokenStream2; use quote::quote; @@ -13,14 +13,11 @@ use crate::{ pub fn codegen(app: &App, extra: &Extra) -> Vec<TokenStream2> { let mut items = vec![]; - let mut seen = BTreeMap::<u8, HashSet<_>>::new(); + let mut seen = HashSet::<_>::new(); for (scheduler, schedulees) in app.schedule_callers() { let m = extra.monotonic(); let instant = quote!(<#m as rtic::Monotonic>::Instant); - let sender = scheduler.core(app); - let cfg_sender = util::cfg_core(sender, app.args.cores); - let seen = seen.entry(sender).or_default(); let mut methods = vec![]; for name in schedulees { @@ -35,29 +32,24 @@ pub fn codegen(app: &App, extra: &Extra) -> Vec<TokenStream2> { let body = schedule_body::codegen(scheduler, &name, app); - let section = util::link_section("text", sender); methods.push(quote!( #(#cfgs)* - #section - fn #name(&self, instant: #instant #(,#args)*) -> Result<(), #ty> { + pub fn #name(&self, instant: #instant #(,#args)*) -> Result<(), #ty> { #body } )); } else { - let schedule = util::schedule_ident(name, sender); + let schedule = util::schedule_ident(name); if !seen.contains(name) { - // generate a `schedule_${name}_S${sender}` function + // Generate a `schedule_${name}_S${sender}` function seen.insert(name); let body = schedule_body::codegen(scheduler, &name, app); - let section = util::link_section("text", sender); items.push(quote!( - #cfg_sender #(#cfgs)* - #section - unsafe fn #schedule( + pub unsafe fn #schedule( priority: &rtic::export::Priority, instant: #instant #(,#args)* @@ -70,7 +62,7 @@ pub fn codegen(app: &App, extra: &Extra) -> Vec<TokenStream2> { methods.push(quote!( #(#cfgs)* #[inline(always)] - fn #name(&self, instant: #instant #(,#args)*) -> Result<(), #ty> { + pub fn #name(&self, instant: #instant #(,#args)*) -> Result<(), #ty> { unsafe { #schedule(self.priority(), instant #(,#untupled)*) } @@ -88,7 +80,6 @@ pub fn codegen(app: &App, extra: &Extra) -> Vec<TokenStream2> { let scheduler = scheduler.ident(app); debug_assert!(!methods.is_empty()); items.push(quote!( - #cfg_sender impl<#lt> #scheduler::Schedule<#lt> { #(#methods)* } diff --git a/macros/src/codegen/schedule_body.rs b/macros/src/codegen/schedule_body.rs index 8fd026c2..644930d7 100644 --- a/macros/src/codegen/schedule_body.rs +++ b/macros/src/codegen/schedule_body.rs @@ -6,12 +6,10 @@ use syn::Ident; use crate::codegen::util; pub fn codegen(scheduler: Context, name: &Ident, app: &App) -> TokenStream2 { - let sender = scheduler.core(app); let schedulee = &app.software_tasks[name]; - let receiver = schedulee.args.core; - let fq = util::fq_ident(name, sender); - let tq = util::tq_ident(sender); + let fq = util::fq_ident(name); + let tq = util::tq_ident(); let (dequeue, enqueue) = if scheduler.is_init() { (quote!(#fq.dequeue()), quote!(#tq.enqueue_unchecked(nr);)) } else { @@ -21,8 +19,8 @@ pub fn codegen(scheduler: Context, name: &Ident, app: &App) -> TokenStream2 { ) }; - let write_instant = if app.uses_schedule(receiver) { - let instants = util::instants_ident(name, sender); + let write_instant = if app.uses_schedule() { + let instants = util::instants_ident(name); Some(quote!( #instants.get_unchecked_mut(usize::from(index)).as_mut_ptr().write(instant); @@ -32,8 +30,8 @@ pub fn codegen(scheduler: Context, name: &Ident, app: &App) -> TokenStream2 { }; let (_, tupled, _, _) = util::regroup_inputs(&schedulee.inputs); - let inputs = util::inputs_ident(name, sender); - let t = util::schedule_t_ident(sender); + let inputs = util::inputs_ident(name); + let t = util::schedule_t_ident(); quote!( unsafe { use rtic::Mutex as _; diff --git a/macros/src/codegen/software_tasks.rs b/macros/src/codegen/software_tasks.rs index 14a57633..4ae37e4e 100644 --- a/macros/src/codegen/software_tasks.rs +++ b/macros/src/codegen/software_tasks.rs @@ -1,5 +1,5 @@ use proc_macro2::TokenStream as TokenStream2; -use quote::quote; +use quote::{format_ident, quote}; use rtic_syntax::{ast::App, Context}; use crate::{ @@ -13,7 +13,7 @@ pub fn codegen( analysis: &Analysis, extra: &Extra, ) -> ( - // const_app_software_tasks -- free queues, buffers and `${task}Resources` constructors + // mod_app_software_tasks -- free queues, buffers and `${task}Resources` constructors Vec<TokenStream2>, // root_software_tasks -- items that must be placed in the root of the crate: // - `${task}Locals` structs @@ -22,14 +22,15 @@ pub fn codegen( Vec<TokenStream2>, // user_software_tasks -- the `#[task]` functions written by the user Vec<TokenStream2>, + // user_software_tasks_imports -- the imports for `#[task]` functions written by the user + Vec<TokenStream2>, ) { - let mut const_app = vec![]; + let mut mod_app = vec![]; let mut root = vec![]; let mut user_tasks = vec![]; + let mut software_tasks_imports = vec![]; for (name, task) in &app.software_tasks { - let receiver = task.args.core; - let inputs = &task.inputs; let (_, _, _, input_ty) = util::regroup_inputs(inputs); @@ -37,103 +38,70 @@ pub fn codegen( let cap_lit = util::capacity_literal(cap); let cap_ty = util::capacity_typenum(cap, true); - // create free queues and inputs / instants buffers - if let Some(free_queues) = analysis.free_queues.get(name) { - for (&sender, &ceiling) in free_queues { - let cfg_sender = util::cfg_core(sender, app.args.cores); - let fq = util::fq_ident(name, sender); - - let (loc, fq_ty, fq_expr, bss, mk_uninit): ( - _, - _, - _, - _, - Box<dyn Fn() -> Option<_>>, - ) = if receiver == sender { - ( - cfg_sender.clone(), - quote!(rtic::export::SCFQ<#cap_ty>), - quote!(rtic::export::Queue(unsafe { - rtic::export::iQueue::u8_sc() - })), - util::link_section("bss", sender), - Box::new(|| util::link_section_uninit(Some(sender))), - ) - } else { - let shared = if cfg!(feature = "heterogeneous") { - Some(quote!(#[rtic::export::shared])) - } else { - None - }; - - ( - shared, - quote!(rtic::export::MCFQ<#cap_ty>), - quote!(rtic::export::Queue(rtic::export::iQueue::u8())), - None, - Box::new(|| util::link_section_uninit(None)), - ) - }; - let loc = &loc; - - const_app.push(quote!( - /// Queue version of a free-list that keeps track of empty slots in - /// the following buffers - #loc - #bss - static mut #fq: #fq_ty = #fq_expr; + // Create free queues and inputs / instants buffers + if let Some(&ceiling) = analysis.free_queues.get(name) { + let fq = util::fq_ident(name); + + let (fq_ty, fq_expr, mk_uninit): (_, _, Box<dyn Fn() -> Option<_>>) = { + ( + quote!(rtic::export::SCFQ<#cap_ty>), + quote!(rtic::export::Queue(unsafe { + rtic::export::iQueue::u8_sc() + })), + Box::new(|| util::link_section_uninit(true)), + ) + }; + mod_app.push(quote!( + /// Queue version of a free-list that keeps track of empty slots in + /// the following buffers + static mut #fq: #fq_ty = #fq_expr; + )); + + // Generate a resource proxy if needed + if let Some(ceiling) = ceiling { + mod_app.push(quote!( + struct #fq<'a> { + priority: &'a rtic::export::Priority, + } + )); + + mod_app.push(util::impl_mutex( + extra, + &[], + false, + &fq, + fq_ty, + ceiling, + quote!(&mut #fq), )); + } + + let ref elems = (0..cap) + .map(|_| quote!(core::mem::MaybeUninit::uninit())) + .collect::<Vec<_>>(); - // Generate a resource proxy if needed - if let Some(ceiling) = ceiling { - const_app.push(quote!( - #cfg_sender - struct #fq<'a> { - priority: &'a rtic::export::Priority, - } - )); - - const_app.push(util::impl_mutex( - extra, - &[], - cfg_sender.as_ref(), - false, - &fq, - fq_ty, - ceiling, - quote!(&mut #fq), - )); - } - - let ref elems = (0..cap) - .map(|_| quote!(core::mem::MaybeUninit::uninit())) - .collect::<Vec<_>>(); - - if app.uses_schedule(receiver) { - let m = extra.monotonic(); - let instants = util::instants_ident(name, sender); - - let uninit = mk_uninit(); - const_app.push(quote!( - #loc - #uninit - /// Buffer that holds the instants associated to the inputs of a task - static mut #instants: - [core::mem::MaybeUninit<<#m as rtic::Monotonic>::Instant>; #cap_lit] = - [#(#elems,)*]; - )); - } + if app.uses_schedule() { + let m = extra.monotonic(); + let instants = util::instants_ident(name); let uninit = mk_uninit(); - let inputs = util::inputs_ident(name, sender); - const_app.push(quote!( - #loc + mod_app.push(quote!( #uninit - /// Buffer that holds the inputs of a task - static mut #inputs: [core::mem::MaybeUninit<#input_ty>; #cap_lit] = + /// Buffer that holds the instants associated to the inputs of a task + static mut #instants: + [core::mem::MaybeUninit<<#m as rtic::Monotonic>::Instant>; #cap_lit] = [#(#elems,)*]; )); } + + let uninit = mk_uninit(); + let inputs = util::inputs_ident(name); + mod_app.push(quote!( + #uninit + /// Buffer that holds the inputs of a task + static mut #inputs: [core::mem::MaybeUninit<#input_ty>; #cap_lit] = + [#(#elems,)*]; + )); } // `${task}Resources` @@ -147,23 +115,27 @@ pub fn codegen( analysis, ); + // Add resources to imports + let name_res = format_ident!("{}Resources", name); + software_tasks_imports.push(quote!( + #[allow(non_snake_case)] + use super::#name_res; + )); + root.push(item); - const_app.push(constructor); + mod_app.push(constructor); } // `${task}Locals` let mut locals_pat = None; if !task.locals.is_empty() { - let (struct_, pat) = - locals::codegen(Context::SoftwareTask(name), &task.locals, receiver, app); + let (struct_, pat) = locals::codegen(Context::SoftwareTask(name), &task.locals, app); locals_pat = Some(pat); root.push(struct_); } - let cfg_receiver = util::cfg_core(receiver, app.args.cores); - let section = util::link_section("text", receiver); let context = &task.context; let attrs = &task.attrs; let cfgs = &task.cfgs; @@ -173,14 +145,17 @@ pub fn codegen( #(#attrs)* #(#cfgs)* #[allow(non_snake_case)] - #cfg_receiver - #section - fn #name(#(#locals_pat,)* #context: #name::Context #(,#inputs)*) { + pub fn #name(#(#locals_pat,)* #context: #name::Context #(,#inputs)*) { use rtic::Mutex as _; #(#stmts)* } )); + software_tasks_imports.push(quote!( + #(#cfgs)* + #[allow(non_snake_case)] + use super::#name; + )); root.push(module::codegen( Context::SoftwareTask(name), @@ -190,5 +165,5 @@ pub fn codegen( )); } - (const_app, root, user_tasks) + (mod_app, root, user_tasks, software_tasks_imports) } diff --git a/macros/src/codegen/spawn.rs b/macros/src/codegen/spawn.rs index 287c92a1..da281516 100644 --- a/macros/src/codegen/spawn.rs +++ b/macros/src/codegen/spawn.rs @@ -1,4 +1,4 @@ -use std::collections::{BTreeMap, HashSet}; +use std::collections::HashSet; use proc_macro2::TokenStream as TokenStream2; use quote::quote; @@ -14,16 +14,12 @@ use crate::{ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> { let mut items = vec![]; - let mut seen = BTreeMap::<u8, HashSet<_>>::new(); + let mut seen = HashSet::<_>::new(); for (spawner, spawnees) in app.spawn_callers() { - let sender = spawner.core(app); - let cfg_sender = util::cfg_core(sender, app.args.cores); - let seen = seen.entry(sender).or_default(); let mut methods = vec![]; for name in spawnees { let spawnee = &app.software_tasks[name]; - let receiver = spawnee.args.core; let cfgs = &spawnee.cfgs; let (args, _, untupled, ty) = util::regroup_inputs(&spawnee.inputs); let args = &args; @@ -34,7 +30,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream let body = spawn_body::codegen(spawner, &name, app, analysis, extra); - let let_instant = if app.uses_schedule(receiver) { + let let_instant = if app.uses_schedule() { let m = extra.monotonic(); Some(quote!(let instant = unsafe { <#m as rtic::Monotonic>::zero() };)) @@ -42,23 +38,21 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream None }; - let section = util::link_section("text", sender); methods.push(quote!( #(#cfgs)* - #section - fn #name(&self #(,#args)*) -> Result<(), #ty> { + pub fn #name(&self #(,#args)*) -> Result<(), #ty> { #let_instant #body } )); } else { - let spawn = util::spawn_ident(name, sender); + let spawn = util::spawn_ident(name); if !seen.contains(name) { - // generate a `spawn_${name}_S${sender}` function + // Generate a `spawn_${name}_S${sender}` function seen.insert(name); - let instant = if app.uses_schedule(receiver) { + let instant = if app.uses_schedule() { let m = extra.monotonic(); Some(quote!(, instant: <#m as rtic::Monotonic>::Instant)) @@ -68,11 +62,8 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream let body = spawn_body::codegen(spawner, &name, app, analysis, extra); - let section = util::link_section("text", sender); items.push(quote!( - #cfg_sender #(#cfgs)* - #section unsafe fn #spawn( priority: &rtic::export::Priority #instant @@ -83,7 +74,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream )); } - let (let_instant, instant) = if app.uses_schedule(receiver) { + let (let_instant, instant) = if app.uses_schedule() { let m = extra.monotonic(); ( @@ -101,7 +92,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream methods.push(quote!( #(#cfgs)* #[inline(always)] - fn #name(&self #(,#args)*) -> Result<(), #ty> { + pub fn #name(&self #(,#args)*) -> Result<(), #ty> { unsafe { #let_instant #spawn(self.priority() #instant #(,#untupled)*) @@ -120,7 +111,6 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream let spawner = spawner.ident(app); debug_assert!(!methods.is_empty()); items.push(quote!( - #cfg_sender impl<#lt> #spawner::Spawn<#lt> { #(#methods)* } diff --git a/macros/src/codegen/spawn_body.rs b/macros/src/codegen/spawn_body.rs index 3433875e..4ecd0757 100644 --- a/macros/src/codegen/spawn_body.rs +++ b/macros/src/codegen/spawn_body.rs @@ -12,13 +12,11 @@ pub fn codegen( analysis: &Analysis, extra: &Extra, ) -> TokenStream2 { - let sender = spawner.core(app); let spawnee = &app.software_tasks[name]; let priority = spawnee.args.priority; - let receiver = spawnee.args.core; - let write_instant = if app.uses_schedule(receiver) { - let instants = util::instants_ident(name, sender); + let write_instant = if app.uses_schedule() { + let instants = util::instants_ident(name); Some(quote!( #instants.get_unchecked_mut(usize::from(index)).as_mut_ptr().write(instant); @@ -27,9 +25,9 @@ pub fn codegen( None }; - let t = util::spawn_t_ident(receiver, priority, sender); - let fq = util::fq_ident(name, sender); - let rq = util::rq_ident(receiver, priority, sender); + let t = util::spawn_t_ident(priority); + let fq = util::fq_ident(name); + let rq = util::rq_ident(priority); let (dequeue, enqueue) = if spawner.is_init() { ( quote!(#fq.dequeue()), @@ -45,20 +43,16 @@ pub fn codegen( }; let device = extra.device; - let enum_ = util::interrupt_ident(receiver, app.args.cores); - let interrupt = &analysis.interrupts[&receiver][&priority]; - let pend = if sender != receiver { - quote!( - #device::xpend(#receiver, #device::#enum_::#interrupt); - ) - } else { + let enum_ = util::interrupt_ident(); + let interrupt = &analysis.interrupts.get(&priority); + let pend = { quote!( rtic::pend(#device::#enum_::#interrupt); ) }; let (_, tupled, _, _) = util::regroup_inputs(&spawnee.inputs); - let inputs = util::inputs_ident(name, sender); + let inputs = util::inputs_ident(name); quote!( unsafe { use rtic::Mutex as _; diff --git a/macros/src/codegen/timer_queue.rs b/macros/src/codegen/timer_queue.rs index 56304001..030158e2 100644 --- a/macros/src/codegen/timer_queue.rs +++ b/macros/src/codegen/timer_queue.rs @@ -8,9 +8,8 @@ use crate::{analyze::Analysis, check::Extra, codegen::util}; pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> { let mut items = vec![]; - for (&sender, timer_queue) in &analysis.timer_queues { - let cfg_sender = util::cfg_core(sender, app.args.cores); - let t = util::schedule_t_ident(sender); + if let Some(timer_queue) = &analysis.timer_queues.first() { + let t = util::schedule_t_ident(); // Enumeration of `schedule`-able tasks { @@ -27,9 +26,8 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream }) .collect::<Vec<_>>(); - let doc = format!("Tasks that can be scheduled from core #{}", sender); + let doc = format!("Tasks that can be scheduled"); items.push(quote!( - #cfg_sender #[doc = #doc] #[allow(non_camel_case_types)] #[derive(Clone, Copy)] @@ -39,27 +37,23 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream )); } - let tq = util::tq_ident(sender); + let tq = util::tq_ident(); // Static variable and resource proxy { - let doc = format!("Core #{} timer queue", sender); + let doc = format!("Timer queue"); let m = extra.monotonic(); let n = util::capacity_typenum(timer_queue.capacity, false); let tq_ty = quote!(rtic::export::TimerQueue<#m, #t, #n>); - let section = util::link_section("bss", sender); items.push(quote!( - #cfg_sender #[doc = #doc] - #section static mut #tq: #tq_ty = rtic::export::TimerQueue( rtic::export::BinaryHeap( rtic::export::iBinaryHeap::new() ) ); - #cfg_sender struct #tq<'a> { priority: &'a rtic::export::Priority, } @@ -68,7 +62,6 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream items.push(util::impl_mutex( extra, &[], - cfg_sender.as_ref(), false, &tq, tq_ty, @@ -88,17 +81,12 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream let cfgs = &task.cfgs; let priority = task.args.priority; - let receiver = task.args.core; - let rq = util::rq_ident(receiver, priority, sender); - let rqt = util::spawn_t_ident(receiver, priority, sender); - let enum_ = util::interrupt_ident(receiver, app.args.cores); - let interrupt = &analysis.interrupts[&receiver][&priority]; + let rq = util::rq_ident(priority); + let rqt = util::spawn_t_ident(priority); + let enum_ = util::interrupt_ident(); + let interrupt = &analysis.interrupts.get(&priority); - let pend = if sender != receiver { - quote!( - #device::xpend(#receiver, #device::#enum_::#interrupt); - ) - } else { + let pend = { quote!( rtic::pend(#device::#enum_::#interrupt); ) @@ -118,12 +106,9 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream .collect::<Vec<_>>(); let priority = timer_queue.priority; - let sys_tick = util::suffixed("SysTick", sender); - let section = util::link_section("text", sender); + let sys_tick = util::suffixed("SysTick"); items.push(quote!( #[no_mangle] - #cfg_sender - #section unsafe fn #sys_tick() { use rtic::Mutex as _; @@ -137,7 +122,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream }) // NOTE `inline(always)` produces faster and smaller code .lock(#[inline(always)] - |tq| tq.dequeue()) + |tq| tq.dequeue()) { match task { #(#arms)* @@ -148,6 +133,5 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream )); } } - items } diff --git a/macros/src/codegen/util.rs b/macros/src/codegen/util.rs index 68aca5d1..2f9f3cce 100644 --- a/macros/src/codegen/util.rs +++ b/macros/src/codegen/util.rs @@ -2,7 +2,7 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::quote; -use rtic_syntax::{ast::App, Context, Core}; +use rtic_syntax::{ast::App, Context}; use syn::{Attribute, Ident, LitInt, PatType}; use crate::check::Extra; @@ -25,34 +25,15 @@ pub fn capacity_typenum(capacity: u8, round_up_to_power_of_two: bool) -> TokenSt quote!(rtic::export::consts::#ident) } -/// Generates a `#[cfg(core = "0")]` attribute if we are in multi-core mode -pub fn cfg_core(core: Core, cores: u8) -> Option<TokenStream2> { - if cores == 1 { - None - } else if cfg!(feature = "heterogeneous") { - let core = core.to_string(); - Some(quote!(#[cfg(core = #core)])) - } else { - None - } -} - /// Identifier for the free queue -/// -/// There may be more than one free queue per task because we need one for each sender core so we -/// include the sender (e.g. `S0`) in the name -pub fn fq_ident(task: &Ident, sender: Core) -> Ident { - Ident::new( - &format!("{}_S{}_FQ", task.to_string(), sender), - Span::call_site(), - ) +pub fn fq_ident(task: &Ident) -> Ident { + Ident::new(&format!("{}_FQ", task.to_string()), Span::call_site()) } /// Generates a `Mutex` implementation pub fn impl_mutex( extra: &Extra, cfgs: &[Attribute], - cfg_core: Option<&TokenStream2>, resources_prefix: bool, name: &Ident, ty: TokenStream2, @@ -68,7 +49,6 @@ pub fn impl_mutex( let device = extra.device; quote!( #(#cfgs)* - #cfg_core impl<'a> rtic::Mutex for #path<'a> { type T = #ty; @@ -91,28 +71,19 @@ pub fn impl_mutex( ) } -/// Generates an identifier for a cross-initialization barrier -pub fn init_barrier(initializer: Core) -> Ident { - Ident::new(&format!("IB{}", initializer), Span::call_site()) -} - /// Generates an identifier for the `INPUTS` buffer (`spawn` & `schedule` API) -pub fn inputs_ident(task: &Ident, sender: Core) -> Ident { - Ident::new(&format!("{}_S{}_INPUTS", task, sender), Span::call_site()) +pub fn inputs_ident(task: &Ident) -> Ident { + Ident::new(&format!("{}_INPUTS", task), Span::call_site()) } /// Generates an identifier for the `INSTANTS` buffer (`schedule` API) -pub fn instants_ident(task: &Ident, sender: Core) -> Ident { - Ident::new(&format!("{}_S{}_INSTANTS", task, sender), Span::call_site()) +pub fn instants_ident(task: &Ident) -> Ident { + Ident::new(&format!("{}_INSTANTS", task), Span::call_site()) } -pub fn interrupt_ident(core: Core, cores: u8) -> Ident { +pub fn interrupt_ident() -> Ident { let span = Span::call_site(); - if cores == 1 { - Ident::new("Interrupt", span) - } else { - Ident::new(&format!("Interrupt_{}", core), span) - } + Ident::new("Interrupt", span) } /// Whether `name` is an exception with configurable priority @@ -141,31 +112,12 @@ fn link_section_index() -> usize { INDEX.fetch_add(1, Ordering::Relaxed) } -pub fn link_section(section: &str, core: Core) -> Option<TokenStream2> { - if cfg!(feature = "homogeneous") { - let section = format!(".{}_{}.rtic{}", section, core, link_section_index()); - Some(quote!(#[link_section = #section])) - } else { - None - } -} - // NOTE `None` means in shared memory -pub fn link_section_uninit(core: Option<Core>) -> Option<TokenStream2> { - let section = if let Some(core) = core { +pub fn link_section_uninit(empty_expr: bool) -> Option<TokenStream2> { + let section = if empty_expr { let index = link_section_index(); - - if cfg!(feature = "homogeneous") { - format!(".uninit_{}.rtic{}", core, index) - } else { - format!(".uninit.rtic{}", index) - } + format!(".uninit.rtic{}", index) } else { - if cfg!(feature = "heterogeneous") { - // `#[shared]` attribute sets the linker section - return None; - } - format!(".uninit.rtic{}", link_section_index()) }; @@ -175,8 +127,8 @@ pub fn link_section_uninit(core: Option<Core>) -> Option<TokenStream2> { /// Generates a pre-reexport identifier for the "locals" struct pub fn locals_ident(ctxt: Context, app: &App) -> Ident { let mut s = match ctxt { - Context::Init(core) => app.inits[&core].name.to_string(), - Context::Idle(core) => app.idles[&core].name.to_string(), + Context::Init => app.inits.first().unwrap().name.to_string(), + Context::Idle => app.idles.first().unwrap().name.to_string(), Context::HardwareTask(ident) | Context::SoftwareTask(ident) => ident.to_string(), }; @@ -185,11 +137,6 @@ pub fn locals_ident(ctxt: Context, app: &App) -> Ident { Ident::new(&s, Span::call_site()) } -/// Generates an identifier for a rendezvous barrier -pub fn rendezvous_ident(core: Core) -> Ident { - Ident::new(&format!("RV{}", core), Span::call_site()) -} - // Regroups the inputs of a task // // `inputs` could be &[`input: Foo`] OR &[`mut x: i32`, `ref y: i64`] @@ -242,8 +189,8 @@ pub fn regroup_inputs( /// Generates a pre-reexport identifier for the "resources" struct pub fn resources_ident(ctxt: Context, app: &App) -> Ident { let mut s = match ctxt { - Context::Init(core) => app.inits[&core].name.to_string(), - Context::Idle(core) => app.idles[&core].name.to_string(), + Context::Init => app.inits.first().unwrap().name.to_string(), + Context::Idle => app.idles.first().unwrap().name.to_string(), Context::HardwareTask(ident) | Context::SoftwareTask(ident) => ident.to_string(), }; @@ -254,72 +201,47 @@ pub fn resources_ident(ctxt: Context, app: &App) -> Ident { /// Generates an identifier for a ready queue /// -/// Each core may have several task dispatchers, one for each priority level. Each task dispatcher -/// in turn may use more than one ready queue because the queues are SPSC queues so one is needed -/// per sender core. -pub fn rq_ident(receiver: Core, priority: u8, sender: Core) -> Ident { - Ident::new( - &format!("R{}_P{}_S{}_RQ", receiver, priority, sender), - Span::call_site(), - ) +/// There may be several task dispatchers, one for each priority level. +/// The ready queues are SPSC queues +pub fn rq_ident(priority: u8) -> Ident { + Ident::new(&format!("P{}_RQ", priority), Span::call_site()) } /// Generates an identifier for a "schedule" function /// -/// The methods of the `Schedule` structs invoke these functions. As one task may be `schedule`-ed -/// by different cores we need one "schedule" function per possible task-sender pair -pub fn schedule_ident(name: &Ident, sender: Core) -> Ident { - Ident::new( - &format!("schedule_{}_S{}", name.to_string(), sender), - Span::call_site(), - ) +/// The methods of the `Schedule` structs invoke these functions. +pub fn schedule_ident(name: &Ident) -> Ident { + Ident::new(&format!("schedule_{}", name.to_string()), Span::call_site()) } /// Generates an identifier for the `enum` of `schedule`-able tasks -pub fn schedule_t_ident(core: Core) -> Ident { - Ident::new(&format!("T{}", core), Span::call_site()) -} - -/// Generates an identifier for a cross-spawn barrier -pub fn spawn_barrier(receiver: Core) -> Ident { - Ident::new(&format!("SB{}", receiver), Span::call_site()) +pub fn schedule_t_ident() -> Ident { + Ident::new(&format!("T"), Span::call_site()) } /// Generates an identifier for a "spawn" function /// -/// The methods of the `Spawn` structs invoke these functions. As one task may be `spawn`-ed by -/// different cores we need one "spawn" function per possible task-sender pair -pub fn spawn_ident(name: &Ident, sender: Core) -> Ident { - Ident::new( - &format!("spawn_{}_S{}", name.to_string(), sender), - Span::call_site(), - ) +/// The methods of the `Spawn` structs invoke these functions. +pub fn spawn_ident(name: &Ident) -> Ident { + Ident::new(&format!("spawn_{}", name.to_string()), Span::call_site()) } /// Generates an identifier for the `enum` of `spawn`-able tasks /// /// This identifier needs the same structure as the `RQ` identifier because there's one ready queue /// for each of these `T` enums -pub fn spawn_t_ident(receiver: Core, priority: u8, sender: Core) -> Ident { - Ident::new( - &format!("R{}_P{}_S{}_T", receiver, priority, sender), - Span::call_site(), - ) +pub fn spawn_t_ident(priority: u8) -> Ident { + Ident::new(&format!("P{}_T", priority), Span::call_site()) } -pub fn suffixed(name: &str, core: u8) -> Ident { +pub fn suffixed(name: &str) -> Ident { let span = Span::call_site(); - - if cfg!(feature = "homogeneous") { - Ident::new(&format!("{}_{}", name, core), span) - } else { - Ident::new(name, span) - } + Ident::new(name, span) } /// Generates an identifier for a timer queue /// -/// At most there's one timer queue per core -pub fn tq_ident(core: Core) -> Ident { - Ident::new(&format!("TQ{}", core), Span::call_site()) +/// At most there is one timer queue +pub fn tq_ident() -> Ident { + Ident::new(&format!("TQ"), Span::call_site()) } |