Module tock_registers::interfaces
source · [−]Expand description
Interfaces (traits) to register types
This module contains traits which reflect standardized interfaces
to different types of registers. Examples of registers
implementing these interfaces are ReadWrite
or
InMemoryRegister
.
Each trait has two associated type parameters, namely:
-
T
:UIntLike
, indicating the underlying integer type used to represent the register’s raw contents. -
R
:RegisterLongName
, functioning as a type to identify this register’s descriptive name and semantic meaning. It is further used to impose type constraints on values passed through the API, such asFieldValue
.
Registers can have different access levels, which are mapped to different traits respectively:
-
Readable
: indicates that the current value of this register can be read. Implementations will need to provide theget
method. -
Writeable
: indicates that the value of this register can be set. Implementations will need to provide theset
method. -
ReadWriteable
: indicates that this register can be modified. It is not sufficient for registers to be both read- and writable, they must also have the same semantic meaning when read from and written to. This is not true in general, for example a memory-mapped UART register might transmit when writing and receive when reading.If a type implements both
Readable
andWriteable
, and the associatedRegisterLongName
type parameters are identical, it will automatically implementReadWriteable
. In particular, forAliased
this is – in general – not the case, soregister_bitfields![u8, A [ DUMMY OFFSET(0) NUMBITS(1) [], ], ]; let read_write_reg: &ReadWrite<u8, A::Register> = unsafe { core::mem::transmute(Box::leak(Box::new(0_u8))) }; ReadWriteable::modify(read_write_reg, A::DUMMY::SET);
works, but not
ⓘregister_bitfields![u8, A [ DUMMY OFFSET(0) NUMBITS(1) [], ], B [ DUMMY OFFSET(0) NUMBITS(1) [], ], ]; let aliased_reg: &Aliased<u8, A::Register, B::Register> = unsafe { core::mem::transmute(Box::leak(Box::new(0_u8))) }; ReadWriteable::modify(aliased_reg, A::DUMMY::SET);
Example: implementing a custom register type
These traits can be used to implement custom register types, which
are compatible to the ones shipped in this crate. For example, to
define a register which sets a u8
value using a Cell reference,
always reads the bitwise-negated vale and prints every written
value to the console:
struct DummyRegister<'a, R: RegisterLongName> {
cell_ref: &'a Cell<u8>,
_register_long_name: PhantomData<R>,
}
impl<'a, R: RegisterLongName> Readable for DummyRegister<'a, R> {
type T = u8;
type R = R;
fn get(&self) -> u8 {
// Return the bitwise-inverse of the current value
!self.cell_ref.get()
}
}
impl<'a, R: RegisterLongName> Writeable for DummyRegister<'a, R> {
type T = u8;
type R = R;
fn set(&self, value: u8) {
println!("Setting Cell to {:02x?}!", value);
self.cell_ref.set(value);
}
}
register_bitfields![u8,
DummyReg [
HIGH OFFSET(4) NUMBITS(4) [
A = 0b0001,
B = 0b0010,
C = 0b0100,
D = 0b1000,
],
LOW OFFSET(0) NUMBITS(4) [],
],
];
// Create a new DummyRegister over some Cell<u8>
let cell = Cell::new(0);
let dummy = DummyRegister {
cell_ref: &cell,
_register_long_name: PhantomData,
};
// Set a value and read it back. This demonstrates the raw getters
// and setters of Writeable and Readable
dummy.set(0xFA);
assert!(dummy.get() == 0x05);
// Use some of the automatically derived APIs, such as
// ReadWriteable::modify and Readable::read
dummy.modify(DummyReg::HIGH::C);
assert!(dummy.read(DummyReg::HIGH) == 0xb);
Traits
Readable
and Writeable
register, over the same
RegisterLongName
Readable register
Writeable register