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> {}