diff options
Diffstat (limited to 'rtic-macros/src/codegen')
| -rw-r--r-- | rtic-macros/src/codegen/async_dispatchers.rs | 20 | ||||
| -rw-r--r-- | rtic-macros/src/codegen/bindings/cortex.rs | 24 | ||||
| -rw-r--r-- | rtic-macros/src/codegen/bindings/esp32c3.rs | 33 | ||||
| -rw-r--r-- | rtic-macros/src/codegen/bindings/template.rs | 7 | ||||
| -rw-r--r-- | rtic-macros/src/codegen/main.rs | 35 | ||||
| -rw-r--r-- | rtic-macros/src/codegen/module.rs | 24 | ||||
| -rw-r--r-- | rtic-macros/src/codegen/util.rs | 9 |
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()) +} |
