This commit is contained in:
Jorge Aparicio 2019-06-20 06:19:59 +02:00
parent b150ab29e2
commit 4e51bb68b9
33 changed files with 143 additions and 142 deletions

View file

@ -35,8 +35,8 @@ const APP: () = {
}
}
#[interrupt(spawn = [foo])]
fn UART0(c: UART0::Context) {
#[task(binds = UART0, spawn = [foo])]
fn uart0(c: uart0::Context) {
hprintln!("UART0(baseline = {:?})", c.start).unwrap();
// `foo` inherits the baseline of `UART0`: its `start` time

View file

@ -30,7 +30,7 @@ const APP: () = {
loop {}
}
#[interrupt(binds = UART0)]
#[task(binds = UART0)]
fn foo(_: foo::Context) {
static mut TIMES: u32 = 0;

View file

@ -16,8 +16,8 @@ const APP: () = {
rtfm::pend(Interrupt::UART0);
}
#[interrupt(spawn = [foo, bar])]
fn UART0(c: UART0::Context) {
#[task(binds = UART0, spawn = [foo, bar])]
fn uart0(c: uart0::Context) {
c.spawn.foo(0).unwrap();
c.spawn.foo(1).unwrap();
c.spawn.foo(2).unwrap();

View file

@ -20,8 +20,8 @@ const APP: () = {
rtfm::pend(Interrupt::UART1);
}
#[interrupt(resources = [SHARED])]
fn UART0(c: UART0::Context) {
#[task(binds = UART0, resources = [SHARED])]
fn uart0(c: uart0::Context) {
static mut STATE: u32 = 0;
hprintln!("UART0(STATE = {})", *STATE).unwrap();
@ -33,8 +33,8 @@ const APP: () = {
debug::exit(debug::EXIT_SUCCESS);
}
#[interrupt(priority = 2, resources = [SHARED])]
fn UART1(c: UART1::Context) {
#[task(binds = UART1, priority = 2, resources = [SHARED])]
fn uart1(c: uart1::Context) {
static mut STATE: u32 = 0;
hprintln!("UART1(STATE = {})", *STATE).unwrap();

View file

@ -33,8 +33,8 @@ const APP: () = {
loop {}
}
#[interrupt]
fn UART0(_: UART0::Context) {
#[task(binds = UART0)]
fn uart0(_: uart0::Context) {
static mut TIMES: u32 = 0;
// Safe access to local `static mut` variable

View file

@ -47,8 +47,8 @@ const APP: () = {
}
}
#[interrupt(resources = [P])]
fn UART0(c: UART0::Context) {
#[task(binds = UART0, resources = [P])]
fn uart0(c: uart0::Context) {
c.resources.P.enqueue(42).unwrap();
}
};

View file

@ -19,8 +19,8 @@ const APP: () = {
}
// when omitted priority is assumed to be `1`
#[interrupt(resources = [SHARED])]
fn GPIOA(mut c: GPIOA::Context) {
#[task(binds = GPIOA, resources = [SHARED])]
fn gpioa(mut c: gpioa::Context) {
hprintln!("A").unwrap();
// the lower priority task requires a critical section to access the data
@ -44,16 +44,16 @@ const APP: () = {
debug::exit(debug::EXIT_SUCCESS);
}
#[interrupt(priority = 2, resources = [SHARED])]
fn GPIOB(c: GPIOB::Context) {
#[task(binds = GPIOB, priority = 2, resources = [SHARED])]
fn gpiob(c: gpiob::Context) {
// the higher priority task does *not* need a critical section
*c.resources.SHARED += 1;
hprintln!("D - SHARED = {}", *c.resources.SHARED).unwrap();
}
#[interrupt(priority = 3)]
fn GPIOC(_: GPIOC::Context) {
#[task(binds = GPIOC, priority = 3)]
fn gpioc(_: gpioc::Context) {
hprintln!("C").unwrap();
}
};

View file

@ -29,8 +29,8 @@ const APP: () = {
rtfm::pend(Interrupt::I2C0);
}
#[interrupt(priority = 2, spawn = [foo, bar])]
fn I2C0(c: I2C0::Context) {
#[task(binds = I2C0, priority = 2, spawn = [foo, bar])]
fn i2c0(c: i2c0::Context) {
// claim a memory block, leave it uninitialized and ..
let x = P::alloc().unwrap().freeze();

View file

@ -31,16 +31,16 @@ const APP: () = {
}
// `SHARED` can be access from this context
#[interrupt(resources = [SHARED])]
fn UART0(c: UART0::Context) {
#[task(binds = UART0, resources = [SHARED])]
fn uart0(c: uart0::Context) {
*c.resources.SHARED += 1;
hprintln!("UART0: SHARED = {}", c.resources.SHARED).unwrap();
}
// `SHARED` can be access from this context
#[interrupt(resources = [SHARED])]
fn UART1(c: UART1::Context) {
#[task(binds = UART1, resources = [SHARED])]
fn uart1(c: uart1::Context) {
*c.resources.SHARED += 1;
hprintln!("UART1: SHARED = {}", c.resources.SHARED).unwrap();

View file

@ -25,8 +25,8 @@ const APP: () = {
rtfm::pend(Interrupt::UART0);
}
#[interrupt(resources = [SHARED])]
fn UART0(c: UART0::Context) {
#[task(binds = UART0, resources = [SHARED])]
fn uart0(c: uart0::Context) {
if let Some(message) = c.resources.SHARED.take() {
// `message` has been received
drop(message);

View file

@ -23,15 +23,15 @@ const APP: () = {
init::LateResources { KEY: 0xdeadbeef }
}
#[interrupt(resources = [KEY])]
fn UART0(c: UART0::Context) {
#[task(binds = UART0, resources = [KEY])]
fn uart0(c: uart0::Context) {
hprintln!("UART0(KEY = {:#x})", c.resources.KEY).unwrap();
debug::exit(debug::EXIT_SUCCESS);
}
#[interrupt(priority = 2, resources = [KEY])]
fn UART1(c: UART1::Context) {
#[task(binds = UART1, priority = 2, resources = [KEY])]
fn uart1(c: uart1::Context) {
hprintln!("UART1(KEY = {:#x})", c.resources.KEY).unwrap();
}
};

View file

@ -12,12 +12,14 @@ const APP: () = {
#[init]
fn init(_: init::Context) {}
#[exception(binds = SVCall)]
// Cortex-M exception
#[task(binds = SVCall)]
fn foo(c: foo::Context) {
foo_trampoline(c)
}
#[interrupt(binds = UART0)]
// LM3S6965 interrupt
#[task(binds = UART0)]
fn bar(c: bar::Context) {
bar_trampoline(c)
}

View file

@ -51,8 +51,8 @@ const APP: () = {
loop {}
}
#[interrupt(resources = [O3, S1, S2, S3])]
fn UART0(c: UART0::Context) {
#[task(binds = UART0, resources = [O3, S1, S2, S3])]
fn uart0(c: uart0::Context) {
// owned by interrupt == `&mut`
let _: &mut u32 = c.resources.O3;
@ -66,8 +66,8 @@ const APP: () = {
let _: &u32 = c.resources.S3;
}
#[interrupt(resources = [S2, O5])]
fn UART1(c: UART1::Context) {
#[task(binds = UART1, resources = [S2, O5])]
fn uart1(c: uart1::Context) {
// owned by interrupt == `&` if read-only
let _: &u32 = c.resources.O5;

View file

@ -26,15 +26,15 @@ const APP: () = {
loop {}
}
#[exception(schedule = [foo, bar, baz])]
fn SVCall(c: SVCall::Context) {
#[task(binds = SVCall, schedule = [foo, bar, baz])]
fn svcall(c: svcall::Context) {
let _: Result<(), ()> = c.schedule.foo(c.start + 70.cycles());
let _: Result<(), u32> = c.schedule.bar(c.start + 80.cycles(), 0);
let _: Result<(), (u32, u32)> = c.schedule.baz(c.start + 90.cycles(), 0, 1);
}
#[interrupt(schedule = [foo, bar, baz])]
fn UART0(c: UART0::Context) {
#[task(binds = UART0, schedule = [foo, bar, baz])]
fn uart0(c: uart0::Context) {
let _: Result<(), ()> = c.schedule.foo(c.start + 100.cycles());
let _: Result<(), u32> = c.schedule.bar(c.start + 110.cycles(), 0);
let _: Result<(), (u32, u32)> = c.schedule.baz(c.start + 120.cycles(), 0, 1);

View file

@ -25,15 +25,15 @@ const APP: () = {
loop {}
}
#[exception(spawn = [foo, bar, baz])]
fn SVCall(c: SVCall::Context) {
#[task(binds = SVCall, spawn = [foo, bar, baz])]
fn svcall(c: svcall::Context) {
let _: Result<(), ()> = c.spawn.foo();
let _: Result<(), u32> = c.spawn.bar(0);
let _: Result<(), (u32, u32)> = c.spawn.baz(0, 1);
}
#[interrupt(spawn = [foo, bar, baz])]
fn UART0(c: UART0::Context) {
#[task(binds = UART0, spawn = [foo, bar, baz])]
fn uart0(c: uart0::Context) {
let _: Result<(), ()> = c.spawn.foo();
let _: Result<(), u32> = c.spawn.bar(0);
let _: Result<(), (u32, u32)> = c.spawn.baz(0, 1);

View file

@ -24,19 +24,19 @@ const APP: () = {
debug::exit(debug::EXIT_SUCCESS);
}
#[exception(schedule = [foo], spawn = [foo])]
fn SVCall(c: SVCall::Context) {
#[task(binds = SVCall, schedule = [foo], spawn = [foo])]
fn svcall(c: svcall::Context) {
let _: Instant = c.start;
let _: SVCall::Schedule = c.schedule;
let _: SVCall::Spawn = c.spawn;
let _: svcall::Schedule = c.schedule;
let _: svcall::Spawn = c.spawn;
}
#[interrupt(resources = [SHARED], schedule = [foo], spawn = [foo])]
fn UART0(c: UART0::Context) {
#[task(binds = UART0, resources = [SHARED], schedule = [foo], spawn = [foo])]
fn uart0(c: uart0::Context) {
let _: Instant = c.start;
let _: resources::SHARED = c.resources.SHARED;
let _: UART0::Schedule = c.schedule;
let _: UART0::Spawn = c.spawn;
let _: uart0::Schedule = c.schedule;
let _: uart0::Spawn = c.spawn;
}
#[task(priority = 2, resources = [SHARED], schedule = [foo], spawn = [foo])]

View file

@ -3,7 +3,7 @@ use std::collections::HashSet;
use proc_macro2::Span;
use rtfm_syntax::{
analyze::Analysis,
ast::{App, CustomArg, HardwareTaskKind},
ast::{App, CustomArg},
};
use syn::{parse, Path};
@ -44,18 +44,9 @@ pub fn app<'a>(app: &'a App, analysis: &Analysis) -> parse::Result<Extra<'a>> {
// check that all exceptions are valid; only exceptions with configurable priorities are
// accepted
for (name, task) in app
.hardware_tasks
.iter()
.filter(|(_, task)| task.kind == HardwareTaskKind::Exception)
{
let name_s = task.args.binds(name).to_string();
for (name, task) in &app.hardware_tasks {
let name_s = task.args.binds.to_string();
match &*name_s {
// NOTE that some of these don't exist on ARMv6-M but we don't check that here -- the
// code we generate will check that the exception actually exists on ARMv6-M
"MemoryManagement" | "BusFault" | "UsageFault" | "SecureFault" | "SVCall"
| "DebugMonitor" | "PendSV" => {} // OK
"SysTick" => {
if analysis.timer_queues.get(&task.args.core).is_some() {
return Err(parse::Error::new(
@ -67,12 +58,14 @@ pub fn app<'a>(app: &'a App, analysis: &Analysis) -> parse::Result<Extra<'a>> {
}
}
_ => {
"NonMaskableInt" | "HardFault" => {
return Err(parse::Error::new(
name.span(),
"only exceptions with configurable priority can be used as hardware tasks",
));
}
_ => {}
}
}

View file

@ -50,9 +50,9 @@ pub fn codegen(
};
let symbol = if cfg!(feature = "homogeneous") {
util::suffixed(&task.args.binds(name).to_string(), core)
util::suffixed(&task.args.binds.to_string(), core)
} else {
task.args.binds(name).clone()
task.args.binds.clone()
};
let priority = task.args.priority;

View file

@ -1,6 +1,6 @@
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use rtfm_syntax::ast::{App, HardwareTaskKind};
use rtfm_syntax::ast::App;
use crate::{analyze::Analysis, check::Extra, codegen::util};
@ -52,9 +52,9 @@ pub fn codegen(
.get(&core)
.iter()
.flat_map(|interrupts| *interrupts)
.chain(app.hardware_tasks.iter().flat_map(|(name, task)| {
if task.kind == HardwareTaskKind::Interrupt {
Some((&task.args.priority, task.args.binds(name)))
.chain(app.hardware_tasks.values().flat_map(|task| {
if !util::is_exception(&task.args.binds) {
Some((&task.args.priority, &task.args.binds))
} else {
// we do exceptions in another pass
None
@ -102,9 +102,9 @@ pub fn codegen(
}
// set exception priorities
for (name, priority) in app.hardware_tasks.iter().filter_map(|(name, task)| {
if task.kind == HardwareTaskKind::Exception {
Some((task.args.binds(name), task.args.priority))
for (name, priority) in app.hardware_tasks.values().filter_map(|task| {
if util::is_exception(&task.args.binds) {
Some((&task.args.binds, task.args.priority))
} else {
None
}

View file

@ -113,6 +113,18 @@ pub fn interrupt_ident(core: Core, cores: u8) -> Ident {
}
}
/// Whether `name` is an exception with configurable priority
pub fn is_exception(name: &Ident) -> bool {
let s = name.to_string();
match &*s {
"MemoryManagement" | "BusFault" | "UsageFault" | "SecureFault" | "SVCall"
| "DebugMonitor" | "PendSV" | "SysTick" => true,
_ => false,
}
}
/// Generates a pre-reexport identifier for the "late resources" struct
pub fn late_resources_ident(init: &Ident) -> Ident {
Ident::new(

View file

@ -16,19 +16,14 @@ mod tests;
#[proc_macro_attribute]
pub fn app(args: TokenStream, input: TokenStream) -> TokenStream {
let (app, analysis) = match rtfm_syntax::parse(
args,
input,
Settings {
parse_cores: cfg!(feature = "heterogeneous") || cfg!(feature = "homogeneous"),
parse_exception: true,
parse_extern_interrupt: true,
parse_interrupt: true,
parse_schedule: true,
optimize_priorities: true,
..Settings::default()
},
) {
let mut settings = Settings::default();
settings.optimize_priorities = true;
settings.parse_binds = true;
settings.parse_cores = cfg!(feature = "heterogeneous") || cfg!(feature = "homogeneous");
settings.parse_extern_interrupt = true;
settings.parse_schedule = true;
let (app, analysis) = match rtfm_syntax::parse(args, input, settings) {
Err(e) => return e.to_compile_error().into(),
Ok(x) => x,
};

View file

@ -3,6 +3,10 @@ use rtfm_syntax::Settings;
#[test]
fn analyze() {
let mut settings = Settings::default();
settings.parse_cores = true;
settings.parse_extern_interrupt = true;
let (app, analysis) = rtfm_syntax::parse2(
quote!(device = pac, cores = 2),
quote!(
@ -35,13 +39,9 @@ fn analyze() {
}
};
),
Settings {
parse_cores: true,
parse_extern_interrupt: true,
..Settings::default()
},
settings,
)
.unwrap();
.unwrap();
let analysis = crate::analyze::app(analysis, &app);

View file

@ -3,6 +3,8 @@ use rtfm_syntax::Settings;
#[test]
fn analyze() {
let mut settings = Settings::default();
settings.parse_extern_interrupt = true;
let (app, analysis) = rtfm_syntax::parse2(
quote!(device = pac),
quote!(
@ -20,10 +22,7 @@ fn analyze() {
}
};
),
Settings {
parse_extern_interrupt: true,
..Settings::default()
},
settings,
)
.unwrap();

View file

@ -2,6 +2,6 @@
#[rtfm::app(device = lm3s6965)]
const APP: () = {
#[exception]
fn NonMaskableInt(_: NonMaskableInt::Context) {}
#[task(binds = NonMaskableInt)]
fn nmi(_: nmi::Context) {}
};

View file

@ -1,8 +1,8 @@
error: only exceptions with configurable priority can be used as hardware tasks
--> $DIR/exception-invalid.rs:6:8
|
6 | fn NonMaskableInt(_: NonMaskableInt::Context) {}
| ^^^^^^^^^^^^^^
6 | fn nmi(_: nmi::Context) {}
| ^^^
error: aborting due to previous error

View file

@ -2,8 +2,8 @@
#[rtfm::app(device = lm3s6965)]
const APP: () = {
#[exception]
fn SysTick(_: SysTick::Context) {}
#[task(binds = SysTick)]
fn sys_tick(_: sys_tick::Context) {}
#[task(schedule = [foo])]
fn foo(_: foo::Context) {}

View file

@ -1,8 +1,8 @@
error: this exception can't be used because it's being used by the runtime
--> $DIR/exception-systick-used.rs:6:8
|
6 | fn SysTick(_: SysTick::Context) {}
| ^^^^^^^
6 | fn sys_tick(_: sys_tick::Context) {}
| ^^^^^^^^
error: aborting due to previous error

View file

@ -2,7 +2,7 @@
#[rtfm::app(device = lm3s6965)]
const APP: () = {
#[interrupt(binds = UART0)]
#[task(binds = UART0)]
fn a(_: a::Context) {}
extern "C" {

View file

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

View file

@ -20,16 +20,16 @@ const APP: () = {
loop {}
}
#[exception]
fn SVCall(_: SVCall::Context) {
#[task(binds = SVCall)]
fn svcall(_: svcall::Context) {
#[cfg(never)]
static mut FOO: u32 = 0;
FOO;
}
#[interrupt]
fn UART0(_: UART0::Context) {
#[task(binds = UART0)]
fn uart0(_: uart0::Context) {
#[cfg(never)]
static mut FOO: u32 = 0;

View file

@ -41,16 +41,16 @@ const APP: () = {
loop {}
}
#[interrupt(resources = [O3, S1, S2, S3])]
fn UART0(c: UART0::Context) {
#[task(binds = UART0, resources = [O3, S1, S2, S3])]
fn uart0(c: uart0::Context) {
c.resources.O3;
c.resources.S1;
c.resources.S2;
c.resources.S3;
}
#[interrupt(resources = [S2, O5])]
fn UART1(c: UART1::Context) {
#[task(binds = UART1, resources = [S2, O5])]
fn uart1(c: uart1::Context) {
c.resources.S2;
c.resources.O5;
}

View file

@ -70,7 +70,7 @@ error[E0609]: no field `S3` on type `idleResources<'_>`
|
= note: available fields are: `__marker__`
error[E0609]: no field `O3` on type `UART0Resources<'_>`
error[E0609]: no field `O3` on type `uart0Resources<'_>`
--> $DIR/resources-cfg.rs:46:21
|
46 | c.resources.O3;
@ -78,7 +78,7 @@ error[E0609]: no field `O3` on type `UART0Resources<'_>`
|
= note: available fields are: `__marker__`
error[E0609]: no field `S1` on type `UART0Resources<'_>`
error[E0609]: no field `S1` on type `uart0Resources<'_>`
--> $DIR/resources-cfg.rs:47:21
|
47 | c.resources.S1;
@ -86,7 +86,7 @@ error[E0609]: no field `S1` on type `UART0Resources<'_>`
|
= note: available fields are: `__marker__`
error[E0609]: no field `S2` on type `UART0Resources<'_>`
error[E0609]: no field `S2` on type `uart0Resources<'_>`
--> $DIR/resources-cfg.rs:48:21
|
48 | c.resources.S2;
@ -94,7 +94,7 @@ error[E0609]: no field `S2` on type `UART0Resources<'_>`
|
= note: available fields are: `__marker__`
error[E0609]: no field `S3` on type `UART0Resources<'_>`
error[E0609]: no field `S3` on type `uart0Resources<'_>`
--> $DIR/resources-cfg.rs:49:21
|
49 | c.resources.S3;
@ -102,7 +102,7 @@ error[E0609]: no field `S3` on type `UART0Resources<'_>`
|
= note: available fields are: `__marker__`
error[E0609]: no field `S2` on type `UART1Resources<'_>`
error[E0609]: no field `S2` on type `uart1Resources<'_>`
--> $DIR/resources-cfg.rs:54:21
|
54 | c.resources.S2;
@ -110,7 +110,7 @@ error[E0609]: no field `S2` on type `UART1Resources<'_>`
|
= note: available fields are: `__marker__`
error[E0609]: no field `O5` on type `UART1Resources<'_>`
error[E0609]: no field `O5` on type `uart1Resources<'_>`
--> $DIR/resources-cfg.rs:55:21
|
55 | c.resources.O5;

View file

@ -7,32 +7,32 @@ const APP: () = {
#[init]
fn init(_: init::Context) {}
#[interrupt(priority = 1)]
fn GPIOA(_: GPIOA::Context) {}
#[task(binds = GPIOA, priority = 1)]
fn gpioa(_: gpioa::Context) {}
#[interrupt(priority = 2)]
fn GPIOB(_: GPIOB::Context) {}
#[task(binds = GPIOB, priority = 2)]
fn gpiob(_: gpiob::Context) {}
#[interrupt(priority = 3)]
fn GPIOC(_: GPIOC::Context) {}
#[task(binds = GPIOC, priority = 3)]
fn gpioc(_: gpioc::Context) {}
#[interrupt(priority = 4)]
fn GPIOD(_: GPIOD::Context) {}
#[task(binds = GPIOD, priority = 4)]
fn gpiod(_: gpiod::Context) {}
#[interrupt(priority = 5)]
fn GPIOE(_: GPIOE::Context) {}
#[task(binds = GPIOE, priority = 5)]
fn gpioe(_: gpioe::Context) {}
#[interrupt(priority = 6)]
fn UART0(_: UART0::Context) {}
#[task(binds = UART0, priority = 6)]
fn uart0(_: uart0::Context) {}
#[interrupt(priority = 7)]
fn UART1(_: UART1::Context) {}
#[task(binds = UART1, priority = 7)]
fn uart1(_: uart1::Context) {}
// OK, this is the maximum priority supported by the device
#[interrupt(priority = 8)]
fn SSI0(_: SSI0::Context) {}
#[task(binds = SSI0, priority = 8)]
fn ssi0(_: ssi0::Context) {}
// this value is too high!
#[interrupt(priority = 9)]
fn I2C0(_: I2C0::Context) {}
#[task(binds = I2C0, priority = 9)]
fn i2c0(_: i2c0::Context) {}
};