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}