move dispatchers to app argument

This commit is contained in:
Per Lindgren 2020-10-23 10:35:56 +02:00
parent 86699039e9
commit 1c244a995d
37 changed files with 124 additions and 287 deletions

View file

@ -5,6 +5,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased] ## [Unreleased]
- Move dispatchers from extern block to app argument.
## [v0.5.5] - 2020-08-27 ## [v0.5.5] - 2020-08-27
- Includes the previous soundness fix. - Includes the previous soundness fix.

View file

@ -6,6 +6,37 @@ This section describes how to upgrade from v0.5.x to v0.6.0 of the RTIC framewor
Change the version of `cortex-m-rtic` to `"0.6.0"`. Change the version of `cortex-m-rtic` to `"0.6.0"`.
## Move Dispatchers from `extern "C"` to app arguments.
Change
``` rust
#[rtic::app(/* .. */)]
const APP: () = {
[code here]
// RTIC requires that unused interrupts are declared in an extern block when
// using software tasks; these free interrupts will be used to dispatch the
// software tasks.
extern "C" {
fn SSI0();
fn QEI0();
}
};
```
into
``` rust
#[rtic::app(/* .. */, dispatchers = [SSI0, QEI0])]
mod app {
[code here]
}
```
This works also for ram functions, see examples/ramfunc.rs
## Module instead of Const ## Module instead of Const
With the support of attributes on modules the `const APP` workaround is not needed. With the support of attributes on modules the `const APP` workaround is not needed.

View file

@ -8,7 +8,7 @@
use panic_semihosting as _; use panic_semihosting as _;
// NOTE: does NOT properly work on QEMU // NOTE: does NOT properly work on QEMU
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] #[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT, dispatchers = [SSI0])]
mod app { mod app {
use cortex_m_semihosting::{debug, hprintln}; use cortex_m_semihosting::{debug, hprintln};
use lm3s6965::Interrupt; use lm3s6965::Interrupt;
@ -47,11 +47,4 @@ mod app {
// `foo` inherits the baseline of `UART0`: its `start` time // `foo` inherits the baseline of `UART0`: its `start` time
foo::spawn().unwrap(); foo::spawn().unwrap();
} }
// RTIC requires that unused interrupts are declared in an extern block when
// using software tasks; these free interrupts will be used to dispatch the
// software tasks.
extern "C" {
fn SSI0();
}
} }

View file

@ -7,7 +7,7 @@
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965, dispatchers = [SSI0])]
mod app { mod app {
use cortex_m_semihosting::{debug, hprintln}; use cortex_m_semihosting::{debug, hprintln};
use lm3s6965::Interrupt; use lm3s6965::Interrupt;
@ -40,11 +40,4 @@ mod app {
debug::exit(debug::EXIT_SUCCESS); debug::exit(debug::EXIT_SUCCESS);
} }
// RTIC requires that unused interrupts are declared in an extern block when
// using software tasks; these free interrupts will be used to dispatch the
// software tasks.
extern "C" {
fn SSI0();
}
} }

View file

@ -7,7 +7,7 @@
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965, dispatchers = [SSI0, QEI0])]
mod app { mod app {
use cortex_m_semihosting::debug; use cortex_m_semihosting::debug;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@ -83,12 +83,4 @@ mod app {
) )
.ok(); .ok();
} }
// RTIC requires that unused interrupts are declared in an extern block when
// using software tasks; these free interrupts will be used to dispatch the
// software tasks.
extern "C" {
fn SSI0();
fn QEI0();
}
} }

View file

@ -7,7 +7,7 @@
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965, dispatchers = [SSI0, QEI0])]
mod app { mod app {
use cortex_m_semihosting::debug; use cortex_m_semihosting::debug;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@ -62,12 +62,4 @@ mod app {
) )
.ok(); .ok();
} }
// RTIC requires that unused interrupts are declared in an extern block when
// using software tasks; these free interrupts will be used to dispatch the
// software tasks.
extern "C" {
fn SSI0();
fn QEI0();
}
} }

View file

@ -7,7 +7,7 @@
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] #[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT, dispatchers = [SSI0])]
mod app { mod app {
use rtic::cyccnt::U32Ext; use rtic::cyccnt::U32Ext;
@ -32,8 +32,4 @@ mod app {
fn task2(_cx: task2::Context) { fn task2(_cx: task2::Context) {
task1::schedule(_cx.scheduled + 100.cycles()).ok(); task1::schedule(_cx.scheduled + 100.cycles()).ok();
} }
extern "C" {
fn SSI0();
}
} }

View file

@ -7,7 +7,7 @@
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965, dispatchers = [SSI0])]
mod app { mod app {
use cortex_m_semihosting::{debug, hprintln}; use cortex_m_semihosting::{debug, hprintln};
@ -45,11 +45,4 @@ mod app {
foo::spawn().unwrap(); foo::spawn().unwrap();
} }
// RTIC requires that unused interrupts are declared in an extern block when
// using software tasks; these free interrupts will be used to dispatch the
// software tasks.
extern "C" {
fn SSI0();
}
} }

View file

@ -12,7 +12,7 @@ pub struct NotSync {
_0: PhantomData<*const ()>, _0: PhantomData<*const ()>,
} }
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965, dispatchers = [SSI0])]
mod app { mod app {
use super::NotSync; use super::NotSync;
use core::marker::PhantomData; use core::marker::PhantomData;
@ -40,11 +40,4 @@ mod app {
fn bar(c: bar::Context) { fn bar(c: bar::Context) {
let _: &NotSync = c.resources.shared; let _: &NotSync = c.resources.shared;
} }
// RTIC requires that unused interrupts are declared in an extern block when
// using software tasks; these free interrupts will be used to dispatch the
// software tasks.
extern "C" {
fn SSI0();
}
} }

View file

@ -8,7 +8,7 @@
use panic_semihosting as _; use panic_semihosting as _;
// NOTE: does NOT work on QEMU! // NOTE: does NOT work on QEMU!
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] #[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT, dispatchers = [SSI0])]
mod app { mod app {
use cortex_m_semihosting::hprintln; use cortex_m_semihosting::hprintln;
use rtic::cyccnt::{Instant, U32Ext}; use rtic::cyccnt::{Instant, U32Ext};
@ -31,11 +31,4 @@ mod app {
foo::schedule(cx.scheduled + PERIOD.cycles()).unwrap(); foo::schedule(cx.scheduled + PERIOD.cycles()).unwrap();
} }
// RTIC requires that unused interrupts are declared in an extern block when
// using software tasks; these free interrupts will be used to dispatch the
// software tasks.
extern "C" {
fn SSI0();
}
} }

View file

@ -15,7 +15,7 @@ use rtic::app;
// Declare a pool of 128-byte memory blocks // Declare a pool of 128-byte memory blocks
pool!(P: [u8; 128]); pool!(P: [u8; 128]);
#[app(device = lm3s6965)] #[app(device = lm3s6965, dispatchers = [SSI0, QEI0])]
mod app { mod app {
use crate::{Box, Pool}; use crate::{Box, Pool};
use cortex_m_semihosting::{debug, hprintln}; use cortex_m_semihosting::{debug, hprintln};
@ -65,12 +65,4 @@ mod app {
// this is done automatically so we can omit the call to `drop` // this is done automatically so we can omit the call to `drop`
// drop(x); // drop(x);
} }
// RTIC requires that unused interrupts are declared in an extern block when
// using software tasks; these free interrupts will be used to dispatch the
// software tasks.
extern "C" {
fn SSI0();
fn QEI0();
}
} }

View file

@ -7,7 +7,14 @@
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(
device = lm3s6965,
dispatchers = [
UART0,
#[link_section = ".data.UART1"]
UART1
])
]
mod app { mod app {
use cortex_m_semihosting::{debug, hprintln}; use cortex_m_semihosting::{debug, hprintln};
@ -33,12 +40,4 @@ mod app {
fn bar(_: bar::Context) { fn bar(_: bar::Context) {
foo::spawn().unwrap(); foo::spawn().unwrap();
} }
extern "C" {
fn UART0();
// run the task dispatcher from RAM
#[link_section = ".data.UART1"]
fn UART1();
}
} }

View file

@ -8,7 +8,7 @@
use panic_halt as _; use panic_halt as _;
// NOTE: does NOT work on QEMU! // NOTE: does NOT work on QEMU!
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] #[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT, dispatchers = [SSI0])]
mod app { mod app {
use cortex_m::peripheral::DWT; use cortex_m::peripheral::DWT;
use cortex_m_semihosting::hprintln; use cortex_m_semihosting::hprintln;
@ -46,11 +46,4 @@ mod app {
fn bar(_: bar::Context) { fn bar(_: bar::Context) {
hprintln!("bar @ {:?}", Instant::now()).unwrap(); hprintln!("bar @ {:?}", Instant::now()).unwrap();
} }
// RTIC requires that unused interrupts are declared in an extern block when
// using software tasks; these free interrupts will be used to dispatch the
// software tasks.
extern "C" {
fn SSI0();
}
} }

View file

@ -7,7 +7,7 @@
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965, dispatchers = [SSI0])]
mod app { mod app {
use cortex_m_semihosting::{debug, hprintln}; use cortex_m_semihosting::{debug, hprintln};
@ -26,11 +26,4 @@ mod app {
} }
foo::spawn(2, 3).unwrap(); foo::spawn(2, 3).unwrap();
} }
// RTIC requires that unused interrupts are declared in an extern block when
// using software tasks; these free interrupts will be used to dispatch the
// software tasks.
extern "C" {
fn SSI0();
}
} }

View file

@ -7,7 +7,7 @@
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965, dispatchers = [SSI0])]
mod app { mod app {
use cortex_m_semihosting::{debug, hprintln}; use cortex_m_semihosting::{debug, hprintln};
@ -32,11 +32,4 @@ mod app {
hprintln!("foo2 {}", x).unwrap(); hprintln!("foo2 {}", x).unwrap();
foo::spawn(x, 0).unwrap(); foo::spawn(x, 0).unwrap();
} }
// RTIC requires that unused interrupts are declared in an extern block when
// using software tasks; these free interrupts will be used to dispatch the
// software tasks.
extern "C" {
fn SSI0();
}
} }

View file

@ -5,7 +5,7 @@
use panic_halt as _; use panic_halt as _;
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] #[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT, dispatchers = [SSI0, QEI0])]
mod app { mod app {
#[resources] #[resources]
struct Resources { struct Resources {
@ -47,12 +47,4 @@ mod app {
#[cfg(never)] #[cfg(never)]
#[task] #[task]
fn quux(_: quux::Context) {} fn quux(_: quux::Context) {}
// RTIC requires that unused interrupts are declared in an extern block when
// using software tasks; these free interrupts will be used to dispatch the
// software tasks.
extern "C" {
fn SSI0();
fn QEI0();
}
} }

View file

@ -7,7 +7,7 @@
use panic_halt as _; use panic_halt as _;
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] #[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT, dispatchers = [SSI0])]
mod app { mod app {
#[init] #[init]
fn init(c: init::Context) -> init::LateResources { fn init(c: init::Context) -> init::LateResources {
@ -18,11 +18,4 @@ mod app {
#[task] #[task]
fn some_task(_: some_task::Context) {} fn some_task(_: some_task::Context) {}
// RTIC requires that unused interrupts are declared in an extern block when
// using software tasks; these free interrupts will be used to dispatch the
// software tasks.
extern "C" {
fn SSI0();
}
} }

View file

@ -7,7 +7,7 @@
use panic_halt as _; use panic_halt as _;
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)] #[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT, dispatchers = [SSI0])]
mod app { mod app {
use rtic::cyccnt::{Instant, U32Ext as _}; use rtic::cyccnt::{Instant, U32Ext as _};
@ -57,11 +57,4 @@ mod app {
#[task] #[task]
fn baz(_: baz::Context, _x: u32, _y: u32) {} fn baz(_: baz::Context, _x: u32, _y: u32) {}
// RTIC requires that unused interrupts are declared in an extern block when
// using software tasks; these free interrupts will be used to dispatch the
// software tasks.
extern "C" {
fn SSI0();
}
} }

View file

@ -7,7 +7,7 @@
use panic_halt as _; use panic_halt as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965, dispatchers = [SSI0])]
mod app { mod app {
#[init] #[init]
fn init(_: init::Context) -> init::LateResources { fn init(_: init::Context) -> init::LateResources {
@ -55,11 +55,4 @@ mod app {
#[task] #[task]
fn baz(_: baz::Context, _x: u32, _y: u32) {} fn baz(_: baz::Context, _x: u32, _y: u32) {}
// RTIC requires that unused interrupts are declared in an extern block when
// using software tasks; these free interrupts will be used to dispatch the
// software tasks.
extern "C" {
fn SSI0();
}
} }

View file

@ -5,7 +5,7 @@
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965, dispatchers = [SSI0])]
mod app { mod app {
use cortex_m_semihosting::debug; use cortex_m_semihosting::debug;
@ -20,11 +20,4 @@ mod app {
fn taskmain(_: taskmain::Context) { fn taskmain(_: taskmain::Context) {
debug::exit(debug::EXIT_SUCCESS); debug::exit(debug::EXIT_SUCCESS);
} }
// RTIC requires that unused interrupts are declared in an extern block when
// using software tasks; these free interrupts will be used to dispatch the
// software tasks.
extern "C" {
fn SSI0();
}
} }

View file

@ -7,7 +7,7 @@
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965, dispatchers = [SSI0, QEI0])]
mod app { mod app {
use cortex_m_semihosting::{debug, hprintln}; use cortex_m_semihosting::{debug, hprintln};
@ -47,12 +47,4 @@ mod app {
fn baz(_: baz::Context) { fn baz(_: baz::Context) {
hprintln!("baz").unwrap(); hprintln!("baz").unwrap();
} }
// RTIC requires that unused interrupts are declared in an extern block when
// using software tasks; these free interrupts will be used to dispatch the
// software tasks.
extern "C" {
fn SSI0();
fn QEI0();
}
} }

View file

@ -7,7 +7,7 @@
use panic_semihosting as _; use panic_semihosting as _;
#[rtic::app(device = lm3s6965, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)] #[rtic::app(device = lm3s6965, peripherals = true, monotonic = rtic::cyccnt::CYCCNT, dispatchers = [SSI0])]
mod app { mod app {
use cortex_m_semihosting::debug; use cortex_m_semihosting::debug;
use rtic::cyccnt; use rtic::cyccnt;
@ -48,11 +48,4 @@ mod app {
let _: &mut u32 = cx.resources.shared; let _: &mut u32 = cx.resources.shared;
let _: foo::Resources = cx.resources; let _: foo::Resources = cx.resources;
} }
// RTIC requires that unused interrupts are declared in an extern block when
// using software tasks; these free interrupts will be used to dispatch the
// software tasks.
extern "C" {
fn SSI0();
}
} }

View file

@ -3,7 +3,7 @@ use std::collections::{BTreeMap, BTreeSet};
use rtic_syntax::{ use rtic_syntax::{
analyze::{self, Priority}, analyze::{self, Priority},
ast::App, ast::{App, ExternInterrupt},
P, P,
}; };
use syn::Ident; use syn::Ident;
@ -11,7 +11,7 @@ use syn::Ident;
/// Extend the upstream `Analysis` struct with our field /// Extend the upstream `Analysis` struct with our field
pub struct Analysis { pub struct Analysis {
parent: P<analyze::Analysis>, parent: P<analyze::Analysis>,
pub interrupts: BTreeMap<Priority, Ident>, pub interrupts: BTreeMap<Priority, (Ident, ExternInterrupt)>,
} }
impl ops::Deref for Analysis { impl ops::Deref for Analysis {
@ -22,23 +22,23 @@ impl ops::Deref for Analysis {
} }
} }
// Assign an `extern` interrupt to each priority level // Assign an interrupt to each priority level
pub fn app(analysis: P<analyze::Analysis>, app: &App) -> P<Analysis> { pub fn app(analysis: P<analyze::Analysis>, app: &App) -> P<Analysis> {
let mut interrupts = BTreeMap::new(); // the set of priorities (each priority only once)
let priorities = app let priorities = app
.software_tasks .software_tasks
.values() .values()
.map(|task| task.args.priority) .map(|task| task.args.priority)
.collect::<BTreeSet<_>>(); .collect::<BTreeSet<_>>();
if !priorities.is_empty() { // map from priorities to interrupts (holding name and attributes)
interrupts = priorities let interrupts: BTreeMap<Priority, _> = priorities
.iter() .iter()
.cloned() .cloned()
.rev() .rev()
.zip(app.extern_interrupts.keys().cloned()) .zip(&app.args.extern_interrupts)
.collect(); .map(|(p, (id, ext))| (p, (id.clone(), ext.clone())))
} .collect();
P::new(Analysis { P::new(Analysis {
parent: analysis, parent: analysis,

View file

@ -1,28 +1,19 @@
use std::collections::HashSet; use std::collections::HashSet;
use proc_macro2::Span; use proc_macro2::Span;
use rtic_syntax::{ use rtic_syntax::{analyze::Analysis, ast::App};
analyze::Analysis,
ast::{App, CustomArg},
};
use syn::{parse, Path}; use syn::{parse, Path};
pub struct Extra<'a> { pub struct Extra {
pub device: &'a Path, pub device: Path,
pub monotonic: Option<&'a Path>, pub monotonic: Option<Path>,
pub peripherals: bool, pub peripherals: bool,
} }
impl<'a> Extra<'a> { pub fn app(app: &App, _analysis: &Analysis) -> parse::Result<Extra> {
pub fn monotonic(&self) -> &'a Path {
self.monotonic.expect("UNREACHABLE")
}
}
pub fn app<'a>(app: &'a App, _analysis: &Analysis) -> parse::Result<Extra<'a>> {
// Check that external (device-specific) interrupts are not named after known (Cortex-M) // Check that external (device-specific) interrupts are not named after known (Cortex-M)
// exceptions // exceptions
for name in app.extern_interrupts.keys() { for name in app.args.extern_interrupts.keys() {
let name_s = name.to_string(); let name_s = name.to_string();
match &*name_s { match &*name_s {
@ -51,11 +42,11 @@ pub fn app<'a>(app: &'a App, _analysis: &Analysis) -> parse::Result<Extra<'a>> {
.collect::<HashSet<_>>(); .collect::<HashSet<_>>();
let need = priorities.len(); let need = priorities.len();
let given = app.extern_interrupts.len(); let given = app.args.extern_interrupts.len();
if need > given { if need > given {
let s = { let s = {
format!( format!(
"not enough `extern` interrupts to dispatch \ "not enough interrupts to dispatch \
all software tasks (need: {}; given: {})", all software tasks (need: {}; given: {})",
need, given need, given
) )
@ -66,52 +57,6 @@ pub fn app<'a>(app: &'a App, _analysis: &Analysis) -> parse::Result<Extra<'a>> {
return Err(parse::Error::new(first.unwrap().span(), &s)); return Err(parse::Error::new(first.unwrap().span(), &s));
} }
let mut device = None;
let mut monotonic = None;
let mut peripherals = false;
for (k, v) in &app.args.custom {
let ks = k.to_string();
match &*ks {
"device" => match v {
CustomArg::Path(p) => device = Some(p),
_ => {
return Err(parse::Error::new(
k.span(),
"unexpected argument value; this should be a path",
));
}
},
"monotonic" => match v {
CustomArg::Path(p) => monotonic = Some(p),
_ => {
return Err(parse::Error::new(
k.span(),
"unexpected argument value; this should be a path",
));
}
},
"peripherals" => match v {
CustomArg::Bool(x) => peripherals = *x,
_ => {
return Err(parse::Error::new(
k.span(),
"unexpected argument value; this should be a boolean",
));
}
},
_ => {
return Err(parse::Error::new(k.span(), "unexpected argument"));
}
}
}
// Check that all exceptions are valid; only exceptions with configurable priorities are // Check that all exceptions are valid; only exceptions with configurable priorities are
// accepted // accepted
for (name, task) in &app.hardware_tasks { for (name, task) in &app.hardware_tasks {
@ -119,7 +64,7 @@ pub fn app<'a>(app: &'a App, _analysis: &Analysis) -> parse::Result<Extra<'a>> {
match &*name_s { match &*name_s {
"SysTick" => { "SysTick" => {
// If the timer queue is used, then SysTick is unavailable // If the timer queue is used, then SysTick is unavailable
if monotonic.is_some() { if app.args.monotonic.is_some() {
return Err(parse::Error::new( return Err(parse::Error::new(
name.span(), name.span(),
"this exception can't be used because it's being used by the runtime", "this exception can't be used because it's being used by the runtime",
@ -140,11 +85,11 @@ pub fn app<'a>(app: &'a App, _analysis: &Analysis) -> parse::Result<Extra<'a>> {
} }
} }
if let Some(device) = device { if let Some(device) = app.args.device.clone() {
Ok(Extra { Ok(Extra {
device, device,
monotonic, monotonic: app.args.monotonic.clone(),
peripherals, peripherals: app.args.peripherals,
}) })
} else { } else {
Err(parse::Error::new( Err(parse::Error::new(

View file

@ -86,7 +86,7 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
let user_imports = &app.user_imports; let user_imports = &app.user_imports;
let user_code = &app.user_code; let user_code = &app.user_code;
let name = &app.name; let name = &app.name;
let device = extra.device; let device = &extra.device;
// Get the list of all tasks // Get the list of all tasks
// Currently unused, might be useful // Currently unused, might be useful

View file

@ -119,11 +119,13 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
)); ));
let doc = format!("Interrupt handler to dispatch tasks at priority {}", level); let doc = format!("Interrupt handler to dispatch tasks at priority {}", level);
let interrupt = util::suffixed(&interrupts[&level].to_string()); let interrupt = util::suffixed(&interrupts[&level].0.to_string());
let attribute = &interrupts[&level].1.attrs;
items.push(quote!( items.push(quote!(
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[doc = #doc] #[doc = #doc]
#[no_mangle] #[no_mangle]
#(#attribute)*
unsafe fn #interrupt() { unsafe fn #interrupt() {
/// The priority of this interrupt handler /// The priority of this interrupt handler
const PRIORITY: u8 = #level; const PRIORITY: u8 = #level;

View file

@ -29,7 +29,7 @@ pub fn codegen(
let mut user_tasks = vec![]; let mut user_tasks = vec![];
for (name, task) in &app.hardware_tasks { for (name, task) in &app.hardware_tasks {
let (let_instant, instant) = if let Some(m) = extra.monotonic { let (let_instant, instant) = if let Some(ref m) = extra.monotonic {
( (
Some(quote!(let instant = <#m as rtic::Monotonic>::now();)), Some(quote!(let instant = <#m as rtic::Monotonic>::now();)),
Some(quote!(, instant)), Some(quote!(, instant)),

View file

@ -23,7 +23,7 @@ pub fn codegen(
let mut lt = None; let mut lt = None;
match ctxt { match ctxt {
Context::Init => { Context::Init => {
if let Some(m) = extra.monotonic { if let Some(m) = &extra.monotonic {
fields.push(quote!( fields.push(quote!(
/// System start time = `Instant(0 /* cycles */)` /// System start time = `Instant(0 /* cycles */)`
pub start: <#m as rtic::Monotonic>::Instant pub start: <#m as rtic::Monotonic>::Instant
@ -43,7 +43,7 @@ pub fn codegen(
} }
if extra.peripherals { if extra.peripherals {
let device = extra.device; let device = &extra.device;
fields.push(quote!( fields.push(quote!(
/// Device peripherals /// Device peripherals
@ -67,7 +67,7 @@ pub fn codegen(
Context::Idle => {} Context::Idle => {}
Context::HardwareTask(..) => { Context::HardwareTask(..) => {
if let Some(m) = extra.monotonic { if let Some(m) = &extra.monotonic {
fields.push(quote!( fields.push(quote!(
/// Time at which this handler started executing /// Time at which this handler started executing
pub start: <#m as rtic::Monotonic>::Instant pub start: <#m as rtic::Monotonic>::Instant
@ -80,7 +80,7 @@ pub fn codegen(
} }
Context::SoftwareTask(..) => { Context::SoftwareTask(..) => {
if let Some(m) = extra.monotonic { if let Some(m) = &extra.monotonic {
fields.push(quote!( fields.push(quote!(
/// The time at which this task was scheduled to run /// The time at which this task was scheduled to run
pub scheduled: <#m as rtic::Monotonic>::Instant pub scheduled: <#m as rtic::Monotonic>::Instant
@ -162,7 +162,7 @@ pub fn codegen(
}; };
let instant = if needs_instant { let instant = if needs_instant {
let m = extra.monotonic(); let m = extra.monotonic.clone().expect("RTIC-ICE: UNREACHABLE");
Some(quote!(, instant: <#m as rtic::Monotonic>::Instant)) Some(quote!(, instant: <#m as rtic::Monotonic>::Instant))
} else { } else {
@ -205,9 +205,13 @@ pub fn codegen(
let app_name = &app.name; let app_name = &app.name;
let app_path = quote! {crate::#app_name}; let app_path = quote! {crate::#app_name};
let device = extra.device; let device = &extra.device;
let enum_ = util::interrupt_ident(); let enum_ = util::interrupt_ident();
let interrupt = &analysis.interrupts.get(&priority); let interrupt = &analysis
.interrupts
.get(&priority)
.expect("RTIC-ICE: interrupt identifer not found")
.0;
// Spawn caller // Spawn caller
items.push(quote!( items.push(quote!(
@ -240,7 +244,7 @@ pub fn codegen(
})); }));
// Schedule caller // Schedule caller
if let Some(m) = extra.monotonic { 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();

View file

@ -26,22 +26,20 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
let mut core: rtic::export::Peripherals = rtic::export::Peripherals::steal().into(); let mut core: rtic::export::Peripherals = rtic::export::Peripherals::steal().into();
)); ));
let device = extra.device; let device = &extra.device;
let nvic_prio_bits = quote!(#device::NVIC_PRIO_BITS); let nvic_prio_bits = quote!(#device::NVIC_PRIO_BITS);
let interrupt_ids = analysis.interrupts.iter().map(|(p, (id, _))| (p, id));
// Unmask interrupts and set their priorities // Unmask interrupts and set their priorities
for (&priority, name) in analysis for (&priority, name) in interrupt_ids.chain(app.hardware_tasks.values().flat_map(|task| {
.interrupts if !util::is_exception(&task.args.binds) {
.iter() Some((&task.args.priority, &task.args.binds))
.chain(app.hardware_tasks.values().flat_map(|task| { } else {
if !util::is_exception(&task.args.binds) { // We do exceptions in another pass
Some((&task.args.priority, &task.args.binds)) None
} else { }
// We do exceptions in another pass })) {
None
}
}))
{
// Compile time assert that this priority is supported by the device // Compile time assert that this priority is supported by the device
stmts.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];)); stmts.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];));

View file

@ -57,7 +57,7 @@ pub fn codegen(
.map(|_| quote!(core::mem::MaybeUninit::uninit())) .map(|_| quote!(core::mem::MaybeUninit::uninit()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
if let Some(m) = extra.monotonic { if let Some(m) = &extra.monotonic {
let instants = util::instants_ident(name); let instants = util::instants_ident(name);
let uninit = mk_uninit(); let uninit = mk_uninit();

View file

@ -8,7 +8,7 @@ use crate::{analyze::Analysis, check::Extra, codegen::util};
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 let Some(m) = extra.monotonic { if let Some(m) = &extra.monotonic {
let t = util::schedule_t_ident(); let t = util::schedule_t_ident();
// Enumeration of `schedule`-able tasks // Enumeration of `schedule`-able tasks
@ -71,7 +71,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
let rq = util::rq_ident(priority); let rq = util::rq_ident(priority);
let rqt = util::spawn_t_ident(priority); let rqt = util::spawn_t_ident(priority);
let enum_ = util::interrupt_ident(); let enum_ = util::interrupt_ident();
let interrupt = &analysis.interrupts.get(&priority); let interrupt = &analysis.interrupts.get(&priority).expect("RTIC-ICE: interrupt not found").0;
let pend = { let pend = {
quote!( quote!(

View file

@ -46,7 +46,7 @@ pub fn impl_mutex(
(quote!(#name), quote!(self.priority)) (quote!(#name), quote!(self.priority))
}; };
let device = extra.device; let device = &extra.device;
quote!( quote!(
#(#cfgs)* #(#cfgs)*
impl<'a> rtic::Mutex for #path<'a> { impl<'a> rtic::Mutex for #path<'a> {

View file

@ -6,7 +6,8 @@ fn analyze() {
let mut settings = Settings::default(); let mut settings = Settings::default();
settings.parse_extern_interrupt = true; settings.parse_extern_interrupt = true;
let (app, analysis) = rtic_syntax::parse2( let (app, analysis) = rtic_syntax::parse2(
quote!(device = pac), // First interrupt is assigned to the highest priority dispatcher
quote!(device = pac, dispatchers = [B, A]),
quote!( quote!(
mod app { mod app {
#[task(priority = 1)] #[task(priority = 1)]
@ -14,12 +15,6 @@ fn analyze() {
#[task(priority = 2)] #[task(priority = 2)]
fn b(_: b::Context) {} fn b(_: b::Context) {}
// First interrupt is assigned to the highest priority dispatcher
extern "C" {
fn B();
fn A();
}
} }
), ),
settings, settings,
@ -29,6 +24,6 @@ fn analyze() {
let analysis = crate::analyze::app(analysis, &app); let analysis = crate::analyze::app(analysis, &app);
let interrupts = &analysis.interrupts; let interrupts = &analysis.interrupts;
assert_eq!(interrupts.len(), 2); assert_eq!(interrupts.len(), 2);
assert_eq!(interrupts[&2].to_string(), "B"); assert_eq!(interrupts[&2].0.to_string(), "B");
assert_eq!(interrupts[&1].to_string(), "A"); assert_eq!(interrupts[&1].0.to_string(), "A");
} }

View file

@ -1,4 +1,4 @@
error: not enough `extern` interrupts to dispatch all software tasks (need: 1; given: 0) error: not enough interrupts to dispatch all software tasks (need: 1; given: 0)
--> $DIR/extern-interrupt-not-enough.rs:6:8 --> $DIR/extern-interrupt-not-enough.rs:6:8
| |
6 | fn a(_: a::Context) {} 6 | fn a(_: a::Context) {}

View file

@ -1,6 +1,6 @@
#![no_main] #![no_main]
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965, dispatchers = [UART0])]
mod app { mod app {
#[task(binds = UART0)] #[task(binds = UART0)]
fn a(_: a::Context) {} fn a(_: a::Context) {}

View file

@ -1,4 +1,4 @@
error: `extern` interrupts can't be used as hardware tasks error: dispatcher interrupts can't be used as hardware tasks
--> $DIR/extern-interrupt-used.rs:5:20 --> $DIR/extern-interrupt-used.rs:5:20
| |
5 | #[task(binds = UART0)] 5 | #[task(binds = UART0)]

View file

@ -1,7 +1,7 @@
#![no_main] #![no_main]
use panic_halt as _; use panic_halt as _;
#[rtic::app(device = lm3s6965)] #[rtic::app(device = lm3s6965, dispatchers = [SSI0])]
mod app { mod app {
#[init] #[init]
fn init(_: init::Context) -> init::LateResources { fn init(_: init::Context) -> init::LateResources {
@ -46,8 +46,4 @@ mod app {
FOO; FOO;
} }
extern "C" {
fn UART1();
}
} }