Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Controlling read and write access width to memory mapped registers in C

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

like image 614
srking Avatar asked Jun 14 '10 18:06

srking


1 Answers

Your concerns are covered by the volatile qualifier.

6.7.3/6 "Type qualifiers" says:

An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Therefore any expression referring to such an object shall be evaluated strictly according to the rules of the abstract machine, as described in 5.1.2.3. Furthermore, at every sequence point the value last stored in the object shall agree with that prescribed by the abstract machine, except as modified by the unknown factors mentioned previously. What constitutes an access to an object that has volatile-qualified type is implementation-defined.

5.1.2.3 "Program execution" says (among other things):

In the abstract machine, all expressions are evaluated as specified by the semantics.

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:

An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced (including any caused by calling a function or accessing a volatile object).

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).

like image 154
Michael Burr Avatar answered Sep 28 '22 06:09

Michael Burr