aboutsummaryrefslogtreecommitdiff
path: root/rtic-macros/src/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'rtic-macros/src/codegen')
-rw-r--r--rtic-macros/src/codegen/async_dispatchers.rs20
-rw-r--r--rtic-macros/src/codegen/bindings/cortex.rs24
-rw-r--r--rtic-macros/src/codegen/bindings/esp32c3.rs33
-rw-r--r--rtic-macros/src/codegen/bindings/template.rs7
-rw-r--r--rtic-macros/src/codegen/main.rs35
-rw-r--r--rtic-macros/src/codegen/module.rs24
-rw-r--r--rtic-macros/src/codegen/util.rs9
7 files changed, 117 insertions, 35 deletions
diff --git a/rtic-macros/src/codegen/async_dispatchers.rs b/rtic-macros/src/codegen/async_dispatchers.rs
index 54db2b3..9144b2a 100644
--- a/rtic-macros/src/codegen/async_dispatchers.rs
+++ b/rtic-macros/src/codegen/async_dispatchers.rs
@@ -2,7 +2,7 @@ use crate::syntax::ast::App;
use crate::{
analyze::Analysis,
codegen::{
- bindings::{async_entry, interrupt_entry, interrupt_exit, handler_config},
+ bindings::{async_entry, handler_config, interrupt_entry, interrupt_exit},
util,
},
};
@@ -17,15 +17,12 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 {
// Generate executor definition and priority in global scope
for (name, _) in app.software_tasks.iter() {
- let type_name = util::internal_task_ident(name, "F");
let exec_name = util::internal_task_ident(name, "EXEC");
items.push(quote!(
- #[allow(non_camel_case_types)]
- type #type_name = impl core::future::Future;
#[allow(non_upper_case_globals)]
- static #exec_name: rtic::export::executor::AsyncTaskExecutor<#type_name> =
- rtic::export::executor::AsyncTaskExecutor::new();
+ static #exec_name: rtic::export::executor::AsyncTaskExecutorPtr =
+ rtic::export::executor::AsyncTaskExecutorPtr::new();
));
}
@@ -50,13 +47,18 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 {
for name in channel.tasks.iter() {
let exec_name = util::internal_task_ident(name, "EXEC");
+ let from_ptr_n_args =
+ util::from_ptr_n_args_ident(app.software_tasks[name].inputs.len());
+
// TODO: Fix cfg
// let task = &app.software_tasks[name];
// let cfgs = &task.cfgs;
stmts.push(quote!(
- #exec_name.poll(|| {
- #exec_name.set_pending();
+ let exec = rtic::export::executor::AsyncTaskExecutor::#from_ptr_n_args(#name, &#exec_name);
+ exec.poll(|| {
+ let exec = rtic::export::executor::AsyncTaskExecutor::#from_ptr_n_args(#name, &#exec_name);
+ exec.set_pending();
#pend_interrupt
});
));
@@ -68,7 +70,7 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 {
let entry_stmts = interrupt_entry(app, analysis);
let exit_stmts = interrupt_exit(app, analysis);
let async_entry_stmts = async_entry(app, analysis, dispatcher_name.clone());
- let config = handler_config(app,analysis,dispatcher_name.clone());
+ let config = handler_config(app, analysis, dispatcher_name.clone());
items.push(quote!(
#[allow(non_snake_case)]
#[doc = #doc]
diff --git a/rtic-macros/src/codegen/bindings/cortex.rs b/rtic-macros/src/codegen/bindings/cortex.rs
index ffa0245..69b5ee5 100644
--- a/rtic-macros/src/codegen/bindings/cortex.rs
+++ b/rtic-macros/src/codegen/bindings/cortex.rs
@@ -29,11 +29,35 @@ fn is_exception(name: &Ident) -> bool {
| "SysTick"
)
}
+
pub fn interrupt_ident() -> Ident {
let span = Span::call_site();
Ident::new("interrupt", span)
}
+pub fn check_stack_overflow_before_init(
+ _app: &App,
+ _analysis: &CodegenAnalysis,
+) -> Vec<TokenStream2> {
+ vec![quote!(
+ // Check for stack overflow using symbols from `cortex-m-rt`.
+ extern "C" {
+ pub static _stack_start: u32;
+ pub static __ebss: u32;
+ }
+
+ let stack_start = &_stack_start as *const _ as u32;
+ let ebss = &__ebss as *const _ as u32;
+
+ if stack_start > ebss {
+ // No flip-link usage, check the MSP for overflow.
+ if rtic::export::msp::read() <= ebss {
+ panic!("Stack overflow after allocating executors");
+ }
+ }
+ )]
+}
+
#[cfg(feature = "cortex-m-source-masking")]
mod source_masking {
use super::*;
diff --git a/rtic-macros/src/codegen/bindings/esp32c3.rs b/rtic-macros/src/codegen/bindings/esp32c3.rs
index a8d58b7..4b14cae 100644
--- a/rtic-macros/src/codegen/bindings/esp32c3.rs
+++ b/rtic-macros/src/codegen/bindings/esp32c3.rs
@@ -72,7 +72,7 @@ mod esp32c3 {
}
pub fn pre_init_enable_interrupts(app: &App, analysis: &CodegenAnalysis) -> Vec<TokenStream2> {
let mut stmts = vec![];
- let mut curr_cpu_id:u8 = 1; //cpu interrupt id 0 is reserved
+ let mut curr_cpu_id: u8 = 1; //cpu interrupt id 0 is reserved
let rt_err = util::rt_err_ident();
let max_prio: usize = 15; //unfortunately this is not part of pac, but we know that max prio is 15.
let interrupt_ids = analysis.interrupts.iter().map(|(p, (id, _))| (p, id));
@@ -158,6 +158,29 @@ mod esp32c3 {
vec![]
}
+ pub fn check_stack_overflow_before_init(
+ _app: &App,
+ _analysis: &CodegenAnalysis,
+ ) -> Vec<TokenStream2> {
+ vec![quote!(
+ // Check for stack overflow using symbols from `risc-v-rt`.
+ extern "C" {
+ pub static _stack_start: u32;
+ pub static __ebss: u32;
+ }
+
+ let stack_start = &_stack_start as *const _ as u32;
+ let ebss = &__ebss as *const _ as u32;
+
+ if stack_start > ebss {
+ // No flip-link usage, check the SP for overflow.
+ if rtic::export::read_sp() <= ebss {
+ panic!("Stack overflow after allocating executors");
+ }
+ }
+ )]
+ }
+
pub fn async_entry(
_app: &App,
_analysis: &CodegenAnalysis,
@@ -199,11 +222,9 @@ mod esp32c3 {
.values()
.filter_map(|task| Some((&task.args.priority, &task.args.binds))),
) {
- if *name == dispatcher_name{
- let ret = &("cpu_int_".to_owned()+&curr_cpu_id.to_string()+"_handler");
- stmts.push(
- quote!(#[export_name = #ret])
- );
+ if *name == dispatcher_name {
+ let ret = &("cpu_int_".to_owned() + &curr_cpu_id.to_string() + "_handler");
+ stmts.push(quote!(#[export_name = #ret]));
}
curr_cpu_id += 1;
}
diff --git a/rtic-macros/src/codegen/bindings/template.rs b/rtic-macros/src/codegen/bindings/template.rs
index d929dd8..b5488b7 100644
--- a/rtic-macros/src/codegen/bindings/template.rs
+++ b/rtic-macros/src/codegen/bindings/template.rs
@@ -43,6 +43,13 @@ pub fn interrupt_exit(_app: &App, _analysis: &CodegenAnalysis) -> Vec<TokenStrea
vec![]
}
+pub fn check_stack_overflow_before_init(
+ _app: &App,
+ _analysis: &CodegenAnalysis,
+) -> Vec<TokenStream2> {
+ vec![]
+}
+
pub fn async_entry(
_app: &App,
_analysis: &CodegenAnalysis,
diff --git a/rtic-macros/src/codegen/main.rs b/rtic-macros/src/codegen/main.rs
index 3848ab0..5612796 100644
--- a/rtic-macros/src/codegen/main.rs
+++ b/rtic-macros/src/codegen/main.rs
@@ -1,9 +1,12 @@
-use crate::{analyze::Analysis, codegen::util, syntax::ast::App};
+use super::{assertions, post_init, pre_init};
+use crate::{
+ analyze::Analysis,
+ codegen::{bindings, util},
+ syntax::ast::App,
+};
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
-use super::{assertions, post_init, pre_init};
-
/// Generates code for `fn main`
pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 {
let assertion_stmts = assertions::codegen(app, analysis);
@@ -19,12 +22,26 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 {
let dispatcher = util::zero_prio_dispatcher_ident();
quote!(#dispatcher();)
} else {
- quote!(loop {
- })
+ quote!(loop {})
};
+ let mut executor_allocations = Vec::new();
+
+ for (name, _) in app.software_tasks.iter() {
+ let exec_name = util::internal_task_ident(name, "EXEC");
+ let new_n_args = util::new_n_args_ident(app.software_tasks[name].inputs.len());
+
+ executor_allocations.push(quote!(
+ let executor = ::core::mem::ManuallyDrop::new(rtic::export::executor::AsyncTaskExecutor::#new_n_args(#name));
+ executors_size += ::core::mem::size_of_val(&executor);
+ #exec_name.set_in_main(&executor);
+ ));
+ }
+
let main = util::suffixed("main");
let init_name = &app.init.name;
+ let msp_check = bindings::check_stack_overflow_before_init(app, analysis);
+
quote!(
#[doc(hidden)]
#[no_mangle]
@@ -38,9 +55,15 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 {
f();
}
+ // Generate allocations for async executors.
+ let mut executors_size = 0;
+ #(#executor_allocations)*
+
+ #(#msp_check)*
+
// Wrap late_init_stmts in a function to ensure that stack space is reclaimed.
__rtic_init_resources(||{
- let (shared_resources, local_resources) = #init_name(#init_name::Context::new(core.into()));
+ let (shared_resources, local_resources) = #init_name(#init_name::Context::new(core.into(), executors_size));
#(#post_init_stmts)*
});
diff --git a/rtic-macros/src/codegen/module.rs b/rtic-macros/src/codegen/module.rs
index 7d3ac54..c8afe07 100644
--- a/rtic-macros/src/codegen/module.rs
+++ b/rtic-macros/src/codegen/module.rs
@@ -21,6 +21,11 @@ pub fn codegen(ctxt: Context, app: &App, analysis: &Analysis) -> TokenStream2 {
pub core: rtic::export::Peripherals
));
+ fields.push(quote!(
+ /// The space used to allocate async executors in bytes.
+ pub executors_size: usize
+ ));
+
if app.args.peripherals {
let device = &app.args.device;
@@ -40,6 +45,7 @@ pub fn codegen(ctxt: Context, app: &App, analysis: &Analysis) -> TokenStream2 {
values.push(quote!(cs: rtic::export::CriticalSection::new()));
values.push(quote!(core));
+ values.push(quote!(executors_size));
}
Context::Idle | Context::HardwareTask(_) | Context::SoftwareTask(_) => {}
@@ -92,7 +98,7 @@ pub fn codegen(ctxt: Context, app: &App, analysis: &Analysis) -> TokenStream2 {
};
let core = if ctxt.is_init() {
- Some(quote!(core: rtic::export::Peripherals,))
+ Some(quote!(core: rtic::export::Peripherals, executors_size: usize))
} else {
None
};
@@ -147,11 +153,10 @@ pub fn codegen(ctxt: Context, app: &App, analysis: &Analysis) -> TokenStream2 {
};
let internal_spawn_ident = util::internal_task_ident(name, "spawn");
+ let from_ptr_n_args = util::from_ptr_n_args_ident(spawnee.inputs.len());
let (input_args, input_tupled, input_untupled, input_ty) =
util::regroup_inputs(&spawnee.inputs);
- let type_name = util::internal_task_ident(name, "F");
-
// Spawn caller
items.push(quote!(
#(#cfgs)*
@@ -159,18 +164,11 @@ pub fn codegen(ctxt: Context, app: &App, analysis: &Analysis) -> TokenStream2 {
#[allow(non_snake_case)]
#[doc(hidden)]
pub fn #internal_spawn_ident(#(#input_args,)*) -> Result<(), #input_ty> {
- // New TAIT requirement hack; the opaque type must be in the argument or return
- // position of a function...
- #[inline(always)]
- fn tait_hack(#(#input_args,)*) -> #type_name {
- #name(unsafe { #name::Context::new() } #(,#input_untupled)*)
- }
-
// SAFETY: If `try_allocate` succeeds one must call `spawn`, which we do.
unsafe {
- if #exec_name.try_allocate() {
- let f = tait_hack(#(#input_untupled,)*);
- #exec_name.spawn(f);
+ let exec = rtic::export::executor::AsyncTaskExecutor::#from_ptr_n_args(#name, &#exec_name);
+ if exec.try_allocate() {
+ exec.spawn(#name(unsafe { #name::Context::new() } #(,#input_untupled)*));
#pend_interrupt
Ok(())
diff --git a/rtic-macros/src/codegen/util.rs b/rtic-macros/src/codegen/util.rs
index 430e853..b4682ee 100644
--- a/rtic-macros/src/codegen/util.rs
+++ b/rtic-macros/src/codegen/util.rs
@@ -8,7 +8,6 @@ pub use super::bindings::interrupt_ident;
const RTIC_INTERNAL: &str = "__rtic_internal";
-
/// Mark a name as internal
pub fn mark_internal_name(name: &str) -> Ident {
Ident::new(&format!("{RTIC_INTERNAL}_{name}"), Span::call_site())
@@ -166,3 +165,11 @@ pub fn rt_err_ident() -> Ident {
Span::call_site(),
)
}
+
+pub fn from_ptr_n_args_ident(n: usize) -> Ident {
+ Ident::new(&format!("from_ptr_{}_args", n + 1), Span::call_site())
+}
+
+pub fn new_n_args_ident(n: usize) -> Ident {
+ Ident::new(&format!("new_{}_args", n + 1), Span::call_site())
+}