I've been studying cortex-m crate code. Mostly the ITM struct. What I can't understand is how is it possible for code:
#![no_main]
#![no_std]
use panic_itm as _;
use stm32f1xx_hal as _;
use cortex_m::{iprintln, Peripherals};
use cortex_m_rt::entry;
#[entry]
fn main() -> ! {
let mut p = Peripherals::take().unwrap();
let stim = &mut p.ITM.stim[0];
iprintln!(stim, "Hello, world!");
loop {}
}
To even compile and work. ITM struct foes not have any fields. RegisterBlock is created while accessing any field in ITM struct ?. Looks like a black magic for me.
Yep, when you write ITM.field, the Deref impl is called and a RegisterBlock is created. Note that creating this RegisterBlock just involves creating a pointer and turning it into a reference, so this “creation” is not exactly an expensive operation: It's as cheap as typing an integer somewhere in your code.
The Deref impl creates the RegisterBlock by casting the value 0xE000_0000 to a pointer. This means that when using fields of RegisterBlock, you're just accessing whatever happens to be there.
Since the stim field is a fixed-size array, it is stored in-line, and not somewhere else like you have with Vec. This means that the contents of the stim field is just whatever values happen to be in memory at address 0xE000_0000.