Closed faulesocke closed 5 years ago
The idea behind this crate is that you have a volatile memory location, for example the memory mapped register of some hardware device. Let's say there is an memory mapped u32
register at address 0xdead000
. Normally we would create a reference to it using unsafe:
let register = unsafe{ &mut *(0xdead000 as *mut u32) };
However, this way the compiler doesn't know that the memory address is volatile and uses normal read/write operations to access it, which might be reordered or optimized out. To avoid this, we use the Volatile
wrapper:
let register = unsafe{ &mut *(dead000 as *mut Volatile<u32>) };
Now we have to use special read
/write
methods of the Volatile
wrapper that tell the compiler that each read/write should be performed exactly at the place where it is written and not optimized out.
Volatile arrays are currently difficult to abstract because there are no const generics in Rust yet. You can either wrap the whole array in a Volatile
or use an array of Volatile
s (e.g. [Volatile<u32>; 100]
). The first approach has the problem that each read/write has to load/store the complete array, even if only a single entry is accessed. The second approach can access individual entries but is slower when accessing many entries because the compiler generates many small memory accesses instead of a few large ones.
I hope that https://github.com/rust-lang/rust/pull/53645 is merged soon. It implements a first version of const generics. This would allows us to create a generic VolatileArray
and VolatileSlice
types, which would allow accessing an arbitrary number of array/slice elements with a single volatile read/write operation.
I hope this helps!
Wow, now I understood it, this approach is quite clever. Thanks a lot.
Hey there,
would it be possible, to provide a short but complete usage example, that allows, for example reading a volatile array?
From reading the source and the documentation I don't really get, how this thing works and how to make it perform volatile reads.