diff --git a/Cargo.toml b/Cargo.toml index 5675d76749..37db8565e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,13 +10,13 @@ keywords = ["arm", "cortex-m"] license = "MIT OR Apache-2.0" name = "cortex-m-rtfm" repository = "https://github.com/japaric/cortex-m-rtfm" -version = "0.2.2" +version = "0.3.0" [dependencies] -cortex-m = "0.3.1" +cortex-m = { git = "https://github.com/japaric/cortex-m" } untagged-option = "0.1.1" rtfm-core = "0.1.0" -cortex-m-rtfm-macros = "0.2.1" +cortex-m-rtfm-macros = { path = "macros" } [target.'cfg(target_arch = "x86_64")'.dev-dependencies] compiletest_rs = "0.3.3" @@ -27,7 +27,8 @@ version = "0.3.3" [dev-dependencies.stm32f103xx] features = ["rt"] -version = "0.7.5" +git = "https://github.com/japaric/stm32f103xx" +# version = "0.8.0" [profile.release] lto = true diff --git a/examples/generics.rs b/examples/generics.rs index 57c9b8ebc6..afcafa0a40 100644 --- a/examples/generics.rs +++ b/examples/generics.rs @@ -12,6 +12,11 @@ use stm32f103xx::{SPI1, GPIOA}; app! { device: stm32f103xx, + resources: { + static GPIOA: GPIOA; + static SPI1: SPI1; + }, + tasks: { EXTI0: { path: exti0, @@ -27,7 +32,12 @@ app! { }, } -fn init(_p: init::Peripherals) {} +fn init(p: init::Peripherals) -> init::LateResourceValues { + init::LateResourceValues { + GPIOA: p.device.GPIOA, + SPI1: p.device.SPI1, + } +} fn idle() -> ! { loop { diff --git a/examples/one-task.rs b/examples/one-task.rs index e58d9fcd90..38f0135467 100644 --- a/examples/one-task.rs +++ b/examples/one-task.rs @@ -7,8 +7,9 @@ extern crate cortex_m; extern crate cortex_m_rtfm as rtfm; extern crate stm32f103xx; -use cortex_m::peripheral::SystClkSource; +use cortex_m::peripheral::syst::SystClkSource; use rtfm::{app, Threshold}; +use stm32f103xx::GPIOC; app! { device: stm32f103xx, @@ -35,9 +36,8 @@ app! { // These are the resources this task has access to. // - // A resource can be a peripheral like `GPIOC` or a static variable - // like `ON` - resources: [GPIOC, ON], + // The resources listed here must also appear in `app.resources` + resources: [ON], }, } } @@ -47,19 +47,20 @@ fn init(p: init::Peripherals, r: init::Resources) { r.ON; // power on GPIOC - p.RCC.apb2enr.modify(|_, w| w.iopcen().enabled()); + p.device.RCC.apb2enr.modify(|_, w| w.iopcen().enabled()); // configure PC13 as output - p.GPIOC.bsrr.write(|w| w.bs13().set()); - p.GPIOC + p.device.GPIOC.bsrr.write(|w| w.bs13().set()); + p.device + .GPIOC .crh .modify(|_, w| w.mode13().output().cnf13().push()); // configure the system timer to generate one interrupt every second - p.SYST.set_clock_source(SystClkSource::Core); - p.SYST.set_reload(8_000_000); // 1s - p.SYST.enable_interrupt(); - p.SYST.enable_counter(); + p.core.SYST.set_clock_source(SystClkSource::Core); + p.core.SYST.set_reload(8_000_000); // 1s + p.core.SYST.enable_interrupt(); + p.core.SYST.enable_counter(); } fn idle() -> ! { @@ -74,15 +75,22 @@ fn idle() -> ! { // // `r` is the set of resources this task has access to. `SYS_TICK::Resources` // has one field per resource declared in `app!`. +#[allow(unsafe_code)] fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) { // toggle state **r.ON = !**r.ON; if **r.ON { // set the pin PC13 high - r.GPIOC.bsrr.write(|w| w.bs13().set()); + // NOTE(unsafe) atomic write to a stateless register + unsafe { + (*GPIOC::ptr()).bsrr.write(|w| w.bs13().set()); + } } else { // set the pin PC13 low - r.GPIOC.bsrr.write(|w| w.br13().reset()); + // NOTE(unsafe) atomic write to a stateless register + unsafe { + (*GPIOC::ptr()).bsrr.write(|w| w.br13().reset()); + } } } diff --git a/examples/zero-tasks.rs b/examples/zero-tasks.rs index 9176103d43..58e6afc76c 100644 --- a/examples/zero-tasks.rs +++ b/examples/zero-tasks.rs @@ -25,8 +25,9 @@ app! { // this function. fn init(p: init::Peripherals) { // This function has access to all the peripherals of the device - p.GPIOA; - p.RCC; + p.core.SYST; + p.device.GPIOA; + p.device.RCC; // .. } diff --git a/macros/src/check.rs b/macros/src/check.rs index 3cd112acfd..63cac1fa5e 100644 --- a/macros/src/check.rs +++ b/macros/src/check.rs @@ -63,16 +63,15 @@ pub fn app(app: check::App) -> Result { tasks: app.tasks .into_iter() .map(|(k, v)| { - let v = ::check::task(k.as_ref(), v) - .chain_err(|| format!("checking task `{}`", k))?; + let v = + ::check::task(k.as_ref(), v).chain_err(|| format!("checking task `{}`", k))?; Ok((k, v)) }) .collect::>()?, }; - ::check::resources(&app) - .chain_err(|| "checking `resources`")?; + ::check::resources(&app).chain_err(|| "checking `resources`")?; Ok(app) } @@ -93,6 +92,17 @@ fn resources(app: &App) -> Result<()> { bail!("resource `{}` is unused", resource); } + for (name, task) in &app.tasks { + for resource in &task.resources { + ensure!( + app.resources.contains_key(&resource), + "task {} contains an undeclared resource with name {}", + name, + resource + ); + } + } + Ok(()) } diff --git a/macros/src/trans.rs b/macros/src/trans.rs index 96ff770b64..bc69f24e95 100644 --- a/macros/src/trans.rs +++ b/macros/src/trans.rs @@ -27,12 +27,7 @@ pub fn app(app: &App, ownerships: &Ownerships) -> Tokens { quote!(#(#root)*) } -fn idle( - app: &App, - ownerships: &Ownerships, - main: &mut Vec, - root: &mut Vec, -) { +fn idle(app: &App, ownerships: &Ownerships, main: &mut Vec, root: &mut Vec) { let krate = krate(); let mut mod_items = vec![]; @@ -45,8 +40,6 @@ fn idle( } if !app.idle.resources.is_empty() { - let device = &app.device; - let mut needs_reexport = false; for name in &app.idle.resources { if ownerships[name].is_owned() { @@ -66,32 +59,26 @@ fn idle( let mut rfields = vec![]; for name in &app.idle.resources { if ownerships[name].is_owned() { - if let Some(resource) = app.resources.get(name) { - let ty = &resource.ty; + 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, - }); + rfields.push(quote! { + pub #name: &'static mut #ty, + }); - let _name = Ident::new(format!("_{}", name.as_ref())); - rexprs.push(if resource.expr.is_some() { - quote! { - #name: &mut #super_::#_name, - } - } else { - quote! { - #name: #super_::#_name.as_mut(), - } - }); + let _name = Ident::new(format!("_{}", name.as_ref())); + rexprs.push(if resource.expr.is_some() { + quote! { + #name: &mut #super_::#_name, + } } else { - rfields.push(quote! { - pub #name: &'static mut ::#device::#name, - }); - - rexprs.push(quote! { - #name: &mut *::#device::#name.get(), - }); - } + quote! { + #name: #super_::#_name.as_mut(), + } + }); } else { rfields.push(quote! { pub #name: #super_::_resource::#name, @@ -161,12 +148,20 @@ fn init(app: &App, main: &mut Vec, root: &mut Vec) { let device = &app.device; let krate = krate(); - let mut tys = vec![quote!(#device::Peripherals)]; - let mut exprs = vec![quote!(#device::Peripherals::all())]; + 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() + let (init_resources, late_resources): (Vec<_>, Vec<_>) = app.resources + .iter() .partition(|&(_, res)| res.expr.is_some()); if !init_resources.is_empty() { @@ -255,7 +250,10 @@ fn init(app: &App, main: &mut Vec, root: &mut Vec) { root.push(quote! { #[allow(unsafe_code)] mod init { - pub use ::#device::Peripherals; + pub struct Peripherals { + pub core: ::#device::CorePeripherals, + pub device: ::#device::Peripherals, + } #(#mod_items)* } @@ -268,7 +266,7 @@ fn init(app: &App, main: &mut Vec, root: &mut Vec) { Kind::Exception(ref e) => { if exceptions.is_empty() { exceptions.push(quote! { - let scb = &*#device::SCB.get(); + let scb = &*#device::SCB::ptr(); }); } @@ -284,7 +282,7 @@ fn init(app: &App, main: &mut Vec, root: &mut Vec) { // Interrupt. These can be enabled / disabled through the NVIC if interrupts.is_empty() { interrupts.push(quote! { - let nvic = &*#device::NVIC.get(); + let nvic = &*#device::NVIC::ptr(); }); } @@ -355,154 +353,81 @@ fn resources(app: &App, ownerships: &Ownerships, root: &mut Vec) { // For owned resources we don't need claim() or borrow() } Ownership::Shared { ceiling } => { - if let Some(resource) = app.resources.get(name) { - let ty = &resource.ty; - let res_rvalue = if resource.expr.is_some() { - quote!(#_name) - } else { - quote!(#_name.some) - }; - - impl_items.push(quote! { - type Data = #ty; - - fn borrow<'cs>( - &'cs self, - t: &'cs #krate::Threshold, - ) -> &'cs #krate::Static<#ty> { - assert!(t.value() >= #ceiling); - - unsafe { #krate::Static::ref_(&#res_rvalue) } - } - - fn borrow_mut<'cs>( - &'cs mut self, - t: &'cs #krate::Threshold, - ) -> &'cs mut #krate::Static<#ty> { - assert!(t.value() >= #ceiling); - - unsafe { - #krate::Static::ref_mut(&mut #res_rvalue) - } - } - - fn claim( - &self, - t: &mut #krate::Threshold, - f: F, - ) -> R - where - F: FnOnce( - &#krate::Static<#ty>, - &mut #krate::Threshold) -> R - { - unsafe { - #krate::claim( - #krate::Static::ref_(&#res_rvalue), - #ceiling, - #device::NVIC_PRIO_BITS, - t, - f, - ) - } - } - - fn claim_mut( - &mut self, - t: &mut #krate::Threshold, - f: F, - ) -> R - where - F: FnOnce( - &mut #krate::Static<#ty>, - &mut #krate::Threshold) -> R - { - unsafe { - #krate::claim( - #krate::Static::ref_mut(&mut #res_rvalue), - #ceiling, - #device::NVIC_PRIO_BITS, - t, - f, - ) - } - } - }); + let resource = app.resources + .get(name) + .expect(&format!("BUG: resource {} has no definition", name)); + let ty = &resource.ty; + let res_rvalue = if resource.expr.is_some() { + quote!(#_name) } else { - impl_items.push(quote! { - type Data = #device::#name; + quote!(#_name.some) + }; - fn borrow<'cs>( - &'cs self, - t: &'cs #krate::Threshold, - ) -> &'cs #krate::Static<#device::#name> { - assert!(t.value() >= #ceiling); + impl_items.push(quote! { + type Data = #ty; - unsafe { - #krate::Static::ref_(&*#device::#name.get()) - } + fn borrow<'cs>( + &'cs self, + t: &'cs #krate::Threshold, + ) -> &'cs #krate::Static<#ty> { + assert!(t.value() >= #ceiling); + + unsafe { #krate::Static::ref_(&#res_rvalue) } + } + + fn borrow_mut<'cs>( + &'cs mut self, + t: &'cs #krate::Threshold, + ) -> &'cs mut #krate::Static<#ty> { + assert!(t.value() >= #ceiling); + + unsafe { + #krate::Static::ref_mut(&mut #res_rvalue) } + } - fn borrow_mut<'cs>( - &'cs mut self, - t: &'cs #krate::Threshold, - ) -> &'cs mut #krate::Static<#device::#name> { - assert!(t.value() >= #ceiling); - - unsafe { - #krate::Static::ref_mut( - &mut *#device::#name.get(), - ) - } + fn claim( + &self, + t: &mut #krate::Threshold, + f: F, + ) -> R + where + F: FnOnce( + &#krate::Static<#ty>, + &mut #krate::Threshold) -> R + { + unsafe { + #krate::claim( + #krate::Static::ref_(&#res_rvalue), + #ceiling, + #device::NVIC_PRIO_BITS, + t, + f, + ) } + } - fn claim( - &self, - t: &mut #krate::Threshold, - f: F, - ) -> R - where - F: FnOnce( - &#krate::Static<#device::#name>, - &mut #krate::Threshold) -> R - { - unsafe { - #krate::claim( - #krate::Static::ref_( - &*#device::#name.get(), - ), - #ceiling, - #device::NVIC_PRIO_BITS, - t, - f, - ) - } + fn claim_mut( + &mut self, + t: &mut #krate::Threshold, + f: F, + ) -> R + where + F: FnOnce( + &mut #krate::Static<#ty>, + &mut #krate::Threshold) -> R + { + unsafe { + #krate::claim( + #krate::Static::ref_mut(&mut #res_rvalue), + #ceiling, + #device::NVIC_PRIO_BITS, + t, + f, + ) } - - fn claim_mut( - &mut self, - t: &mut #krate::Threshold, - f: F, - ) -> R - where - F: FnOnce( - &mut #krate::Static<#device::#name>, - &mut #krate::Threshold) -> R - { - unsafe { - #krate::claim( - #krate::Static::ref_mut( - &mut *#device::#name.get(), - ), - #ceiling, - #device::NVIC_PRIO_BITS, - t, - f, - ) - } - } - }); - } + } + }); impls.push(quote! { #[allow(unsafe_code)] @@ -560,9 +485,7 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec) { let _name = Ident::new(format!("_{}", name.as_ref())); match ownerships[name] { - Ownership::Shared { ceiling } - if ceiling > task.priority => - { + Ownership::Shared { ceiling } if ceiling > task.priority => { needs_threshold = true; fields.push(quote! { @@ -577,35 +500,26 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec) { } _ => { lifetime = Some(quote!('a)); - if let Some(resource) = app.resources.get(name) { - needs_reexport = true; - let ty = &resource.ty; + let resource = app.resources + .get(name) + .expect(&format!("BUG: resource {} has no definition", name)); - fields.push(quote! { - pub #name: &'a mut ::#krate::Static<#ty>, - }); + needs_reexport = true; + let ty = &resource.ty; - exprs.push(if resource.expr.is_some() { - quote! { - #name: ::#krate::Static::ref_mut(&mut ::#_name), - } - } else { - quote! { - #name: ::#krate::Static::ref_mut(::#_name.as_mut()), - } - }); + fields.push(quote! { + pub #name: &'a mut ::#krate::Static<#ty>, + }); + + exprs.push(if resource.expr.is_some() { + quote! { + #name: ::#krate::Static::ref_mut(&mut ::#_name), + } } else { - fields.push(quote! { - pub #name: - &'a mut ::#krate::Static<::#device::#name>, - }); - - exprs.push(quote! { - #name: ::#krate::Static::ref_mut( - &mut *::#device::#name.get(), - ), - }); - } + quote! { + #name: ::#krate::Static::ref_mut(::#_name.as_mut()), + } + }); } } } @@ -666,8 +580,7 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec) { let path = &task.path; let _name = Ident::new(format!("_{}", name)); - let export_name = - Lit::Str(name.as_ref().to_owned(), StrStyle::Cooked); + let export_name = Lit::Str(name.as_ref().to_owned(), StrStyle::Cooked); root.push(quote! { #[allow(non_snake_case)] #[allow(unsafe_code)] diff --git a/src/lib.rs b/src/lib.rs index 4ab8ec58d9..f5481bc401 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -160,6 +160,6 @@ where I: Nr, { // NOTE(safe) atomic write - let nvic = unsafe { &*cortex_m::peripheral::NVIC.get() }; + let nvic = unsafe { &*cortex_m::peripheral::NVIC::ptr() }; nvic.set_pending(interrupt); }