Skip to content
Snippets Groups Projects
Commit 3fbebbd3 authored by Jorge Aparicio's avatar Jorge Aparicio
Browse files

model the registers after `Cell`

parent caa1be62
No related branches found
No related tags found
No related merge requests found
...@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ...@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased] ## [Unreleased]
### Changed
- The `modify` and `write` operations now take `&self`.
- [breaking-change] `RO` and `RW` no longer implement `Sync`. This is required
to make the new `modify` and `write` sound.
- [breaking-change] `RO`, `RW` and `WO` now require that the inner value be
`Copy`-able.
- docs: remove "guarantee" about some operations being atomic as this crate may
be used in architectures different than the ARM Cortex-M.
## [v0.1.2] - 2016-10-15 ## [v0.1.2] - 2016-10-15
### Added ### Added
...@@ -25,6 +38,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ...@@ -25,6 +38,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Read-Only (`RO`), Read-Write (`RW`) and Write-Only (`WO`) registers - Read-Only (`RO`), Read-Write (`RW`) and Write-Only (`WO`) registers
[Unreleased]: https://github.com/japaric/rustc-cfg/compare/v0.1.2...HEAD [Unreleased]: https://github.com/japaric/volatile-register/compare/v0.1.2...HEAD
[v0.1.2]: https://github.com/japaric/rustc-cfg/compare/v0.1.1...v0.1.2 [v0.1.2]: https://github.com/japaric/volatile-register/compare/v0.1.1...v0.1.2
[v0.1.1]: https://github.com/japaric/rustc-cfg/compare/v0.1.0...v0.1.1 [v0.1.1]: https://github.com/japaric/volatile-register/compare/v0.1.0...v0.1.1
...@@ -5,8 +5,11 @@ authors = [ ...@@ -5,8 +5,11 @@ authors = [
] ]
description = "Volatile access to memory mapped hardware registers" description = "Volatile access to memory mapped hardware registers"
documentation = "https://docs.rs/volatile-register" documentation = "https://docs.rs/volatile-register"
keywords = ["volatile", "register"] keywords = ["no-std", "volatile", "register"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
name = "volatile-register" name = "volatile-register"
repository = "https://github.com/japaric/volatile-register" repository = "https://github.com/japaric/volatile-register"
version = "0.1.2" version = "0.2.0"
[dependencies]
vcell = "0.1.0"
...@@ -2,105 +2,103 @@ ...@@ -2,105 +2,103 @@
//! //!
//! # Usage //! # Usage
//! //!
//! ``` //! ``` no_run
//! use volatile_register::{RO, RW, WO}; //! use volatile_register::RW;
//! //!
//! /// A struct that represents the memory mapped register block for the GPIO //! // Create a struct that represents the memory mapped register block
//! /// (General Purpose I/O) peripherals. //! /// Nested Vector Interrupt Controller
//! #[repr(C)] //! #[repr(C)]
//! pub struct Gpio { //! pub struct Nvic {
//! /// Control Register //! /// Interrupt Set-Enable
//! cr: RW<u32>, //! pub iser: [RW<u32>; 8],
//! /// Input Data Register //! reserved0: [u32; 24],
//! idr: RO<u32>, //! /// Interrupt Clear-Enable
//! /// Output Data Register //! pub icer: [RW<u32>; 8],
//! odr: WO<u32>, //! reserved1: [u32; 24],
//! // .. more registers .. //! // .. more registers ..
//! } //! }
//! //!
//! /// Accessor to the register block associated to the GPIOA peripheral //! // Access the registers by casting the base address of the register block
//! fn gpioa() -> &'static Gpio { //! // to the previously declared `struct`
//! const ADDRESS: usize = 0x40010800; //! let nvic = 0xE000_E100 as *const Nvic;
//! //! // Unsafe because the compiler can't verify the address is correct
//! unsafe { &*(ADDRESS as *const Gpio) } //! unsafe { (*nvic).iser[0].write(1) }
//! }
//!
//! /// Accessor to the register block associated to the GPIOC peripheral
//! /// NOTE(unsafe) This function hands out mutable aliases to a single address.
//! unsafe fn gpioc_mut() -> &'static mut Gpio {
//! const ADDRESS: usize = 0x40011000;
//!
//! unsafe { &mut *(ADDRESS as *mut Gpio) }
//! }
//! ``` //! ```
#![deny(missing_docs)] #![deny(missing_docs)]
#![no_std] #![no_std]
use core::cell::UnsafeCell; extern crate vcell;
use core::ptr;
use vcell::VolatileCell;
/// Read-Only register /// Read-Only register
#[repr(C)] pub struct RO<T>
pub struct RO<T> { where T: Copy
register: T, {
register: VolatileCell<T>,
} }
impl<T> RO<T> impl<T> RO<T>
where T: Copy where T: Copy
{ {
/// Uninterruptible if `T` is a word, halfword or byte /// Reads the value of the register
#[inline(always)] #[inline(always)]
pub fn read(&self) -> T { pub fn read(&self) -> T {
unsafe { ptr::read_volatile(&self.register) } self.register.get()
} }
} }
/// Read-Write register /// Read-Write register
#[repr(C)] pub struct RW<T>
pub struct RW<T> { where T: Copy
register: T, {
register: VolatileCell<T>,
} }
impl<T> RW<T> impl<T> RW<T>
where T: Copy where T: Copy
{ {
/// Uninterruptible if `T` is a word, halfword or byte /// Performs a read-modify-write operation
///
/// NOTE: `unsafe` because writes to a register are side effectful
#[inline(always)] #[inline(always)]
pub fn read(&self) -> T { pub unsafe fn modify<F>(&self, f: F)
unsafe { ptr::read_volatile(&self.register) } where F: FnOnce(T) -> T
{
self.register.set(f(self.register.get()));
} }
/// Uninterruptible if `T` is a word, halfword or byte /// Reads the value of the register
#[inline(always)] #[inline(always)]
pub fn write(&mut self, value: T) { pub fn read(&self) -> T {
unsafe { self.register.get()
ptr::write_volatile(&mut self.register, value);
}
} }
/// Perform a read-modify-write, using `func` to perform the modification. /// Writes a `value` into the register
pub fn modify<F>(&mut self, func: F) where F: FnOnce(T) -> T { ///
let mut t = self.read(); /// NOTE: `unsafe` because writes to a register are side effectful
t = func(t); #[inline(always)]
self.write(t); pub unsafe fn write(&self, value: T) {
self.register.set(value)
} }
} }
/// Write-Only register /// Write-Only register
#[repr(C)] pub struct WO<T>
pub struct WO<T> { where T: Copy
register: UnsafeCell<T>, {
register: VolatileCell<T>,
} }
impl<T> WO<T> impl<T> WO<T>
where T: Copy where T: Copy
{ {
/// Uninterruptible if `T` is a word, halfword or byte /// Writes `value` into the register
///
/// NOTE: `unsafe` because writes to a register are side effectful
#[inline(always)] #[inline(always)]
pub fn write(&self, value: T) { pub unsafe fn write(&self, value: T) {
unsafe { ptr::write_volatile(self.register.get(), value) } self.register.set(value)
} }
} }
unsafe impl<T> Sync for WO<T> where T: Sync {}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment