From 3fbebbd33e1276086d343809ef9e547f19f0122d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio <japaricious@gmail.com> Date: Tue, 7 Mar 2017 21:56:55 -0500 Subject: [PATCH] model the registers after `Cell` --- CHANGELOG.md | 19 +++++++-- Cargo.toml | 7 +++- src/lib.rs | 110 +++++++++++++++++++++++++-------------------------- 3 files changed, 75 insertions(+), 61 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d2da00..81394c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [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 ### Added @@ -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 -[Unreleased]: https://github.com/japaric/rustc-cfg/compare/v0.1.2...HEAD -[v0.1.2]: https://github.com/japaric/rustc-cfg/compare/v0.1.1...v0.1.2 -[v0.1.1]: https://github.com/japaric/rustc-cfg/compare/v0.1.0...v0.1.1 +[Unreleased]: https://github.com/japaric/volatile-register/compare/v0.1.2...HEAD +[v0.1.2]: https://github.com/japaric/volatile-register/compare/v0.1.1...v0.1.2 +[v0.1.1]: https://github.com/japaric/volatile-register/compare/v0.1.0...v0.1.1 diff --git a/Cargo.toml b/Cargo.toml index 04019d8..569e620 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,8 +5,11 @@ authors = [ ] description = "Volatile access to memory mapped hardware registers" documentation = "https://docs.rs/volatile-register" -keywords = ["volatile", "register"] +keywords = ["no-std", "volatile", "register"] license = "MIT OR Apache-2.0" name = "volatile-register" repository = "https://github.com/japaric/volatile-register" -version = "0.1.2" +version = "0.2.0" + +[dependencies] +vcell = "0.1.0" diff --git a/src/lib.rs b/src/lib.rs index 83274c3..2139385 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,105 +2,103 @@ //! //! # Usage //! -//! ``` -//! use volatile_register::{RO, RW, WO}; +//! ``` no_run +//! use volatile_register::RW; //! -//! /// A struct that represents the memory mapped register block for the GPIO -//! /// (General Purpose I/O) peripherals. +//! // Create a struct that represents the memory mapped register block +//! /// Nested Vector Interrupt Controller //! #[repr(C)] -//! pub struct Gpio { -//! /// Control Register -//! cr: RW<u32>, -//! /// Input Data Register -//! idr: RO<u32>, -//! /// Output Data Register -//! odr: WO<u32>, +//! pub struct Nvic { +//! /// Interrupt Set-Enable +//! pub iser: [RW<u32>; 8], +//! reserved0: [u32; 24], +//! /// Interrupt Clear-Enable +//! pub icer: [RW<u32>; 8], +//! reserved1: [u32; 24], //! // .. more registers .. //! } //! -//! /// Accessor to the register block associated to the GPIOA peripheral -//! fn gpioa() -> &'static Gpio { -//! const ADDRESS: usize = 0x40010800; -//! -//! unsafe { &*(ADDRESS as *const Gpio) } -//! } -//! -//! /// 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) } -//! } +//! // Access the registers by casting the base address of the register block +//! // to the previously declared `struct` +//! let nvic = 0xE000_E100 as *const Nvic; +//! // Unsafe because the compiler can't verify the address is correct +//! unsafe { (*nvic).iser[0].write(1) } //! ``` #![deny(missing_docs)] #![no_std] -use core::cell::UnsafeCell; -use core::ptr; +extern crate vcell; + +use vcell::VolatileCell; /// Read-Only register -#[repr(C)] -pub struct RO<T> { - register: T, +pub struct RO<T> + where T: Copy +{ + register: VolatileCell<T>, } impl<T> RO<T> where T: Copy { - /// Uninterruptible if `T` is a word, halfword or byte + /// Reads the value of the register #[inline(always)] pub fn read(&self) -> T { - unsafe { ptr::read_volatile(&self.register) } + self.register.get() } } /// Read-Write register -#[repr(C)] -pub struct RW<T> { - register: T, +pub struct RW<T> + where T: Copy +{ + register: VolatileCell<T>, } impl<T> RW<T> 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)] - pub fn read(&self) -> T { - unsafe { ptr::read_volatile(&self.register) } + pub unsafe fn modify<F>(&self, f: F) + 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)] - pub fn write(&mut self, value: T) { - unsafe { - ptr::write_volatile(&mut self.register, value); - } + pub fn read(&self) -> T { + self.register.get() } - /// Perform a read-modify-write, using `func` to perform the modification. - pub fn modify<F>(&mut self, func: F) where F: FnOnce(T) -> T { - let mut t = self.read(); - t = func(t); - self.write(t); + /// Writes a `value` into the register + /// + /// NOTE: `unsafe` because writes to a register are side effectful + #[inline(always)] + pub unsafe fn write(&self, value: T) { + self.register.set(value) } } /// Write-Only register -#[repr(C)] -pub struct WO<T> { - register: UnsafeCell<T>, +pub struct WO<T> + where T: Copy +{ + register: VolatileCell<T>, } impl<T> WO<T> 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)] - pub fn write(&self, value: T) { - unsafe { ptr::write_volatile(self.register.get(), value) } + pub unsafe fn write(&self, value: T) { + self.register.set(value) } } - -unsafe impl<T> Sync for WO<T> where T: Sync {} -- GitLab