1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use rtic_syntax::{ast::App, Context};
use crate::{
analyze::Analysis,
check::Extra,
codegen::{locals, module, resources_struct, util},
};
pub fn codegen(
app: &App,
analysis: &Analysis,
extra: &Extra,
) -> (
// 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
// - `${task}Resources` structs
// - `${task}` modules
Vec<TokenStream2>,
// user_software_tasks -- the `#[task]` functions written by the user
Vec<TokenStream2>,
) {
let mut mod_app = vec![];
let mut root = vec![];
let mut user_tasks = vec![];
for (name, task) in &app.software_tasks {
let inputs = &task.inputs;
let (_, _, _, input_ty) = util::regroup_inputs(inputs);
let cap = task.args.capacity;
let cap_lit = util::capacity_literal(cap);
let cap_ty = util::capacity_typenum(cap, true);
// Create free queues and inputs / instants buffers
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;
));
let elems = &(0..cap)
.map(|_| quote!(core::mem::MaybeUninit::uninit()))
.collect::<Vec<_>>();
if let Some(m) = extra.monotonic {
let instants = util::instants_ident(name);
let uninit = mk_uninit();
mod_app.push(quote!(
#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,)*];
));
}
let uninit = mk_uninit();
let inputs_ident = util::inputs_ident(name);
mod_app.push(quote!(
#uninit
/// Buffer that holds the inputs of a task
static mut #inputs_ident: [core::mem::MaybeUninit<#input_ty>; #cap_lit] =
[#(#elems,)*];
));
// `${task}Resources`
let mut needs_lt = false;
if !task.args.resources.is_empty() {
let (item, constructor) = resources_struct::codegen(
Context::SoftwareTask(name),
task.args.priority,
&mut needs_lt,
app,
analysis,
);
root.push(item);
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, app);
locals_pat = Some(pat);
root.push(struct_);
}
let context = &task.context;
let attrs = &task.attrs;
let cfgs = &task.cfgs;
let stmts = &task.stmts;
let locals_pat = locals_pat.iter();
user_tasks.push(quote!(
#(#attrs)*
#(#cfgs)*
#[allow(non_snake_case)]
fn #name(#(#locals_pat,)* #context: #name::Context #(,#inputs)*) {
use rtic::Mutex as _;
#(#stmts)*
}
));
root.push(module::codegen(
Context::SoftwareTask(name),
needs_lt,
app,
analysis,
extra,
));
}
(mod_app, root, user_tasks)
}
|