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