diff options
Diffstat (limited to 'macros/src/trans.rs')
| -rw-r--r-- | macros/src/trans.rs | 631 |
1 files changed, 0 insertions, 631 deletions
diff --git a/macros/src/trans.rs b/macros/src/trans.rs deleted file mode 100644 index dcd6cfb..0000000 --- a/macros/src/trans.rs +++ /dev/null @@ -1,631 +0,0 @@ -use proc_macro2::{TokenStream, Span}; -use syn::{Ident, LitStr}; - -use analyze::Ownerships; -use check::{App, Kind}; - -fn krate() -> Ident { - Ident::new("rtfm", Span::call_site()) -} - -pub fn app(app: &App, ownerships: &Ownerships) -> TokenStream { - let mut root = vec![]; - let mut main = vec![quote!(#![allow(path_statements)])]; - - ::trans::tasks(app, ownerships, &mut root, &mut main); - ::trans::init(app, &mut main, &mut root); - ::trans::idle(app, ownerships, &mut main, &mut root); - ::trans::resources(app, ownerships, &mut root); - - root.push(quote! { - #[allow(unsafe_code)] - fn main() { - #(#main)* - } - }); - - quote!(#(#root)*) -} - -fn idle(app: &App, ownerships: &Ownerships, main: &mut Vec<TokenStream>, root: &mut Vec<TokenStream>) { - let krate = krate(); - - let mut mod_items = vec![]; - let mut tys = vec![]; - let mut exprs = vec![]; - - if !app.idle.resources.is_empty() { - tys.push(quote!(&mut #krate::Threshold)); - exprs.push(quote!(unsafe { &mut #krate::Threshold::new(0) })); - } - - if !app.idle.resources.is_empty() { - let mut needs_reexport = false; - for name in &app.idle.resources { - if ownerships[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", Span::call_site())) - }; - let mut rexprs = vec![]; - let mut rfields = vec![]; - for name in &app.idle.resources { - if ownerships[name].is_owned() { - let resource = app.resources.get(name).expect(&format!( - "BUG: resource {} assigned to `idle` has no definition", - name - )); - let ty = &resource.ty; - - rfields.push(quote! { - pub #name: &'static mut #ty, - }); - - let _name = Ident::new(&name.to_string(), Span::call_site()); - rexprs.push(if resource.expr.is_some() { - quote! { - #name: &mut #super_::#_name, - } - } else { - quote! { - #name: #super_::#_name.as_mut(), - } - }); - } else { - rfields.push(quote! { - pub #name: ::idle::#name, - }); - - rexprs.push(quote! { - #name: ::idle::#name { _0: ::core::marker::PhantomData }, - }); - } - } - - if needs_reexport { - root.push(quote! { - #[allow(non_camel_case_types)] - #[allow(non_snake_case)] - pub struct _idleResources { - #(#rfields)* - } - }); - - mod_items.push(quote! { - pub use ::_idleResources as Resources; - }); - } else { - mod_items.push(quote! { - #[allow(non_snake_case)] - pub struct Resources { - #(#rfields)* - } - }); - } - - mod_items.push(quote! { - #[allow(unsafe_code)] - impl Resources { - pub unsafe fn new() -> Self { - Resources { - #(#rexprs)* - } - } - } - }); - - tys.push(quote!(idle::Resources)); - exprs.push(quote!(unsafe { idle::Resources::new() })); - } - - let device = &app.device; - for name in &app.idle.resources { - let ceiling = ownerships[name].ceiling(); - - // owned resource - if ceiling == 0 { - continue; - } - - let _name = Ident::new(&name.to_string(), Span::call_site()); - let resource = app.resources - .get(name) - .expect(&format!("BUG: resource {} has no definition", name)); - - let ty = &resource.ty; - let _static = if resource.expr.is_some() { - quote!(#_name) - } else { - quote!(#_name.some) - }; - - mod_items.push(quote! { - #[allow(non_camel_case_types)] - pub struct #name { _0: ::core::marker::PhantomData<*const ()> } - }); - - root.push(quote! { - #[allow(unsafe_code)] - unsafe impl #krate::Resource for idle::#name { - type Data = #ty; - - fn borrow<'cs>(&'cs self, t: &'cs Threshold) -> &'cs Self::Data { - assert!(t.value() >= #ceiling); - - unsafe { &#_static } - } - - fn borrow_mut<'cs>( - &'cs mut self, - t: &'cs Threshold, - ) -> &'cs mut Self::Data { - assert!(t.value() >= #ceiling); - - unsafe { &mut #_static } - } - - fn claim<R, F>(&self, t: &mut Threshold, f: F) -> R - where - F: FnOnce(&Self::Data, &mut Threshold) -> R - { - unsafe { - #krate::claim( - &#_static, - #ceiling, - #device::NVIC_PRIO_BITS, - t, - f, - ) - } - } - - fn claim_mut<R, F>(&mut self, t: &mut Threshold, f: F) -> R - where - F: FnOnce(&mut Self::Data, &mut Threshold) -> R - { - unsafe { - #krate::claim( - &mut #_static, - #ceiling, - #device::NVIC_PRIO_BITS, - t, - f, - ) - } - } - } - }); - } - - if !mod_items.is_empty() { - root.push(quote! { - #[allow(unsafe_code)] - mod idle { - #(#mod_items)* - } - }); - } - - let idle = &app.idle.path; - main.push(quote! { - // type check - let idle: fn(#(#tys),*) -> ! = #idle; - - idle(#(#exprs),*); - }); -} - -fn init(app: &App, main: &mut Vec<TokenStream>, root: &mut Vec<TokenStream>) { - let device = &app.device; - let krate = krate(); - - let mut tys = vec![quote!(init::Peripherals)]; - let mut exprs = vec![ - quote!{ - init::Peripherals { - core: ::#device::CorePeripherals::steal(), - device: ::#device::Peripherals::steal(), - } - }, - ]; - let mut ret = None; - let mut mod_items = vec![]; - - let (init_resources, late_resources): (Vec<_>, Vec<_>) = app.resources - .iter() - .partition(|&(_, res)| res.expr.is_some()); - - if !init_resources.is_empty() { - let mut fields = vec![]; - let mut lifetime = None; - let mut rexprs = vec![]; - - for (name, resource) in init_resources { - let ty = &resource.ty; - - if app.init.resources.contains(name) { - fields.push(quote! { - pub #name: &'static mut #ty, - }); - - let expr = &resource.expr; - rexprs.push(quote!(#name: { - static mut #name: #ty = #expr; - &mut #name - },)); - } else { - let _name = Ident::new(&name.to_string(), Span::call_site()); - lifetime = Some(quote!('a)); - - fields.push(quote! { - pub #name: &'a mut #ty, - }); - - rexprs.push(quote! { - #name: &mut ::#_name, - }); - } - } - - 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; - - #[allow(unsafe_code)] - impl<#lifetime> Resources<#lifetime> { - pub unsafe fn new() -> Self { - Resources { - #(#rexprs)* - } - } - } - }); - - tys.push(quote!(init::Resources)); - exprs.push(quote!(init::Resources::new())); - } - - // Initialization statements for late resources - let mut late_resource_init = vec![]; - - if !late_resources.is_empty() { - // `init` must initialize and return resources - - let mut fields = vec![]; - - for (name, resource) in late_resources { - let _name = Ident::new(&name.to_string(), Span::call_site()); - - let ty = &resource.ty; - - fields.push(quote! { - pub #name: #ty, - }); - - late_resource_init.push(quote! { - #_name = #krate::UntaggedOption { some: _late_resources.#name }; - }); - } - - root.push(quote! { - #[allow(non_camel_case_types)] - #[allow(non_snake_case)] - pub struct _initLateResources { - #(#fields)* - } - }); - - mod_items.push(quote! { - pub use ::_initLateResources as LateResources; - }); - - // `init` must return the initialized resources - ret = Some(quote!( -> ::init::LateResources)); - } - - root.push(quote! { - #[allow(unsafe_code)] - mod init { - pub struct Peripherals { - pub core: ::#device::CorePeripherals, - pub device: ::#device::Peripherals, - } - - #(#mod_items)* - } - }); - - let mut exceptions = vec![]; - let mut interrupts = vec![]; - for (name, task) in &app.tasks { - match task.kind { - Kind::Exception(ref e) => { - if exceptions.is_empty() { - exceptions.push(quote! { - let scb = &*#device::SCB::ptr(); - }); - } - - let nr = e.nr(); - 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[#nr - 4].write(hw); - }); - } - Kind::Interrupt { enabled } => { - // Interrupt. These are enabled / disabled through the NVIC - if interrupts.is_empty() { - interrupts.push(quote! { - use #device::Interrupt; - - let mut nvic: #device::NVIC = core::mem::transmute(()); - }); - } - - 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(Interrupt::#name, hw); - }); - - if enabled { - interrupts.push(quote! { - nvic.enable(Interrupt::#name); - }); - } else { - interrupts.push(quote! { - nvic.disable(Interrupt::#name); - }); - } - } - } - } - - let init = &app.init.path; - main.push(quote! { - // type check - let init: fn(#(#tys,)*) #ret = #init; - - #krate::atomic(unsafe { &mut #krate::Threshold::new(0) }, |_t| unsafe { - let _late_resources = init(#(#exprs,)*); - #(#late_resource_init)* - - #(#exceptions)* - #(#interrupts)* - }); - }); -} - -fn resources(app: &App, ownerships: &Ownerships, root: &mut Vec<TokenStream>) { - let krate = krate(); - - for name in ownerships.keys() { - let _name = Ident::new(&name.to_string(), Span::call_site()); - - // Declare the static that holds the resource - let resource = app.resources - .get(name) - .expect(&format!("BUG: resource {} has no definition", name)); - - let expr = &resource.expr; - let ty = &resource.ty; - - root.push(match *expr { - Some(ref expr) => quote! { - static mut #_name: #ty = #expr; - }, - None => quote! { - // Resource initialized in `init` - static mut #_name: #krate::UntaggedOption<#ty> = - #krate::UntaggedOption { none: () }; - }, - }); - } -} - -fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<TokenStream>, main: &mut Vec<TokenStream>) { - let device = &app.device; - let krate = krate(); - - for (tname, task) in &app.tasks { - let mut exprs = vec![]; - let mut fields = vec![]; - let mut items = vec![]; - - let has_resources = !task.resources.is_empty(); - - if has_resources { - for rname in &task.resources { - let ceiling = ownerships[rname].ceiling(); - let _rname = Ident::new(&rname.to_string(), Span::call_site()); - let resource = app.resources - .get(rname) - .expect(&format!("BUG: resource {} has no definition", rname)); - - let ty = &resource.ty; - let _static = if resource.expr.is_some() { - quote!(#_rname) - } else { - quote!(#_rname.some) - }; - - items.push(quote! { - #[allow(non_camel_case_types)] - pub struct #rname { _0: PhantomData<*const ()> } - }); - - root.push(quote! { - #[allow(unsafe_code)] - unsafe impl #krate::Resource for #tname::#rname { - type Data = #ty; - - fn borrow<'cs>(&'cs self, t: &'cs Threshold) -> &'cs Self::Data { - assert!(t.value() >= #ceiling); - - unsafe { &#_static } - } - - fn borrow_mut<'cs>( - &'cs mut self, - t: &'cs Threshold, - ) -> &'cs mut Self::Data { - assert!(t.value() >= #ceiling); - - unsafe { &mut #_static } - } - - fn claim<R, F>(&self, t: &mut Threshold, f: F) -> R - where - F: FnOnce(&Self::Data, &mut Threshold) -> R - { - unsafe { - #krate::claim( - &#_static, - #ceiling, - #device::NVIC_PRIO_BITS, - t, - f, - ) - } - } - - fn claim_mut<R, F>(&mut self, t: &mut Threshold, f: F) -> R - where - F: FnOnce(&mut Self::Data, &mut Threshold) -> R - { - unsafe { - #krate::claim( - &mut #_static, - #ceiling, - #device::NVIC_PRIO_BITS, - t, - f, - ) - } - } - } - }); - - if ceiling <= task.priority { - root.push(quote! { - #[allow(unsafe_code)] - impl core::ops::Deref for #tname::#rname { - type Target = #ty; - - fn deref(&self) -> &Self::Target { - unsafe { &#_static } - } - } - - #[allow(unsafe_code)] - impl core::ops::DerefMut for #tname::#rname { - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { &mut #_static } - } - } - }) - } - - fields.push(quote! { - pub #rname: #rname, - }); - - exprs.push(quote! { - #rname: #rname { _0: PhantomData }, - }); - } - - items.push(quote! { - #[allow(non_snake_case)] - pub struct Resources { - #(#fields)* - } - }); - - items.push(quote! { - #[allow(unsafe_code)] - impl Resources { - pub unsafe fn new() -> Self { - Resources { - #(#exprs)* - } - } - } - }); - } - - let mut tys = vec![]; - let mut exprs = vec![]; - - let priority = task.priority; - if has_resources { - tys.push(quote!(&mut #krate::Threshold)); - exprs.push(quote! { - &mut if #priority == 1 << #device::NVIC_PRIO_BITS { - #krate::Threshold::new(::core::u8::MAX) - } else { - #krate::Threshold::new(#priority) - } - }); - } - - if has_resources { - tys.push(quote!(#tname::Resources)); - exprs.push(quote!(#tname::Resources::new())); - } - - let path = &task.path; - let _tname = Ident::new(&tname.to_string(), Span::call_site()); - let export_name = LitStr::new(&tname.to_string(), Span::call_site()); - root.push(quote! { - #[allow(non_snake_case)] - #[allow(unsafe_code)] - #[export_name = #export_name] - pub unsafe extern "C" fn #_tname() { - let f: fn(#(#tys,)*) = #path; - - f(#(#exprs,)*) - } - }); - - root.push(quote!{ - #[allow(non_snake_case)] - #[allow(unsafe_code)] - mod #tname { - #[allow(unused_imports)] - use core::marker::PhantomData; - - #[allow(dead_code)] - #[deny(const_err)] - pub const CHECK_PRIORITY: (u8, u8) = ( - #priority - 1, - (1 << ::#device::NVIC_PRIO_BITS) - #priority, - ); - - #(#items)* - } - }); - - // after miri landed (?) rustc won't analyze `const` items unless they are used so we force - // evaluation with this path statement - main.push(quote!(#tname::CHECK_PRIORITY;)); - } -} |
