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 thegetmethod. -
Writeable: indicates that the value of this register can be set. Implementations will need to provide thesetmethod. -
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
ReadableandWriteable, and the associatedRegisterLongNametype parameters are identical, it will automatically implementReadWriteable. In particular, forAliasedthis 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