diff options
Diffstat (limited to 'rtic-macros/src/codegen')
| -rw-r--r-- | rtic-macros/src/codegen/async_dispatchers.rs | 7 | ||||
| -rw-r--r-- | rtic-macros/src/codegen/bindings.rs | 14 | ||||
| -rw-r--r-- | rtic-macros/src/codegen/bindings/cortex.rs | 21 | ||||
| -rw-r--r-- | rtic-macros/src/codegen/bindings/esp32c3.rs | 213 | ||||
| -rw-r--r-- | rtic-macros/src/codegen/bindings/template.rs | 17 | ||||
| -rw-r--r-- | rtic-macros/src/codegen/hardware_tasks.rs | 4 | ||||
| -rw-r--r-- | rtic-macros/src/codegen/util.rs | 6 |
7 files changed, 273 insertions, 9 deletions
diff --git a/rtic-macros/src/codegen/async_dispatchers.rs b/rtic-macros/src/codegen/async_dispatchers.rs index 289a63b..54db2b3 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::{interrupt_entry, interrupt_exit}, + bindings::{async_entry, interrupt_entry, interrupt_exit, handler_config}, util, }, }; @@ -67,14 +67,17 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 { let attribute = &interrupts.get(&level).expect("UNREACHABLE").1.attrs; 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()); items.push(quote!( #[allow(non_snake_case)] #[doc = #doc] #[no_mangle] #(#attribute)* + #(#config)* unsafe fn #dispatcher_name() { #(#entry_stmts)* + #(#async_entry_stmts)* /// The priority of this interrupt handler const PRIORITY: u8 = #level; diff --git a/rtic-macros/src/codegen/bindings.rs b/rtic-macros/src/codegen/bindings.rs index c328ee0..60605f3 100644 --- a/rtic-macros/src/codegen/bindings.rs +++ b/rtic-macros/src/codegen/bindings.rs @@ -1,3 +1,11 @@ +#[cfg(not(any( + feature = "cortex-m-source-masking", + feature = "cortex-m-basepri", + feature = "test-template", + feature = "riscv-esp32c3" +)))] +compile_error!("No backend selected"); + #[cfg(any(feature = "cortex-m-source-masking", feature = "cortex-m-basepri"))] pub use cortex::*; @@ -9,3 +17,9 @@ mod cortex; #[cfg(feature = "test-template")] mod template; + +#[cfg(feature = "riscv-esp32c3")] +pub use esp32c3::*; + +#[cfg(feature = "riscv-esp32c3")] +mod esp32c3;
\ No newline at end of file diff --git a/rtic-macros/src/codegen/bindings/cortex.rs b/rtic-macros/src/codegen/bindings/cortex.rs index eba2afc..ffa0245 100644 --- a/rtic-macros/src/codegen/bindings/cortex.rs +++ b/rtic-macros/src/codegen/bindings/cortex.rs @@ -3,7 +3,7 @@ use crate::{ codegen::util, syntax::{analyze::Analysis as SyntaxAnalysis, ast::App}, }; -use proc_macro2::TokenStream as TokenStream2; +use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::quote; use std::collections::HashSet; use syn::{parse, Attribute, Ident}; @@ -29,6 +29,10 @@ fn is_exception(name: &Ident) -> bool { | "SysTick" ) } +pub fn interrupt_ident() -> Ident { + let span = Span::call_site(); + Ident::new("interrupt", span) +} #[cfg(feature = "cortex-m-source-masking")] mod source_masking { @@ -323,6 +327,14 @@ pub fn interrupt_exit(_app: &App, _analysis: &CodegenAnalysis) -> Vec<TokenStrea vec![] } +pub fn async_entry( + _app: &App, + _analysis: &CodegenAnalysis, + _dispatcher_name: Ident, +) -> Vec<TokenStream2> { + vec![] +} + pub fn async_prio_limit(app: &App, analysis: &CodegenAnalysis) -> Vec<TokenStream2> { let max = if let Some(max) = analysis.max_async_prio { quote!(#max) @@ -338,3 +350,10 @@ pub fn async_prio_limit(app: &App, analysis: &CodegenAnalysis) -> Vec<TokenStrea static RTIC_ASYNC_MAX_LOGICAL_PRIO: u8 = #max; )] } +pub fn handler_config( + _app: &App, + _analysis: &CodegenAnalysis, + _dispatcher_name: Ident, +) -> Vec<TokenStream2> { + vec![] +} diff --git a/rtic-macros/src/codegen/bindings/esp32c3.rs b/rtic-macros/src/codegen/bindings/esp32c3.rs new file mode 100644 index 0000000..a8d58b7 --- /dev/null +++ b/rtic-macros/src/codegen/bindings/esp32c3.rs @@ -0,0 +1,213 @@ +#[cfg(feature = "riscv-esp32c3")] +pub use esp32c3::*; + +#[cfg(feature = "riscv-esp32c3")] +mod esp32c3 { + use crate::{ + analyze::Analysis as CodegenAnalysis, + codegen::util, + syntax::{analyze::Analysis as SyntaxAnalysis, ast::App}, + }; + use proc_macro2::{Span, TokenStream as TokenStream2}; + use quote::quote; + use std::collections::HashSet; + use syn::{parse, Attribute, Ident}; + + #[allow(clippy::too_many_arguments)] + pub fn impl_mutex( + _app: &App, + _analysis: &CodegenAnalysis, + cfgs: &[Attribute], + resources_prefix: bool, + name: &Ident, + ty: &TokenStream2, + ceiling: u8, + ptr: &TokenStream2, + ) -> TokenStream2 { + let path = if resources_prefix { + quote!(shared_resources::#name) + } else { + quote!(#name) + }; + quote!( + #(#cfgs)* + impl<'a> rtic::Mutex for #path<'a> { + type T = #ty; + + #[inline(always)] + fn lock<RTIC_INTERNAL_R>(&mut self, f: impl FnOnce(&mut #ty) -> RTIC_INTERNAL_R) -> RTIC_INTERNAL_R { + /// Priority ceiling + const CEILING: u8 = #ceiling; + unsafe { + rtic::export::lock( + #ptr, + CEILING, + f, + ) + } + } + } + ) + } + + pub fn interrupt_ident() -> Ident { + let span = Span::call_site(); + Ident::new("Interrupt", span) + } + + pub fn extra_assertions(_: &App, _: &SyntaxAnalysis) -> Vec<TokenStream2> { + vec![] + } + + pub fn pre_init_checks(app: &App, _: &SyntaxAnalysis) -> Vec<TokenStream2> { + let mut stmts = vec![]; + // check that all dispatchers exists in the `Interrupt` enumeration regardless of whether + // they are used or not + let rt_err = util::rt_err_ident(); + + for name in app.args.dispatchers.keys() { + stmts.push(quote!(let _ = #rt_err::Interrupt::#name;)); + } + stmts + } + 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 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)); + // Unmask interrupts and set their priorities + for (&priority, name) in interrupt_ids.chain( + app.hardware_tasks + .values() + .filter_map(|task| Some((&task.args.priority, &task.args.binds))), + ) { + let es = format!( + "Maximum priority used by interrupt vector '{name}' is more than supported by hardware" + ); + // Compile time assert that this priority is supported by the device + stmts.push(quote!( + const _: () = if (#max_prio) <= #priority as usize { ::core::panic!(#es); }; + )); + stmts.push(quote!( + rtic::export::enable( + #rt_err::Interrupt::#name, + #priority, + #curr_cpu_id, + ); + )); + curr_cpu_id += 1; + } + stmts + } + + pub fn architecture_specific_analysis( + app: &App, + _analysis: &SyntaxAnalysis, + ) -> parse::Result<()> { + //check if the dispatchers are supported + for name in app.args.dispatchers.keys() { + let name_s = name.to_string(); + match &*name_s { + "FROM_CPU_INTR0" | "FROM_CPU_INTR1" | "FROM_CPU_INTR2" | "FROM_CPU_INTR3" => {} + + _ => { + return Err(parse::Error::new( + name.span(), + "Only FROM_CPU_INTRX are supported as dispatchers", + )); + } + } + } + + // Check that there are enough external interrupts to dispatch the software tasks and the timer + // queue handler + let mut first = None; + let priorities = app + .software_tasks + .iter() + .map(|(name, task)| { + first = Some(name); + task.args.priority + }) + .filter(|prio| *prio > 0) + .collect::<HashSet<_>>(); + + let need = priorities.len(); + let given = app.args.dispatchers.len(); + if need > given { + let s = { + format!( + "not enough interrupts to dispatch \ + all software tasks (need: {need}; given: {given})" + ) + }; + + // If not enough tasks and first still is None, may cause + // "custom attribute panicked" due to unwrap on None + return Err(parse::Error::new(first.unwrap().span(), s)); + } + Ok(()) + } + + pub fn interrupt_entry(_app: &App, _analysis: &CodegenAnalysis) -> Vec<TokenStream2> { + vec![] + } + + pub fn interrupt_exit(_app: &App, _analysis: &CodegenAnalysis) -> Vec<TokenStream2> { + vec![] + } + + pub fn async_entry( + _app: &App, + _analysis: &CodegenAnalysis, + dispatcher_name: Ident, + ) -> Vec<TokenStream2> { + let mut stmts = vec![]; + stmts.push(quote!( + rtic::export::unpend(rtic::export::Interrupt::#dispatcher_name); //simulate cortex-m behavior by unpending the interrupt on entry. + )); + stmts + } + + pub fn async_prio_limit(app: &App, analysis: &CodegenAnalysis) -> Vec<TokenStream2> { + let max = if let Some(max) = analysis.max_async_prio { + quote!(#max) + } else { + // No limit + let device = &app.args.device; + quote!(1 << #device::NVIC_PRIO_BITS) + }; + + vec![quote!( + /// Holds the maximum priority level for use by async HAL drivers. + #[no_mangle] + static RTIC_ASYNC_MAX_LOGICAL_PRIO: u8 = #max; + )] + } + pub fn handler_config( + app: &App, + analysis: &CodegenAnalysis, + dispatcher_name: Ident, + ) -> Vec<TokenStream2> { + let mut stmts = vec![]; + let mut curr_cpu_id = 1; + //let mut ret = ""; + let interrupt_ids = analysis.interrupts.iter().map(|(p, (id, _))| (p, id)); + for (_, name) in interrupt_ids.chain( + app.hardware_tasks + .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]) + ); + } + curr_cpu_id += 1; + } + + stmts + } +} diff --git a/rtic-macros/src/codegen/bindings/template.rs b/rtic-macros/src/codegen/bindings/template.rs index 690dfb0..d929dd8 100644 --- a/rtic-macros/src/codegen/bindings/template.rs +++ b/rtic-macros/src/codegen/bindings/template.rs @@ -43,6 +43,21 @@ pub fn interrupt_exit(_app: &App, _analysis: &CodegenAnalysis) -> Vec<TokenStrea vec![] } -pub fn async_prio_limit(_app: &App, _analysis: &CodegenAnalysis) -> Vec<TokenStream2> { +pub fn async_entry( + _app: &App, + _analysis: &CodegenAnalysis, + _dispatcher_name: Ident, +) -> Vec<TokenStream2> { + vec![] +} + +pub fn async_prio_limit(app: &App, _analysis: &CodegenAnalysis) -> Vec<TokenStream2> { + vec![] +} +pub fn handler_config( + _app: &App, + _analysis: &CodegenAnalysis, + dispatcher_name: Ident, +) -> Vec<TokenStream2> { vec![] } diff --git a/rtic-macros/src/codegen/hardware_tasks.rs b/rtic-macros/src/codegen/hardware_tasks.rs index 2c5254e..ee85f59 100644 --- a/rtic-macros/src/codegen/hardware_tasks.rs +++ b/rtic-macros/src/codegen/hardware_tasks.rs @@ -2,7 +2,7 @@ use crate::syntax::{ast::App, Context}; use crate::{ analyze::Analysis, codegen::{ - bindings::{interrupt_entry, interrupt_exit}, + bindings::{interrupt_entry, interrupt_exit, handler_config}, local_resources_struct, module, shared_resources_struct, }, }; @@ -22,12 +22,14 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 { let attrs = &task.attrs; let entry_stmts = interrupt_entry(app, analysis); let exit_stmts = interrupt_exit(app, analysis); + let config = handler_config(app, analysis, symbol.clone()); mod_app.push(quote!( #[allow(non_snake_case)] #[no_mangle] #(#attrs)* #(#cfgs)* + #(#config)* unsafe fn #symbol() { #(#entry_stmts)* diff --git a/rtic-macros/src/codegen/util.rs b/rtic-macros/src/codegen/util.rs index 2f44edb..430e853 100644 --- a/rtic-macros/src/codegen/util.rs +++ b/rtic-macros/src/codegen/util.rs @@ -3,13 +3,11 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::quote; use syn::{Ident, PatType}; +//hook the target specific interrupt_ident function +pub use super::bindings::interrupt_ident; const RTIC_INTERNAL: &str = "__rtic_internal"; -pub fn interrupt_ident() -> Ident { - let span = Span::call_site(); - Ident::new("interrupt", span) -} /// Mark a name as internal pub fn mark_internal_name(name: &str) -> Ident { |
