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

    however, I noticed that in a recent codebase that my company aquired,
    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. Advertisements

  2. Mike Halloran

    Eric Sosman Guest

    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

    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;
    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, Mar 3, 2008
    1. Advertisements

  3. Mike Halloran

    Richard Bos Guest

    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 Bos, Mar 3, 2008
    1. Advertisements

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.