aboutsummaryrefslogtreecommitdiff
path: root/macros/src/codegen
diff options
context:
space:
mode:
authorGravatar bors[bot] <26634292+bors[bot]@users.noreply.github.com> 2021-03-04 19:12:35 +0000
committerGravatar GitHub <noreply@github.com> 2021-03-04 19:12:35 +0000
commit89a5c8004efaa8f42c86a1aedb609f49ec511333 (patch)
tree6db5b553e24a540284edc3f3fbf87043c638defc /macros/src/codegen
parent81a8a591353b1ea0208c68b28ee81286629039cc (diff)
parent2e4a4ffd87c8a031f27635c060042019511523dc (diff)
downloadrtic-89a5c8004efaa8f42c86a1aedb609f49ec511333.tar.gz
rtic-89a5c8004efaa8f42c86a1aedb609f49ec511333.tar.zst
rtic-89a5c8004efaa8f42c86a1aedb609f49ec511333.zip
Merge #436v0.6.0-alpha.1
436: New monotonic r=AfoHT a=korken89 Design document: https://hackmd.io/vWa9GvssR8qBfUYgMZm0CQ Closes #433 Closes #432 Closes #427 Closes #426 Closes #403 Closes #332 Closes #312 Closes #309 Closes #299 Closes #292 Closes #247 Closes #219 Co-authored-by: Emil Fresk <emil.fresk@gmail.com>
Diffstat (limited to 'macros/src/codegen')
-rw-r--r--macros/src/codegen/assertions.rs8
-rw-r--r--macros/src/codegen/dispatchers.rs43
-rw-r--r--macros/src/codegen/hardware_tasks.rs13
-rw-r--r--macros/src/codegen/init.rs35
-rw-r--r--macros/src/codegen/locals.rs1
-rw-r--r--macros/src/codegen/module.rs259
-rw-r--r--macros/src/codegen/post_init.rs18
-rw-r--r--macros/src/codegen/pre_init.rs58
-rw-r--r--macros/src/codegen/resources.rs3
-rw-r--r--macros/src/codegen/resources_struct.rs3
-rw-r--r--macros/src/codegen/software_tasks.rs21
-rw-r--r--macros/src/codegen/timer_queue.rs73
-rw-r--r--macros/src/codegen/util.rs41
13 files changed, 346 insertions, 230 deletions
diff --git a/macros/src/codegen/assertions.rs b/macros/src/codegen/assertions.rs
index 4d9aae47..a8a4491b 100644
--- a/macros/src/codegen/assertions.rs
+++ b/macros/src/codegen/assertions.rs
@@ -2,9 +2,10 @@ use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use crate::analyze::Analysis;
+use rtic_syntax::ast::App;
/// Generates compile-time assertions that check that types implement the `Send` / `Sync` traits
-pub fn codegen(analysis: &Analysis) -> Vec<TokenStream2> {
+pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
let mut stmts = vec![];
for ty in &analysis.send_types {
@@ -15,5 +16,10 @@ pub fn codegen(analysis: &Analysis) -> Vec<TokenStream2> {
stmts.push(quote!(rtic::export::assert_sync::<#ty>();));
}
+ for (_, monotonic) in &app.monotonics {
+ let ty = &monotonic.ty;
+ stmts.push(quote!(rtic::export::assert_monotonic::<#ty>();));
+ }
+
stmts
}
diff --git a/macros/src/codegen/dispatchers.rs b/macros/src/codegen/dispatchers.rs
index a6c695f1..dc33b1af 100644
--- a/macros/src/codegen/dispatchers.rs
+++ b/macros/src/codegen/dispatchers.rs
@@ -5,7 +5,7 @@ use rtic_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> {
+pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStream2> {
let mut items = vec![];
let interrupts = &analysis.interrupts;
@@ -26,15 +26,16 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
})
.collect::<Vec<_>>();
- let doc = format!(
- "Software tasks to be dispatched at priority level {}",
- level,
- );
+ // 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]
+ // #[doc = #doc]
+ #[doc(hidden)]
pub enum #t {
#(#variants,)*
}
@@ -42,6 +43,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
let n = util::capacity_typenum(channel.capacity, true);
let rq = util::rq_ident(level);
+ let rq = util::mark_internal_ident(&rq);
let (rq_ty, rq_expr) = {
(
quote!(rtic::export::SCRQ<#t, #n>),
@@ -51,12 +53,12 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
)
};
- let doc = format!(
- "Queue of tasks ready to be dispatched at priority level {}",
- level
- );
+ // let doc = format!(
+ // "Queue of tasks ready to be dispatched at priority level {}",
+ // level
+ // );
items.push(quote!(
- #[doc = #doc]
+ #[doc(hidden)]
static mut #rq: #rq_ty = #rq_expr;
));
@@ -67,23 +69,11 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
let task = &app.software_tasks[name];
let cfgs = &task.cfgs;
let fq = util::fq_ident(name);
+ let fq = util::mark_internal_ident(&fq);
let inputs = util::inputs_ident(name);
+ let inputs = util::mark_internal_ident(&inputs);
let (_, tupled, pats, _) = util::regroup_inputs(&task.inputs);
- let (let_instant, instant) = if extra.monotonic.is_some() {
- let instants = util::instants_ident(name);
-
- (
- 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 {
@@ -97,12 +87,11 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
#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);
#app_path::#name(
#locals_new
- #name::Context::new(priority #instant)
+ #name::Context::new(priority)
#(,#pats)*
)
}
diff --git a/macros/src/codegen/hardware_tasks.rs b/macros/src/codegen/hardware_tasks.rs
index 6930d3e0..4a1d7492 100644
--- a/macros/src/codegen/hardware_tasks.rs
+++ b/macros/src/codegen/hardware_tasks.rs
@@ -29,15 +29,6 @@ pub fn codegen(
let mut user_tasks = vec![];
for (name, task) in &app.hardware_tasks {
- let (let_instant, instant) = if let Some(ref m) = extra.monotonic {
- (
- Some(quote!(let instant = <#m as rtic::Monotonic>::now();)),
- Some(quote!(, instant)),
- )
- } else {
- (None, None)
- };
-
let locals_new = if task.locals.is_empty() {
quote!()
} else {
@@ -55,12 +46,10 @@ pub fn codegen(
unsafe fn #symbol() {
const PRIORITY: u8 = #priority;
- #let_instant
-
rtic::export::run(PRIORITY, || {
#app_path::#name(
#locals_new
- #name::Context::new(&rtic::export::Priority::new(PRIORITY) #instant)
+ #name::Context::new(&rtic::export::Priority::new(PRIORITY))
)
});
}
diff --git a/macros/src/codegen/init.rs b/macros/src/codegen/init.rs
index 6376ce31..aa9adcb0 100644
--- a/macros/src/codegen/init.rs
+++ b/macros/src/codegen/init.rs
@@ -5,7 +5,7 @@ use rtic_syntax::{ast::App, Context};
use crate::{
analyze::Analysis,
check::Extra,
- codegen::{locals, module, resources_struct, util},
+ codegen::{locals, module, resources_struct},
};
type CodegenResult = (
@@ -32,32 +32,6 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> CodegenResult {
let mut root_init = 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
- )
- })
- })
- .collect::<Vec<_>>();
-
- let late_resources = util::late_resources_ident(&name);
-
- root_init.push(quote!(
- /// Resources initialized at runtime
- #[allow(non_snake_case)]
- pub struct #late_resources {
- #(#late_fields),*
- }
- ));
-
let mut locals_pat = None;
let mut locals_new = None;
if !init.locals.is_empty() {
@@ -72,10 +46,13 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> CodegenResult {
let attrs = &init.attrs;
let stmts = &init.stmts;
let locals_pat = locals_pat.iter();
+
+ let user_init_return = quote! {#name::LateResources, #name::Monotonics};
+
let user_init = Some(quote!(
#(#attrs)*
#[allow(non_snake_case)]
- fn #name(#(#locals_pat,)* #context: #name::Context) -> #name::LateResources {
+ fn #name(#(#locals_pat,)* #context: #name::Context) -> (#user_init_return) {
#(#stmts)*
}
));
@@ -92,7 +69,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> CodegenResult {
let app_path = quote! {crate::#app_name};
let locals_new = locals_new.iter();
let call_init = Some(
- quote!(let late = #app_path::#name(#(#locals_new,)* #name::Context::new(core.into()));),
+ quote!(let (late, mut monotonics) = #app_path::#name(#(#locals_new,)* #name::Context::new(core.into()));),
);
root_init.push(module::codegen(
diff --git a/macros/src/codegen/locals.rs b/macros/src/codegen/locals.rs
index 336c0b21..5725a151 100644
--- a/macros/src/codegen/locals.rs
+++ b/macros/src/codegen/locals.rs
@@ -49,6 +49,7 @@ pub fn codegen(
));
items.push(quote!(
#(#cfgs)*
+ #[doc(hidden)]
static mut #name: #ty = #expr
));
values.push(quote!(
diff --git a/macros/src/codegen/module.rs b/macros/src/codegen/module.rs
index 2ff4801e..75435b54 100644
--- a/macros/src/codegen/module.rs
+++ b/macros/src/codegen/module.rs
@@ -18,29 +18,16 @@ pub fn codegen(
let mut task_cfgs = vec![];
let name = ctxt.ident(app);
+ let app_name = &app.name;
+ let app_path = quote! {crate::#app_name};
- let mut needs_instant = false;
let mut lt = None;
match ctxt {
Context::Init => {
- if let Some(m) = &extra.monotonic {
- fields.push(quote!(
- /// System start time = `Instant(0 /* cycles */)`
- pub start: <#m as rtic::Monotonic>::Instant
- ));
-
- values.push(quote!(start: <#m as rtic::Monotonic>::zero()));
-
- fields.push(quote!(
- /// Core (Cortex-M) peripherals minus the SysTick
- pub core: rtic::Peripherals
- ));
- } else {
- fields.push(quote!(
- /// Core (Cortex-M) peripherals
- pub core: rtic::export::Peripherals
- ));
- }
+ fields.push(quote!(
+ /// Core (Cortex-M) peripherals
+ pub core: rtic::export::Peripherals
+ ));
if extra.peripherals {
let device = &extra.device;
@@ -66,31 +53,9 @@ pub fn codegen(
Context::Idle => {}
- Context::HardwareTask(..) => {
- if let Some(m) = &extra.monotonic {
- fields.push(quote!(
- /// Time at which this handler started executing
- pub start: <#m as rtic::Monotonic>::Instant
- ));
+ Context::HardwareTask(_) => {}
- values.push(quote!(start: instant));
-
- needs_instant = true;
- }
- }
-
- Context::SoftwareTask(..) => {
- if let Some(m) = &extra.monotonic {
- fields.push(quote!(
- /// The time at which this task was scheduled to run
- pub scheduled: <#m as rtic::Monotonic>::Instant
- ));
-
- values.push(quote!(scheduled: instant));
-
- needs_instant = true;
- }
- }
+ Context::SoftwareTask(_) => {}
}
if ctxt.has_locals(app) {
@@ -103,6 +68,7 @@ pub fn codegen(
if ctxt.has_resources(app) {
let ident = util::resources_ident(ctxt, app);
+ let ident = util::mark_internal_ident(&ident);
let lt = if resources_tick {
lt = Some(quote!('a));
Some(quote!('a))
@@ -129,12 +95,45 @@ pub fn codegen(
}
if let Context::Init = ctxt {
- let init = &app.inits.first().unwrap();
- let late_resources = util::late_resources_ident(&init.name);
+ 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
+ )
+ })
+ })
+ .collect::<Vec<_>>();
items.push(quote!(
- #[doc(inline)]
- pub use super::#late_resources as LateResources;
+ /// Resources initialized at runtime
+ #[allow(non_snake_case)]
+ pub struct LateResources {
+ #(#late_fields),*
+ }
+ ));
+
+ let monotonic_types: Vec<_> = app
+ .monotonics
+ .iter()
+ .map(|(_, monotonic)| {
+ let mono = &monotonic.ty;
+ quote! {#mono}
+ })
+ .collect();
+
+ items.push(quote!(
+ /// Monotonics used by the system
+ #[allow(non_snake_case)]
+ pub struct Monotonics(
+ #(pub #monotonic_types),*
+ );
));
}
@@ -146,11 +145,7 @@ pub fn codegen(
};
let core = if ctxt.is_init() {
- if extra.monotonic.is_some() {
- Some(quote!(core: rtic::Peripherals,))
- } else {
- Some(quote!(core: rtic::export::Peripherals,))
- }
+ Some(quote!(core: rtic::export::Peripherals,))
} else {
None
};
@@ -161,14 +156,6 @@ pub fn codegen(
Some(quote!(priority: &#lt rtic::export::Priority))
};
- let instant = if needs_instant {
- let m = extra.monotonic.clone().expect("RTIC-ICE: UNREACHABLE");
-
- Some(quote!(, instant: <#m as rtic::Monotonic>::Instant))
- } else {
- None
- };
-
items.push(quote!(
/// Execution context
pub struct Context<#lt> {
@@ -177,7 +164,7 @@ pub fn codegen(
impl<#lt> Context<#lt> {
#[inline(always)]
- pub unsafe fn new(#core #priority #instant) -> Self {
+ pub unsafe fn new(#core #priority) -> Self {
Context {
#(#values,)*
}
@@ -195,15 +182,15 @@ pub fn codegen(
let cfgs = &spawnee.cfgs;
// Store a copy of the task cfgs
task_cfgs = cfgs.clone();
- let (args, tupled, _untupled, ty) = util::regroup_inputs(&spawnee.inputs);
+ let (args, tupled, untupled, ty) = util::regroup_inputs(&spawnee.inputs);
let args = &args;
let tupled = &tupled;
let fq = util::fq_ident(name);
+ let fq = util::mark_internal_ident(&fq);
let rq = util::rq_ident(priority);
+ let rq = util::mark_internal_ident(&rq);
let inputs = util::inputs_ident(name);
-
- let app_name = &app.name;
- let app_path = quote! {crate::#app_name};
+ let inputs = util::mark_internal_ident(&inputs);
let device = &extra.device;
let enum_ = util::interrupt_ident();
@@ -216,11 +203,8 @@ pub fn codegen(
// Spawn caller
items.push(quote!(
#(#cfgs)*
+ /// Spawns the task directly
pub fn spawn(#(#args,)*) -> Result<(), #ty> {
- // #let_instant // do we need it?
- use rtic::Mutex as _;
- use rtic::mutex_prelude::*;
-
let input = #tupled;
unsafe {
@@ -245,45 +229,114 @@ pub fn codegen(
}));
// Schedule caller
- if let Some(m) = &extra.monotonic {
- let instants = util::instants_ident(name);
+ for (_, monotonic) in &app.monotonics {
+ let instants = util::monotonic_instants_ident(name, &monotonic.ident);
+ let instants = util::mark_internal_ident(&instants);
+ let monotonic_name = monotonic.ident.to_string();
- let tq = util::tq_ident();
+ let tq = util::tq_ident(&monotonic.ident.to_string());
+ let tq = util::mark_internal_ident(&tq);
let t = util::schedule_t_ident();
+ let m = &monotonic.ident;
+ let mono_type = &monotonic.ty;
+ let m_ident = util::monotonic_ident(&monotonic_name);
+ let m_ident = util::mark_internal_ident(&m_ident);
+ let m_isr = &monotonic.args.binds;
+ let enum_ = util::interrupt_ident();
+
+ if monotonic.args.default {
+ items.push(quote!(pub use #m::spawn_after;));
+ items.push(quote!(pub use #m::spawn_at;));
+ }
+
+ let (enable_interrupt, pend) = if &*m_isr.to_string() == "SysTick" {
+ (
+ quote!(core::mem::transmute::<_, cortex_m::peripheral::SYST>(())
+ .enable_interrupt()),
+ quote!(cortex_m::peripheral::SCB::set_pendst()),
+ )
+ } else {
+ let rt_err = util::rt_err_ident();
+ (
+ quote!(rtic::export::NVIC::unmask(#app_path::#rt_err::#enum_::#m_isr)),
+ quote!(rtic::pend(#app_path::#rt_err::#enum_::#m_isr)),
+ )
+ };
+
+ let user_imports = &app.user_imports;
items.push(quote!(
- #(#cfgs)*
- pub fn schedule(
- instant: <#m as rtic::Monotonic>::Instant
- #(,#args)*
- ) -> Result<(), #ty> {
- unsafe {
- use rtic::Mutex as _;
- use rtic::mutex_prelude::*;
-
- let input = #tupled;
- if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.dequeue()) {
- #app_path::#inputs
- .get_unchecked_mut(usize::from(index))
- .as_mut_ptr()
- .write(input);
-
- #app_path::#instants
- .get_unchecked_mut(usize::from(index))
- .as_mut_ptr()
- .write(instant);
-
- let nr = rtic::export::NotReady {
- instant,
- index,
- task: #app_path::#t::#name,
- };
-
- rtic::export::interrupt::free(|_| #app_path::#tq.enqueue_unchecked(nr));
-
- Ok(())
+ /// Holds methods related to this monotonic
+ pub mod #m {
+ #(
+ #[allow(unused_imports)]
+ #user_imports
+ )*
+
+ #(#cfgs)*
+ /// Spawns the task after a set duration relative to the current time
+ ///
+ /// This will use the time `Instant::new(0)` as baseline if called in `#[init]`,
+ /// so if you use a non-resetable timer use `spawn_at` when in `#[init]`
+ pub fn spawn_after<D>(
+ duration: D
+ #(,#args)*
+ ) -> Result<(), #ty>
+ where D: rtic::time::duration::Duration + rtic::time::fixed_point::FixedPoint,
+ D::T: Into<<#app_path::#mono_type as rtic::time::Clock>::T>,
+ {
+
+ let instant = if rtic::export::interrupt::free(|_| unsafe { #app_path::#m_ident.is_none() }) {
+ rtic::time::Instant::new(0)
} else {
- Err(input)
+ #app_path::#m::now()
+ };
+
+ spawn_at(instant + duration #(,#untupled)*)
+ }
+
+ #(#cfgs)*
+ /// Spawns the task at a fixed time instant
+ pub fn spawn_at(
+ instant: rtic::time::Instant<#app_path::#mono_type>
+ #(,#args)*
+ ) -> Result<(), #ty> {
+ unsafe {
+ let input = #tupled;
+ if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.dequeue()) {
+ #app_path::#inputs
+ .get_unchecked_mut(usize::from(index))
+ .as_mut_ptr()
+ .write(input);
+
+ #app_path::#instants
+ .get_unchecked_mut(usize::from(index))
+ .as_mut_ptr()
+ .write(instant);
+
+ let nr = rtic::export::NotReady {
+ instant,
+ index,
+ task: #app_path::#t::#name,
+ };
+
+ rtic::export::interrupt::free(|_|
+ if let Some(mono) = #app_path::#m_ident.as_mut() {
+ #app_path::#tq.enqueue_unchecked(
+ nr,
+ || #enable_interrupt,
+ || #pend,
+ mono)
+ } else {
+ // We can only use the timer queue if `init` has returned, and it
+ // writes the `Some(monotonic)` we are accessing here.
+ core::hint::unreachable_unchecked()
+ });
+
+ Ok(())
+ } else {
+ Err(input)
+ }
}
}
}));
diff --git a/macros/src/codegen/post_init.rs b/macros/src/codegen/post_init.rs
index 5545944d..96c5df80 100644
--- a/macros/src/codegen/post_init.rs
+++ b/macros/src/codegen/post_init.rs
@@ -1,6 +1,7 @@
-use proc_macro2::TokenStream as TokenStream2;
+use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::quote;
use rtic_syntax::ast::App;
+use syn::Index;
use crate::{analyze::Analysis, codegen::util};
@@ -12,7 +13,7 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
if !analysis.late_resources.is_empty() {
// BTreeSet wrapped in a vector
for name in analysis.late_resources.first().unwrap() {
- let mangled_name = util::mangle_ident(&name);
+ let mangled_name = util::mark_internal_ident(&name);
// If it's live
let cfgs = app.late_resources[name].cfgs.clone();
if analysis.locations.get(name).is_some() {
@@ -25,6 +26,19 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
}
}
+ for (i, (monotonic, _)) in app.monotonics.iter().enumerate() {
+ let idx = Index {
+ index: i as u32,
+ span: Span::call_site(),
+ };
+ stmts.push(quote!(monotonics.#idx.reset();));
+
+ // Store the monotonic
+ let name = util::monotonic_ident(&monotonic.to_string());
+ let name = util::mark_internal_ident(&name);
+ stmts.push(quote!(#name = Some(monotonics.#idx);));
+ }
+
// Enable the interrupts -- this completes the `init`-ialization phase
stmts.push(quote!(rtic::export::interrupt::enable();));
diff --git a/macros/src/codegen/pre_init.rs b/macros/src/codegen/pre_init.rs
index 969de84a..d5105445 100644
--- a/macros/src/codegen/pre_init.rs
+++ b/macros/src/codegen/pre_init.rs
@@ -8,6 +8,8 @@ use crate::{analyze::Analysis, check::Extra, codegen::util};
pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> {
let mut stmts = vec![];
+ let rt_err = util::rt_err_ident();
+
// Disable interrupts -- `init` must run with interrupts disabled
stmts.push(quote!(rtic::export::interrupt::disable();));
@@ -15,6 +17,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
for (name, task) in &app.software_tasks {
let cap = task.args.capacity;
let fq_ident = util::fq_ident(name);
+ let fq_ident = util::mark_internal_ident(&fq_ident);
stmts.push(quote!(
(0..#cap).for_each(|i| #fq_ident.enqueue_unchecked(i));
@@ -47,14 +50,14 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
let interrupt = util::interrupt_ident();
stmts.push(quote!(
core.NVIC.set_priority(
- you_must_enable_the_rt_feature_for_the_pac_in_your_cargo_toml::#interrupt::#name,
+ #rt_err::#interrupt::#name,
rtic::export::logical2hw(#priority, #nvic_prio_bits),
);
));
// NOTE unmask the interrupt *after* setting its priority: changing the priority of a pended
// interrupt is implementation defined
- stmts.push(quote!(rtic::export::NVIC::unmask(you_must_enable_the_rt_feature_for_the_pac_in_your_cargo_toml::#interrupt::#name);));
+ stmts.push(quote!(rtic::export::NVIC::unmask(#rt_err::#interrupt::#name);));
}
// Set exception priorities
@@ -74,23 +77,48 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
);));
}
- // Initialize the SysTick if there exist a TimerQueue
- if extra.monotonic.is_some() {
- let priority = analysis.channels.keys().max().unwrap();
+ // Initialize monotonic's interrupts
+ for (_, monotonic) in app.monotonics.iter()
+ //.map(|(ident, monotonic)| (ident, &monotonic.args.priority, &monotonic.args.binds))
+ {
+ let priority = &monotonic.args.priority;
+ let binds = &monotonic.args.binds;
// 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(
- rtic::export::SystemHandler::SysTick,
- rtic::export::logical2hw(#priority, #nvic_prio_bits),
- );));
-
- stmts.push(quote!(
- core.SYST.set_clock_source(rtic::export::SystClkSource::Core);
- core.SYST.enable_counter();
- core.DCB.enable_trace();
- ));
+ let app_name = &app.name;
+ let app_path = quote! {crate::#app_name};
+ let mono_type = &monotonic.ty;
+
+ if &*binds.to_string() == "SysTick" {
+ stmts.push(quote!(
+ core.SCB.set_priority(
+ rtic::export::SystemHandler::SysTick,
+ rtic::export::logical2hw(#priority, #nvic_prio_bits),
+ );
+
+ // Always enable monotonic interrupts if they should never be off
+ if !<#mono_type as rtic::Monotonic>::DISABLE_INTERRUPT_ON_EMPTY_QUEUE {
+ core::mem::transmute::<_, cortex_m::peripheral::SYST>(())
+ .enable_interrupt();
+ }
+ ));
+ } else {
+ // NOTE this also checks that the interrupt exists in the `Interrupt` enumeration
+ let interrupt = util::interrupt_ident();
+ stmts.push(quote!(
+ core.NVIC.set_priority(
+ #rt_err::#interrupt::#binds,
+ rtic::export::logical2hw(#priority, #nvic_prio_bits),
+ );
+
+ // Always enable monotonic interrupts if they should never be off
+ if !<#mono_type as rtic::Monotonic>::DISABLE_INTERRUPT_ON_EMPTY_QUEUE {
+ rtic::export::NVIC::unmask(#app_path::#rt_err::#interrupt::#binds);
+ }
+ ));
+ }
}
// If there's no user `#[idle]` then optimize returning from interrupt handlers
diff --git a/macros/src/codegen/resources.rs b/macros/src/codegen/resources.rs
index 76871e59..fa52b86d 100644
--- a/macros/src/codegen/resources.rs
+++ b/macros/src/codegen/resources.rs
@@ -21,7 +21,7 @@ pub fn codegen(
for (name, res, expr, _) in app.resources(analysis) {
let cfgs = &res.cfgs;
let ty = &res.ty;
- let mangled_name = util::mangle_ident(&name);
+ let mangled_name = util::mark_internal_ident(&name);
{
let section = if expr.is_none() {
@@ -42,6 +42,7 @@ pub fn codegen(
let attrs = &res.attrs;
mod_app.push(quote!(
#[allow(non_upper_case_globals)]
+ #[doc(hidden)]
#(#attrs)*
#(#cfgs)*
#section
diff --git a/macros/src/codegen/resources_struct.rs b/macros/src/codegen/resources_struct.rs
index bffe9431..8ed8a291 100644
--- a/macros/src/codegen/resources_struct.rs
+++ b/macros/src/codegen/resources_struct.rs
@@ -31,7 +31,7 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2,
None
};
let ty = &res.ty;
- let mangled_name = util::mangle_ident(&name);
+ let mangled_name = util::mark_internal_ident(&name);
// let ownership = &analysis.ownerships[name];
let r_prop = &res.properties;
@@ -112,6 +112,7 @@ pub fn codegen(ctxt: Context, needs_lt: &mut bool, app: &App) -> (TokenStream2,
let doc = format!("Resources `{}` has access to", ctxt.ident(app));
let ident = util::resources_ident(ctxt, app);
+ let ident = util::mark_internal_ident(&ident);
let item = quote!(
#[allow(non_snake_case)]
#[doc = #doc]
diff --git a/macros/src/codegen/software_tasks.rs b/macros/src/codegen/software_tasks.rs
index 9cb5f7a9..a39fe4cc 100644
--- a/macros/src/codegen/software_tasks.rs
+++ b/macros/src/codegen/software_tasks.rs
@@ -37,6 +37,7 @@ pub fn codegen(
// Create free queues and inputs / instants buffers
let fq = util::fq_ident(name);
+ let fq = util::mark_internal_ident(&fq);
let (fq_ty, fq_expr, mk_uninit): (_, _, Box<dyn Fn() -> Option<_>>) = {
(
@@ -48,8 +49,9 @@ pub fn codegen(
)
};
mod_app.push(quote!(
- /// Queue version of a free-list that keeps track of empty slots in
- /// the following buffers
+ // /// Queue version of a free-list that keeps track of empty slots in
+ // /// the following buffers
+ #[doc(hidden)]
static mut #fq: #fq_ty = #fq_expr;
));
@@ -57,24 +59,29 @@ pub fn codegen(
.map(|_| quote!(core::mem::MaybeUninit::uninit()))
.collect::<Vec<_>>();
- if let Some(m) = &extra.monotonic {
- let instants = util::instants_ident(name);
+ for (_, monotonic) in &app.monotonics {
+ let instants = util::monotonic_instants_ident(name, &monotonic.ident);
+ let instants = util::mark_internal_ident(&instants);
+ let mono_type = &monotonic.ty;
let uninit = mk_uninit();
mod_app.push(quote!(
#uninit
- /// Buffer that holds the instants associated to the inputs of a task
+ // /// Buffer that holds the instants associated to the inputs of a task
+ #[doc(hidden)]
static mut #instants:
- [core::mem::MaybeUninit<<#m as rtic::Monotonic>::Instant>; #cap_lit] =
+ [core::mem::MaybeUninit<rtic::time::Instant<#mono_type>>; #cap_lit] =
[#(#elems,)*];
));
}
let uninit = mk_uninit();
let inputs_ident = util::inputs_ident(name);
+ let inputs_ident = util::mark_internal_ident(&inputs_ident);
mod_app.push(quote!(
#uninit
- /// Buffer that holds the inputs of a task
+ // /// Buffer that holds the inputs of a task
+ #[doc(hidden)]
static mut #inputs_ident: [core::mem::MaybeUninit<#input_ty>; #cap_lit] =
[#(#elems,)*];
));
diff --git a/macros/src/codegen/timer_queue.rs b/macros/src/codegen/timer_queue.rs
index fa2c7b36..82d0ac98 100644
--- a/macros/src/codegen/timer_queue.rs
+++ b/macros/src/codegen/timer_queue.rs
@@ -5,10 +5,10 @@ use rtic_syntax::ast::App;
use crate::{analyze::Analysis, check::Extra, codegen::util};
/// Generates timer queues and timer queue handlers
-pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> {
+pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStream2> {
let mut items = vec![];
- if let Some(m) = &extra.monotonic {
+ if !app.monotonics.is_empty() {
let t = util::schedule_t_ident();
// Enumeration of `schedule`-able tasks
@@ -26,9 +26,10 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
})
.collect::<Vec<_>>();
- let doc = "Tasks that can be scheduled".to_string();
+ // let doc = "Tasks that can be scheduled".to_string();
items.push(quote!(
- #[doc = #doc]
+ // #[doc = #doc]
+ #[doc(hidden)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy)]
enum #t {
@@ -36,32 +37,54 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
}
));
}
+ }
- let tq = util::tq_ident();
+ for (_, monotonic) in &app.monotonics {
+ let monotonic_name = monotonic.ident.to_string();
+ let tq = util::tq_ident(&monotonic_name);
+ let tq = util::mark_internal_ident(&tq);
+ let t = util::schedule_t_ident();
+ let mono_type = &monotonic.ty;
+ let m_ident = util::monotonic_ident(&monotonic_name);
+ let m_ident = util::mark_internal_ident(&m_ident);
+ let app_name = &app.name;
+ let app_path = quote! {crate::#app_name};
- // Static variable and resource proxy
+ // Static variables and resource proxy
{
- let doc = "Timer queue".to_string();
+ // let doc = &format!("Timer queue for {}", monotonic_name);
let cap = app
.software_tasks
.iter()
.map(|(_name, task)| task.args.capacity)
.sum();
let n = util::capacity_typenum(cap, false);
- let tq_ty = quote!(rtic::export::TimerQueue<#m, #t, #n>);
+ let tq_ty = quote!(rtic::export::TimerQueue<#mono_type, #t, #n>);
items.push(quote!(
- #[doc = #doc]
+ #[doc(hidden)]
static mut #tq: #tq_ty = rtic::export::TimerQueue(
rtic::export::BinaryHeap(
rtic::export::iBinaryHeap::new()
)
);
));
+
+ let mono = util::monotonic_ident(&monotonic_name);
+ let mono = util::mark_internal_ident(&mono);
+ // let doc = &format!("Storage for {}", monotonic_name);
+
+ items.push(quote!(
+ #[doc(hidden)]
+ static mut #mono: Option<#mono_type> = None;
+ ));
}
// Timer queue handler
{
+ let enum_ = util::interrupt_ident();
+ let rt_err = util::rt_err_ident();
+
let arms = app
.software_tasks
.iter()
@@ -69,13 +92,15 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
let cfgs = &task.cfgs;
let priority = task.args.priority;
let rq = util::rq_ident(priority);
+ let rq = util::mark_internal_ident(&rq);
let rqt = util::spawn_t_ident(priority);
- let enum_ = util::interrupt_ident();
+
+ // The interrupt that runs the task dispatcher
let interrupt = &analysis.interrupts.get(&priority).expect("RTIC-ICE: interrupt not found").0;
let pend = {
quote!(
- rtic::pend(you_must_enable_the_rt_feature_for_the_pac_in_your_cargo_toml::#enum_::#interrupt);
+ rtic::pend(#rt_err::#enum_::#interrupt);
)
};
@@ -90,21 +115,39 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
})
.collect::<Vec<_>>();
- let sys_tick = util::suffixed("SysTick");
+ let bound_interrupt = &monotonic.args.binds;
+ let disable_isr = if &*bound_interrupt.to_string() == "SysTick" {
+ quote!(core::mem::transmute::<_, cortex_m::peripheral::SYST>(()).disable_interrupt())
+ } else {
+ quote!(rtic::export::NVIC::mask(#rt_err::#enum_::#bound_interrupt))
+ };
+
items.push(quote!(
#[no_mangle]
- unsafe fn #sys_tick() {
- use rtic::Mutex as _;
+ #[allow(non_snake_case)]
+ unsafe fn #bound_interrupt() {
- while let Some((task, index)) = rtic::export::interrupt::free(|_| #tq.dequeue())
+ while let Some((task, index)) = rtic::export::interrupt::free(|_|
+ if let Some(mono) = #app_path::#m_ident.as_mut() {
+ #tq.dequeue(|| #disable_isr, mono)
+ } else {
+ // We can only use the timer queue if `init` has returned, and it
+ // writes the `Some(monotonic)` we are accessing here.
+ core::hint::unreachable_unchecked()
+ })
{
match task {
#(#arms)*
}
}
+
+ rtic::export::interrupt::free(|_| if let Some(mono) = #app_path::#m_ident.as_mut() {
+ mono.on_interrupt();
+ });
}
));
}
}
+
items
}
diff --git a/macros/src/codegen/util.rs b/macros/src/codegen/util.rs
index fb8f1a84..6589f62d 100644
--- a/macros/src/codegen/util.rs
+++ b/macros/src/codegen/util.rs
@@ -77,8 +77,11 @@ pub fn inputs_ident(task: &Ident) -> Ident {
}
/// Generates an identifier for the `INSTANTS` buffer (`schedule` API)
-pub fn instants_ident(task: &Ident) -> Ident {
- Ident::new(&format!("{}_INSTANTS", task), Span::call_site())
+pub fn monotonic_instants_ident(task: &Ident, monotonic: &Ident) -> Ident {
+ Ident::new(
+ &format!("{}_{}_INSTANTS", task, monotonic),
+ Span::call_site(),
+ )
}
pub fn interrupt_ident() -> Ident {
@@ -103,16 +106,8 @@ pub fn is_exception(name: &Ident) -> bool {
)
}
-/// Generates a pre-reexport identifier for the "late resources" struct
-pub fn late_resources_ident(init: &Ident) -> Ident {
- Ident::new(
- &format!("{}LateResources", init.to_string()),
- Span::call_site(),
- )
-}
-
-/// Mangle an ident
-pub fn mangle_ident(ident: &Ident) -> Ident {
+/// Mark an ident as internal
+pub fn mark_internal_ident(ident: &Ident) -> Ident {
Ident::new(
&format!("__rtic_internal_{}", ident.to_string()),
Span::call_site(),
@@ -222,7 +217,7 @@ pub fn rq_ident(priority: u8) -> Ident {
/// Generates an identifier for the `enum` of `schedule`-able tasks
pub fn schedule_t_ident() -> Ident {
- Ident::new(&"SCHED_T".to_string(), Span::call_site())
+ Ident::new(&"SCHED_T", Span::call_site())
}
/// Generates an identifier for the `enum` of `spawn`-able tasks
@@ -233,14 +228,26 @@ pub fn spawn_t_ident(priority: u8) -> Ident {
Ident::new(&format!("P{}_T", priority), Span::call_site())
}
+/// Suffixed identifier
pub fn suffixed(name: &str) -> Ident {
let span = Span::call_site();
Ident::new(name, span)
}
/// Generates an identifier for a timer queue
-///
-/// At most there is one timer queue
-pub fn tq_ident() -> Ident {
- Ident::new(&"TQ".to_string(), Span::call_site())
+pub fn tq_ident(name: &str) -> Ident {
+ Ident::new(&format!("TQ_{}", name), Span::call_site())
+}
+
+/// Generates an identifier for monotonic timer storage
+pub fn monotonic_ident(name: &str) -> Ident {
+ Ident::new(&format!("MONOTONIC_STORAGE_{}", name), Span::call_site())
+}
+
+/// The name to get better RT flag errors
+pub fn rt_err_ident() -> Ident {
+ Ident::new(
+ &"you_must_enable_the_rt_feature_for_the_pac_in_your_cargo_toml",
+ Span::call_site(),
+ )
}