tock_registers/
interfaces.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//! Interfaces (traits) to register types
6//!
7//! This module contains traits which reflect standardized interfaces
8//! to different types of registers. Examples of registers
9//! implementing these interfaces are [`ReadWrite`](crate::registers::ReadWrite) or
10//! [`InMemoryRegister`](crate::registers::InMemoryRegister).
11//!
12//! Each trait has two associated type parameters, namely:
13//!
14//! - `T`: [`UIntLike`](crate::UIntLike), indicating the underlying
15//!   integer type used to represent the register's raw contents.
16//!
17//! - `R`: [`RegisterLongName`](crate::RegisterLongName), functioning
18//!   as a type to identify this register's descriptive name and
19//!   semantic meaning. It is further used to impose type constraints
20//!   on values passed through the API, such as
21//!   [`FieldValue`](crate::fields::FieldValue).
22//!
23//! Registers can have different access levels, which are mapped to
24//! different traits respectively:
25//!
26//! - [`Readable`]: indicates that the current value of this register
27//!   can be read. Implementations will need to provide the
28//!   [`get`](crate::interfaces::Readable::get) method.
29//!
30//! - [`Writeable`]: indicates that the value of this register can be
31//!   set. Implementations will need to provide the
32//!   [`set`](crate::interfaces::Writeable::set) method.
33//!
34//! - [`ReadWriteable`]: indicates that this register can be
35//!   _modified_. It is not sufficient for registers to be both read-
36//!   and writable, they must also have the same semantic meaning when
37//!   read from and written to. This is not true in general, for
38//!   example a memory-mapped UART register might transmit when
39//!   writing and receive when reading.
40//!
41//!   If a type implements both [`Readable`] and [`Writeable`], and
42//!   the associated [`RegisterLongName`](crate::RegisterLongName)
43//!   type parameters are identical, it will automatically implement
44//!   [`ReadWriteable`]. In particular, for
45//!   [`Aliased`](crate::registers::Aliased) this is -- in general --
46//!   not the case, so
47//!
48//!   ```rust
49//!   # use tock_registers::interfaces::{Readable, Writeable, ReadWriteable};
50//!   # use tock_registers::registers::ReadWrite;
51//!   # use tock_registers::register_bitfields;
52//!   register_bitfields![u8,
53//!       A [
54//!           DUMMY OFFSET(0) NUMBITS(1) [],
55//!       ],
56//!   ];
57//!   let read_write_reg: &ReadWrite<u8, A::Register> = unsafe {
58//!       core::mem::transmute(Box::leak(Box::new(0_u8)))
59//!   };
60//!   ReadWriteable::modify(read_write_reg, A::DUMMY::SET);
61//!   ```
62//!
63//!   works, but not
64//!
65//!   ```compile_fail
66//!   # use tock_registers::interfaces::{Readable, Writeable, ReadWriteable};
67//!   # use tock_registers::registers::Aliased;
68//!   # use tock_registers::register_bitfields;
69//!   register_bitfields![u8,
70//!       A [
71//!           DUMMY OFFSET(0) NUMBITS(1) [],
72//!       ],
73//!       B [
74//!           DUMMY OFFSET(0) NUMBITS(1) [],
75//!       ],
76//!   ];
77//!   let aliased_reg: &Aliased<u8, A::Register, B::Register> = unsafe {
78//!       core::mem::transmute(Box::leak(Box::new(0_u8)))
79//!   };
80//!   ReadWriteable::modify(aliased_reg, A::DUMMY::SET);
81//!   ```
82//!
83//! ## Example: implementing a custom register type
84//!
85//! These traits can be used to implement custom register types, which
86//! are compatible to the ones shipped in this crate. For example, to
87//! define a register which sets a `u8` value using a Cell reference,
88//! always reads the bitwise-negated vale and prints every written
89//! value to the console:
90//!
91//! ```rust
92//! # use core::cell::Cell;
93//! # use core::marker::PhantomData;
94//! #
95//! # use tock_registers::interfaces::{Readable, Writeable, ReadWriteable};
96//! # use tock_registers::RegisterLongName;
97//! # use tock_registers::register_bitfields;
98//! #
99//! struct DummyRegister<'a, R: RegisterLongName> {
100//!     cell_ref: &'a Cell<u8>,
101//!     _register_long_name: PhantomData<R>,
102//! }
103//!
104//! impl<'a, R: RegisterLongName> Readable for DummyRegister<'a, R> {
105//!     type T = u8;
106//!     type R = R;
107//!
108//!     fn get(&self) -> u8 {
109//!         // Return the bitwise-inverse of the current value
110//!         !self.cell_ref.get()
111//!     }
112//! }
113//!
114//! impl<'a, R: RegisterLongName> Writeable for DummyRegister<'a, R> {
115//!     type T = u8;
116//!     type R = R;
117//!
118//!     fn set(&self, value: u8) {
119//!         println!("Setting Cell to {:02x?}!", value);
120//!         self.cell_ref.set(value);
121//!     }
122//! }
123//!
124//! register_bitfields![u8,
125//!     DummyReg [
126//!         HIGH OFFSET(4) NUMBITS(4) [
127//!             A = 0b0001,
128//!             B = 0b0010,
129//!             C = 0b0100,
130//!             D = 0b1000,
131//!         ],
132//!         LOW OFFSET(0) NUMBITS(4) [],
133//!     ],
134//! ];
135//!
136//! // Create a new DummyRegister over some Cell<u8>
137//! let cell = Cell::new(0);
138//! let dummy = DummyRegister {
139//!     cell_ref: &cell,
140//!     _register_long_name: PhantomData,
141//! };
142//!
143//! // Set a value and read it back. This demonstrates the raw getters
144//! // and setters of Writeable and Readable
145//! dummy.set(0xFA);
146//! assert!(dummy.get() == 0x05);
147//!
148//! // Use some of the automatically derived APIs, such as
149//! // ReadWriteable::modify and Readable::read
150//! dummy.modify(DummyReg::HIGH::C);
151//! assert!(dummy.read(DummyReg::HIGH) == 0xb);
152//! ```
153
154use crate::fields::{Field, FieldValue, TryFromValue};
155use crate::{LocalRegisterCopy, RegisterLongName, UIntLike};
156
157/// Readable register
158///
159/// Register which at least supports reading the current value. Only
160/// [`Readable::get`] must be implemented, as for other methods a
161/// default implementation is provided.
162///
163/// A register that is both [`Readable`] and [`Writeable`] will also
164/// automatically be [`ReadWriteable`], if the [`RegisterLongName`] of
165/// [`Readable`] is the same as that of [`Writeable`] (i.e. not for
166/// [`Aliased`](crate::registers::Aliased) registers).
167pub trait Readable {
168    type T: UIntLike;
169    type R: RegisterLongName;
170
171    /// Get the raw register value
172    fn get(&self) -> Self::T;
173
174    #[inline]
175    /// Read the value of the given field
176    fn read(&self, field: Field<Self::T, Self::R>) -> Self::T {
177        field.read(self.get())
178    }
179
180    /// Set the raw register value
181    ///
182    /// The [`register_bitfields!`](crate::register_bitfields) macro will
183    /// generate an enum containing the various named field variants and
184    /// implementing the required [`TryFromValue`] trait. It is accessible as
185    /// `$REGISTER_NAME::$FIELD_NAME::Value`.
186    ///
187    /// This method can be useful to symbolically represent read register field
188    /// states throughout the codebase and to enforce exhaustive matches over
189    /// all defined valid register field values.
190    ///
191    /// ## Usage Example
192    ///
193    /// ```rust
194    /// # use tock_registers::interfaces::Readable;
195    /// # use tock_registers::registers::InMemoryRegister;
196    /// # use tock_registers::register_bitfields;
197    /// register_bitfields![u8,
198    ///     EXAMPLEREG [
199    ///         TESTFIELD OFFSET(0) NUMBITS(2) [
200    ///             Foo = 0,
201    ///             Bar = 1,
202    ///             Baz = 2,
203    ///         ],
204    ///     ],
205    /// ];
206    ///
207    /// let reg: InMemoryRegister<u8, EXAMPLEREG::Register> =
208    ///     InMemoryRegister::new(2);
209    ///
210    /// match reg.read_as_enum(EXAMPLEREG::TESTFIELD) {
211    ///     Some(EXAMPLEREG::TESTFIELD::Value::Foo) => "Tock",
212    ///     Some(EXAMPLEREG::TESTFIELD::Value::Bar) => "is",
213    ///     Some(EXAMPLEREG::TESTFIELD::Value::Baz) => "awesome!",
214    ///     None => panic!("boo!"),
215    /// };
216    /// ```
217    #[inline]
218    fn read_as_enum<E: TryFromValue<Self::T, EnumType = E>>(
219        &self,
220        field: Field<Self::T, Self::R>,
221    ) -> Option<E> {
222        field.read_as_enum(self.get())
223    }
224
225    #[inline]
226    /// Make a local copy of the register
227    fn extract(&self) -> LocalRegisterCopy<Self::T, Self::R> {
228        LocalRegisterCopy::new(self.get())
229    }
230
231    #[inline]
232    /// Check if one or more bits in a field are set
233    fn is_set(&self, field: Field<Self::T, Self::R>) -> bool {
234        field.is_set(self.get())
235    }
236
237    /// Check if any bits corresponding to the mask in the passed `FieldValue` are set.
238    /// This function is identical to `is_set()` but operates on a `FieldValue` rather
239    /// than a `Field`, allowing for checking if any bits are set across multiple,
240    /// non-contiguous portions of a bitfield.
241    #[inline]
242    fn any_matching_bits_set(&self, field: FieldValue<Self::T, Self::R>) -> bool {
243        field.any_matching_bits_set(self.get())
244    }
245
246    #[inline]
247    /// Check if all specified parts of a field match
248    fn matches_all(&self, field: FieldValue<Self::T, Self::R>) -> bool {
249        field.matches_all(self.get())
250    }
251
252    /// Check if any of the passed parts of a field exactly match the contained
253    /// value. This allows for matching on unset bits, or matching on specific values
254    /// in multi-bit fields.
255    #[inline]
256    fn matches_any(&self, fields: &[FieldValue<Self::T, Self::R>]) -> bool {
257        fields
258            .iter()
259            .any(|field| self.get() & field.mask() == field.value)
260    }
261}
262
263/// Writeable register
264///
265/// Register which at least supports setting a value. Only
266/// [`Writeable::set`] must be implemented, as for other methods a
267/// default implementation is provided.
268///
269/// A register that is both [`Readable`] and [`Writeable`] will also
270/// automatically be [`ReadWriteable`], if the [`RegisterLongName`] of
271/// [`Readable`] is the same as that of [`Writeable`] (i.e. not for
272/// [`Aliased`](crate::registers::Aliased) registers).
273pub trait Writeable {
274    type T: UIntLike;
275    type R: RegisterLongName;
276
277    /// Set the raw register value
278    fn set(&self, value: Self::T);
279
280    #[inline]
281    /// Write the value of one or more fields, overwriting the other fields with zero
282    fn write(&self, field: FieldValue<Self::T, Self::R>) {
283        self.set(field.value);
284    }
285
286    #[inline]
287    /// Write the value of one or more fields, maintaining the value of unchanged fields via a
288    /// provided original value, rather than a register read.
289    fn modify_no_read(
290        &self,
291        original: LocalRegisterCopy<Self::T, Self::R>,
292        field: FieldValue<Self::T, Self::R>,
293    ) {
294        self.set(field.modify(original.get()));
295    }
296}
297
298/// [`Readable`] and [`Writeable`] register, over the same
299/// [`RegisterLongName`]
300///
301/// Register which supports both reading and setting a value.
302///
303/// **This trait does not have to be implemented manually!** It is
304/// automatically implemented for every type that is both [`Readable`]
305/// and [`Writeable`], as long as [`Readable::R`] == [`Writeable::R`]
306/// (i.e. not for [`Aliased`](crate::registers::Aliased) registers).
307pub trait ReadWriteable {
308    type T: UIntLike;
309    type R: RegisterLongName;
310
311    /// Write the value of one or more fields, leaving the other fields unchanged
312    fn modify(&self, field: FieldValue<Self::T, Self::R>);
313}
314
315impl<T: UIntLike, R: RegisterLongName, S> ReadWriteable for S
316where
317    S: Readable<T = T, R = R> + Writeable<T = T, R = R>,
318{
319    type T = T;
320    type R = R;
321
322    #[inline]
323    fn modify(&self, field: FieldValue<Self::T, Self::R>) {
324        self.set(field.modify(self.get()));
325    }
326}