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}