-
Notifications
You must be signed in to change notification settings - Fork 16
Description
Currently, reasoning about bitfields in the general sense is rather difficult, because the functions they provide are unique. This is usually quite advantageous, as that lets them be const without much effort. However, under some circumstances it would make sense to be able to reason about converting between bitfields and their raw types without extra manual boilerplate.
Consider an MMIO-banked peripheral, for which that peripheral's banked location may vary between hardware platforms, but has a single API, with a series of registers offset from it's base location.
trait Peripheral {
const BASE: usize;
}It would be nice to be able to have a trait RawBitfield or similar that could provide more generic conversion functions such that I could do:
trait Peripheral {
const BASE: usize;
}
trait RawBitfield {
type Raw: Sized;
fn from_raw(raw: Self::Raw) -> Self;
fn into_raw(self) -> Self::Raw;
}
trait Register: RawBitfield {
const OFFSET: usize;
}
trait ReadRegister<Reg: Register>: Peripheral {
fn read(&self) -> Reg {
unsafe {
let reg = (Self::BASE + Reg::OFFSET) as *const Reg::Raw;
Reg::from_raw(core::ptr::read_volatile(reg))
}
}
}
trait WriteRegister<Reg: Register>: Peripheral {
fn write(&mut self, reg: Reg) {
unsafe {
let addr = (Self::BASE + Reg::OFFSET) as *mut Reg::Raw;
addr.write_volatile(reg.into_raw());
}
}
}This would open up some interesting possibilities for writing MMIO devices, at the very least, and as a HAL/PAC author, especially as one for a subset of devices without available SVD descriptors, one I would make much use of.
It would probably be worth gating this on a macro parameter, or even a feature flag, to avoid nuking the trait solver on large projects.