tock_registers/
registers.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//! Implementation of included register types.
6//!
7//! This module provides a standard set of register types, which can
8//! describe different access levels:
9//!
10//! - [`ReadWrite`] for registers which can be read and written to
11//! - [`ReadOnly`] for registers which can only be read
12//! - [`WriteOnly`] for registers which can only be written to
13//! - [`Aliased`] for registers which can be both read and written,
14//!   but represent different registers depending on the operation
15//! - [`InMemoryRegister`] provide a register-type in RAM using
16//!   volatile operations
17//!
18//! These types can be disabled by removing the `register_types` crate
19//! feature (part of the default features). This is useful if this
20//! crate should be used only as an interface library, or if all
21//! unsafe code should be disabled.
22
23use core::cell::UnsafeCell;
24use core::marker::PhantomData;
25
26use crate::interfaces::{Readable, Writeable};
27use crate::{RegisterLongName, UIntLike};
28
29/// Read/Write registers.
30///
31/// For accessing and manipulating the register contents, the
32/// [`Readable`], [`Writeable`] and
33/// [`ReadWriteable`](crate::interfaces::ReadWriteable) traits are
34/// implemented.
35// To successfully alias this structure onto hardware registers in memory, this
36// struct must be exactly the size of the `T` and is thus marked
37// `repr(transparent)` over an `UnsafeCell<T>`, which itself is
38// `repr(transparent)` over `T`.
39//
40// This struct is constructed by casting a pointer to it (or, implicitly, by
41// casting a pointer to a larger struct that containts this type). As such, it
42// does not have a public constructor and Rust thinks it's dead code and should
43// be removed. We `allow(dead_code)` here to suppress this warning.
44#[allow(dead_code)]
45#[repr(transparent)]
46pub struct ReadWrite<T: UIntLike, R: RegisterLongName = ()> {
47    value: UnsafeCell<T>,
48    associated_register: PhantomData<R>,
49}
50impl<T: UIntLike, R: RegisterLongName> Readable for ReadWrite<T, R> {
51    type T = T;
52    type R = R;
53
54    #[inline]
55    fn get(&self) -> Self::T {
56        unsafe { ::core::ptr::read_volatile(self.value.get()) }
57    }
58}
59impl<T: UIntLike, R: RegisterLongName> Writeable for ReadWrite<T, R> {
60    type T = T;
61    type R = R;
62
63    #[inline]
64    fn set(&self, value: T) {
65        unsafe { ::core::ptr::write_volatile(self.value.get(), value) }
66    }
67}
68
69/// Read-only registers.
70///
71/// For accessing the register contents the [`Readable`] trait is
72/// implemented.
73// To successfully alias this structure onto hardware registers in memory, this
74// struct must be exactly the size of the `T` and is thus marked
75// `repr(transparent)` over an `UnsafeCell<T>`, which itself is
76// `repr(transparent)` over `T`.
77//
78// This struct is constructed by casting a pointer to it (or, implicitly, by
79// casting a pointer to a larger struct that containts this type). As such, it
80// does not have a public constructor and Rust thinks it's dead code and should
81// be removed. We `allow(dead_code)` here to suppress this warning.
82#[allow(dead_code)]
83#[repr(transparent)]
84pub struct ReadOnly<T: UIntLike, R: RegisterLongName = ()> {
85    value: T,
86    associated_register: PhantomData<R>,
87}
88impl<T: UIntLike, R: RegisterLongName> Readable for ReadOnly<T, R> {
89    type T = T;
90    type R = R;
91
92    #[inline]
93    fn get(&self) -> T {
94        unsafe { ::core::ptr::read_volatile(&self.value) }
95    }
96}
97
98/// Write-only registers.
99///
100/// For setting the register contents the [`Writeable`] trait is
101/// implemented.
102// To successfully alias this structure onto hardware registers in memory, this
103// struct must be exactly the size of the `T` and is thus marked
104// `repr(transparent)` over an `UnsafeCell<T>`, which itself is
105// `repr(transparent)` over `T`.
106//
107// This struct is constructed by casting a pointer to it (or, implicitly, by
108// casting a pointer to a larger struct that containts this type). As such, it
109// does not have a public constructor and Rust thinks it's dead code and should
110// be removed. We `allow(dead_code)` here to suppress this warning.
111#[allow(dead_code)]
112#[repr(transparent)]
113pub struct WriteOnly<T: UIntLike, R: RegisterLongName = ()> {
114    value: UnsafeCell<T>,
115    associated_register: PhantomData<R>,
116}
117impl<T: UIntLike, R: RegisterLongName> Writeable for WriteOnly<T, R> {
118    type T = T;
119    type R = R;
120
121    #[inline]
122    fn set(&self, value: T) {
123        unsafe { ::core::ptr::write_volatile(self.value.get(), value) }
124    }
125}
126
127/// Read-only and write-only registers aliased to the same address.
128///
129/// Unlike the [`ReadWrite`] register, this represents a register
130/// which has different meanings based on if it is written or read.
131/// This might be found on a device where control and status registers
132/// are accessed via the same memory address via writes and reads,
133/// respectively.
134///
135/// This register implements [`Readable`] and [`Writeable`], but in
136/// general does not implement
137/// [`ReadWriteable`](crate::interfaces::ReadWriteable) (only if the
138/// type parameters `R` and `W` are identical, in which case a
139/// [`ReadWrite`] register might be a better choice).
140// To successfully alias this structure onto hardware registers in memory, this
141// struct must be exactly the size of the `T` and is thus marked
142// `repr(transparent)` over an `UnsafeCell<T>`, which itself is
143// `repr(transparent)` over `T`.
144//
145// This struct is constructed by casting a pointer to it (or, implicitly, by
146// casting a pointer to a larger struct that containts this type). As such, it
147// does not have a public constructor and Rust thinks it's dead code and should
148// be removed. We `allow(dead_code)` here to suppress this warning.
149#[allow(dead_code)]
150#[repr(transparent)]
151pub struct Aliased<T: UIntLike, R: RegisterLongName = (), W: RegisterLongName = ()> {
152    value: UnsafeCell<T>,
153    associated_register: PhantomData<(R, W)>,
154}
155impl<T: UIntLike, R: RegisterLongName, W: RegisterLongName> Readable for Aliased<T, R, W> {
156    type T = T;
157    type R = R;
158
159    #[inline]
160    fn get(&self) -> Self::T {
161        unsafe { ::core::ptr::read_volatile(self.value.get()) }
162    }
163}
164impl<T: UIntLike, R: RegisterLongName, W: RegisterLongName> Writeable for Aliased<T, R, W> {
165    type T = T;
166    type R = W;
167
168    #[inline]
169    fn set(&self, value: Self::T) {
170        unsafe { ::core::ptr::write_volatile(self.value.get(), value) }
171    }
172}
173
174/// In memory volatile register.
175///
176/// Like [`ReadWrite`], but can be safely constructed using the
177/// [`InMemoryRegister::new`] method. It will always be initialized to
178/// the passed in, well-defined initial value.
179///
180/// For accessing and manipulating the register contents, the
181/// [`Readable`], [`Writeable`] and
182/// [`ReadWriteable`](crate::interfaces::ReadWriteable) traits are
183/// implemented.
184// To successfully alias this structure onto hardware registers in memory, this
185// struct must be exactly the size of the `T`.
186#[repr(transparent)]
187pub struct InMemoryRegister<T: UIntLike, R: RegisterLongName = ()> {
188    value: UnsafeCell<T>,
189    associated_register: PhantomData<R>,
190}
191
192impl<T: UIntLike, R: RegisterLongName> InMemoryRegister<T, R> {
193    pub const fn new(value: T) -> Self {
194        InMemoryRegister {
195            value: UnsafeCell::new(value),
196            associated_register: PhantomData,
197        }
198    }
199}
200impl<T: UIntLike, R: RegisterLongName> Readable for InMemoryRegister<T, R> {
201    type T = T;
202    type R = R;
203
204    #[inline]
205    fn get(&self) -> Self::T {
206        unsafe { ::core::ptr::read_volatile(self.value.get()) }
207    }
208}
209impl<T: UIntLike, R: RegisterLongName> Writeable for InMemoryRegister<T, R> {
210    type T = T;
211    type R = R;
212
213    #[inline]
214    fn set(&self, value: T) {
215        unsafe { ::core::ptr::write_volatile(self.value.get(), value) }
216    }
217}