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/).
## [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
......@@ -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"
......@@ -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 {}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment