I’m using and x86 based core to manipulate a 32-bit memory mapped register. My hardware behaves correctly only if the CPU generates 32-bit wide reads and writes to this register. The register is aligned on a 32-bit address and is not addressable at byte granularity.
What can I do to guarantee that my C (or C99) compiler will only generate full 32-bit wide reads and writes in all cases?
For example, if I do a read-modify-write operation like this:
volatile uint32_t* p_reg = 0xCAFE0000;
*p_reg |= 0x01;
I don’t want the compiler to get smart about the fact that only the bottom byte changes and generate 8-bit wide read/writes. Since the machine code is often more dense for 8-bit operations on x86, I’m afraid of unwanted optimizations. Disabling optimizations in general is not an option.
—– EDIT ——-
An interesting and very relevant paper: http://www.cs.utah.edu/~regehr/papers/emsoft08-preprint.pdf
Your concerns are covered by the
volatilequalifier.6.7.3/6 “Type qualifiers” says:
5.1.2.3 “Program execution” says (among other things):
This is followed by a sentence that is commonly referred to as the ‘as-if’ rule, which allows an implementation to not follow the abstract machine semantics if the end result is the same:
But, 6.7.3/6 essentially says that volatile-qualified types used in an expression cannot have the ‘as-if’ rule applied – the actual abstract machine semantics must be followed. Therefore, if pointer to a volatile 32-bit type is dereferenced, then the full 32-bit value must be read or written (depending on the operation).