Volatile and Registers

Discussion in 'C Programming' started by Mike Halloran, Mar 3, 2008.

  1. 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?
    Mike Halloran, Mar 3, 2008
    #1
    1. Advertising

  2. Mike Halloran

    Eric Sosman Guest

    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
    lid
    Eric Sosman, Mar 3, 2008
    #2
    1. Advertising

  3. Mike Halloran

    Richard Bos Guest

    Eric Sosman <> 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
    Richard Bos, Mar 3, 2008
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Calvin
    Replies:
    0
    Views:
    583
    Calvin
    Nov 23, 2005
  2. ben
    Replies:
    5
    Views:
    583
    Ulrich Eckhardt
    Jan 11, 2005
  3. Robert Gamble

    Floating Point and Wide Registers

    Robert Gamble, Aug 21, 2006, in forum: C Programming
    Replies:
    70
    Views:
    1,154
    Jun Woong
    Sep 4, 2006
  4. Haai
    Replies:
    0
    Views:
    1,327
  5. rehansherwani
    Replies:
    0
    Views:
    407
    rehansherwani
    Jul 6, 2008
Loading...

Share This Page