2022-12-31 14:45:13 +01:00
|
|
|
use crate::syntax::{ast::App, Context};
|
|
|
|
use crate::{analyze::Analysis, codegen::util};
|
2019-06-13 23:56:59 +02:00
|
|
|
use proc_macro2::TokenStream as TokenStream2;
|
|
|
|
use quote::quote;
|
|
|
|
|
2022-02-18 19:38:48 +01:00
|
|
|
#[allow(clippy::too_many_lines)]
|
2023-01-07 11:24:13 +01:00
|
|
|
pub fn codegen(ctxt: Context, app: &App, analysis: &Analysis) -> TokenStream2 {
|
2019-06-13 23:56:59 +02:00
|
|
|
let mut items = vec![];
|
2021-05-06 19:40:37 +02:00
|
|
|
let mut module_items = vec![];
|
2019-06-13 23:56:59 +02:00
|
|
|
let mut fields = vec![];
|
|
|
|
let mut values = vec![];
|
2022-12-31 14:45:13 +01:00
|
|
|
// Used to copy task cfgs to the whole module
|
|
|
|
let mut task_cfgs = vec![];
|
2019-06-13 23:56:59 +02:00
|
|
|
|
|
|
|
let name = ctxt.ident(app);
|
2021-03-14 21:27:21 +01:00
|
|
|
|
2019-06-13 23:56:59 +02:00
|
|
|
match ctxt {
|
2020-08-27 13:21:56 +02:00
|
|
|
Context::Init => {
|
2020-12-10 20:33:13 +01:00
|
|
|
fields.push(quote!(
|
|
|
|
/// Core (Cortex-M) peripherals
|
|
|
|
pub core: rtic::export::Peripherals
|
|
|
|
));
|
2019-06-13 23:56:59 +02:00
|
|
|
|
2022-12-31 14:45:13 +01:00
|
|
|
if app.args.peripherals {
|
|
|
|
let device = &app.args.device;
|
2019-06-13 23:56:59 +02:00
|
|
|
|
|
|
|
fields.push(quote!(
|
|
|
|
/// Device peripherals
|
|
|
|
pub device: #device::Peripherals
|
|
|
|
));
|
|
|
|
|
|
|
|
values.push(quote!(device: #device::Peripherals::steal()));
|
|
|
|
}
|
|
|
|
|
2020-10-01 20:01:25 +02:00
|
|
|
fields.push(quote!(
|
|
|
|
/// Critical section token for init
|
2023-01-07 11:24:13 +01:00
|
|
|
pub cs: rtic::export::CriticalSection<'a>
|
2020-10-01 20:01:25 +02:00
|
|
|
));
|
|
|
|
|
|
|
|
values.push(quote!(cs: rtic::export::CriticalSection::new()));
|
|
|
|
|
2019-06-13 23:56:59 +02:00
|
|
|
values.push(quote!(core));
|
|
|
|
}
|
|
|
|
|
2022-02-18 19:38:48 +01:00
|
|
|
Context::Idle | Context::HardwareTask(_) | Context::SoftwareTask(_) => {}
|
2019-06-13 23:56:59 +02:00
|
|
|
}
|
|
|
|
|
2021-07-06 22:47:48 +02:00
|
|
|
if ctxt.has_local_resources(app) {
|
|
|
|
let ident = util::local_resources_ident(ctxt, app);
|
|
|
|
|
2021-05-06 19:40:37 +02:00
|
|
|
module_items.push(quote!(
|
2019-06-13 23:56:59 +02:00
|
|
|
#[doc(inline)]
|
2021-07-06 22:47:48 +02:00
|
|
|
pub use super::#ident as LocalResources;
|
2019-06-13 23:56:59 +02:00
|
|
|
));
|
2021-07-06 22:47:48 +02:00
|
|
|
|
|
|
|
fields.push(quote!(
|
|
|
|
/// Local Resources this task has access to
|
2023-01-07 11:24:13 +01:00
|
|
|
pub local: #name::LocalResources<'a>
|
2021-07-06 22:47:48 +02:00
|
|
|
));
|
|
|
|
|
|
|
|
values.push(quote!(local: #name::LocalResources::new()));
|
2019-06-13 23:56:59 +02:00
|
|
|
}
|
|
|
|
|
2021-07-06 22:47:48 +02:00
|
|
|
if ctxt.has_shared_resources(app) {
|
|
|
|
let ident = util::shared_resources_ident(ctxt, app);
|
2019-06-13 23:56:59 +02:00
|
|
|
|
2021-05-06 19:40:37 +02:00
|
|
|
module_items.push(quote!(
|
2019-06-13 23:56:59 +02:00
|
|
|
#[doc(inline)]
|
2021-07-06 22:47:48 +02:00
|
|
|
pub use super::#ident as SharedResources;
|
2019-06-13 23:56:59 +02:00
|
|
|
));
|
|
|
|
|
|
|
|
fields.push(quote!(
|
2021-07-06 22:47:48 +02:00
|
|
|
/// Shared Resources this task has access to
|
2023-01-07 11:24:13 +01:00
|
|
|
pub shared: #name::SharedResources<'a>
|
2019-06-13 23:56:59 +02:00
|
|
|
));
|
|
|
|
|
2023-01-07 11:24:13 +01:00
|
|
|
values.push(quote!(shared: #name::SharedResources::new()));
|
2019-06-13 23:56:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
let doc = match ctxt {
|
2022-12-31 14:45:13 +01:00
|
|
|
Context::Idle => "Idle loop",
|
|
|
|
Context::Init => "Initialization function",
|
|
|
|
Context::HardwareTask(_) => "Hardware task",
|
|
|
|
Context::SoftwareTask(_) => "Software task",
|
2019-06-13 23:56:59 +02:00
|
|
|
};
|
|
|
|
|
2021-05-06 19:40:37 +02:00
|
|
|
let v = Vec::new();
|
|
|
|
let cfgs = match ctxt {
|
2023-01-04 20:29:16 +01:00
|
|
|
Context::HardwareTask(t) => &app.hardware_tasks[t].cfgs,
|
|
|
|
Context::SoftwareTask(t) => &app.software_tasks[t].cfgs,
|
2021-05-06 19:40:37 +02:00
|
|
|
_ => &v,
|
|
|
|
};
|
|
|
|
|
2019-06-13 23:56:59 +02:00
|
|
|
let core = if ctxt.is_init() {
|
2020-12-08 20:49:13 +01:00
|
|
|
Some(quote!(core: rtic::export::Peripherals,))
|
2019-06-13 23:56:59 +02:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2021-05-06 19:40:37 +02:00
|
|
|
let internal_context_name = util::internal_task_ident(name, "Context");
|
|
|
|
|
2019-06-13 23:56:59 +02:00
|
|
|
items.push(quote!(
|
2023-01-22 00:26:09 +01:00
|
|
|
#(#cfgs)*
|
2022-12-31 14:45:13 +01:00
|
|
|
/// Execution context
|
2021-08-19 08:21:18 +02:00
|
|
|
#[allow(non_snake_case)]
|
|
|
|
#[allow(non_camel_case_types)]
|
2023-01-07 11:24:13 +01:00
|
|
|
pub struct #internal_context_name<'a> {
|
|
|
|
#[doc(hidden)]
|
|
|
|
__rtic_internal_p: ::core::marker::PhantomData<&'a ()>,
|
2019-06-13 23:56:59 +02:00
|
|
|
#(#fields,)*
|
|
|
|
}
|
|
|
|
|
2021-05-06 19:40:37 +02:00
|
|
|
#(#cfgs)*
|
2023-01-07 11:24:13 +01:00
|
|
|
impl<'a> #internal_context_name<'a> {
|
2019-06-13 23:56:59 +02:00
|
|
|
#[inline(always)]
|
2023-01-07 11:24:13 +01:00
|
|
|
pub unsafe fn new(#core) -> Self {
|
2021-05-06 19:40:37 +02:00
|
|
|
#internal_context_name {
|
2023-01-07 11:24:13 +01:00
|
|
|
__rtic_internal_p: ::core::marker::PhantomData,
|
2019-06-13 23:56:59 +02:00
|
|
|
#(#values,)*
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
));
|
|
|
|
|
2021-05-06 19:40:37 +02:00
|
|
|
module_items.push(quote!(
|
|
|
|
#(#cfgs)*
|
2022-12-31 14:45:13 +01:00
|
|
|
#[doc(inline)]
|
2021-05-06 19:40:37 +02:00
|
|
|
pub use super::#internal_context_name as Context;
|
|
|
|
));
|
|
|
|
|
2020-10-05 21:57:44 +02:00
|
|
|
if let Context::SoftwareTask(..) = ctxt {
|
|
|
|
let spawnee = &app.software_tasks[name];
|
|
|
|
let priority = spawnee.args.priority;
|
|
|
|
let cfgs = &spawnee.cfgs;
|
2022-12-31 14:45:13 +01:00
|
|
|
// Store a copy of the task cfgs
|
|
|
|
task_cfgs = cfgs.clone();
|
2020-10-05 21:57:44 +02:00
|
|
|
|
2022-12-31 14:45:13 +01:00
|
|
|
let device = &app.args.device;
|
2020-10-05 21:57:44 +02:00
|
|
|
let enum_ = util::interrupt_ident();
|
2023-01-03 15:10:59 +01:00
|
|
|
let interrupt = &analysis
|
|
|
|
.interrupts
|
|
|
|
.get(&priority)
|
|
|
|
.expect("RTIC-ICE: interrupt identifer not found")
|
|
|
|
.0;
|
2020-10-05 21:57:44 +02:00
|
|
|
|
2021-05-06 19:40:37 +02:00
|
|
|
let internal_spawn_ident = util::internal_task_ident(name, "spawn");
|
|
|
|
|
2020-10-11 18:38:38 +02:00
|
|
|
// Spawn caller
|
2023-01-03 15:10:59 +01:00
|
|
|
let rq = util::rq_async_ident(name);
|
|
|
|
items.push(quote!(
|
2020-10-05 21:57:44 +02:00
|
|
|
|
2023-01-03 15:10:59 +01:00
|
|
|
#(#cfgs)*
|
|
|
|
/// Spawns the task directly
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub fn #internal_spawn_ident() -> Result<(), ()> {
|
|
|
|
unsafe {
|
2023-01-04 21:33:41 +01:00
|
|
|
// TODO: Fix this to be compare and swap
|
|
|
|
if #rq.load(core::sync::atomic::Ordering::Acquire) {
|
|
|
|
Err(())
|
|
|
|
} else {
|
|
|
|
#rq.store(true, core::sync::atomic::Ordering::Release);
|
2023-01-03 15:10:59 +01:00
|
|
|
rtic::pend(#device::#enum_::#interrupt);
|
2023-01-04 21:33:41 +01:00
|
|
|
Ok(())
|
2022-12-31 14:45:13 +01:00
|
|
|
}
|
2023-01-03 15:10:59 +01:00
|
|
|
}
|
|
|
|
}));
|
2020-10-11 18:38:38 +02:00
|
|
|
|
2021-05-06 19:40:37 +02:00
|
|
|
module_items.push(quote!(
|
|
|
|
#(#cfgs)*
|
2022-12-31 14:45:13 +01:00
|
|
|
#[doc(inline)]
|
2021-05-06 19:40:37 +02:00
|
|
|
pub use super::#internal_spawn_ident as spawn;
|
|
|
|
));
|
2020-10-05 21:57:44 +02:00
|
|
|
}
|
|
|
|
|
2022-02-18 19:38:48 +01:00
|
|
|
if items.is_empty() {
|
|
|
|
quote!()
|
|
|
|
} else {
|
2019-06-13 23:56:59 +02:00
|
|
|
quote!(
|
2021-05-06 19:40:37 +02:00
|
|
|
#(#items)*
|
2022-12-31 14:45:13 +01:00
|
|
|
|
2019-06-13 23:56:59 +02:00
|
|
|
#[allow(non_snake_case)]
|
2022-12-31 14:45:13 +01:00
|
|
|
#(#task_cfgs)*
|
2019-06-13 23:56:59 +02:00
|
|
|
#[doc = #doc]
|
|
|
|
pub mod #name {
|
2021-05-06 19:40:37 +02:00
|
|
|
#(#module_items)*
|
2019-06-13 23:56:59 +02:00
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|