aboutsummaryrefslogtreecommitdiff
path: root/macros/src
diff options
context:
space:
mode:
authorGravatar bors[bot] <bors[bot]@users.noreply.github.com> 2018-12-15 20:18:11 +0000
committerGravatar bors[bot] <bors[bot]@users.noreply.github.com> 2018-12-15 20:18:11 +0000
commiteba691a5f2ac42d6a50203f58632209a27ab9566 (patch)
tree69488293ab75c55308991c10ea40efaf61b891e1 /macros/src
parent31df3e2ca9cf6f343a90432002a66684506dd46e (diff)
parente03c09874fd557126d8ae3d21e5b90681d358ef0 (diff)
downloadrtic-eba691a5f2ac42d6a50203f58632209a27ab9566.tar.gz
rtic-eba691a5f2ac42d6a50203f58632209a27ab9566.tar.zst
rtic-eba691a5f2ac42d6a50203f58632209a27ab9566.zip
Merge #111
111: some refactors r=japaric a=japaric Co-authored-by: Jorge Aparicio <jorge@japaric.io>
Diffstat (limited to 'macros/src')
-rw-r--r--macros/src/codegen.rs285
1 files changed, 155 insertions, 130 deletions
diff --git a/macros/src/codegen.rs b/macros/src/codegen.rs
index 6f5e1007..8e1970f5 100644
--- a/macros/src/codegen.rs
+++ b/macros/src/codegen.rs
@@ -24,58 +24,55 @@ struct Context {
// Alias
#[cfg(feature = "timer-queue")]
baseline: Ident,
- // Dispatcher -> Alias (`enum`)
- enums: HashMap<u8, Ident>,
- // Task -> Alias (`static` / resource)
- free_queues: Aliases,
+ dispatchers: HashMap<u8, Dispatcher>,
// Alias (`fn`)
idle: Ident,
// Alias (`fn`)
init: Ident,
- // Task -> Alias (`static`)
- inputs: Aliases,
// Alias
priority: Ident,
- // Dispatcher -> Alias (`static` / resource)
- ready_queues: HashMap<u8, Ident>,
// For non-singletons this maps the resource name to its `static mut` variable name
statics: Aliases,
/// Task -> Alias (`struct`)
resources: HashMap<Kind, Resources>,
- // Task -> Alias (`static`)
- #[cfg(feature = "timer-queue")]
- scheduleds: Aliases,
- // Task -> Alias (`fn`)
- spawn_fn: Aliases,
// Alias (`enum`)
schedule_enum: Ident,
// Task -> Alias (`fn`)
schedule_fn: Aliases,
- tasks: Aliases,
+ tasks: HashMap<Ident, Task>,
// Alias (`struct` / `static mut`)
timer_queue: Ident,
}
+struct Dispatcher {
+ enum_: Ident,
+ ready_queue: Ident,
+}
+
+struct Task {
+ alias: Ident,
+ free_queue: Ident,
+ inputs: Ident,
+ spawn_fn: Ident,
+
+ #[cfg(feature = "timer-queue")]
+ scheduleds: Ident,
+}
+
impl Default for Context {
fn default() -> Self {
Context {
#[cfg(feature = "timer-queue")]
baseline: mk_ident(None),
- enums: HashMap::new(),
- free_queues: Aliases::new(),
+ dispatchers: HashMap::new(),
idle: mk_ident(Some("idle")),
init: mk_ident(Some("init")),
- inputs: Aliases::new(),
priority: mk_ident(None),
- ready_queues: HashMap::new(),
statics: Aliases::new(),
resources: HashMap::new(),
- #[cfg(feature = "timer-queue")]
- scheduleds: Aliases::new(),
- spawn_fn: Aliases::new(),
schedule_enum: mk_ident(None),
schedule_fn: Aliases::new(),
- tasks: Aliases::new(),
+ tasks: HashMap::new(),
timer_queue: mk_ident(None),
}
}
@@ -145,7 +142,7 @@ pub fn app(app: &App, analysis: &Analysis) -> TokenStream {
let timer_queue = timer_queue(&ctxt, app, analysis);
- let pre_init = pre_init(&ctxt, analysis);
+ let pre_init = pre_init(&ctxt, &app, analysis);
let assertions = assertions(app, analysis);
@@ -388,16 +385,6 @@ fn post_init(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok
// the device into compile errors
let device = &app.args.device;
let nvic_prio_bits = quote!(#device::NVIC_PRIO_BITS);
- for (name, interrupt) in &app.interrupts {
- let priority = interrupt.args.priority;
- exprs.push(quote!(p.NVIC.enable(#device::Interrupt::#name)));
- exprs.push(quote!(assert!(#priority <= (1 << #nvic_prio_bits))));
- exprs.push(quote!(p.NVIC.set_priority(
- #device::Interrupt::#name,
- ((1 << #nvic_prio_bits) - #priority) << (8 - #nvic_prio_bits),
- )));
- }
-
for (name, exception) in &app.exceptions {
let priority = exception.args.priority;
exprs.push(quote!(assert!(#priority <= (1 << #nvic_prio_bits))));
@@ -416,16 +403,6 @@ fn post_init(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok
)));
}
- for (priority, dispatcher) in &analysis.dispatchers {
- let name = &dispatcher.interrupt;
- exprs.push(quote!(p.NVIC.enable(#device::Interrupt::#name)));
- exprs.push(quote!(assert!(#priority <= (1 << #nvic_prio_bits))));
- exprs.push(quote!(p.NVIC.set_priority(
- #device::Interrupt::#name,
- ((1 << #nvic_prio_bits) - #priority) << (8 - #nvic_prio_bits),
- )));
- }
-
if app.idle.is_none() {
// Set SLEEPONEXIT bit to enter sleep mode when returning from ISR
exprs.push(quote!(p.SCB.scr.modify(|r| r | 1 << 1)));
@@ -802,15 +779,6 @@ fn prelude(
}
if !spawn.is_empty() {
- // Populate `spawn_fn`
- for task in spawn {
- if ctxt.spawn_fn.contains_key(task) {
- continue;
- }
-
- ctxt.spawn_fn.insert(task.clone(), mk_ident(None));
- }
-
if kind.is_idle() {
items.push(quote!(
#[allow(unused_variables)]
@@ -1067,6 +1035,8 @@ fn interrupts(
fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenStream {
let mut items = vec![];
+
+ // first pass to generate buffers (statics and resources) and spawn aliases
for (name, task) in &app.tasks {
#[cfg(feature = "timer-queue")]
let scheduleds_alias = mk_ident(None);
@@ -1074,21 +1044,7 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok
let inputs_alias = mk_ident(None);
let task_alias = mk_ident(Some(&name.to_string()));
- let attrs = &task.attrs;
let inputs = &task.inputs;
- let locals = mk_locals(&task.statics, false);
- let stmts = &task.stmts;
-
- let prelude = prelude(
- ctxt,
- Kind::Task(name.clone()),
- &task.args.resources,
- &task.args.spawn,
- &task.args.schedule,
- app,
- task.args.priority,
- analysis,
- );
let ty = tuple_ty(inputs);
@@ -1121,28 +1077,8 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok
() => quote!(),
};
- let scheduled_let = match () {
- #[cfg(feature = "timer-queue")]
- () => {
- let baseline = &ctxt.baseline;
- quote!(let scheduled = #baseline;)
- }
- #[cfg(not(feature = "timer-queue"))]
- () => quote!(),
- };
-
- let baseline_arg = match () {
- #[cfg(feature = "timer-queue")]
- () => {
- let baseline = &ctxt.baseline;
- quote!(#baseline: rtfm::Instant,)
- }
- #[cfg(not(feature = "timer-queue"))]
- () => quote!(),
- };
let inputs_symbol = format!("{}::INPUTS::{}", name, inputs_alias);
let free_symbol = format!("{}::FREE_QUEUE::{}", name, free_alias);
- let unsafety = &task.unsafety;
items.push(quote!(
// FIXME(MaybeUninit) MaybeUninit won't be necessary when core::mem::MaybeUninit
// stabilizes because heapless constructors will work in const context
@@ -1158,18 +1094,50 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok
rtfm::export::MaybeUninit::uninitialized();
#scheduleds_static
+ ));
- #(#attrs)*
- #unsafety fn #task_alias(#baseline_arg #(#inputs,)*) {
- #(#locals)*
+ ctxt.tasks.insert(
+ name.clone(),
+ Task {
+ alias: task_alias,
+ free_queue: free_alias,
+ inputs: inputs_alias,
+ spawn_fn: mk_ident(None),
- #prelude
+ #[cfg(feature = "timer-queue")]
+ scheduleds: scheduleds_alias,
+ },
+ );
+ }
- #scheduled_let
+ // second pass to generate the actual task function
+ for (name, task) in &app.tasks {
+ let attrs = &task.attrs;
+ let inputs = &task.inputs;
+ let locals = mk_locals(&task.statics, false);
+ let stmts = &task.stmts;
+ let unsafety = &task.unsafety;
- #(#stmts)*
+ let scheduled_let = match () {
+ #[cfg(feature = "timer-queue")]
+ () => {
+ let baseline = &ctxt.baseline;
+ quote!(let scheduled = #baseline;)
}
- ));
+ #[cfg(not(feature = "timer-queue"))]
+ () => quote!(),
+ };
+
+ let prelude = prelude(
+ ctxt,
+ Kind::Task(name.clone()),
+ &task.args.resources,
+ &task.args.spawn,
+ &task.args.schedule,
+ app,
+ task.args.priority,
+ analysis,
+ );
items.push(module(
ctxt,
@@ -1179,11 +1147,28 @@ fn tasks(ctxt: &mut Context, app: &App, analysis: &Analysis) -> proc_macro2::Tok
app,
));
- #[cfg(feature = "timer-queue")]
- ctxt.scheduleds.insert(name.clone(), scheduleds_alias);
- ctxt.free_queues.insert(name.clone(), free_alias);
- ctxt.inputs.insert(name.clone(), inputs_alias);
- ctxt.tasks.insert(name.clone(), task_alias);
+ let task_alias = &ctxt.tasks[name].alias;
+ let baseline_arg = match () {
+ #[cfg(feature = "timer-queue")]
+ () => {
+ let baseline = &ctxt.baseline;
+ quote!(#baseline: rtfm::Instant,)
+ }
+ #[cfg(not(feature = "timer-queue"))]
+ () => quote!(),
+ };
+ items.push(quote!(
+ #(#attrs)*
+ #unsafety fn #task_alias(#baseline_arg #(#inputs,)*) {
+ #(#locals)*
+
+ #prelude
+
+ #scheduled_let
+
+ #(#stmts)*
+ }
+ ));
}
quote!(#(#items)*)
@@ -1233,17 +1218,18 @@ fn dispatchers(
.tasks
.iter()
.map(|task| {
- let inputs = &ctxt.inputs[task];
- let free = &ctxt.free_queues[task];
+ let task_ = &ctxt.tasks[task];
+ let inputs = &task_.inputs;
+ let free = &task_.free_queue;
let pats = tuple_pat(&app.tasks[task].inputs);
- let alias = &ctxt.tasks[task];
+ let alias = &task_.alias;
let baseline_let;
let call;
match () {
#[cfg(feature = "timer-queue")]
() => {
- let scheduleds = &ctxt.scheduleds[task];
+ let scheduleds = &task_.scheduleds;
baseline_let = quote!(
let baseline =
ptr::read(#scheduleds.get_ref().get_unchecked(usize::from(index)));
@@ -1284,8 +1270,13 @@ fn dispatchers(
}
));
- ctxt.ready_queues.insert(*level, ready_alias);
- ctxt.enums.insert(*level, enum_alias);
+ ctxt.dispatchers.insert(
+ *level,
+ Dispatcher {
+ ready_queue: ready_alias,
+ enum_: enum_alias,
+ },
+ );
}
(quote!(#(#data)*), quote!(#(#dispatchers)*))
@@ -1299,21 +1290,24 @@ fn spawn(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenSt
let priority = &ctxt.priority;
#[cfg(feature = "timer-queue")]
let baseline = &ctxt.baseline;
- for (task, alias) in &ctxt.spawn_fn {
- let free = &ctxt.free_queues[task];
- let level = app.tasks[task].args.priority;
- let ready = &ctxt.ready_queues[&level];
- let enum_ = &ctxt.enums[&level];
+ for (name, task) in &ctxt.tasks {
+ let alias = &task.spawn_fn;
+ let task_ = &app.tasks[name];
+ let free = &task.free_queue;
+ let level = task_.args.priority;
+ let dispatcher = &ctxt.dispatchers[&level];
+ let ready = &dispatcher.ready_queue;
+ let enum_ = &dispatcher.enum_;
let dispatcher = &analysis.dispatchers[&level].interrupt;
- let inputs = &ctxt.inputs[task];
- let args = &app.tasks[task].inputs;
+ let inputs = &task.inputs;
+ let args = &task_.inputs;
let ty = tuple_ty(args);
let pats = tuple_pat(args);
let scheduleds_write = match () {
#[cfg(feature = "timer-queue")]
() => {
- let scheduleds = &ctxt.scheduleds[task];
+ let scheduleds = &ctxt.tasks[name].scheduleds;
quote!(
ptr::write(
#scheduleds.get_mut().get_unchecked_mut(usize::from(index)),
@@ -1348,7 +1342,7 @@ fn spawn(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenSt
#scheduleds_write
#ready { #priority }.lock(|rq| {
- rq.split().0.enqueue_unchecked((#enum_::#task, index))
+ rq.split().0.enqueue_unchecked((#enum_::#name, index))
});
rtfm::pend(#device::Interrupt::#dispatcher);
@@ -1372,7 +1366,7 @@ fn spawn(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenSt
let mut methods = vec![];
for task in spawn {
- let alias = &ctxt.spawn_fn[task];
+ let alias = &ctxt.tasks[task].spawn_fn;
let inputs = &app.tasks[task].inputs;
let ty = tuple_ty(inputs);
let pats = tuple_pat(inputs);
@@ -1416,10 +1410,11 @@ fn schedule(ctxt: &Context, app: &App) -> proc_macro2::TokenStream {
let priority = &ctxt.priority;
let timer_queue = &ctxt.timer_queue;
for (task, alias) in &ctxt.schedule_fn {
- let free = &ctxt.free_queues[task];
+ let task_ = &ctxt.tasks[task];
+ let free = &task_.free_queue;
let enum_ = &ctxt.schedule_enum;
- let inputs = &ctxt.inputs[task];
- let scheduleds = &ctxt.scheduleds[task];
+ let inputs = &task_.inputs;
+ let scheduleds = &task_.scheduleds;
let args = &app.tasks[task].inputs;
let ty = tuple_ty(args);
let pats = tuple_pat(args);
@@ -1538,8 +1533,9 @@ fn timer_queue(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::T
.iter()
.map(|task| {
let level = app.tasks[task].args.priority;
- let tenum = &ctxt.enums[&level];
- let ready = &ctxt.ready_queues[&level];
+ let dispatcher_ = &ctxt.dispatchers[&level];
+ let tenum = &dispatcher_.enum_;
+ let ready = &dispatcher_.ready_queue;
let dispatcher = &analysis.dispatchers[&level].interrupt;
quote!(
@@ -1576,7 +1572,7 @@ fn timer_queue(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::T
quote!(#(#items)*)
}
-fn pre_init(ctxt: &Context, analysis: &Analysis) -> proc_macro2::TokenStream {
+fn pre_init(ctxt: &Context, app: &App, analysis: &Analysis) -> proc_macro2::TokenStream {
let mut exprs = vec![];
// FIXME(MaybeUninit) Because we are using a fake MaybeUninit we need to set the Option tag to
@@ -1584,23 +1580,27 @@ fn pre_init(ctxt: &Context, analysis: &Analysis) -> proc_macro2::TokenStream {
// be constructed in const context; we have to initialize them at runtime (i.e. here).
// these are `MaybeUninit` arrays
- for inputs in ctxt.inputs.values() {
+ for task in ctxt.tasks.values() {
+ let inputs = &task.inputs;
exprs.push(quote!(#inputs.set(core::mem::uninitialized());))
}
#[cfg(feature = "timer-queue")]
- for inputs in ctxt.scheduleds.values() {
- exprs.push(quote!(#inputs.set(core::mem::uninitialized());))
+ for task in ctxt.tasks.values() {
+ let scheduleds = &task.scheduleds;
+ exprs.push(quote!(#scheduleds.set(core::mem::uninitialized());))
}
// these are `MaybeUninit` `ReadyQueue`s
- for queue in ctxt.ready_queues.values() {
- exprs.push(quote!(#queue.set(rtfm::export::ReadyQueue::new());))
+ for dispatcher in ctxt.dispatchers.values() {
+ let rq = &dispatcher.ready_queue;
+ exprs.push(quote!(#rq.set(rtfm::export::ReadyQueue::new());))
}
// these are `MaybeUninit` `FreeQueue`s
- for free in ctxt.free_queues.values() {
- exprs.push(quote!(#free.set(rtfm::export::FreeQueue::new());))
+ for task in ctxt.tasks.values() {
+ let fq = &task.free_queue;
+ exprs.push(quote!(#fq.set(rtfm::export::FreeQueue::new());))
}
// end-of-FIXME
@@ -1612,15 +1612,40 @@ fn pre_init(ctxt: &Context, analysis: &Analysis) -> proc_macro2::TokenStream {
}
// Populate the `FreeQueue`s
- for (task, alias) in &ctxt.free_queues {
- let capacity = analysis.capacities[task];
+ for (name, task) in &ctxt.tasks {
+ let fq = &task.free_queue;
+ let capacity = analysis.capacities[name];
exprs.push(quote!(
for i in 0..#capacity {
- #alias.get_mut().enqueue_unchecked(i);
+ #fq.get_mut().enqueue_unchecked(i);
}
))
}
+ // TODO turn the assertions that check that the priority is not larger than what's supported by
+ // the device into compile errors
+ let device = &app.args.device;
+ let nvic_prio_bits = quote!(#device::NVIC_PRIO_BITS);
+ for (name, interrupt) in &app.interrupts {
+ let priority = interrupt.args.priority;
+ exprs.push(quote!(p.NVIC.enable(#device::Interrupt::#name);));
+ exprs.push(quote!(assert!(#priority <= (1 << #nvic_prio_bits));));
+ exprs.push(quote!(p.NVIC.set_priority(
+ #device::Interrupt::#name,
+ ((1 << #nvic_prio_bits) - #priority) << (8 - #nvic_prio_bits),
+ );));
+ }
+
+ for (priority, dispatcher) in &analysis.dispatchers {
+ let name = &dispatcher.interrupt;
+ exprs.push(quote!(p.NVIC.enable(#device::Interrupt::#name);));
+ exprs.push(quote!(assert!(#priority <= (1 << #nvic_prio_bits));));
+ exprs.push(quote!(p.NVIC.set_priority(
+ #device::Interrupt::#name,
+ ((1 << #nvic_prio_bits) - #priority) << (8 - #nvic_prio_bits),
+ );));
+ }
+
// Set the cycle count to 0 and disable it while `init` executes
if cfg!(feature = "timer-queue") {
exprs.push(quote!(p.DWT.ctrl.modify(|r| r & !1);));