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}