I was going through the STM32F3 Discovery board tutorial, embedonomicon and learning Rust at the same time, and was thinking that perhaps a Register Type might be a useful idea.
-
Imagine an unsigned int where we specify the memory address, not the compiler/linker.
let DBGMCU_IDCODE: r32 @ 0xE004_2000;
-
This would put the register type under the standard borrow and safety checking rules. unsafe {} no longer needed.
-
The register type can inherit all the methods and traits as its unsigned int cousin.
-
r8, r16, r32, r64 type names.
-
Directly interoperable with unsigned ints of same size.
let myInt32: u32 = myRegister32;
-
Store addresses of functions in registers (or specific memory locations) for interrupts and call backs.
-
Store addresses of buffers for DMA, IO, encryption and math operations.
-
Avoid a lot of confusing C-like pointer messiness.
It would be different from the unsigned int in these ways:
- No heap or stack allocation. (except meta data?)
- Volatile [in the sense that a A/D register will always read a different value.]
- Never initialized, unless explicitly initialized.
- Never set to a value when dropped.
- Never optimized out, or cached.
If registers are possible, then structs can abstract groups of registers.
rstruct! GPIOx {
MODER: r32 @ BASE,
OTYPER: r32 @ BASE + 4,
OSPEEDR: r32 @ BASE + 8,
...
BRR: r32 @ BASE + 28,
}
let mut gpioA: GPIOx @ 0x4800_0000 {
// Nothing needed here, the address
// given will become 'BASE' to set
// the register addresses above
};
And large arrays of register types could be abstracted to buffers:
let mut framebuffer: [r32 @ 0xC000_0000; 480 * 240]; // 480*240*32bpp
--
In short, we could move a lot of unsafe code into the safe realm with some register types.
--
If we take the example from
https://rust-embedded.github.io/bookshelf/discovery/07-registers/index.html
We could change all the
*(GPIOE_BSRR as *mut u32)
into just:
GPIOE_BSRR
We can drop unsafe{}, AND be under the safety/borrow checker:
...
fn main() -> ! {
aux7::init();
let mut PIOE_BSRR: r32 @ 0x48001018;
GPIOE_BSRR = 1 << 9;
GPIOE_BSRR = 1 << 11;
GPIOE_BSRR = 1 << (9 + 16);
GPIOE_BSRR = 1 << (11 + 16);
loop { }
}
Anyway, just an idea. I'm new to Rust and haven't enjoyed learning a language this much in a LOOONG time.