|
| 1 | +//! Interfaces (traits) to register types |
| 2 | +//! |
| 3 | +//! This module contains traits which reflect standardized interfaces |
| 4 | +//! to different types of registers. Examples of registers |
| 5 | +//! implementing these interfaces are [`ReadWrite`](crate::registers::ReadWrite) or |
| 6 | +//! [`InMemoryRegister`](crate::registers::InMemoryRegister). |
| 7 | +//! |
| 8 | +//! Each trait has two associated type parameters, namely: |
| 9 | +//! |
| 10 | +//! - `T`: [`IntLike`](crate::registers::IntLike), indicating the |
| 11 | +//! underlying integer type used to represent the register's raw |
| 12 | +//! contents. |
| 13 | +//! |
| 14 | +//! - `R`: [`RegisterLongName`](crate::registers::RegisterLongName), |
| 15 | +//! functioning as a type to identify this register's descriptive |
| 16 | +//! name and semantic meaning. It is further used to impose type |
| 17 | +//! constraints on values passed through the API, such as |
| 18 | +//! [`FieldValue`](crate::registers::FieldValue). |
| 19 | +//! |
| 20 | +//! Registers can have different access levels, which are mapped to |
| 21 | +//! different traits respectively: |
| 22 | +//! |
| 23 | +//! - [`Readable`]: indicates that the current value of this register |
| 24 | +//! can be read. Implementations will need to provide the |
| 25 | +//! [`get`](crate::interfaces::Readable::get) method. |
| 26 | +//! |
| 27 | +//! - [`Writeable`]: indicates that the value of this register can be |
| 28 | +//! set. Implementations will need to provide the |
| 29 | +//! [`set`](crate::interfaces::Writeable::set) method. |
| 30 | +//! |
| 31 | +//! - [`ReadWriteable`]: indicates that this register can be |
| 32 | +//! _modified_. It is not sufficient for registers to be both read- |
| 33 | +//! and writable, they must also have the same semantic meaning when |
| 34 | +//! read from and written to. This is not true in general, for |
| 35 | +//! example a memory-mapped UART register might transmit when |
| 36 | +//! writing and receive when reading. |
| 37 | +//! |
| 38 | +//! If a type implements both [`Readable`] and [`Writeable`], and the |
| 39 | +//! associated |
| 40 | +//! [`RegisterLongName`](crate::registers::RegisterLongName) type |
| 41 | +//! parameters are identical, it will automatically implement |
| 42 | +//! [`ReadWriteable`]. In particular, for |
| 43 | +//! [`Aliased`](crate::registers::Aliased) this is -- in general -- |
| 44 | +//! not the case, so |
| 45 | +//! |
| 46 | +//! ```rust |
| 47 | +//! # use tock_registers::interfaces::{Readable, Writeable, ReadWriteable}; |
| 48 | +//! # use tock_registers::registers::ReadWrite; |
| 49 | +//! # use tock_registers::register_bitfields; |
| 50 | +//! register_bitfields![u8, |
| 51 | +//! A [ |
| 52 | +//! DUMMY OFFSET(0) NUMBITS(1) [], |
| 53 | +//! ], |
| 54 | +//! ]; |
| 55 | +//! let read_write_reg: &ReadWrite<u8, A::Register> = unsafe { |
| 56 | +//! core::mem::transmute(Box::leak(Box::new(0_u8))) |
| 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 | +//! ## Example: implementing a custom register type |
| 82 | +//! |
| 83 | +//! These traits can be used to implement custom register types, which |
| 84 | +//! are compatible to the ones shipped in this crate. For example, to |
| 85 | +//! define a register which sets a `u8` value using a Cell reference, |
| 86 | +//! always reads the bitwise-negated vale and prints every written |
| 87 | +//! value to the console: |
| 88 | +//! |
| 89 | +//! ```rust |
| 90 | +//! # use core::cell::Cell; |
| 91 | +//! # use core::marker::PhantomData; |
| 92 | +//! # |
| 93 | +//! # use tock_registers::interfaces::{Readable, Writeable, ReadWriteable}; |
| 94 | +//! # use tock_registers::registers::RegisterLongName; |
| 95 | +//! # use tock_registers::register_bitfields; |
| 96 | +//! # |
| 97 | +//! struct DummyRegister<'a, R: RegisterLongName> { |
| 98 | +//! cell_ref: &'a Cell<u8>, |
| 99 | +//! _register_long_name: PhantomData<R>, |
| 100 | +//! } |
| 101 | +//! |
| 102 | +//! impl<'a, R: RegisterLongName> Readable for DummyRegister<'a, R> { |
| 103 | +//! type T = u8; |
| 104 | +//! type R = R; |
| 105 | +//! |
| 106 | +//! fn get(&self) -> u8 { |
| 107 | +//! // Return the bitwise-inverse of the current value |
| 108 | +//! !self.cell_ref.get() |
| 109 | +//! } |
| 110 | +//! } |
| 111 | +//! |
| 112 | +//! impl<'a, R: RegisterLongName> Writeable for DummyRegister<'a, R> { |
| 113 | +//! type T = u8; |
| 114 | +//! type R = R; |
| 115 | +//! |
| 116 | +//! fn set(&self, value: u8) { |
| 117 | +//! println!("Setting Cell to {:02x?}!", value); |
| 118 | +//! self.cell_ref.set(value); |
| 119 | +//! } |
| 120 | +//! } |
| 121 | +//! |
| 122 | +//! register_bitfields![u8, |
| 123 | +//! DummyReg [ |
| 124 | +//! HIGH OFFSET(4) NUMBITS(4) [ |
| 125 | +//! A = 0b0001, |
| 126 | +//! B = 0b0010, |
| 127 | +//! C = 0b0100, |
| 128 | +//! D = 0b1000, |
| 129 | +//! ], |
| 130 | +//! LOW OFFSET(0) NUMBITS(4) [], |
| 131 | +//! ], |
| 132 | +//! ]; |
| 133 | +//! |
| 134 | +//! // Create a new DummyRegister over some Cell<u8> |
| 135 | +//! let cell = Cell::new(0); |
| 136 | +//! let dummy = DummyRegister { |
| 137 | +//! cell_ref: &cell, |
| 138 | +//! _register_long_name: PhantomData, |
| 139 | +//! }; |
| 140 | +//! |
| 141 | +//! // Set a value and read it back. This demonstrates the raw getters |
| 142 | +//! // and setters of Writeable and Readable |
| 143 | +//! dummy.set(0xFA); |
| 144 | +//! assert!(dummy.get() == 0x05); |
| 145 | +//! |
| 146 | +//! // Use some of the automatically derived APIs, such as |
| 147 | +//! // ReadWriteable::modify and Readable::read |
| 148 | +//! dummy.modify(DummyReg::HIGH::C); |
| 149 | +//! assert!(dummy.read(DummyReg::HIGH) == 0xb); |
| 150 | +//! ``` |
| 151 | +
|
| 152 | +use crate::registers::{ |
| 153 | + Field, FieldValue, IntLike, LocalRegisterCopy, RegisterLongName, TryFromValue, |
| 154 | +}; |
| 155 | + |
| 156 | +/// Readable register |
| 157 | +/// |
| 158 | +/// Register which at least supports reading the current value. Only |
| 159 | +/// [`Readable::get`] must be implemented, as for other methods a |
| 160 | +/// default implementation is provided. |
| 161 | +/// |
| 162 | +/// A register that is both [`Readable`] and [`Writeable`] will also |
| 163 | +/// automatically be [`ReadWriteable`], if the [`RegisterLongName`] of |
| 164 | +/// [`Readable`] is the same as that of [`Writeable`] (i.e. not for |
| 165 | +/// [`Aliased`](crate::registers::Aliased) registers). |
| 166 | +pub trait Readable { |
| 167 | + type T: IntLike; |
| 168 | + type R: RegisterLongName; |
| 169 | + |
| 170 | + /// Get the raw register value |
| 171 | + fn get(&self) -> Self::T; |
| 172 | + |
| 173 | + #[inline] |
| 174 | + /// Read the value of the given field |
| 175 | + fn read(&self, field: Field<Self::T, Self::R>) -> Self::T { |
| 176 | + field.read(self.get()) |
| 177 | + } |
| 178 | + |
| 179 | + #[inline] |
| 180 | + /// Set the raw register value |
| 181 | + fn read_as_enum<E: TryFromValue<Self::T, EnumType = E>>( |
| 182 | + &self, |
| 183 | + field: Field<Self::T, Self::R>, |
| 184 | + ) -> Option<E> { |
| 185 | + field.read_as_enum(self.get()) |
| 186 | + } |
| 187 | + |
| 188 | + #[inline] |
| 189 | + /// Make a local copy of the register |
| 190 | + fn extract(&self) -> LocalRegisterCopy<Self::T, Self::R> { |
| 191 | + LocalRegisterCopy::new(self.get()) |
| 192 | + } |
| 193 | + |
| 194 | + #[inline] |
| 195 | + /// Check if one or more bits in a field are set |
| 196 | + fn is_set(&self, field: Field<Self::T, Self::R>) -> bool { |
| 197 | + field.is_set(self.get()) |
| 198 | + } |
| 199 | + |
| 200 | + #[inline] |
| 201 | + /// Check if any specified parts of a field match |
| 202 | + fn matches_any(&self, field: FieldValue<Self::T, Self::R>) -> bool { |
| 203 | + field.matches_any(self.get()) |
| 204 | + } |
| 205 | + |
| 206 | + #[inline] |
| 207 | + /// Check if all specified parts of a field match |
| 208 | + fn matches_all(&self, field: FieldValue<Self::T, Self::R>) -> bool { |
| 209 | + field.matches_all(self.get()) |
| 210 | + } |
| 211 | +} |
| 212 | + |
| 213 | +/// Writeable register |
| 214 | +/// |
| 215 | +/// Register which at least supports setting a value. Only |
| 216 | +/// [`Writeable::set`] must be implemented, as for other methods a |
| 217 | +/// default implementation is provided. |
| 218 | +/// |
| 219 | +/// A register that is both [`Readable`] and [`Writeable`] will also |
| 220 | +/// automatically be [`ReadWriteable`], if the [`RegisterLongName`] of |
| 221 | +/// [`Readable`] is the same as that of [`Writeable`] (i.e. not for |
| 222 | +/// [`Aliased`](crate::registers::Aliased) registers). |
| 223 | +pub trait Writeable { |
| 224 | + type T: IntLike; |
| 225 | + type R: RegisterLongName; |
| 226 | + |
| 227 | + /// Set the raw register value |
| 228 | + fn set(&self, value: Self::T); |
| 229 | + |
| 230 | + #[inline] |
| 231 | + /// Write the value of one or more fields, overwriting the other fields with zero |
| 232 | + fn write(&self, field: FieldValue<Self::T, Self::R>) { |
| 233 | + self.set(field.value); |
| 234 | + } |
| 235 | + |
| 236 | + #[inline] |
| 237 | + /// Write the value of one or more fields, maintaining the value of unchanged fields via a |
| 238 | + /// provided original value, rather than a register read. |
| 239 | + fn modify_no_read( |
| 240 | + &self, |
| 241 | + original: LocalRegisterCopy<Self::T, Self::R>, |
| 242 | + field: FieldValue<Self::T, Self::R>, |
| 243 | + ) { |
| 244 | + self.set(field.modify(original.get())); |
| 245 | + } |
| 246 | +} |
| 247 | + |
| 248 | +/// [`Readable`] and [`Writeable`] register, over the same |
| 249 | +/// [`RegisterLongName`] |
| 250 | +/// |
| 251 | +/// Register which supports both reading and setting a value. |
| 252 | +/// |
| 253 | +/// **This trait does not have to be implemented manually!** It is |
| 254 | +/// automatically implemented for every type that is both [`Readable`] |
| 255 | +/// and [`Writeable`], as long as [`Readable::R`] == [`Writeable::R`] |
| 256 | +/// (i.e. not for [`Aliased`](crate::registers::Aliased) registers). |
| 257 | +pub trait ReadWriteable { |
| 258 | + type T: IntLike; |
| 259 | + type R: RegisterLongName; |
| 260 | + |
| 261 | + /// Write the value of one or more fields, leaving the other fields unchanged |
| 262 | + fn modify(&self, field: FieldValue<Self::T, Self::R>); |
| 263 | +} |
| 264 | + |
| 265 | +impl<T: IntLike, R: RegisterLongName, S> ReadWriteable for S |
| 266 | +where |
| 267 | + S: Readable<T = T, R = R> + Writeable<T = T, R = R>, |
| 268 | +{ |
| 269 | + type T = T; |
| 270 | + type R = R; |
| 271 | + |
| 272 | + #[inline] |
| 273 | + fn modify(&self, field: FieldValue<Self::T, Self::R>) { |
| 274 | + self.set(field.modify(self.get())); |
| 275 | + } |
| 276 | +} |
0 commit comments