From 81275bfa4f41e2066770087f3a33cad4227eab41 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 13 Jun 2019 23:56:59 +0200 Subject: rtfm-syntax refactor + heterogeneous multi-core support --- macros/src/codegen/post_init.rs | 139 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 macros/src/codegen/post_init.rs (limited to 'macros/src/codegen/post_init.rs') diff --git a/macros/src/codegen/post_init.rs b/macros/src/codegen/post_init.rs new file mode 100644 index 0000000..f492d31 --- /dev/null +++ b/macros/src/codegen/post_init.rs @@ -0,0 +1,139 @@ +use proc_macro2::TokenStream as TokenStream2; +use quote::quote; + +use crate::{analyze::Analysis, check::Extra, codegen::util}; + +/// Generates code that runs after `#[init]` returns +pub fn codegen( + core: u8, + analysis: &Analysis, + extra: &Extra, +) -> (Vec, Vec) { + let mut const_app = vec![]; + 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 + if analysis.locations.get(name).is_some() { + stmts.push(quote!(#name.as_mut_ptr().write(late.#name);)); + } + } + } + + if analysis.timer_queues.is_empty() { + // cross-initialization barriers -- notify *other* cores that their resources have been + // initialized + if analysis.initialization_barriers.contains_key(&core) { + let ib = util::init_barrier(core); + + const_app.push(quote!( + #[rtfm::export::shared] + static #ib: rtfm::export::Barrier = rtfm::export::Barrier::new(); + )); + + stmts.push(quote!( + #ib.release(); + )); + } + + // then wait until the other cores have initialized *our* resources + for (&initializer, users) in &analysis.initialization_barriers { + if users.contains(&core) { + let ib = util::init_barrier(initializer); + + 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 rtfm::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); + + const_app.push(quote!( + #[rtfm::export::shared] + static #rv: rtfm::export::Barrier = rtfm::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 rtfm::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 + stmts.push(quote!(rtfm::export::interrupt::enable();)); + + (const_app, stmts) +} -- cgit v1.2.3 From 9897728709528a02545523bea72576abce89dc4c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 18 Jun 2019 10:31:31 +0200 Subject: add homogeneous multi-core support --- macros/src/codegen/post_init.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'macros/src/codegen/post_init.rs') diff --git a/macros/src/codegen/post_init.rs b/macros/src/codegen/post_init.rs index f492d31..3f1e445 100644 --- a/macros/src/codegen/post_init.rs +++ b/macros/src/codegen/post_init.rs @@ -27,9 +27,16 @@ pub fn codegen( // initialized if analysis.initialization_barriers.contains_key(&core) { let ib = util::init_barrier(core); + let shared = if cfg!(feature = "heterogeneous") { + Some(quote!( + #[rtfm::export::shared] + )) + } else { + None + }; const_app.push(quote!( - #[rtfm::export::shared] + #shared static #ib: rtfm::export::Barrier = rtfm::export::Barrier::new(); )); @@ -84,9 +91,16 @@ pub fn codegen( if core == FIRST { for &i in analysis.timer_queues.keys() { let rv = util::rendezvous_ident(i); + let shared = if cfg!(feature = "heterogeneous") { + Some(quote!( + #[rtfm::export::shared] + )) + } else { + None + }; const_app.push(quote!( - #[rtfm::export::shared] + #shared static #rv: rtfm::export::Barrier = rtfm::export::Barrier::new(); )); -- cgit v1.2.3 From 14d63f496118f4243f28ddf3218523aa36a80322 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 3 Jul 2019 20:36:52 +0200 Subject: fix (cross-core) initialization barriers --- macros/src/codegen/post_init.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'macros/src/codegen/post_init.rs') diff --git a/macros/src/codegen/post_init.rs b/macros/src/codegen/post_init.rs index 3f1e445..19773e4 100644 --- a/macros/src/codegen/post_init.rs +++ b/macros/src/codegen/post_init.rs @@ -25,8 +25,12 @@ pub fn codegen( if analysis.timer_queues.is_empty() { // cross-initialization barriers -- notify *other* cores that their resources have been // initialized - if analysis.initialization_barriers.contains_key(&core) { - let ib = util::init_barrier(core); + 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!( #[rtfm::export::shared] @@ -46,14 +50,12 @@ pub fn codegen( } // then wait until the other cores have initialized *our* resources - for (&initializer, users) in &analysis.initialization_barriers { - if users.contains(&core) { - let ib = util::init_barrier(initializer); + if analysis.initialization_barriers.contains_key(&core) { + let ib = util::init_barrier(core); - stmts.push(quote!( - #ib.wait(); - )); - } + stmts.push(quote!( + #ib.wait(); + )); } // cross-spawn barriers: wait until other cores are ready to receive messages -- cgit v1.2.3