Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   Volatile and Registers (http://www.velocityreviews.com/forums/t595731-volatile-and-registers.html)

Mike Halloran 03-03-2008 02:19 PM

Volatile and Registers
 
Normally, when I write software to access a register, I will do
something like this:
*((volatile u32*) 0x00000022) = 5; (with some wrappers to make it
cleaner)

however, I noticed that in a recent codebase that my company aquired,
volatile
is not used:
*((u32*) 0x00000022) = 5;

Is this a proper way of coding? I was under the understanding that if
volatile is not used, the code could be optimized out. Is this
correct? What does
everyone else do?

Eric Sosman 03-03-2008 02:46 PM

Re: Volatile and Registers
 
Mike Halloran wrote:
> Normally, when I write software to access a register, I will do
> something like this:
> *((volatile u32*) 0x00000022) = 5; (with some wrappers to make it
> cleaner)
>
> however, I noticed that in a recent codebase that my company aquired,
> volatile
> is not used:
> *((u32*) 0x00000022) = 5;
>
> Is this a proper way of coding? I was under the understanding that if
> volatile is not used, the code could be optimized out. Is this
> correct? What does
> everyone else do?


First, I hope you realize that converting integers to
and from pointers is inherently "unclean," and relies on
characteristics of the particular system you happen to be
using. It's a common technique for getting at things like
hardware registers, but it's not a portable technique.

Now, as to `volatile'. Nothing in the "register-ness"
of the target location requires `volatile' in and of itself,
but in some circumstances you may need it. For example, you
might send output to some device by writing successive bytes
to an I/O register:

u32 *ioreg = (u32*)0x00000022;
*ioreg = 'H';
*ioreg = 'e';
*ioreg = 'l';
*ioreg = 'l';
*ioreg = 'o';

This may well fail if the compiler observes that the results
of the first four assignments are unused and so eliminates
them, leaving you with only the last. Adding `volatile' to
the pointer declaration

volatile u32 *ioreg = (u32*)0x00000022;

tells the compiler that each access to `*ioreg' counts as a
necessary side-effect, and obliges it to retain all five
assignments.

It also requires the compiler to generate the side-effects
in the proper order. Let's imagine an I/O device with both a
"command register" and a "data register:"

u32 *cmnd = (u32*)0x1000;
u32 *data = (u32*)0x1004;
*data = '?';
*cmnd = CMD_STROBE;

Alas, this might not work: The compiler could decide to swap
the order of the assignments or maybe to combine them both into
one 64-bit store. By declaring both pointers `volatile' you
tell the compiler that each access is a side-effect, and
since the compiler is not allowed to rearrange the order of
side-effects the two assignments will be performed in the
order you intended.

My examples have involved assigning to the volatile
object, but reading from it may also be a side-effect. For
example, imagine a hardware timer:

hires_t *timer = (hires_t*)0x12345678;
hires_t t0, t1;
t0 = *timer;
lengthy_computation();
t1 = *timer;
printf ("Elapsed time: %f microseconds\n",
(double)(t1 - t0) / (HIRES_TICKS_PER_SEC * 1e6));

If the compiler deduces that lengthy_computation() does not
store to `*timer', it may fetch the value of `*timer' just
once, making `t0' and `t1' equal no matter how long the
computation runs. The desired side-effect of reading the
updated value of `*timer' has been lost. Again, the cure is
to use `volatile' to tell the compiler that the side-effect
exists and is required, and to force it to fetch twice.

Summary: Whether `volatile' is needed depends not on the
nature of the location being accessed, but on what you plan
to do with it.

--
Eric Sosman
esosman@ieee-dot-org.invalid

Richard Bos 03-03-2008 03:34 PM

Re: Volatile and Registers
 
Eric Sosman <esosman@ieee-dot-org.invalid> wrote:

> Mike Halloran wrote:
> > Normally, when I write software to access a register, I will do
> > something like this:
> > *((volatile u32*) 0x00000022) = 5; (with some wrappers to make it
> > cleaner)

>
> First, I hope you realize that converting integers to
> and from pointers is inherently "unclean," and relies on
> characteristics of the particular system you happen to be
> using. It's a common technique for getting at things like
> hardware registers, but it's not a portable technique.


Actually, the technique itself is portable. The numbers are not. I would
not expect any given system to let you write to any given address, but
if some system does allow you to write directly to some addresses, this
is precisely the technique I would expect to be able to use.

Richard


All times are GMT. The time now is 03:42 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.