Microcontrollers often require a register to be read to clear certain status conditions. Is there a portable way in C to ensure that a read is not optimized away if the data is not used? Is it sufficient that the pointer to the memory mapped register is declared as volatile? In other words, would the following always work on standard compliant compilers?
void func(void)
{
volatile unsigned int *REGISTER = (volatile unsigned int *) 0x12345678;
*REGISTER;
}
I understand that dealing with functionality like this runs into compiler-dependent issues. So, my definition of portable is a bit loose in this case. I just mean that it would work as widely as possible with the most popular toolchains.
Perhaps GNU C specific extensions is not considered very portable, but here is another alternative.
This will translate to the following assembler line (compiled with gcc x86 and optimized with -O2) :
movl SOME_REGISTER(%rip), %eax?
I get the same assembler from:
... as suggested in another answer, but
read1()
will handle different register sizes. Even though I'm not sure if usingread2()
with 8 or 16-bit registers would ever be an issue, there are at least no warnings on parameter type.People argue quite strenuously about exactly what
volatile
means. I think most people agree that the construct you show was intended to do what you want, but there is no general agreement that the language in the C standard actually guarantees it as of C99. (The situation may have been improved in C2011; I haven't read that yet.)A nonstandard, but fairly widely supported by embedded compilers, alternative that may be more likely to work is
(The 'volatile' here appies to the 'asm' and means 'this may not be deleted even though it has no output operands. It is not necessary to put it on the pointer as well.)
The major remaining drawback of this construct is that you still have no guarantee that the compiler will generate a one-instruction memory read. With C2011, using
_Atomic unsigned int
might be sufficient, but in the absence of that feature, you pretty much have to write a real (nonempty) assembly insert yourself if you need that guarantee.EDIT: Another wrinkle occurred to me this morning. If reading from the memory location has the side-effect of changing the value at that memory location, you need
to prevent mis-optimization of other reads from that location. (To be 100% clear, this change will not change the assembly language generated for
func
itself, but may affect optimization of surrounding code, particularly iffunc
is inlined.)Compilers usually do not optimize assembly inlines (it's hard to analyze them properly). Moreover, it seems to be a proper solution: you want more explicit control over the registers and it's natural for assembly.
Since you're programming a microcontroller, I assume that there is some assembly already in your code, so a bit of inline assembly won't be a problem.
IIRC, the C standard is a bit loose in the definition of use, so the
*REGISTER
is not necessarily interpreted as doing a read.But the following should do:
That is, the result of the memory reference has to be used somewhere. The
x
does not need to be volatile, however.UPDATE: To avoid the warning of _unused variable you could do with a no-op function. A static and/or inline function should be optimized away without runtime penalty:
UPDATE 2: I've just came up with a nicer function:
Now, this function can be used both for read-and-use and for read-and-discard. 8-)
Yes, the C standard guarantees that code accessing a volatile variable will not be optimized away.
C11 5.1.2.3/2
C11 5.1.2.3/4
C11 5.1.2.3/6