[En-Nut-Discussion] Hardware Register Access Using Volatile Pointer

Harald Kipp harald.kipp at egnite.de
Tue Apr 26 09:27:50 CEST 2011

Hi Bernd,

On 4/25/2011 10:45 PM, Bernd Walter wrote:
> On Mon, Apr 25, 2011 at 07:51:25PM +0200, Harald Kipp wrote:
>> #define inr(_reg)   (*((volatile unsigned int *)(_reg)))
> The Atmel ARM include has something like this:
> typedef volatile unsigned int AT91_REG;// Hardware register definition typedef struct
> _AT91S_SYS {
> AT91_REG         AIC_SMR[32];   // Source Mode Register
> AT91_REG         AIC_SVR[32];   // Source Vector Register

IMHO, that's even worse. inr() and outr() offer much more flexibility.

>> The problem is, that the compiler will not guarantee, that the
>> sequence of statements is kept. To force this, a memory barrier
>> can be used
> Which statements can be reordered?

Any, as long as this doesn't break the logic of statements.

The order of accesses to volatile memory is kept. But when mixing
volatile and non-volatile accesses, the optimizer may re-order the
statements, which may introduce unexpected side effects.

I vaguely remember such a case, but cannot remember where that happened 
exactly. Let me try to construct a lousy example. Let's assume, we have 
an interrupt routine running in two modes, controlled by a global variable.

   /* Set mode used by IRQ function. */
   imode = 0;
   /* Enable interrupts. */
   outr(EIR, 1);

The compiler may decide to execute

   outr(EIR, 1);
   imode = 0;

Of course we could declare imode as volatile too to force the compiler 
to execute the statements in right order. BUT:

1. imode is not volatile per definition, because its content will not 
change out of the scope of the compiler.

2. Each time imode is used at other places, the compiler will generate 
less optimal code.

> A memory barrier usually is more than just a compiler thing, since
> it pushed things out to the coherence point for other CPUs or DMA.

I know, but when implemented as

  asm volatile("": : :"memory");

it is just a compiler thing. It simply tells GCC to write out all values 
which are temporarily kept in registers. This will have the effect, that 
outr() and inr() are working correctly even if the pointers are not 
declared as pointers to volatiles.

> - IMHO the compiler shouldn't reorder things around volatile
> variables.

Is this documented (guaranteed) anywhere?

> With the original volatile it must read, since it is volatile. In
> your cae with the barrier I'm not sure, since it's not reading from
> a volatile memory anymore it might be optimized away.

That's the point. I assume too, that the suggested approach will remove 
inr(). Further, I'm not sure, that an access to volatile memory will be 
kept, if the result is not used in the code. I wasn't able to find any 
document on this either.



More information about the En-Nut-Discussion mailing list