Flattened the _ out of it

This commit is contained in:
Emil Fresk 2021-05-06 19:40:37 +02:00
parent aad8f81991
commit b4509bdbfe
11 changed files with 146 additions and 147 deletions

View file

@ -7,15 +7,11 @@
use panic_semihosting as _;
pub struct SomeStruct;
#[rtic::app(device = lm3s6965, dispatchers = [SSI0])]
mod app {
use dwt_systick_monotonic::DwtSystick;
use rtic::time::duration::Seconds;
use super::SomeStruct;
#[monotonic(binds = SysTick, default = true)]
type MyMono = DwtSystick<8_000_000>; // 8 MHz

View file

@ -22,4 +22,5 @@ proc-macro2 = "1"
proc-macro-error = "1"
quote = "1"
syn = "1"
rtic-syntax = "0.5.0-alpha.2"
# rtic-syntax = "0.5.0-alpha.2"
rtic-syntax = { path = "../../rtic-syntax" }

View file

@ -97,8 +97,6 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
let user_code = &app.user_code;
let name = &app.name;
let device = &extra.device;
let app_name = &app.name;
let app_path = quote! {crate::#app_name};
let monotonic_parts: Vec<_> = app
.monotonics
@ -106,7 +104,6 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
.map(|(_, monotonic)| {
let name = &monotonic.ident;
let name_str = &name.to_string();
let ty = &monotonic.ty;
let ident = util::monotonic_ident(&name_str);
let ident = util::mark_internal_ident(&ident);
let panic_str = &format!(
@ -117,7 +114,6 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
"This module holds the static implementation for `{}::now()`",
name_str
);
let user_imports = &app.user_imports;
let default_monotonic = if monotonic.args.default {
quote!(pub use #name::now;)
@ -131,17 +127,13 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
#[doc = #doc]
#[allow(non_snake_case)]
pub mod #name {
#(
#[allow(unused_imports)]
#user_imports
)*
/// Read the current time from this monotonic
pub fn now() -> rtic::time::Instant<#ty> {
pub fn now() -> rtic::time::Instant<super::super::#name> {
rtic::export::interrupt::free(|_| {
use rtic::Monotonic as _;
use rtic::time::Clock as _;
if let Some(m) = unsafe{ #app_path::#ident.get_mut_unchecked() } {
if let Some(m) = unsafe{ super::super::#ident.get_mut_unchecked() } {
if let Ok(v) = m.try_now() {
v
} else {
@ -163,11 +155,6 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
/// Holds static methods for each monotonic.
pub mod monotonics {
#(
#[allow(unused_imports)]
#user_imports
)*
#(#monotonic_parts)*
}
)

View file

@ -82,8 +82,6 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
quote!(#name::Locals::new(),)
};
let app_name = &app.name;
let app_path = quote! {crate::#app_name};
quote!(
#(#cfgs)*
#t::#name => {
@ -95,7 +93,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
.read();
#fq.get_mut_unchecked().split().0.enqueue_unchecked(index);
let priority = &rtic::export::Priority::new(PRIORITY);
#app_path::#name(
#name(
#locals_new
#name::Context::new(priority)
#(,#pats)*

View file

@ -40,8 +40,6 @@ pub fn codegen(
let cfgs = &task.cfgs;
let attrs = &task.attrs;
let app_name = &app.name;
let app_path = quote! {crate::#app_name};
mod_app.push(quote!(
#[allow(non_snake_case)]
#[no_mangle]
@ -51,7 +49,7 @@ pub fn codegen(
const PRIORITY: u8 = #priority;
rtic::export::run(PRIORITY, || {
#app_path::#name(
#name(
#locals_new
#name::Context::new(&rtic::export::Priority::new(PRIORITY))
)

View file

@ -74,10 +74,8 @@ pub fn codegen(
}
));
let app_name = &app.name;
let app_path = quote! {crate::#app_name};
let locals_new = locals_new.iter();
let call_idle = quote!(#app_path::#name(
let call_idle = quote!(#name(
#(#locals_new,)*
#name::Context::new(&rtic::export::Priority::new(0))
));

View file

@ -65,11 +65,9 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> CodegenResult {
mod_app = Some(constructor);
}
let app_name = &app.name;
let app_path = quote! {crate::#app_name};
let locals_new = locals_new.iter();
let call_init = Some(
quote!(let (late, mut monotonics) = #app_path::#name(#(#locals_new,)* #name::Context::new(core.into()));),
quote!(let (late, mut monotonics) = #name(#(#locals_new,)* #name::Context::new(core.into()));),
);
root_init.push(module::codegen(

View file

@ -1,9 +1,8 @@
use crate::{analyze::Analysis, check::Extra, codegen::util};
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use rtic_syntax::{ast::App, Context};
use crate::{analyze::Analysis, check::Extra, codegen::util};
pub fn codegen(
ctxt: Context,
resources_tick: bool,
@ -12,48 +11,13 @@ pub fn codegen(
extra: &Extra,
) -> TokenStream2 {
let mut items = vec![];
let mut module_items = vec![];
let mut fields = vec![];
let mut values = vec![];
// Used to copy task cfgs to the whole module
let mut task_cfgs = vec![];
let name = ctxt.ident(app);
let app_name = &app.name;
let app_path = quote! {crate::#app_name};
let all_task_imports: Vec<_> = app
.software_tasks
.iter()
.map(|(name, st)| {
if !st.is_extern {
let cfgs = &st.cfgs;
quote! {
#(#cfgs)*
#[allow(unused_imports)]
use #app_path::#name as #name;
}
} else {
quote!()
}
})
.chain(app.hardware_tasks.iter().map(|(name, ht)| {
if !ht.is_extern {
quote! {
#[allow(unused_imports)]
use #app_path::#name as #name;
}
} else {
quote!()
}
}))
.chain(app.user_types.iter().map(|ty| {
let t = &ty.ident;
quote! {
#[allow(unused_imports)]
use super::#t;
}
}))
.collect();
let mut lt = None;
match ctxt {
@ -94,7 +58,7 @@ pub fn codegen(
if ctxt.has_locals(app) {
let ident = util::locals_ident(ctxt, app);
items.push(quote!(
module_items.push(quote!(
#[doc(inline)]
pub use super::#ident as Locals;
));
@ -110,14 +74,14 @@ pub fn codegen(
None
};
items.push(quote!(
module_items.push(quote!(
#[doc(inline)]
pub use super::#ident as Resources;
));
fields.push(quote!(
/// Resources this task has access to
pub resources: Resources<#lt>
pub resources: #name::Resources<#lt>
));
let priority = if ctxt.is_init() {
@ -125,7 +89,7 @@ pub fn codegen(
} else {
Some(quote!(priority))
};
values.push(quote!(resources: Resources::new(#priority)));
values.push(quote!(resources: #name::Resources::new(#priority)));
}
if let Context::Init = ctxt {
@ -145,13 +109,17 @@ pub fn codegen(
})
.collect::<Vec<_>>();
let internal_late_ident = util::mark_internal_name("LateResources");
items.push(quote!(
/// Resources initialized at runtime
#[allow(non_snake_case)]
pub struct LateResources {
pub struct #internal_late_ident {
#(#late_fields),*
}
));
module_items.push(quote!(
pub use super::#internal_late_ident as LateResources;
));
let monotonic_types: Vec<_> = app
.monotonics
@ -162,13 +130,19 @@ pub fn codegen(
})
.collect();
let internal_monotonics_ident = util::mark_internal_name("Monotonics");
items.push(quote!(
/// Monotonics used by the system
#[allow(non_snake_case)]
pub struct Monotonics(
pub struct #internal_monotonics_ident(
#(pub #monotonic_types),*
);
));
module_items.push(quote!(
pub use super::#internal_monotonics_ident as Monotonics;
));
}
let doc = match ctxt {
@ -178,6 +152,19 @@ pub fn codegen(
Context::SoftwareTask(_) => "Software task",
};
let v = Vec::new();
let cfgs = match ctxt {
Context::HardwareTask(t) => {
&app.hardware_tasks[t].cfgs
// ...
},
Context::SoftwareTask(t) => {
&app.software_tasks[t].cfgs
// ...
},
_ => &v,
};
let core = if ctxt.is_init() {
Some(quote!(core: rtic::export::Peripherals,))
} else {
@ -190,22 +177,31 @@ pub fn codegen(
Some(quote!(priority: &#lt rtic::export::Priority))
};
let internal_context_name = util::internal_task_ident(name, "Context");
items.push(quote!(
#(#cfgs)*
/// Execution context
pub struct Context<#lt> {
pub struct #internal_context_name<#lt> {
#(#fields,)*
}
impl<#lt> Context<#lt> {
#(#cfgs)*
impl<#lt> #internal_context_name<#lt> {
#[inline(always)]
pub unsafe fn new(#core #priority) -> Self {
Context {
#internal_context_name {
#(#values,)*
}
}
}
));
module_items.push(quote!(
#(#cfgs)*
pub use super::#internal_context_name as Context;
));
// not sure if this is the right way, maybe its backwards,
// that spawn_module should put in in root
@ -234,26 +230,26 @@ pub fn codegen(
.expect("RTIC-ICE: interrupt identifer not found")
.0;
let internal_spawn_ident = util::internal_task_ident(name, "spawn");
// Spawn caller
items.push(quote!(
#(#all_task_imports)*
#(#cfgs)*
/// Spawns the task directly
pub fn spawn(#(#args,)*) -> Result<(), #ty> {
pub fn #internal_spawn_ident(#(#args,)*) -> Result<(), #ty> {
let input = #tupled;
unsafe {
if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.get_mut_unchecked().dequeue()) {
#app_path::#inputs
if let Some(index) = rtic::export::interrupt::free(|_| #fq.get_mut_unchecked().dequeue()) {
#inputs
.get_mut_unchecked()
.get_unchecked_mut(usize::from(index))
.as_mut_ptr()
.write(input);
rtic::export::interrupt::free(|_| {
#app_path::#rq.get_mut_unchecked().enqueue_unchecked((#app_path::#t::#name, index));
#rq.get_mut_unchecked().enqueue_unchecked((#t::#name, index));
});
rtic::pend(#device::#enum_::#interrupt);
@ -266,6 +262,11 @@ pub fn codegen(
}));
module_items.push(quote!(
#(#cfgs)*
pub use super::#internal_spawn_ident as spawn;
));
// Schedule caller
for (_, monotonic) in &app.monotonics {
let instants = util::monotonic_instants_ident(name, &monotonic.ident);
@ -282,12 +283,6 @@ pub fn codegen(
let m_isr = &monotonic.args.binds;
let enum_ = util::interrupt_ident();
if monotonic.args.default {
items.push(quote!(pub use #m::spawn_after;));
items.push(quote!(pub use #m::spawn_at;));
items.push(quote!(pub use #m::SpawnHandle;));
}
let (enable_interrupt, pend) = if &*m_isr.to_string() == "SysTick" {
(
quote!(core::mem::transmute::<_, cortex_m::peripheral::SYST>(())
@ -297,49 +292,56 @@ pub fn codegen(
} else {
let rt_err = util::rt_err_ident();
(
quote!(rtic::export::NVIC::unmask(#app_path::#rt_err::#enum_::#m_isr)),
quote!(rtic::pend(#app_path::#rt_err::#enum_::#m_isr)),
quote!(rtic::export::NVIC::unmask(#rt_err::#enum_::#m_isr)),
quote!(rtic::pend(#rt_err::#enum_::#m_isr)),
)
};
let user_imports = &app.user_imports;
let tq_marker = util::mark_internal_ident(&util::timer_queue_marker_ident());
// For future use
// let doc = format!(" RTIC internal: {}:{}", file!(), line!());
// items.push(quote!(#[doc = #doc]));
let internal_spawn_handle_ident =
util::internal_monotonics_ident(name, m, "SpawnHandle");
let internal_spawn_at_ident = util::internal_monotonics_ident(name, m, "spawn_at");
let internal_spawn_after_ident =
util::internal_monotonics_ident(name, m, "spawn_after");
if monotonic.args.default {
module_items.push(quote!(
pub use #m::spawn_after;
pub use #m::spawn_at;
pub use #m::SpawnHandle;
));
}
module_items.push(quote!(
pub mod #m {
pub use super::super::#internal_spawn_after_ident as spawn_after;
pub use super::super::#internal_spawn_at_ident as spawn_at;
pub use super::super::#internal_spawn_handle_ident as SpawnHandle;
}
));
items.push(quote!(
/// Holds methods related to this monotonic
pub mod #m {
use super::*;
#[allow(unused_imports)]
use #app_path::#tq_marker;
#[allow(unused_imports)]
use #app_path::#t;
#(
#[allow(unused_imports)]
#user_imports
)*
pub struct SpawnHandle {
pub struct #internal_spawn_handle_ident {
#[doc(hidden)]
marker: u32,
}
impl SpawnHandle {
impl #internal_spawn_handle_ident {
pub fn cancel(self) -> Result<#ty, ()> {
rtic::export::interrupt::free(|_| unsafe {
let tq = &mut *#app_path::#tq.get_mut_unchecked().as_mut_ptr();
let tq = &mut *#tq.get_mut_unchecked().as_mut_ptr();
if let Some((_task, index)) = tq.cancel_marker(self.marker) {
// Get the message
let msg = #app_path::#inputs
let msg = #inputs
.get_unchecked()
.get_unchecked(usize::from(index))
.as_ptr()
.read();
// Return the index to the free queue
#app_path::#fq.get_mut_unchecked().split().0.enqueue_unchecked(index);
#fq.get_mut_unchecked().split().0.enqueue_unchecked(index);
Ok(msg)
} else {
@ -351,20 +353,20 @@ pub fn codegen(
#[inline]
pub fn reschedule_after<D>(self, duration: D) -> Result<Self, ()>
where D: rtic::time::duration::Duration + rtic::time::fixed_point::FixedPoint,
D::T: Into<<#app_path::#mono_type as rtic::time::Clock>::T>,
D::T: Into<<#mono_type as rtic::time::Clock>::T>,
{
self.reschedule_at(#app_path::monotonics::#m::now() + duration)
self.reschedule_at(monotonics::#m::now() + duration)
}
pub fn reschedule_at(self, instant: rtic::time::Instant<#app_path::#mono_type>) -> Result<Self, ()>
pub fn reschedule_at(self, instant: rtic::time::Instant<#mono_type>) -> Result<Self, ()>
{
rtic::export::interrupt::free(|_| unsafe {
let marker = *#tq_marker.get_mut_unchecked();
*#tq_marker.get_mut_unchecked() = #tq_marker.get_mut_unchecked().wrapping_add(1);
let tq = &mut *#app_path::#tq.get_mut_unchecked().as_mut_ptr();
let tq = &mut *#tq.get_mut_unchecked().as_mut_ptr();
tq.update_marker(self.marker, marker, instant, || #pend).map(|_| SpawnHandle { marker })
tq.update_marker(self.marker, marker, instant, || #pend).map(|_| #name::#m::SpawnHandle { marker })
})
}
}
@ -374,39 +376,39 @@ pub fn codegen(
///
/// This will use the time `Instant::new(0)` as baseline if called in `#[init]`,
/// so if you use a non-resetable timer use `spawn_at` when in `#[init]`
pub fn spawn_after<D>(
pub fn #internal_spawn_after_ident<D>(
duration: D
#(,#args)*
) -> Result<SpawnHandle, #ty>
) -> Result<#name::#m::SpawnHandle, #ty>
where D: rtic::time::duration::Duration + rtic::time::fixed_point::FixedPoint,
D::T: Into<<#app_path::#mono_type as rtic::time::Clock>::T>,
D::T: Into<<#mono_type as rtic::time::Clock>::T>,
{
let instant = if rtic::export::interrupt::free(|_| unsafe { #app_path::#m_ident.get_mut_unchecked().is_none() }) {
let instant = if rtic::export::interrupt::free(|_| unsafe { #m_ident.get_mut_unchecked().is_none() }) {
rtic::time::Instant::new(0)
} else {
#app_path::monotonics::#m::now()
monotonics::#m::now()
};
spawn_at(instant + duration #(,#untupled)*)
#internal_spawn_at_ident(instant + duration #(,#untupled)*)
}
#(#cfgs)*
/// Spawns the task at a fixed time instant
pub fn spawn_at(
instant: rtic::time::Instant<#app_path::#mono_type>
pub fn #internal_spawn_at_ident(
instant: rtic::time::Instant<#mono_type>
#(,#args)*
) -> Result<SpawnHandle, #ty> {
) -> Result<#name::#m::SpawnHandle, #ty> {
unsafe {
let input = #tupled;
if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.get_mut_unchecked().dequeue()) {
#app_path::#inputs
if let Some(index) = rtic::export::interrupt::free(|_| #fq.get_mut_unchecked().dequeue()) {
#inputs
.get_mut_unchecked()
.get_unchecked_mut(usize::from(index))
.as_mut_ptr()
.write(input);
#app_path::#instants
#instants
.get_mut_unchecked()
.get_unchecked_mut(usize::from(index))
.as_mut_ptr()
@ -417,44 +419,40 @@ pub fn codegen(
let nr = rtic::export::NotReady {
instant,
index,
task: #app_path::#t::#name,
task: #t::#name,
marker,
};
*#tq_marker.get_mut_unchecked() = #tq_marker.get_mut_unchecked().wrapping_add(1);
let tq = &mut *#app_path::#tq.get_mut_unchecked().as_mut_ptr();
let tq = &mut *#tq.get_mut_unchecked().as_mut_ptr();
tq.enqueue_unchecked(
nr,
|| #enable_interrupt,
|| #pend,
#app_path::#m_ident.get_mut_unchecked().as_mut());
#m_ident.get_mut_unchecked().as_mut());
Ok(SpawnHandle { marker })
Ok(#name::#m::SpawnHandle { marker })
})
} else {
Err(input)
}
}
}
}));
));
}
}
if !items.is_empty() {
let user_imports = &app.user_imports;
quote!(
#(#items)*
#[allow(non_snake_case)]
#(#task_cfgs)*
#[doc = #doc]
pub mod #name {
#(
#[allow(unused_imports)]
#user_imports
)*
#(#items)*
#(#module_items)*
}
)
} else {

View file

@ -93,8 +93,6 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
// Compile time assert that this priority is supported by the device
stmts.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];));
let app_name = &app.name;
let app_path = quote! {crate::#app_name};
let mono_type = &monotonic.ty;
if &*binds.to_string() == "SysTick" {
@ -121,7 +119,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
// Always enable monotonic interrupts if they should never be off
if !<#mono_type as rtic::Monotonic>::DISABLE_INTERRUPT_ON_EMPTY_QUEUE {
rtic::export::NVIC::unmask(#app_path::#rt_err::#interrupt::#binds);
rtic::export::NVIC::unmask(#rt_err::#interrupt::#binds);
}
));
}

View file

@ -57,8 +57,6 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
let mono_type = &monotonic.ty;
let m_ident = util::monotonic_ident(&monotonic_name);
let m_ident = util::mark_internal_ident(&m_ident);
let app_name = &app.name;
let app_path = quote! {crate::#app_name};
// Static variables and resource proxy
{
@ -139,7 +137,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
#[allow(non_snake_case)]
unsafe fn #bound_interrupt() {
while let Some((task, index)) = rtic::export::interrupt::free(|_|
if let Some(mono) = #app_path::#m_ident.get_mut_unchecked().as_mut() {
if let Some(mono) = #m_ident.get_mut_unchecked().as_mut() {
(&mut *#tq.get_mut_unchecked().as_mut_ptr()).dequeue(|| #disable_isr, mono)
} else {
// We can only use the timer queue if `init` has returned, and it
@ -152,7 +150,7 @@ pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStrea
}
}
rtic::export::interrupt::free(|_| if let Some(mono) = #app_path::#m_ident.get_mut_unchecked().as_mut() {
rtic::export::interrupt::free(|_| if let Some(mono) = #m_ident.get_mut_unchecked().as_mut() {
mono.on_interrupt();
});
}

View file

@ -111,6 +111,27 @@ pub fn is_exception(name: &Ident) -> bool {
)
}
/// Generate an internal identifier for monotonics
pub fn internal_monotonics_ident(task: &Ident, monotonic: &Ident, ident_name: &str) -> Ident {
Ident::new(
&format!(
"__rtic_internal_{}_{}_{}",
task.to_string(),
monotonic.to_string(),
ident_name,
),
Span::call_site(),
)
}
/// Generate an internal identifier for tasks
pub fn internal_task_ident(task: &Ident, ident_name: &str) -> Ident {
Ident::new(
&format!("__rtic_internal_{}_{}", task.to_string(), ident_name,),
Span::call_site(),
)
}
/// Mark an ident as internal
pub fn mark_internal_ident(ident: &Ident) -> Ident {
Ident::new(
@ -119,6 +140,14 @@ pub fn mark_internal_ident(ident: &Ident) -> Ident {
)
}
/// Mark an ident as internal
pub fn mark_internal_name(name: &str) -> Ident {
Ident::new(
&format!("__rtic_internal_{}", name),
Span::call_site(),
)
}
fn link_section_index() -> usize {
static INDEX: AtomicUsize = AtomicUsize::new(0);