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}