aboutsummaryrefslogtreecommitdiff
path: root/macros/src/trans.rs
diff options
context:
space:
mode:
Diffstat (limited to 'macros/src/trans.rs')
-rw-r--r--macros/src/trans.rs470
1 files changed, 234 insertions, 236 deletions
diff --git a/macros/src/trans.rs b/macros/src/trans.rs
index 13dc51d1..7f5b2787 100644
--- a/macros/src/trans.rs
+++ b/macros/src/trans.rs
@@ -1,21 +1,21 @@
-use quote::Tokens;
-use syn::Ident;
+use quote::{Ident, Tokens};
-use syntax::{App, Kind};
-use util::{Ceiling, Ceilings};
+use analyze::{Ownership, Ownerships};
+use check::App;
fn krate() -> Ident {
- Ident::new("rtfm")
+ Ident::from("rtfm")
}
-pub fn app(app: &App, ceilings: &Ceilings) -> Tokens {
- let mut main = vec![];
+pub fn app(app: &App, ownerships: &Ownerships) -> Tokens {
let mut root = vec![];
+ let mut main = vec![];
- super::trans::init(app, &mut main, &mut root);
- super::trans::idle(app, ceilings, &mut main, &mut root);
- super::trans::resources(app, ceilings, &mut root);
- super::trans::tasks(app, ceilings, &mut root);
+ // ::trans::check(app, &mut main);
+ ::trans::init(app, &mut main, &mut root);
+ ::trans::idle(app, ownerships, &mut main, &mut root);
+ ::trans::resources(app, ownerships, &mut root);
+ ::trans::tasks(app, ownerships, &mut root);
root.push(quote! {
fn main() {
@@ -26,127 +26,15 @@ pub fn app(app: &App, ceilings: &Ceilings) -> Tokens {
quote!(#(#root)*)
}
-fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
- let device = &app.device;
- let krate = krate();
-
- let mut tys = vec![quote!(init::Peripherals)];
- let mut exprs = vec![quote!(init::Peripherals::all())];
- let mut mod_items = vec![];
-
- if !app.resources.is_empty() {
- let mut fields = vec![];
- let mut lifetime = None;
- let mut rexprs = vec![];
-
- for (name, resource) in &app.resources {
- lifetime = Some(quote!('a));
-
- let ty = &resource.ty;
-
- fields.push(quote! {
- pub #name: &'a mut #krate::Static<#ty>,
- });
-
- rexprs.push(quote! {
- #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_items.push(quote! {
- pub use ::_initResources as Resources;
-
- impl<#lifetime> Resources<#lifetime> {
- pub unsafe fn new() -> Self {
- Resources {
- #(#rexprs)*
- }
- }
- }
- });
-
- tys.push(quote!(init::Resources));
- exprs.push(quote!(init::Resources::new()));
- }
-
- root.push(quote! {
- mod init {
- pub use ::#device::Peripherals;
-
- #(#mod_items)*
- }
- });
-
- let mut exceptions = vec![];
- let mut interrupts = vec![];
- for (name, task) in &app.tasks {
- match task.kind {
- Kind::Exception => {
- if exceptions.is_empty() {
- exceptions.push(quote! {
- let scb = #device::SCB.borrow(_cs);
- });
- }
-
- let priority = task.priority;
- exceptions.push(quote! {
- let prio_bits = #device::NVIC_PRIO_BITS;
- let hw = ((1 << prio_bits) - #priority) << (8 - prio_bits);
- scb.shpr[#krate::Exception::#name.nr() - 4].write(hw);
- });
- }
- Kind::Interrupt { enabled } => {
- if interrupts.is_empty() {
- interrupts.push(quote! {
- let nvic = #device::NVIC.borrow(_cs);
- });
- }
-
- let priority = task.priority;
- interrupts.push(quote! {
- let prio_bits = #device::NVIC_PRIO_BITS;
- let hw = ((1 << prio_bits) - #priority) << (8 - prio_bits);
- nvic.set_priority(#device::Interrupt::#name, hw);
- });
-
- if enabled {
- interrupts.push(quote! {
- nvic.enable(#device::Interrupt::#name);
- });
- } else {
- interrupts.push(quote! {
- nvic.disable(#device::Interrupt::#name);
- });
- }
- }
- }
- }
-
- let init = &app.init.path;
- main.push(quote! {
- // type check
- let init: fn(#(#tys,)*) = #init;
-
- #krate::atomic(|_cs| unsafe {
- init(#(#exprs,)*);
-
- #(#exceptions)*
- #(#interrupts)*
- });
- });
-}
+// Check that the exceptions / interrupts are valid
+// Sadly we can't do this test at expansion time. Instead we'll generate some
+// code that won't compile if the interrupt name is invalid.
+// fn check(app: &App, main: &mut Vec<Tokens>) {
+// }
fn idle(
app: &App,
- ceilings: &Ceilings,
+ ownerships: &Ownerships,
main: &mut Vec<Tokens>,
root: &mut Vec<Tokens>,
) {
@@ -160,17 +48,17 @@ fn idle(
!app.idle
.resources
.iter()
- .all(|resource| ceilings[resource].is_owned())
+ .all(|resource| ownerships[resource].is_owned())
{
tys.push(quote!(#krate::Threshold));
exprs.push(quote!(unsafe { #krate::Threshold::new(0) }));
}
- if !app.idle.local.is_empty() {
+ if !app.idle.locals.is_empty() {
let mut lexprs = vec![];
let mut lfields = vec![];
- for (name, resource) in &app.idle.local {
+ for (name, resource) in &app.idle.locals {
let expr = &resource.expr;
let ty = &resource.ty;
@@ -184,16 +72,16 @@ fn idle(
}
mod_items.push(quote! {
- pub struct Local {
+ pub struct Locals {
#(#lfields)*
}
});
- tys.push(quote!(&'static mut idle::Local));
- exprs.push(quote!(unsafe { &mut LOCAL }));
+ tys.push(quote!(&'static mut idle::Locals));
+ exprs.push(quote!(unsafe { &mut LOCALS }));
main.push(quote! {
- static mut LOCAL: idle::Local = idle::Local {
+ static mut LOCALS: idle::Locals = idle::Locals {
#(#lexprs)*
};
});
@@ -205,10 +93,10 @@ fn idle(
let mut needs_reexport = false;
for name in &app.idle.resources {
- if ceilings[name].is_owned() {
+ if ownerships[name].is_owned() {
if app.resources.get(name).is_some() {
needs_reexport = true;
- break
+ break;
}
}
}
@@ -221,7 +109,7 @@ fn idle(
let mut rexprs = vec![];
let mut rfields = vec![];
for name in &app.idle.resources {
- if ceilings[name].is_owned() {
+ if ownerships[name].is_owned() {
lifetime = Some(quote!('a));
if let Some(resource) = app.resources.get(name) {
let ty = &resource.ty;
@@ -305,121 +193,134 @@ fn idle(
});
}
-fn tasks(app: &App, ceilings: &Ceilings, root: &mut Vec<Tokens>) {
+fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
+ let device = &app.device;
let krate = krate();
- for (name, task) in &app.tasks {
- let mut exprs = vec![];
- let mut fields = vec![];
- let mut items = vec![];
+ let mut tys = vec![quote!(#device::Peripherals)];
+ let mut exprs = vec![quote!(#device::Peripherals::all())];
+ let mut mod_items = vec![];
- let device = &app.device;
+ if !app.resources.is_empty() {
+ let mut fields = vec![];
let mut lifetime = None;
- let mut needs_reexport = false;
- for name in &task.resources {
- match ceilings[name] {
- Ceiling::Shared(ceiling) if ceiling > task.priority => {
- fields.push(quote! {
- pub #name: super::_resource::#name,
- });
-
- exprs.push(quote! {
- #name: {
- super::_resource::#name::new()
- },
- });
- }
- _ => {
- lifetime = Some(quote!('a));
- if let Some(resource) = app.resources.get(name) {
- needs_reexport = true;
- let ty = &resource.ty;
-
- fields.push(quote! {
- pub #name: &'a mut ::#krate::Static<#ty>,
- });
+ let mut rexprs = vec![];
- exprs.push(quote! {
- #name: ::#krate::Static::ref_mut(
- &mut *super::#name.get(),
- ),
- });
- } else {
- fields.push(quote! {
- pub #name: &'a mut ::#device::#name,
- });
+ for (name, resource) in &app.resources {
+ lifetime = Some(quote!('a));
- exprs.push(quote! {
- #name: &mut *::#device::#name.get(),
- });
- }
- }
- }
- }
+ let ty = &resource.ty;
- 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)*
- }
+ fields.push(quote! {
+ pub #name: &'a mut #krate::Static<#ty>,
});
- items.push(quote! {
- pub use ::#rname as Resources;
- });
- } else {
- items.push(quote! {
- #[allow(non_snake_case)]
- pub struct Resources<#lifetime> {
- #(#fields)*
- }
+ rexprs.push(quote! {
+ #name: ::#krate::Static::ref_mut(&mut *super::#name.get()),
});
}
- items.push(quote! {
+ root.push(quote! {
+ #[allow(non_camel_case_types)]
+ #[allow(non_snake_case)]
+ pub struct _initResources<#lifetime> {
+ #(#fields)*
+ }
+ });
+
+ mod_items.push(quote! {
+ pub use ::_initResources as Resources;
+
impl<#lifetime> Resources<#lifetime> {
pub unsafe fn new() -> Self {
Resources {
- #(#exprs)*
+ #(#rexprs)*
}
}
}
});
- let priority = task.priority;
- root.push(quote!{
- #[allow(dead_code)]
- #[allow(non_snake_case)]
- mod #name {
- #[deny(dead_code)]
- pub const #name: u8 = #priority;
- #[deny(const_err)]
- const CHECK_PRIORITY: (u8, u8) = (
- #priority - 1,
- (1 << ::#device::NVIC_PRIO_BITS) - #priority,
- );
+ tys.push(quote!(init::Resources));
+ exprs.push(quote!(init::Resources::new()));
+ }
- #(#items)*
+ root.push(quote! {
+ mod init {
+ pub use ::#device::Peripherals;
+
+ #(#mod_items)*
+ }
+ });
+
+ let mut exceptions = vec![];
+ let mut interrupts = vec![];
+ for (name, task) in &app.tasks {
+ if let Some(enabled) = task.enabled {
+ // Interrupt. These can be enabled / disabled through the NVIC
+ if interrupts.is_empty() {
+ interrupts.push(quote! {
+ let nvic = #device::NVIC.borrow(_cs);
+ });
}
- });
+ let priority = task.priority;
+ interrupts.push(quote! {
+ let prio_bits = #device::NVIC_PRIO_BITS;
+ let hw = ((1 << prio_bits) - #priority) << (8 - prio_bits);
+ nvic.set_priority(#device::Interrupt::#name, hw);
+ });
+
+ if enabled {
+ interrupts.push(quote! {
+ nvic.enable(#device::Interrupt::#name);
+ });
+ } else {
+ interrupts.push(quote! {
+ nvic.disable(#device::Interrupt::#name);
+ });
+ }
+ } else {
+ // Exception
+ if exceptions.is_empty() {
+ exceptions.push(quote! {
+ let scb = #device::SCB.borrow(_cs);
+ });
+ }
+
+ let priority = task.priority;
+ exceptions.push(quote! {
+ let prio_bits = #device::NVIC_PRIO_BITS;
+ let hw = ((1 << prio_bits) - #priority) << (8 - prio_bits);
+ scb.shpr[#krate::Exception::#name.nr() - 4].write(hw);
+ });
+ }
}
+
+ let init = &app.init.path;
+ main.push(quote! {
+ // type check
+ let init: fn(#(#tys,)*) = #init;
+
+ #krate::atomic(|_cs| unsafe {
+ init(#(#exprs,)*);
+
+ #(#exceptions)*
+ #(#interrupts)*
+ });
+ });
}
-fn resources(app: &App, ceilings: &Ceilings, root: &mut Vec<Tokens>) {
+fn resources(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
let krate = krate();
let device = &app.device;
let mut items = vec![];
let mut impls = vec![];
- for (name, ceiling) in ceilings {
+ for (name, ownership) in ownerships {
let mut impl_items = vec![];
- match *ceiling {
- Ceiling::Owned(_) => {
+ match *ownership {
+ Ownership::Owned { .. } => {
if let Some(resource) = app.resources.get(name) {
// For owned resources we don't need claim() or borrow(),
// just get()
@@ -432,10 +333,10 @@ fn resources(app: &App, ceilings: &Ceilings, root: &mut Vec<Tokens>) {
});
} else {
// Peripheral
- continue
+ continue;
}
- },
- Ceiling::Shared(ceiling) => {
+ }
+ Ownership::Shared { ceiling } => {
if let Some(resource) = app.resources.get(name) {
let expr = &resource.expr;
let ty = &resource.ty;
@@ -448,20 +349,16 @@ fn resources(app: &App, ceilings: &Ceilings, root: &mut Vec<Tokens>) {
impl_items.push(quote! {
pub fn borrow<'cs>(
&'cs self,
- _cs: &'cs #krate::CriticalSection,
+ cs: &'cs #krate::CriticalSection,
) -> &'cs #krate::Static<#ty> {
- unsafe {
- #krate::Static::ref_(&*#name.get())
- }
+ unsafe { #name.borrow(cs) }
}
pub fn borrow_mut<'cs>(
&'cs mut self,
- _cs: &'cs #krate::CriticalSection,
+ cs: &'cs #krate::CriticalSection,
) -> &'cs mut #krate::Static<#ty> {
- unsafe {
- #krate::Static::ref_mut(&mut *#name.get())
- }
+ unsafe { #name.borrow_mut(cs) }
}
pub fn claim<R, F>(
@@ -513,11 +410,9 @@ fn resources(app: &App, ceilings: &Ceilings, root: &mut Vec<Tokens>) {
impl_items.push(quote! {
pub fn borrow<'cs>(
&'cs self,
- _cs: &'cs #krate::CriticalSection,
+ cs: &'cs #krate::CriticalSection,
) -> &'cs #device::#name {
- unsafe {
- &*#name.get()
- }
+ unsafe { #name.borrow(cs) }
}
pub fn claim<R, F>(
@@ -571,3 +466,106 @@ fn resources(app: &App, ceilings: &Ceilings, root: &mut Vec<Tokens>) {
#(#impls)*
});
}
+
+fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
+ let device = &app.device;
+ let krate = krate();
+
+ for (name, task) in &app.tasks {
+ let mut exprs = vec![];
+ let mut fields = vec![];
+ let mut items = vec![];
+
+ let mut lifetime = None;
+ let mut needs_reexport = false;
+ for name in &task.resources {
+ match ownerships[name] {
+ Ownership::Shared { ceiling } if ceiling > task.priority => {
+ fields.push(quote! {
+ pub #name: super::_resource::#name,
+ });
+
+ exprs.push(quote! {
+ #name: {
+ super::_resource::#name::new()
+ },
+ });
+ }
+ _ => {
+ lifetime = Some(quote!('a));
+ if let Some(resource) = app.resources.get(name) {
+ needs_reexport = true;
+ let ty = &resource.ty;
+
+ fields.push(quote! {
+ pub #name: &'a mut ::#krate::Static<#ty>,
+ });
+
+ exprs.push(quote! {
+ #name: ::#krate::Static::ref_mut(
+ &mut *super::#name.get(),
+ ),
+ });
+ } else {
+ fields.push(quote! {
+ pub #name: &'a mut ::#device::#name,
+ });
+
+ exprs.push(quote! {
+ #name: &mut *::#device::#name.get(),
+ });
+ }
+ }
+ }
+ }
+
+ 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> {
+ pub unsafe fn new() -> Self {
+ Resources {
+ #(#exprs)*
+ }
+ }
+ }
+ });
+
+ let priority = task.priority;
+ root.push(quote!{
+ #[allow(dead_code)]
+ #[allow(non_snake_case)]
+ mod #name {
+ #[deny(dead_code)]
+ pub const #name: u8 = #priority;
+ #[deny(const_err)]
+ const CHECK_PRIORITY: (u8, u8) = (
+ #priority - 1,
+ (1 << ::#device::NVIC_PRIO_BITS) - #priority,
+ );
+
+ #(#items)*
+ }
+ });
+ }
+}