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])]
mod app {
#[monotonic(binds = SomeISR1)]
type Mono1 = hal::Mono1;
type MyMono1 = hal::Mono1;
#[monotonic(binds = SomeISR2)]
type Mono2 = hal::Mono2;
#[monotonic(binds = SomeISR2, default = true)]
type MyMono2 = hal::Mono2;
#[init]
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![];
// 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 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);
@ -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!(
/// Implementation details
pub mod #name {
/// 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;
#(#monotonic_imports)*
#(#user_imports)*
/// User code from within the module

View file

@ -2,9 +2,10 @@ use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use crate::analyze::Analysis;
use rtic_syntax::ast::App;
/// 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![];
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>();));
}
for (_, monotonic) in &app.monotonics {
let ty = &monotonic.ty;
stmts.push(quote!(rtic::export::assert_monotonic::<#ty>();));
}
stmts
}

View file

@ -5,7 +5,7 @@ use rtic_syntax::ast::App;
use crate::{analyze::Analysis, check::Extra, codegen::util};
/// 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 interrupts = &analysis.interrupts;

View file

@ -5,7 +5,7 @@ use rtic_syntax::{ast::App, Context};
use crate::{
analyze::Analysis,
check::Extra,
codegen::{locals, module, resources_struct, util},
codegen::{locals, module, resources_struct},
};
type CodegenResult = (
@ -32,50 +32,6 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> CodegenResult {
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_new = None;
if !init.locals.is_empty() {
@ -91,15 +47,12 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> CodegenResult {
let stmts = &init.stmts;
let locals_pat = locals_pat.iter();
let mut user_init_return = vec![quote! {#name::LateResources}];
if !app.monotonics.is_empty() {
user_init_return.push(quote! {#name::Monotonics});
}
let user_init_return = quote! {#name::LateResources, #name::Monotonics};
let user_init = Some(quote!(
#(#attrs)*
#[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)*
}
));

View file

@ -19,29 +19,13 @@ pub fn codegen(
let name = ctxt.ident(app);
let mut needs_instant = false;
let mut lt = None;
match ctxt {
Context::Init => {
// TODO: What fields are needed?
// if let Some(m) = &extra.monotonic {
// fields.push(quote!(
// /// 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
// ));
// }
fields.push(quote!(
/// Core (Cortex-M) peripherals
pub core: rtic::export::Peripherals
));
if extra.peripherals {
let device = &extra.device;
@ -68,31 +52,11 @@ pub fn codegen(
Context::Idle => {}
Context::HardwareTask(..) => {
// TODO: What fields are needed for monotonic?
// 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;
// }
// None for now.
}
Context::SoftwareTask(..) => {
// TODO: What fields are needed for monotonic?
// 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;
// }
// None for now.
}
}
@ -132,18 +96,45 @@ pub fn codegen(
}
if let Context::Init = ctxt {
let init = &app.inits.first().unwrap();
let late_resources = util::late_resources_ident(&init.name);
let monotonics = util::monotonics_ident(&init.name);
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<_>>();
items.push(quote!(
#[doc(inline)]
pub use super::#late_resources as LateResources;
/// Resources initialized at runtime
#[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!(
#[doc(inline)]
pub use super::#monotonics as Monotonics;
/// Monotonics used by the system
#[allow(non_snake_case)]
pub struct Monotonics(
#(#monotonic_types),*
);
));
}
@ -166,16 +157,6 @@ pub fn codegen(
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!(
/// Execution context
pub struct Context<#lt> {
@ -184,7 +165,7 @@ pub fn codegen(
impl<#lt> Context<#lt> {
#[inline(always)]
pub unsafe fn new(#core #priority #instant) -> Self {
pub unsafe fn new(#core #priority) -> Self {
Context {
#(#values,)*
}
@ -202,7 +183,7 @@ pub fn codegen(
let cfgs = &spawnee.cfgs;
// Store a copy of the task cfgs
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 tupled = &tupled;
let fq = util::fq_ident(name);
@ -251,51 +232,70 @@ pub fn codegen(
}));
// TODO: Needs updating for new monotonic.
// // Schedule caller
// if let Some(m) = &extra.monotonic {
// let instants = util::instants_ident(name);
// Schedule caller
for (_, monotonic) in &app.monotonics {
let instants = util::instants_ident(name);
// let tq = util::tq_ident();
// let t = util::schedule_t_ident();
let tq = util::tq_ident(&monotonic.ident.to_string());
let t = util::schedule_t_ident();
let m = &monotonic.ident;
// items.push(quote!(
// #(#cfgs)*
// pub fn schedule(
// instant: <#m as rtic::Monotonic>::Instant
// #(,#args)*
// ) -> Result<(), #ty> {
// unsafe {
// use rtic::Mutex as _;
// use rtic::mutex_prelude::*;
if monotonic.args.default {
items.push(quote!(pub use #m::spawn_after;));
items.push(quote!(pub use #m::spawn_at;));
}
// 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);
items.push(quote!(
pub mod #m {
#(#cfgs)*
pub fn spawn_after(
duration: rtic::Duration,
#(,#args)*
) -> Result<(), #ty> {
let instant = <#app_path::#m as rtic::Monotonic>::now();
// #app_path::#instants
// .get_unchecked_mut(usize::from(index))
// .as_mut_ptr()
// .write(instant);
spawn_at(instant + duration, #(,#untupled)*)
}
// let nr = rtic::export::NotReady {
// instant,
// index,
// task: #app_path::#t::#name,
// };
#(#cfgs)*
pub fn spawn_at(
instant: Instant<#app_path::#m as rtic::Monotonic>
#(,#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(())
// } else {
// Err(input)
// }
// }
// }));
// }
#app_path::#instants
.get_unchecked_mut(usize::from(index))
.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() {

View file

@ -74,25 +74,26 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
);));
}
// TODO: Update for noew monotonic
// // Initialize the SysTick if there exist a TimerQueue
// if extra.monotonic.is_some() {
// let priority = analysis.channels.keys().max().unwrap();
// Initialize monotonic's interrupts
for (priority, name) in app
.monotonics
.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
// stmts.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];));
// NOTE this also checks that the interrupt exists in the `Interrupt` enumeration
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(
// 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();
// ));
// }
// NOTE we do not unmask the interrupt as this is part of the monotonic to keep track of
}
// If there's no user `#[idle]` then optimize returning from interrupt handlers
if app.idles.is_empty() {

View file

@ -5,7 +5,7 @@ use rtic_syntax::ast::App;
use crate::{analyze::Analysis, check::Extra, codegen::util};
/// 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![];
if !app.monotonics.is_empty() {

View file

@ -16,6 +16,7 @@ pub use cortex_m::{
use heapless::spsc::SingleCore;
pub use heapless::{consts, i::Queue as iQueue, spsc::Queue};
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 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
/// and running the closure with interrupt::free
///

View file

@ -39,7 +39,10 @@ use core::ops::Sub;
use cortex_m::{interrupt::Nr, peripheral::NVIC};
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)]
pub mod export;