Hello, we discussed this shortly on the live stream yesterday, but here is a more detailed issue so we can write everything down.
Right now if you have a struct that represents a special function register (SFR) on an embedded chip and you have a pointer with the type of that struct pointing to a location in memory. You need to make that pointer volatile in order to guarentee the SFR is written to.
Often the SFR's are write only memory (or read only) and because the pointer is marked volatile, the SFR is accessed via the pointer, the generated assembly first reads the write only memory, than orrs that with the value the value you want to write before writing the value. This is inefficient and undefined behavior on many chips.
Here is an example of inefficient (arm thumb) assembly generated:
code:
const SFR = packed struct {
_reserved0_27: u28,
field: u4,
};
export fn initSomeSFR() void {
var sfr1 = @intToPtr(*volatile SFR, 0xdeadbeef);
sfr1.field= 0b0110;
}
assembly:
initSomeSFR:
movs r0, #15 -- Load bitmask
lsls r0, r0, #28 -- 0b11110000000000000000000000000000
ldr r1, .LCPI0_0 -- Load address to write to
ldr r2, [r1] -- Read address value
bics r2, r0 -- bit clear with the mask (and)
movs r0, #3 -- load value to write
lsls r0, r0, #29 -- 0b01100000000000000000000000000000
adds r0, r2, r0 -- add it with the cleared register value (orr)
str r0, [r1] -- store it
bx lr -- return
.LCPI0_0:
.long 3735928559
this is what optimal assembly would look like:
initSomeSFR:
movs r0, #3
lsls r0, r0, #29
ldr r1, .LCPI0_0
str r0, [r1]
bx lr
.LCPI0_0:
.long 3735928559
We discussed some ways of solving this problem yesterday which where:
Solving it as has been done by this C++ library. That uses template meta programming to merge and reorder writes to registers. I think this is very possible to do with the metaprogramming that zig supports
Another option would be to expand volatile semantics and add something along the lines of volatiler volatilew that specify the read or write-onlyness of the memory. This would still not allow the compiler to reorder or merge accesses to a register, so if you would want that functionality you would need to write some compiletime library yourself anyway.
There are some other questions that remain.
- What is the use of
volatiler?, Are there cases where there are write instructions generated if you mark a read only register as normal volatile?
- Are there cases where writing 0's to a field not accessed in a write only register is the wrong thing to do?
Hello, we discussed this shortly on the live stream yesterday, but here is a more detailed issue so we can write everything down.
Right now if you have a struct that represents a special function register (SFR) on an embedded chip and you have a pointer with the type of that struct pointing to a location in memory. You need to make that pointer volatile in order to guarentee the SFR is written to.
Often the SFR's are write only memory (or read only) and because the pointer is marked volatile, the SFR is accessed via the pointer, the generated assembly first reads the write only memory, than orrs that with the value the value you want to write before writing the value. This is inefficient and undefined behavior on many chips.
Here is an example of inefficient (arm thumb) assembly generated:
code:
assembly:
this is what optimal assembly would look like:
We discussed some ways of solving this problem yesterday which where:
Solving it as has been done by this C++ library. That uses template meta programming to merge and reorder writes to registers. I think this is very possible to do with the metaprogramming that zig supports
Another option would be to expand volatile semantics and add something along the lines of
volatilervolatilewthat specify the read or write-onlyness of the memory. This would still not allow the compiler to reorder or merge accesses to a register, so if you would want that functionality you would need to write some compiletime library yourself anyway.There are some other questions that remain.
volatiler?, Are there cases where there are write instructions generated if you mark a read only register as normalvolatile?