aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--macros/src/check.rs21
-rw-r--r--macros/src/lib.rs1
-rw-r--r--macros/src/syntax/mod.rs6
-rw-r--r--macros/src/syntax/parse.rs16
-rw-r--r--macros/src/trans.rs132
-rw-r--r--macros/src/util.rs24
-rw-r--r--src/lib.rs11
7 files changed, 157 insertions, 54 deletions
diff --git a/macros/src/check.rs b/macros/src/check.rs
index ddd9abc4..7c86326a 100644
--- a/macros/src/check.rs
+++ b/macros/src/check.rs
@@ -1,17 +1,12 @@
-use syntax::Resources;
-use util::{Ceiling, Ceilings};
+use syntax::Statics;
+use util::Ceilings;
-pub fn resources(resources: &Resources, ceilings: &Ceilings) {
+pub fn resources(resources: &Statics, ceilings: &Ceilings) {
for resource in resources.keys() {
- if let Some(ceiling) = ceilings.get(&resource) {
- assert_ne!(
- *ceiling,
- Ceiling::Owned,
- "{} should be local data",
- resource
- );
- } else {
- panic!("resource {} is unused", resource)
- }
+ assert!(
+ ceilings.get(&resource).is_some(),
+ "resource {} is unused",
+ resource
+ );
}
}
diff --git a/macros/src/lib.rs b/macros/src/lib.rs
index 05210fbb..a5fdf96d 100644
--- a/macros/src/lib.rs
+++ b/macros/src/lib.rs
@@ -1,3 +1,4 @@
+#![deny(warnings)]
#![feature(plugin_registrar)]
#![feature(proc_macro_internals)]
#![feature(rustc_private)]
diff --git a/macros/src/syntax/mod.rs b/macros/src/syntax/mod.rs
index 53c17a82..757e05ed 100644
--- a/macros/src/syntax/mod.rs
+++ b/macros/src/syntax/mod.rs
@@ -10,7 +10,7 @@ pub struct App {
pub device: Tokens,
pub idle: Idle,
pub init: Init,
- pub resources: Resources,
+ pub resources: Statics,
pub tasks: Tasks,
}
@@ -21,7 +21,7 @@ pub struct Init {
#[derive(Debug)]
pub struct Idle {
- pub local: Resources,
+ pub local: Statics,
pub path: Tokens,
pub resources: HashSet<Ident>,
}
@@ -46,6 +46,6 @@ pub struct Resource {
pub ty: Tokens,
}
-pub type Resources = HashMap<Ident, Resource>;
+pub type Statics = HashMap<Ident, Resource>;
pub type Tasks = HashMap<Ident, Task>;
diff --git a/macros/src/syntax/parse.rs b/macros/src/syntax/parse.rs
index 9cfbd78b..056e804a 100644
--- a/macros/src/syntax/parse.rs
+++ b/macros/src/syntax/parse.rs
@@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet};
use syn::{self, DelimToken, Ident, IntTy, Lit, Token, TokenTree};
-use syntax::{App, Idle, Init, Kind, Resource, Resources, Task, Tasks};
+use syntax::{App, Idle, Init, Kind, Resource, Statics, Task, Tasks};
pub fn app(input: &str) -> App {
let tts = syn::parse_token_trees(input).unwrap();
@@ -96,7 +96,7 @@ pub fn app(input: &str) -> App {
block.delim
);
- resources = Some(super::parse::resources(block.tts));
+ resources = Some(super::parse::statics(block.tts));
}
}
"tasks" => {
@@ -169,7 +169,7 @@ pub fn idle(tts: Vec<TokenTree>) -> Idle {
block.delim
);
- local = Some(super::parse::resources(block.tts));
+ local = Some(super::parse::statics(block.tts));
} else {
panic!("expected block, found {:?}", tt);
}
@@ -273,7 +273,7 @@ pub fn init(tts: Vec<TokenTree>) -> Init {
fn idents(tts: Vec<TokenTree>) -> HashSet<Ident> {
let mut idents = HashSet::new();
- let mut tts = tts.into_iter();
+ let mut tts = tts.into_iter().peekable();
while let Some(tt) = tts.next() {
if let TokenTree::Token(Token::Ident(id)) = tt {
assert!(!idents.contains(&id), "ident {} already listed", id);
@@ -281,6 +281,10 @@ fn idents(tts: Vec<TokenTree>) -> HashSet<Ident> {
if let Some(tt) = tts.next() {
assert_eq!(tt, TokenTree::Token(Token::Comma));
+
+ if tts.peek().is_none() {
+ break;
+ }
} else {
break;
}
@@ -292,7 +296,7 @@ fn idents(tts: Vec<TokenTree>) -> HashSet<Ident> {
idents
}
-pub fn resources(tts: Vec<TokenTree>) -> Resources {
+pub fn statics(tts: Vec<TokenTree>) -> Statics {
let mut resources = HashMap::new();
let mut tts = tts.into_iter();
@@ -502,7 +506,7 @@ fn task(tts: Vec<TokenTree>) -> Task {
);
}
- let resources = resources.expect("resources field is missing");
+ let resources = resources.unwrap_or(HashSet::new());
let priority = priority.expect("priority field is missing");
let kind = if let Some(enabled) = enabled {
Kind::Interrupt { enabled }
diff --git a/macros/src/trans.rs b/macros/src/trans.rs
index 14d24fd8..b1cf7e79 100644
--- a/macros/src/trans.rs
+++ b/macros/src/trans.rs
@@ -39,22 +39,24 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
let ty = &resource.ty;
fields.push(quote! {
- pub #name: &'a mut #ty,
+ pub #name: &'a mut #krate::Static<#ty>,
});
exprs.push(quote! {
- #name: &mut *super::#name.get(),
+ #name: ::#krate::Static::ref_mut(&mut *super::#name.get()),
});
}
root.push(quote! {
+ #[allow(non_camel_case_types)]
+ #[allow(non_snake_case)]
+ pub struct _initResources<#lifetime> {
+ #(#fields)*
+ }
+
mod init {
pub use ::#device::Peripherals;
-
- #[allow(non_snake_case)]
- pub struct Resources<#lifetime> {
- #(#fields)*
- }
+ pub use ::_initResources as Resources;
impl<#lifetime> Resources<#lifetime> {
pub unsafe fn new() -> Self {
@@ -184,36 +186,80 @@ fn idle(
let device = &app.device;
let mut lifetime = None;
+ let mut needs_reexport = false;
+ for name in &app.idle.resources {
+ if ceilings[name].is_owned() {
+ if app.resources.get(name).is_some() {
+ needs_reexport = true;
+ break
+ }
+ }
+ }
+
+ let super_ = if needs_reexport {
+ None
+ } else {
+ Some(Ident::new("super"))
+ };
let mut rexprs = vec![];
let mut rfields = vec![];
for name in &app.idle.resources {
if ceilings[name].is_owned() {
lifetime = Some(quote!('a));
+ if let Some(resource) = app.resources.get(name) {
+ let ty = &resource.ty;
- rfields.push(quote! {
- pub #name: &'a mut ::#device::#name,
- });
+ rfields.push(quote! {
+ pub #name: &'a mut ::#krate::Static<#ty>,
+ });
- rexprs.push(quote! {
- #name: &mut *::#device::#name.get(),
- });
+ rexprs.push(quote! {
+ #name: ::#krate::Static::ref_mut(
+ &mut *#super_::#name.get(),
+ ),
+ });
+ } else {
+ rfields.push(quote! {
+ pub #name: &'a mut ::#device::#name,
+ });
+
+ rexprs.push(quote! {
+ #name: &mut *::#device::#name.get(),
+ });
+ }
} else {
rfields.push(quote! {
- pub #name: super::_resource::#name,
+ pub #name: #super_::_resource::#name,
});
rexprs.push(quote! {
- #name: super::_resource::#name::new(),
+ #name: #super_::_resource::#name::new(),
});
}
}
- mod_items.push(quote! {
- #[allow(non_snake_case)]
- pub struct Resources<#lifetime> {
- #(#rfields)*
- }
+ if needs_reexport {
+ root.push(quote! {
+ #[allow(non_camel_case_types)]
+ #[allow(non_snake_case)]
+ pub struct _idleResources<#lifetime> {
+ #(#rfields)*
+ }
+ });
+ mod_items.push(quote! {
+ pub use ::_idleResources as Resources;
+ });
+ } else {
+ mod_items.push(quote! {
+ #[allow(non_snake_case)]
+ pub struct Resources<#lifetime> {
+ #(#rfields)*
+ }
+ });
+ }
+
+ mod_items.push(quote! {
impl<#lifetime> Resources<#lifetime> {
pub unsafe fn new() -> Self {
Resources {
@@ -252,6 +298,7 @@ fn tasks(app: &App, ceilings: &Ceilings, root: &mut Vec<Tokens>) {
let device = &app.device;
let mut lifetime = None;
+ let mut needs_reexport = false;
for name in &task.resources {
match ceilings[name] {
Ceiling::Shared(ceiling) if ceiling > task.priority => {
@@ -268,6 +315,7 @@ fn tasks(app: &App, ceilings: &Ceilings, root: &mut Vec<Tokens>) {
_ => {
lifetime = Some(quote!('a));
if let Some(resource) = app.resources.get(name) {
+ needs_reexport = true;
let ty = &resource.ty;
fields.push(quote! {
@@ -292,12 +340,27 @@ fn tasks(app: &App, ceilings: &Ceilings, root: &mut Vec<Tokens>) {
}
}
- items.push(quote! {
- #[allow(non_snake_case)]
- pub struct Resources<#lifetime> {
- #(#fields)*
- }
- });
+ if needs_reexport {
+ let rname = Ident::new(format!("_{}Resources", name));
+ root.push(quote! {
+ #[allow(non_camel_case_types)]
+ #[allow(non_snake_case)]
+ pub struct #rname<#lifetime> {
+ #(#fields)*
+ }
+ });
+
+ items.push(quote! {
+ pub use ::#rname as Resources;
+ });
+ } else {
+ items.push(quote! {
+ #[allow(non_snake_case)]
+ pub struct Resources<#lifetime> {
+ #(#fields)*
+ }
+ });
+ }
items.push(quote! {
impl<#lifetime> Resources<#lifetime> {
@@ -339,7 +402,22 @@ fn resources(app: &App, ceilings: &Ceilings, root: &mut Vec<Tokens>) {
let mut impl_items = vec![];
match *ceiling {
- Ceiling::Owned => continue,
+ Ceiling::Owned(_) => {
+ if let Some(resource) = app.resources.get(name) {
+ // For owned resources we don't need claim() or borrow(),
+ // just get()
+ let expr = &resource.expr;
+ let ty = &resource.ty;
+
+ root.push(quote! {
+ static #name: #krate::Resource<#ty> =
+ #krate::Resource::new(#expr);
+ });
+ } else {
+ // Peripheral
+ continue
+ }
+ },
Ceiling::Shared(ceiling) => {
if let Some(resource) = app.resources.get(name) {
let expr = &resource.expr;
diff --git a/macros/src/util.rs b/macros/src/util.rs
index 45f1feef..4722ca7d 100644
--- a/macros/src/util.rs
+++ b/macros/src/util.rs
@@ -1,3 +1,4 @@
+use std::cmp;
use std::collections::HashMap;
use syn::Ident;
@@ -8,13 +9,18 @@ pub type Ceilings = HashMap<Ident, Ceiling>;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Ceiling {
- Owned,
+ // Owned by one or more tasks that have the same priority
+ Owned(u8),
+ // Shared by tasks with different priorities
Shared(u8),
}
impl Ceiling {
pub fn is_owned(&self) -> bool {
- *self == Ceiling::Owned
+ match *self {
+ Ceiling::Owned(_) => true,
+ _ => false,
+ }
}
}
@@ -22,14 +28,22 @@ pub fn compute_ceilings(app: &App) -> Ceilings {
let mut ceilings = HashMap::new();
for resource in &app.idle.resources {
- ceilings.insert(resource.clone(), Ceiling::Owned);
+ ceilings.insert(resource.clone(), Ceiling::Owned(0));
}
for task in app.tasks.values() {
for resource in &task.resources {
if let Some(ceiling) = ceilings.get_mut(resource) {
match *ceiling {
- Ceiling::Owned => *ceiling = Ceiling::Shared(task.priority),
+ Ceiling::Owned(current) => {
+ if current == task.priority {
+ *ceiling = Ceiling::Owned(current);
+ } else {
+ *ceiling = Ceiling::Shared(
+ cmp::max(current, task.priority),
+ );
+ }
+ }
Ceiling::Shared(old) => {
if task.priority > old {
*ceiling = Ceiling::Shared(task.priority);
@@ -40,7 +54,7 @@ pub fn compute_ceilings(app: &App) -> Ceilings {
continue;
}
- ceilings.insert(resource.clone(), Ceiling::Owned);
+ ceilings.insert(resource.clone(), Ceiling::Owned(task.priority));
}
}
diff --git a/src/lib.rs b/src/lib.rs
index f5c8b992..5d49af17 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -12,6 +12,7 @@ pub use cortex_m::asm::{bkpt, wfi};
pub use cortex_m::interrupt::CriticalSection;
pub use cortex_m::interrupt::free as atomic;
pub use static_ref::Static;
+use cortex_m::interrupt::Nr;
#[cfg(not(armv6m))]
use cortex_m::register::{basepri_max, basepri};
@@ -175,6 +176,16 @@ impl Threshold {
impl !Send for Threshold {}
+/// Sets an interrupt as pending
+pub fn set_pending<I>(interrupt: I)
+where
+ I: Nr,
+{
+ // NOTE(safe) atomic write
+ let nvic = unsafe { &*cortex_m::peripheral::NVIC.get() };
+ nvic.set_pending(interrupt);
+}
+
#[macro_export]
macro_rules! task {
($NAME:ident, $body:path) => {