tock_cells/
volatile_cell.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5// This file was vendored into Tock. It comes from
6// https://github.com/japaric/vcell, commit
7// ef556474203e93b3f45f0f8cd8dea3210aa7f844, path src/lib.rs.
8
9//! A type for accessing MMIO registers. `VolatileCell` is just like [`Cell`]
10//! but with [volatile] read / write operations
11//!
12//! [`Cell`]: https://doc.rust-lang.org/std/cell/struct.Cell.html
13//! [volatile]: https://doc.rust-lang.org/std/ptr/fn.read_volatile.html
14
15#![deny(missing_docs)]
16#![deny(warnings)]
17
18use core::cell::UnsafeCell;
19use core::ptr;
20
21/// `VolatileCell` provides a wrapper around unsafe volatile pointer
22/// reads and writes.
23///
24/// This is particularly useful for accessing microcontroller
25/// registers by (unsafely) casting a pointer to the register into a
26/// `VolatileCell`.
27///
28/// ```
29/// use tock_cells::volatile_cell::VolatileCell;
30/// let myptr: *const usize = 0xdeadbeef as *const usize;
31/// let myregister: &VolatileCell<usize> = unsafe { core::mem::transmute(myptr) };
32/// ```
33#[derive(Default)]
34#[repr(transparent)]
35pub struct VolatileCell<T> {
36    value: UnsafeCell<T>,
37}
38
39impl<T> VolatileCell<T> {
40    /// Creates a new `VolatileCell` containing the given value
41    pub const fn new(value: T) -> Self {
42        VolatileCell {
43            value: UnsafeCell::new(value),
44        }
45    }
46
47    /// Performs a memory read and returns a copy of the value represented by
48    /// the cell.
49    ///
50    /// # Side-Effects
51    ///
52    /// `get` _always_ performs a memory read on the underlying location. If
53    /// this location is a memory-mapped I/O register, the side-effects of
54    /// performing the read are register-specific.
55    ///
56    /// # Examples
57    ///
58    /// ```
59    /// use tock_cells::volatile_cell::VolatileCell;
60    ///
61    /// let vc = VolatileCell::new(5);
62    /// let five = vc.get();
63    /// ```
64    #[inline(always)]
65    pub fn get(&self) -> T
66    where
67        T: Copy,
68    {
69        unsafe { ptr::read_volatile(self.value.get()) }
70    }
71
72    /// Performs a memory write with the provided value.
73    ///
74    /// # Side-Effects
75    ///
76    /// `set` _always_ performs a memory write on the underlying location. If
77    /// this location is a memory-mapped I/O register, the side-effects of
78    /// performing the write are register-specific.
79    ///
80    /// # Examples
81    ///
82    /// ```
83    /// use tock_cells::volatile_cell::VolatileCell;
84    ///
85    /// let vc = VolatileCell::new(123);
86    /// vc.set(432);
87    /// ```
88    #[inline(always)]
89    pub fn set(&self, value: T)
90    where
91        T: Copy,
92    {
93        unsafe { ptr::write_volatile(self.value.get(), value) }
94    }
95}
96
97// NOTE implicit because of `UnsafeCell`
98// unsafe impl<T> !Sync for VolatileCell<T> {}