diff --git a/Cargo.toml b/Cargo.toml index c9d6f7b2b2..c80cb41ddb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,5 +4,5 @@ version = "0.1.0" authors = ["Jorge Aparicio "] [dependencies.cortex-m] -branch = "svd2rust" +branch = "ng" git = "https://github.com/japaric/cortex-m" diff --git a/src/lib.rs b/src/lib.rs index 6943b6ee62..e10b534dba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,8 @@ //! //! NOTE ARMv6-M is not supported at the moment. +#![deny(missing_docs)] +#![deny(warnings)] #![feature(asm)] #![feature(const_fn)] #![no_std] @@ -12,146 +14,95 @@ const PRIORITY_BITS: u8 = 4; extern crate cortex_m; -use cortex_m::interrupt::CsToken; +use cortex_m::interrupt::CsCtxt; +use cortex_m::peripheral::Peripheral; use cortex_m::register::{basepri, basepri_max}; use core::cell::UnsafeCell; -use core::marker::PhantomData; -// XXX why is this needed? +// XXX Do we need memory / instruction / compiler barriers here? #[inline(always)] -fn compiler_barrier() { - unsafe { - asm!("" - : - : - : "memory" - : "volatile") - } +unsafe fn claim(f: F, res: *const T, ceiling: u8) -> R + where F: FnOnce(&T) -> R +{ + let old_basepri = basepri::read(); + basepri_max::write(ceiling); + let ret = f(&*res); + basepri::write(old_basepri); + ret } -// XXX why is this needed? -#[inline(always)] -fn memory_barrier() { - unsafe { - asm!("dsb - isb" - : - : - : "memory" - : "volatile") - } -} - -pub struct Peripheral +/// A peripheral as a resource +pub struct ResourceP where T: 'static { - _ty: PhantomData<&'static mut T>, - address: usize, + peripheral: Peripheral, + // NOTE NVIC-style priority ceiling ceiling: u8, } -impl Peripheral { - pub const unsafe fn new(address: usize, ceiling: u8) -> Self { - Peripheral { - _ty: PhantomData, - address: address, - ceiling: ceiling, +impl ResourceP { + /// Wraps a `peripheral` into a `Resource` + /// + /// NOTE `ceiling` must be in the range `[1, 15]` (inclusive) + /// + /// # Unsafety + /// + /// - Do not create two resources that point to the same peripheral + pub const unsafe fn new(p: Peripheral, ceiling: u8) -> Self { + ResourceP { + peripheral: p, + // NOTE elements 1 and 2 of the tuple are a poor man's const context + // range checker + ceiling: (priority(ceiling), ceiling - 1, ceiling + 240).0, } } - pub fn claim(&self, f: F) -> R + /// Claims the resource, blocking tasks with priority lower than `ceiling` + pub fn claim(&'static self, f: F) -> R where F: FnOnce(&T) -> R { - unsafe { - let old_basepri = basepri::read(); - basepri_max::write(priority(self.ceiling)); - memory_barrier(); - let ret = f(&*(self.address as *const T)); - compiler_barrier(); - basepri::write(old_basepri); - ret - } + unsafe { claim(f, self.peripheral.get(), self.ceiling) } } - pub fn claim_mut(&self, f: F) -> R - where F: FnOnce(&mut T) -> R - { - unsafe { - let old_basepri = basepri::read(); - basepri_max::write(priority(self.ceiling)); - memory_barrier(); - let ret = f(&mut *(self.address as *mut T)); - compiler_barrier(); - basepri::write(old_basepri); - ret - } - } - - pub fn take<'a>(&self, _token: &'a CsToken) -> &'a T { - unsafe { - &*(self.address as *const T) - } - } - - pub fn take_mut<'a>(&self, _token: &'a CsToken) -> &'a mut T { - unsafe { - &mut *(self.address as *mut T) - } + /// Borrows the resource for the duration of a critical section + pub fn borrow<'a>(&'static self, _ctxt: &'a CsCtxt) -> &'a T { + unsafe { &*self.peripheral.get() } } } +unsafe impl Sync for ResourceP {} + +/// A resource pub struct Resource { + // NOTE NVIC-style priority ceiling ceiling: u8, data: UnsafeCell, } impl Resource { + /// Initializes a resource + /// + /// NOTE `ceiling` must be in the range `[1, 15]` pub const fn new(data: T, ceiling: u8) -> Self { Resource { - ceiling: ceiling, + // NOTE elements 1 and 2 of the tuple are a poor man's const context + // range checker + ceiling: (priority(ceiling), ceiling - 1, ceiling + 240).0, data: UnsafeCell::new(data), } } - pub fn claim(&self, f: F) -> R + /// Claims the resource, blocking tasks with priority lower than `ceiling` + pub fn claim(&'static self, f: F) -> R where F: FnOnce(&T) -> R { - unsafe { - let old_basepri = basepri::read(); - basepri_max::write(priority(self.ceiling)); - memory_barrier(); - let ret = f(&*self.data.get()); - compiler_barrier(); - basepri::write(old_basepri); - ret - } + unsafe { claim(f, self.data.get(), self.ceiling) } } - pub fn claim_mut(&self, f: F) -> R - where F: FnOnce(&mut T) -> R - { - unsafe { - let old_basepri = basepri::read(); - basepri_max::write(priority(self.ceiling)); - memory_barrier(); - let ret = f(&mut *self.data.get()); - compiler_barrier(); - basepri::write(old_basepri); - ret - } - } - - pub fn take<'a>(&self, _token: &'a CsToken) -> &'a T { - unsafe { - &*self.data.get() - } - } - - pub fn take_mut<'a>(&self, _token: &'a CsToken) -> &'a mut T { - unsafe { - &mut *self.data.get() - } + /// Borrows the resource for the duration of a critical section + pub fn borrow<'cs>(&self, _ctxt: &'cs CsCtxt) -> &'cs T { + unsafe { &*self.data.get() } } } @@ -164,7 +115,14 @@ unsafe impl Sync for Resource {} /// With NVIC priorities, `32` has LOWER priority than `16`. (Also, NVIC /// priorities encode the actual priority in the highest bits of a byte so /// priorities like `1` and `2` aren't actually different) -// TODO review the handling of extreme values +/// +/// NOTE `logical` must be in the range `[1, 15]` (inclusive) pub const fn priority(logical: u8) -> u8 { - ((1 << PRIORITY_BITS) - logical) << (8 - PRIORITY_BITS) + // NOTE elements 1 and 2 of the tuple are a poor man's const context range + // checker + (((1 << PRIORITY_BITS) - logical) << (8 - PRIORITY_BITS), + logical - 1, + logical + 240) + .0 + }