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`], indicating the underlying
15//!   integer type used to represent the register's raw contents.
16//!
17//! - `R`: [`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`].
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`]
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 mut register_memory: u8 = 0;
58//!   let read_write_reg: &ReadWrite<u8, A::Register> = unsafe {
59//!       core::mem::transmute(&mut register_memory)
60//!   };
61//!   ReadWriteable::modify(read_write_reg, A::DUMMY::SET);
62//!   ```
63//!
64//!   works, but not
65//!
66//!   ```compile_fail
67//!   # use tock_registers::interfaces::{Readable, Writeable, ReadWriteable};
68//!   # use tock_registers::registers::Aliased;
69//!   # use tock_registers::register_bitfields;
70//!   register_bitfields![u8,
71//!       A [
72//!           DUMMY OFFSET(0) NUMBITS(1) [],
73//!       ],
74//!       B [
75//!           DUMMY OFFSET(0) NUMBITS(1) [],
76//!       ],
77//!   ];
78//!   let aliased_reg: &Aliased<u8, A::Register, B::Register> = unsafe {
79//!       core::mem::transmute(Box::leak(Box::new(0_u8)))
80//!   };
81//!   ReadWriteable::modify(aliased_reg, A::DUMMY::SET);
82//!   ```
83//!
84//! - [`Debuggable`]: indicates that the register supports producing
85//!   human-readable debug output using the `RegisterDebugValue` type.
86//!   This type can be produced with the
87//!   [`debug`](crate::interfaces::Debuggable::debug) method.  This
88//!   will return a value that implements [`Debug`](core::fmt::Debug).
89//!   It is automticaly implemented for any register implementing
90//!   [`Readable`].
91//!
92//!
93//! ## Example: implementing a custom register type
94//!
95//! These traits can be used to implement custom register types, which
96//! are compatible to the ones shipped in this crate. For example, to
97//! define a register which sets a `u8` value using a Cell reference,
98//! always reads the bitwise-negated vale and prints every written
99//! value to the console:
100//!
101//! ```rust
102//! # use core::cell::Cell;
103//! # use core::marker::PhantomData;
104//! #
105//! # use tock_registers::interfaces::{Readable, Writeable, ReadWriteable};
106//! # use tock_registers::RegisterLongName;
107//! # use tock_registers::register_bitfields;
108//! #
109//! struct DummyRegister<'a, R: RegisterLongName> {
110//!     cell_ref: &'a Cell<u8>,
111//!     _register_long_name: PhantomData<R>,
112//! }
113//!
114//! impl<'a, R: RegisterLongName> Readable for DummyRegister<'a, R> {
115//!     type T = u8;
116//!     type R = R;
117//!
118//!     fn get(&self) -> u8 {
119//!         // Return the bitwise-inverse of the current value
120//!         !self.cell_ref.get()
121//!     }
122//! }
123//!
124//! impl<'a, R: RegisterLongName> Writeable for DummyRegister<'a, R> {
125//!     type T = u8;
126//!     type R = R;
127//!
128//!     fn set(&self, value: u8) {
129//!         println!("Setting Cell to {:02x?}!", value);
130//!         self.cell_ref.set(value);
131//!     }
132//! }
133//!
134//! register_bitfields![u8,
135//!     DummyReg [
136//!         HIGH OFFSET(4) NUMBITS(4) [
137//!             A = 0b0001,
138//!             B = 0b0010,
139//!             C = 0b0100,
140//!             D = 0b1000,
141//!         ],
142//!         LOW OFFSET(0) NUMBITS(4) [],
143//!     ],
144//! ];
145//!
146//! // Create a new DummyRegister over some Cell<u8>
147//! let cell = Cell::new(0);
148//! let dummy = DummyRegister {
149//!     cell_ref: &cell,
150//!     _register_long_name: PhantomData,
151//! };
152//!
153//! // Set a value and read it back. This demonstrates the raw getters
154//! // and setters of Writeable and Readable
155//! dummy.set(0xFA);
156//! assert!(dummy.get() == 0x05);
157//!
158//! // Use some of the automatically derived APIs, such as
159//! // ReadWriteable::modify and Readable::read
160//! dummy.modify(DummyReg::HIGH::C);
161//! assert!(dummy.read(DummyReg::HIGH) == 0xb);
162//! ```
163
164use crate::fields::{Field, FieldValue, TryFromValue};
165use crate::{LocalRegisterCopy, RegisterLongName, UIntLike};
166
167/// Readable register
168///
169/// Register which at least supports reading the current value. Only
170/// [`Readable::get`] must be implemented, as for other methods a
171/// default implementation is provided.
172///
173/// A register that is both [`Readable`] and [`Writeable`] will also
174/// automatically be [`ReadWriteable`], if the [`RegisterLongName`] of
175/// [`Readable`] is the same as that of [`Writeable`] (i.e. not for
176/// [`Aliased`](crate::registers::Aliased) registers).
177pub trait Readable {
178    type T: UIntLike;
179    type R: RegisterLongName;
180
181    /// Get the raw register value
182    fn get(&self) -> Self::T;
183
184    #[inline]
185    /// Read the value of the given field
186    fn read(&self, field: Field<Self::T, Self::R>) -> Self::T {
187        field.read(self.get())
188    }
189
190    /// Set the raw register value
191    ///
192    /// The [`register_bitfields!`](crate::register_bitfields) macro will
193    /// generate an enum containing the various named field variants and
194    /// implementing the required [`TryFromValue`] trait. It is accessible as
195    /// `$REGISTER_NAME::$FIELD_NAME::Value`.
196    ///
197    /// This method can be useful to symbolically represent read register field
198    /// states throughout the codebase and to enforce exhaustive matches over
199    /// all defined valid register field values.
200    ///
201    /// ## Usage Example
202    ///
203    /// ```rust
204    /// # use tock_registers::interfaces::Readable;
205    /// # use tock_registers::registers::InMemoryRegister;
206    /// # use tock_registers::register_bitfields;
207    /// register_bitfields![u8,
208    ///     EXAMPLEREG [
209    ///         TESTFIELD OFFSET(0) NUMBITS(2) [
210    ///             Foo = 0,
211    ///             Bar = 1,
212    ///             Baz = 2,
213    ///         ],
214    ///     ],
215    /// ];
216    ///
217    /// let reg: InMemoryRegister<u8, EXAMPLEREG::Register> =
218    ///     InMemoryRegister::new(2);
219    ///
220    /// match reg.read_as_enum(EXAMPLEREG::TESTFIELD) {
221    ///     Some(EXAMPLEREG::TESTFIELD::Value::Foo) => "Tock",
222    ///     Some(EXAMPLEREG::TESTFIELD::Value::Bar) => "is",
223    ///     Some(EXAMPLEREG::TESTFIELD::Value::Baz) => "awesome!",
224    ///     None => panic!("boo!"),
225    /// };
226    /// ```
227    #[inline]
228    fn read_as_enum<E: TryFromValue<Self::T, EnumType = E>>(
229        &self,
230        field: Field<Self::T, Self::R>,
231    ) -> Option<E> {
232        field.read_as_enum(self.get())
233    }
234
235    #[inline]
236    /// Make a local copy of the register
237    fn extract(&self) -> LocalRegisterCopy<Self::T, Self::R> {
238        LocalRegisterCopy::new(self.get())
239    }
240
241    #[inline]
242    /// Check if one or more bits in a field are set
243    fn is_set(&self, field: Field<Self::T, Self::R>) -> bool {
244        field.is_set(self.get())
245    }
246
247    /// Check if any bits corresponding to the mask in the passed `FieldValue` are set.
248    /// This function is identical to `is_set()` but operates on a `FieldValue` rather
249    /// than a `Field`, allowing for checking if any bits are set across multiple,
250    /// non-contiguous portions of a bitfield.
251    #[inline]
252    fn any_matching_bits_set(&self, field: FieldValue<Self::T, Self::R>) -> bool {
253        field.any_matching_bits_set(self.get())
254    }
255
256    #[inline]
257    /// Check if all specified parts of a field match
258    fn matches_all(&self, field: FieldValue<Self::T, Self::R>) -> bool {
259        field.matches_all(self.get())
260    }
261
262    /// Check if any of the passed parts of a field exactly match the contained
263    /// value. This allows for matching on unset bits, or matching on specific values
264    /// in multi-bit fields.
265    #[inline]
266    fn matches_any(&self, fields: &[FieldValue<Self::T, Self::R>]) -> bool {
267        fields
268            .iter()
269            .any(|field| self.get() & field.mask() == field.value)
270    }
271}
272
273/// [`Debuggable`] is a trait for registers that support human-readable debug
274/// output with [`core::fmt::Debug`].  It extends the [`Readable`] trait and
275/// doesn't require manual implementation.
276///
277/// This is implemented for the register when using the [`register_bitfields`] macro.
278///
279/// The `debug` method returns a value that implements [`core::fmt::Debug`].
280///
281/// [`register_bitfields`]: crate::register_bitfields
282pub trait Debuggable: Readable {
283    /// Returns a [`RegisterDebugValue`](crate::debug::RegisterDebugValue) that
284    /// implements [`core::fmt::Debug`], the debug information is extracted from
285    /// `<Register>::DebugInfo`.
286    #[inline]
287    fn debug(&self) -> crate::debug::RegisterDebugValue<Self::T, Self::R>
288    where
289        Self::R: crate::debug::RegisterDebugInfo<Self::T>,
290    {
291        crate::debug::RegisterDebugValue {
292            data: self.get(),
293            _reg: core::marker::PhantomData,
294        }
295    }
296}
297
298// pass Readable implementation to Debuggable
299impl<T: Readable> Debuggable for T {}
300
301/// Writeable register
302///
303/// Register which at least supports setting a value. Only
304/// [`Writeable::set`] must be implemented, as for other methods a
305/// default implementation is provided.
306///
307/// A register that is both [`Readable`] and [`Writeable`] will also
308/// automatically be [`ReadWriteable`], if the [`RegisterLongName`] of
309/// [`Readable`] is the same as that of [`Writeable`] (i.e. not for
310/// [`Aliased`](crate::registers::Aliased) registers).
311pub trait Writeable {
312    type T: UIntLike;
313    type R: RegisterLongName;
314
315    /// Set the raw register value
316    fn set(&self, value: Self::T);
317
318    #[inline]
319    /// Write the value of one or more fields, overwriting the other fields with zero
320    fn write(&self, field: FieldValue<Self::T, Self::R>) {
321        self.set(field.value);
322    }
323
324    #[inline]
325    /// Write the value of one or more fields, maintaining the value of unchanged fields via a
326    /// provided original value, rather than a register read.
327    fn modify_no_read(
328        &self,
329        original: LocalRegisterCopy<Self::T, Self::R>,
330        field: FieldValue<Self::T, Self::R>,
331    ) {
332        self.set(field.modify(original.get()));
333    }
334}
335
336/// [`Readable`] and [`Writeable`] register, over the same
337/// [`RegisterLongName`]
338///
339/// Register which supports both reading and setting a value.
340///
341/// **This trait does not have to be implemented manually!** It is
342/// automatically implemented for every type that is both [`Readable`]
343/// and [`Writeable`], as long as [`Readable::R`] == [`Writeable::R`]
344/// (i.e. not for [`Aliased`](crate::registers::Aliased) registers).
345pub trait ReadWriteable {
346    type T: UIntLike;
347    type R: RegisterLongName;
348
349    /// Write the value of one or more fields, leaving the other fields unchanged
350    fn modify(&self, field: FieldValue<Self::T, Self::R>);
351}
352
353impl<T: UIntLike, R: RegisterLongName, S> ReadWriteable for S
354where
355    S: Readable<T = T, R = R> + Writeable<T = T, R = R>,
356{
357    type T = T;
358    type R = R;
359
360    #[inline]
361    fn modify(&self, field: FieldValue<Self::T, Self::R>) {
362        self.set(field.modify(self.get()));
363    }
364}