More work

This commit is contained in:
Emil Fresk 2020-12-10 20:33:13 +01:00
parent b23bb1192c
commit 97a48983d2
10 changed files with 155 additions and 176 deletions

View file

@ -9,10 +9,10 @@ use rtic::app;
#[app(device = lm3s6965, dispatchers = [UART])] #[app(device = lm3s6965, dispatchers = [UART])]
mod app { mod app {
#[monotonic(binds = SomeISR1)] #[monotonic(binds = SomeISR1)]
type Mono1 = hal::Mono1; type MyMono1 = hal::Mono1;
#[monotonic(binds = SomeISR2)] #[monotonic(binds = SomeISR2, default = true)]
type Mono2 = hal::Mono2; type MyMono2 = hal::Mono2;
#[init] #[init]
fn init(cx: init::Context) -> (init::LateResources, init::Monotonics) { fn init(cx: init::Context) -> (init::LateResources, init::Monotonics) {

View file

@ -27,13 +27,13 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
let mut user = vec![]; let mut user = vec![];
// Generate the `main` function // Generate the `main` function
let assertion_stmts = assertions::codegen(analysis); let assertion_stmts = assertions::codegen(app, analysis);
let pre_init_stmts = pre_init::codegen(&app, analysis, extra); let pre_init_stmts = pre_init::codegen(app, analysis, extra);
let (mod_app_init, root_init, user_init, call_init) = init::codegen(app, analysis, extra); let (mod_app_init, root_init, user_init, call_init) = init::codegen(app, analysis, extra);
let post_init_stmts = post_init::codegen(&app, analysis); let post_init_stmts = post_init::codegen(app, analysis);
let (mod_app_idle, root_idle, user_idle, call_idle) = idle::codegen(app, analysis, extra); let (mod_app_idle, root_idle, user_idle, call_idle) = idle::codegen(app, analysis, extra);
@ -104,12 +104,20 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
)); ));
} }
let monotonic_imports: Vec<_> = app.monotonics.iter().map(|(_, monotonic)| {
let name = &monotonic.ident;
let ty = &monotonic.ty;
quote!(pub type #name = #ty;)
}).collect();
quote!( quote!(
/// Implementation details /// Implementation details
pub mod #name { pub mod #name {
/// Always include the device crate which contains the vector table /// Always include the device crate which contains the vector table
use #device as you_must_enable_the_rt_feature_for_the_pac_in_your_cargo_toml; use #device as you_must_enable_the_rt_feature_for_the_pac_in_your_cargo_toml;
#(#monotonic_imports)*
#(#user_imports)* #(#user_imports)*
/// User code from within the module /// User code from within the module

View file

@ -2,9 +2,10 @@ use proc_macro2::TokenStream as TokenStream2;
use quote::quote; use quote::quote;
use crate::analyze::Analysis; use crate::analyze::Analysis;
use rtic_syntax::ast::App;
/// Generates compile-time assertions that check that types implement the `Send` / `Sync` traits /// Generates compile-time assertions that check that types implement the `Send` / `Sync` traits
pub fn codegen(analysis: &Analysis) -> Vec<TokenStream2> { pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
let mut stmts = vec![]; let mut stmts = vec![];
for ty in &analysis.send_types { for ty in &analysis.send_types {
@ -15,5 +16,10 @@ pub fn codegen(analysis: &Analysis) -> Vec<TokenStream2> {
stmts.push(quote!(rtic::export::assert_sync::<#ty>();)); stmts.push(quote!(rtic::export::assert_sync::<#ty>();));
} }
for (_, monotonic) in &app.monotonics {
let ty = &monotonic.ty;
stmts.push(quote!(rtic::export::assert_monotonic::<#ty>();));
}
stmts stmts
} }

View file

@ -5,7 +5,7 @@ use rtic_syntax::ast::App;
use crate::{analyze::Analysis, check::Extra, codegen::util}; use crate::{analyze::Analysis, check::Extra, codegen::util};
/// Generates task dispatchers /// Generates task dispatchers
pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> { pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStream2> {
let mut items = vec![]; let mut items = vec![];
let interrupts = &analysis.interrupts; let interrupts = &analysis.interrupts;

View file

@ -5,7 +5,7 @@ use rtic_syntax::{ast::App, Context};
use crate::{ use crate::{
analyze::Analysis, analyze::Analysis,
check::Extra, check::Extra,
codegen::{locals, module, resources_struct, util}, codegen::{locals, module, resources_struct},
}; };
type CodegenResult = ( type CodegenResult = (
@ -32,50 +32,6 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> CodegenResult {
let mut root_init = vec![]; let mut root_init = vec![];
let late_fields = analysis
.late_resources
.iter()
.flat_map(|resources| {
resources.iter().map(|name| {
let ty = &app.late_resources[name].ty;
let cfgs = &app.late_resources[name].cfgs;
quote!(
#(#cfgs)*
pub #name: #ty
)
})
})
.collect::<Vec<_>>();
let late_resources = util::late_resources_ident(&name);
root_init.push(quote!(
/// Resources initialized at runtime
#[allow(non_snake_case)]
pub struct #late_resources {
#(#late_fields),*
}
));
let monotonic_types: Vec<_> = app
.monotonics
.iter()
.map(|(_, monotonic)| {
let mono = &monotonic.ty;
quote! {#mono}
})
.collect();
let monotonics = util::monotonics_ident(&name);
root_init.push(quote!(
/// Monotonics used by the system
#[allow(non_snake_case)]
pub struct #monotonics(
#(#monotonic_types),*
);
));
let mut locals_pat = None; let mut locals_pat = None;
let mut locals_new = None; let mut locals_new = None;
if !init.locals.is_empty() { if !init.locals.is_empty() {
@ -91,15 +47,12 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> CodegenResult {
let stmts = &init.stmts; let stmts = &init.stmts;
let locals_pat = locals_pat.iter(); let locals_pat = locals_pat.iter();
let mut user_init_return = vec![quote! {#name::LateResources}]; let user_init_return = quote! {#name::LateResources, #name::Monotonics};
if !app.monotonics.is_empty() {
user_init_return.push(quote! {#name::Monotonics});
}
let user_init = Some(quote!( let user_init = Some(quote!(
#(#attrs)* #(#attrs)*
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn #name(#(#locals_pat,)* #context: #name::Context) -> (#(#user_init_return,)*) { fn #name(#(#locals_pat,)* #context: #name::Context) -> (#user_init_return) {
#(#stmts)* #(#stmts)*
} }
)); ));

View file

@ -19,29 +19,13 @@ pub fn codegen(
let name = ctxt.ident(app); let name = ctxt.ident(app);
let mut needs_instant = false;
let mut lt = None; let mut lt = None;
match ctxt { match ctxt {
Context::Init => { Context::Init => {
// TODO: What fields are needed? fields.push(quote!(
// if let Some(m) = &extra.monotonic { /// Core (Cortex-M) peripherals
// fields.push(quote!( pub core: rtic::export::Peripherals
// /// System start time = `Instant(0 /* cycles */)` ));
// pub start: <#m as rtic::Monotonic>::Instant
// ));
// values.push(quote!(start: <#m as rtic::Monotonic>::zero()));
// fields.push(quote!(
// /// Core (Cortex-M) peripherals minus the SysTick
// pub core: rtic::Peripherals
// ));
// } else {
// fields.push(quote!(
// /// Core (Cortex-M) peripherals
// pub core: rtic::export::Peripherals
// ));
// }
if extra.peripherals { if extra.peripherals {
let device = &extra.device; let device = &extra.device;
@ -68,31 +52,11 @@ pub fn codegen(
Context::Idle => {} Context::Idle => {}
Context::HardwareTask(..) => { Context::HardwareTask(..) => {
// TODO: What fields are needed for monotonic? // None for now.
// if let Some(m) = &extra.monotonic {
// fields.push(quote!(
// /// Time at which this handler started executing
// pub start: <#m as rtic::Monotonic>::Instant
// ));
// values.push(quote!(start: instant));
// needs_instant = true;
// }
} }
Context::SoftwareTask(..) => { Context::SoftwareTask(..) => {
// TODO: What fields are needed for monotonic? // None for now.
// if let Some(m) = &extra.monotonic {
// fields.push(quote!(
// /// The time at which this task was scheduled to run
// pub scheduled: <#m as rtic::Monotonic>::Instant
// ));
// values.push(quote!(scheduled: instant));
// needs_instant = true;
// }
} }
} }
@ -132,18 +96,45 @@ pub fn codegen(
} }
if let Context::Init = ctxt { if let Context::Init = ctxt {
let init = &app.inits.first().unwrap(); let late_fields = analysis
let late_resources = util::late_resources_ident(&init.name); .late_resources
let monotonics = util::monotonics_ident(&init.name); .iter()
.flat_map(|resources| {
resources.iter().map(|name| {
let ty = &app.late_resources[name].ty;
let cfgs = &app.late_resources[name].cfgs;
quote!(
#(#cfgs)*
pub #name: #ty
)
})
})
.collect::<Vec<_>>();
items.push(quote!( items.push(quote!(
#[doc(inline)] /// Resources initialized at runtime
pub use super::#late_resources as LateResources; #[allow(non_snake_case)]
pub struct LateResources {
#(#late_fields),*
}
)); ));
let monotonic_types: Vec<_> = app
.monotonics
.iter()
.map(|(_, monotonic)| {
let mono = &monotonic.ident;
quote! {#mono}
})
.collect();
items.push(quote!( items.push(quote!(
#[doc(inline)] /// Monotonics used by the system
pub use super::#monotonics as Monotonics; #[allow(non_snake_case)]
pub struct Monotonics(
#(#monotonic_types),*
);
)); ));
} }
@ -166,16 +157,6 @@ pub fn codegen(
Some(quote!(priority: &#lt rtic::export::Priority)) Some(quote!(priority: &#lt rtic::export::Priority))
}; };
// TODO: What is needed for the new monotonic?
// let instant = if needs_instant {
// let m = extra.monotonic.clone().expect("RTIC-ICE: UNREACHABLE");
// Some(quote!(, instant: <#m as rtic::Monotonic>::Instant))
// } else {
// None
// };
let instant = quote!();
items.push(quote!( items.push(quote!(
/// Execution context /// Execution context
pub struct Context<#lt> { pub struct Context<#lt> {
@ -184,7 +165,7 @@ pub fn codegen(
impl<#lt> Context<#lt> { impl<#lt> Context<#lt> {
#[inline(always)] #[inline(always)]
pub unsafe fn new(#core #priority #instant) -> Self { pub unsafe fn new(#core #priority) -> Self {
Context { Context {
#(#values,)* #(#values,)*
} }
@ -202,7 +183,7 @@ pub fn codegen(
let cfgs = &spawnee.cfgs; let cfgs = &spawnee.cfgs;
// Store a copy of the task cfgs // Store a copy of the task cfgs
task_cfgs = cfgs.clone(); task_cfgs = cfgs.clone();
let (args, tupled, _untupled, ty) = util::regroup_inputs(&spawnee.inputs); let (args, tupled, untupled, ty) = util::regroup_inputs(&spawnee.inputs);
let args = &args; let args = &args;
let tupled = &tupled; let tupled = &tupled;
let fq = util::fq_ident(name); let fq = util::fq_ident(name);
@ -251,51 +232,70 @@ pub fn codegen(
})); }));
// TODO: Needs updating for new monotonic. // Schedule caller
// // Schedule caller for (_, monotonic) in &app.monotonics {
// if let Some(m) = &extra.monotonic { let instants = util::instants_ident(name);
// let instants = util::instants_ident(name);
// let tq = util::tq_ident(); let tq = util::tq_ident(&monotonic.ident.to_string());
// let t = util::schedule_t_ident(); let t = util::schedule_t_ident();
let m = &monotonic.ident;
// items.push(quote!( if monotonic.args.default {
// #(#cfgs)* items.push(quote!(pub use #m::spawn_after;));
// pub fn schedule( items.push(quote!(pub use #m::spawn_at;));
// instant: <#m as rtic::Monotonic>::Instant }
// #(,#args)*
// ) -> Result<(), #ty> {
// unsafe {
// use rtic::Mutex as _;
// use rtic::mutex_prelude::*;
// let input = #tupled; items.push(quote!(
// if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.dequeue()) { pub mod #m {
// #app_path::#inputs #(#cfgs)*
// .get_unchecked_mut(usize::from(index)) pub fn spawn_after(
// .as_mut_ptr() duration: rtic::Duration,
// .write(input); #(,#args)*
) -> Result<(), #ty> {
let instant = <#app_path::#m as rtic::Monotonic>::now();
// #app_path::#instants spawn_at(instant + duration, #(,#untupled)*)
// .get_unchecked_mut(usize::from(index)) }
// .as_mut_ptr()
// .write(instant);
// let nr = rtic::export::NotReady { #(#cfgs)*
// instant, pub fn spawn_at(
// index, instant: Instant<#app_path::#m as rtic::Monotonic>
// task: #app_path::#t::#name, #(,#args)*
// }; ) -> Result<(), #ty> {
unsafe {
use rtic::Mutex as _;
use rtic::mutex_prelude::*;
// rtic::export::interrupt::free(|_| #app_path::#tq.enqueue_unchecked(nr)); let input = #tupled;
if let Some(index) = rtic::export::interrupt::free(|_| #app_path::#fq.dequeue()) {
#app_path::#inputs
.get_unchecked_mut(usize::from(index))
.as_mut_ptr()
.write(input);
// Ok(()) #app_path::#instants
// } else { .get_unchecked_mut(usize::from(index))
// Err(input) .as_mut_ptr()
// } .write(instant);
// }
// })); let nr = rtic::export::NotReady {
// } instant,
index,
task: #app_path::#t::#name,
};
rtic::export::interrupt::free(|_| #app_path::#tq.enqueue_unchecked(nr));
// TODO: After adding the scheduled task, check and setup the timer.
Ok(())
} else {
Err(input)
}
}
}
}));
}
} }
if !items.is_empty() { if !items.is_empty() {

View file

@ -74,25 +74,26 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
);)); );));
} }
// TODO: Update for noew monotonic // Initialize monotonic's interrupts
// // Initialize the SysTick if there exist a TimerQueue for (priority, name) in app
// if extra.monotonic.is_some() { .monotonics
// let priority = analysis.channels.keys().max().unwrap(); .iter()
.map(|(_, monotonic)| (&monotonic.args.priority, &monotonic.args.binds))
{
// Compile time assert that this priority is supported by the device
stmts.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];));
// // Compile time assert that this priority is supported by the device // NOTE this also checks that the interrupt exists in the `Interrupt` enumeration
// stmts.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];)); let interrupt = util::interrupt_ident();
stmts.push(quote!(
core.NVIC.set_priority(
you_must_enable_the_rt_feature_for_the_pac_in_your_cargo_toml::#interrupt::#name,
rtic::export::logical2hw(#priority, #nvic_prio_bits),
);
));
// stmts.push(quote!(core.SCB.set_priority( // NOTE we do not unmask the interrupt as this is part of the monotonic to keep track of
// rtic::export::SystemHandler::SysTick, }
// rtic::export::logical2hw(#priority, #nvic_prio_bits),
// );));
// stmts.push(quote!(
// core.SYST.set_clock_source(rtic::export::SystClkSource::Core);
// core.SYST.enable_counter();
// core.DCB.enable_trace();
// ));
// }
// If there's no user `#[idle]` then optimize returning from interrupt handlers // If there's no user `#[idle]` then optimize returning from interrupt handlers
if app.idles.is_empty() { if app.idles.is_empty() {

View file

@ -5,7 +5,7 @@ use rtic_syntax::ast::App;
use crate::{analyze::Analysis, check::Extra, codegen::util}; use crate::{analyze::Analysis, check::Extra, codegen::util};
/// Generates timer queues and timer queue handlers /// Generates timer queues and timer queue handlers
pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> { pub fn codegen(app: &App, analysis: &Analysis, _extra: &Extra) -> Vec<TokenStream2> {
let mut items = vec![]; let mut items = vec![];
if !app.monotonics.is_empty() { if !app.monotonics.is_empty() {

View file

@ -16,6 +16,7 @@ pub use cortex_m::{
use heapless::spsc::SingleCore; use heapless::spsc::SingleCore;
pub use heapless::{consts, i::Queue as iQueue, spsc::Queue}; pub use heapless::{consts, i::Queue as iQueue, spsc::Queue};
pub use heapless::{i::BinaryHeap as iBinaryHeap, BinaryHeap}; pub use heapless::{i::BinaryHeap as iBinaryHeap, BinaryHeap};
pub use rtic_core::monotonic::Monotonic;
pub type SCFQ<N> = Queue<u8, N, u8, SingleCore>; pub type SCFQ<N> = Queue<u8, N, u8, SingleCore>;
pub type SCRQ<T, N> = Queue<(T, u8), N, u8, SingleCore>; pub type SCRQ<T, N> = Queue<(T, u8), N, u8, SingleCore>;
@ -112,6 +113,13 @@ where
{ {
} }
#[inline(always)]
pub fn assert_monotonic<T>()
where
T: Monotonic,
{
}
/// Lock the resource proxy by setting the BASEPRI /// Lock the resource proxy by setting the BASEPRI
/// and running the closure with interrupt::free /// and running the closure with interrupt::free
/// ///

View file

@ -39,7 +39,10 @@ use core::ops::Sub;
use cortex_m::{interrupt::Nr, peripheral::NVIC}; use cortex_m::{interrupt::Nr, peripheral::NVIC};
pub use cortex_m_rtic_macros::app; pub use cortex_m_rtic_macros::app;
pub use rtic_core::{prelude as mutex_prelude, Exclusive, monotonic::Monotonic, Mutex}; pub use rtic_core::{
monotonic::{Clock, Instant, Monotonic},
prelude as mutex_prelude, Exclusive, Mutex,
};
#[doc(hidden)] #[doc(hidden)]
pub mod export; pub mod export;