Re: hardware access

Discussion in 'C++' started by James Harris, Jan 10, 2009.

  1. James Harris

    James Harris Guest

    On 10 Jan, 00:38, "Benjamin David Lunt" <> wrote:
    > Hi guys,
    >
    > I have come across a problem I haven't seen before.
    > I have the following code:
    >
    >   struct S_FOO {
    >     unsigned long bar;
    >   };
    >   volatile struct S_FOO *foo = (struct S_FOO *) address;
    >   if ((foo->bar & 0x000000FF) != 0x10) return FALSE;
    >
    > VC++'s optimizer is looking at that and seeing that I
    > only want the lower byte of foo->bar, so it only reads
    > the byte and skips the AND.  However, the hardware that
    > I am reading from *must* have reads/writes dword aligned
    > and read/write a dword at a time.
    >
    > If I change it to
    >
    >   if ((foo->bar & 0xF00000FF) != 0x10) return FALSE;
    >
    > to make the constant a dword, it reads as expected.
    >
    >   if ((foo->bar & 0x000000FFUL) != 0x10) return FALSE;
    >
    > Adding the UL suffix doesn't help.
    >
    > I thought that the volatile keyword would not allow
    > this to happen.
    >
    > Am I missing something?  Do I need a C/C++ refresher
    > course?
    >
    > I know this may not be the right group to post this
    > question to, but I thought there may be someone in this
    > group that has come across this before.
    >
    > Any comments would be appreciated.  Thanks,
    > Ben


    I don't know if this is correct behaviour or not. Forwarding to
    comp.lang.c++ and comp.lang.c. Maybe folks there can explain this....

    James
    James Harris, Jan 10, 2009
    #1
    1. Advertising

  2. On Jan 11, 2:01 am, James Harris <>
    wrote:
    > On 10 Jan, 00:38, "Benjamin David Lunt" <> wrote:
    >
    >
    >
    > > Hi guys,

    >
    > > I have come across a problem I haven't seen before.
    > > I have the following code:

    >
    > >   struct S_FOO {
    > >     unsigned long bar;
    > >   };
    > >   volatile struct S_FOO *foo = (struct S_FOO *) address;
    > >   if ((foo->bar & 0x000000FF) != 0x10) return FALSE;

    >
    > > VC++'s optimizer is looking at that and seeing that I
    > > only want the lower byte of foo->bar, so it only reads
    > > the byte and skips the AND.  However, the hardware that
    > > I am reading from *must* have reads/writes dword aligned
    > > and read/write a dword at a time.

    >
    > > If I change it to

    >
    > >   if ((foo->bar & 0xF00000FF) != 0x10) return FALSE;

    >
    > > to make the constant a dword, it reads as expected.

    >
    > >   if ((foo->bar & 0x000000FFUL) != 0x10) return FALSE;

    >
    > > Adding the UL suffix doesn't help.

    >
    > > I thought that the volatile keyword would not allow
    > > this to happen.

    >
    > > Am I missing something?  Do I need a C/C++ refresher
    > > course?

    >
    > > I know this may not be the right group to post this
    > > question to, but I thought there may be someone in this
    > > group that has come across this before.

    >
    > > Any comments would be appreciated.  Thanks,
    > > Ben

    >
    > I don't know if this is correct behaviour or not. Forwarding to
    > comp.lang.c++ and comp.lang.c. Maybe folks there can explain this....
    >
    > James


    K&R:

    {
    Declaring an object ... volatile announces that it has special
    properties relevant to
    optimization. Neither [const, volatile] qualifier affects the range of
    values or arithmetic
    properties of the object.

    There are no implementation-dependent semantics for volatile objects.

    The purpose of volatile is to force an implementation to suppress
    optimization that could otherwise occur. For example, for a machine
    with
    memory-mapped input/output, a pointer to a device register might be
    declared
    as a pointer to volatile, in order to prevent the compiler from
    removing apparently redundant references through the pointer.
    }

    I don't know how should the 2nd paragraph above be interpreted as per
    K&R, but the the immediately preceding one implies the size of the
    access shouldn't change as that would be removal of "apparently
    redundant references through the pointer"

    Here's what the C standard says about volatiles in relevant
    paragraphs:

    {
    5.1.2.3 Program execution

    2 Accessing a volatile object, modifying an object, modifying a file,
    or calling a function
    that does any of those operations are all side effects, (ref to
    footnote 11)
    which are changes in the state of
    the execution environment. Evaluation of an expression may produce
    side effects. At
    certain specified points in the execution sequence called sequence
    points, all side effects
    of previous evaluations shall be complete and no side effects of
    subsequent evaluations
    shall have taken place. (A summary of the sequence points is given in
    annex C.)

    3 In the abstract machine, all expressions are evaluated as specified
    by the semantics. An
    actual implementation need not evaluate part of an expression if it
    can deduce that its
    value is not used and that no needed side effects are produced
    (including any caused by
    calling a function or accessing a volatile object).

    6.7.3 Type qualifiers

    6 An object that has volatile-qualified type may be modified in ways
    unknown to the
    implementation or have other unknown side effects. Therefore any
    expression referring
    to such an object shall be evaluated strictly according to the rules
    of the abstract machine,
    as described in 5.1.2.3. Furthermore, at every sequence point the
    value last stored in the
    object shall agree with that prescribed by the abstract machine,
    except as modified by the
    unknown factors mentioned previously. (ref to footnote 114)
    What constitutes an access to an object that
    has volatile-qualified type is implementation-defined.

    footnote 114:
    A volatile declaration may be used to describe an object corresponding
    to a memory-mapped
    input/output port or an object accessed by an asynchronously
    interrupting function. Actions on
    objects so declared shall not be ‘‘optimized out’’ by an
    implementation or reordered except as
    permitted by the rules for evaluating expressions.

    J.3.10 Implementation-defined behavior/Qualifiers
    — What constitutes an access to an object that has volatile-qualified
    type (6.7.3).
    }

    So, as per the standard it seems like it may be up to the
    implementation to define what constitutes a (known and therefore
    unknown) side effect, irrespective of what the actual execution
    environment is.

    Still, to me it sounds somewhat goofy.

    Alex
    Alexei A. Frounze, Jan 11, 2009
    #2
    1. Advertising

  3. James Harris

    CBFalconer Guest

    James Harris wrote:
    > "Benjamin David Lunt" <> wrote:
    >
    >> I have come across a problem I haven't seen before.
    >> I have the following code:
    >>
    >> struct S_FOO {
    >> unsigned long bar;
    >> };
    >> volatile struct S_FOO *foo = (struct S_FOO *) address;
    >> if ((foo->bar & 0x000000FF) != 0x10) return FALSE;
    >>
    >> VC++'s optimizer is looking at that and seeing that I only want
    >> the lower byte of foo->bar, so it only reads the byte and skips
    >> the AND. However, the hardware that I am reading from *must*
    >> have reads/writes dword aligned and read/write a dword at a time.


    It appears to me that your compiler is not correct for your object
    hardware. Are you sure of your facts? Possibly the i/o system
    reads into a buffer, and then only one byte is transferred.

    --
    [mail]: Chuck F (cbfalconer at maineline dot net)
    [page]: <http://cbfalconer.home.att.net>
    Try the download section.
    CBFalconer, Jan 11, 2009
    #3
  4. "CBFalconer" <> wrote in message
    news:...
    > James Harris wrote:
    >> "Benjamin David Lunt" <> wrote:
    >>
    >>> I have come across a problem I haven't seen before.
    >>> I have the following code:
    >>>
    >>> struct S_FOO {
    >>> unsigned long bar;
    >>> };
    >>> volatile struct S_FOO *foo = (struct S_FOO *) address;
    >>> if ((foo->bar & 0x000000FF) != 0x10) return FALSE;
    >>>
    >>> VC++'s optimizer is looking at that and seeing that I only want
    >>> the lower byte of foo->bar, so it only reads the byte and skips
    >>> the AND. However, the hardware that I am reading from *must*
    >>> have reads/writes dword aligned and read/write a dword at a time.

    >
    > It appears to me that your compiler is not correct for your object
    > hardware. Are you sure of your facts? Possibly the i/o system
    > reads into a buffer, and then only one byte is transferred.


    I have also posted to a Microsoft newsgroup and a poster there
    said that VC 2008 compiles it "correctly", or more politically
    correct, the way I want it to be compiled.

    Thanks,
    Ben
    Benjamin David Lunt, Jan 11, 2009
    #4
  5. "James Harris" <> wrote in message
    news:...
    On 10 Jan, 00:38, "Benjamin David Lunt" <> wrote:
    > Hi guys,
    >
    > I have come across a problem I haven't seen before.
    > I have the following code:
    >
    > struct S_FOO {
    > unsigned long bar;
    > };
    > volatile struct S_FOO *foo = (struct S_FOO *) address;
    > if ((foo->bar & 0x000000FF) != 0x10) return FALSE;
    >
    > VC++'s optimizer is looking at that and seeing that I
    > only want the lower byte of foo->bar, so it only reads
    > the byte and skips the AND. However, the hardware that
    > I am reading from *must* have reads/writes dword aligned
    > and read/write a dword at a time.
    >
    > If I change it to
    >
    > if ((foo->bar & 0xF00000FF) != 0x10) return FALSE;
    >
    > to make the constant a dword, it reads as expected.
    >
    > if ((foo->bar & 0x000000FFUL) != 0x10) return FALSE;
    >
    > Adding the UL suffix doesn't help.
    >
    > I thought that the volatile keyword would not allow
    > this to happen.
    >
    > Am I missing something? Do I need a C/C++ refresher
    > course?
    >
    > I know this may not be the right group to post this
    > question to, but I thought there may be someone in this
    > group that has come across this before.
    >
    > Any comments would be appreciated. Thanks,
    > Ben


    I have confirmed that updating to a new version of
    the compiler generates the 'correct' code.

    The new version (15.0.30729.1) generates:

    00000400 B8000000F0 mov eax,0F0000000h
    00000405 8B00 mov eax,[eax]
    00000407 33C9 xor ecx,ecx
    00000409 3C10 cmp al,10h
    0000040B 0F95C1 setnz cl
    0000040E 49 dec ecx
    0000040F 83E122 and ecx,byte 22h
    00000412 8BC1 mov eax,ecx
    00000414 C3 ret

    as it is expected to.

    However, with the good news of the fix, came a lot of bad news.
    The new version of the compiler/linker package now included a lot
    more "baggage" along with my code. For example, it now generated
    a _memset() call to clear/set variables were the old compiler/linker
    package did not. This particular project, I can not have it
    changing the way it generates my code.

    Anyway, since I now know what the fix is, I will have to weigh
    the differences: Find a way to keep the same compiler version
    and get it to read a dword, or update to the new compiler and
    find a way to make the added baggage work. Six of one, half
    a dozen of the other...

    Thanks everyone for your comments,
    Ben
    Benjamin David Lunt, Jan 11, 2009
    #5
  6. James Harris

    James Kanze Guest

    On Jan 11, 12:01 am, James Harris <>
    wrote:
    > On 10 Jan, 00:38, "Benjamin David Lunt" <> wrote:


    > > I have come across a problem I haven't seen before.
    > > I have the following code:


    > > struct S_FOO {
    > > unsigned long bar;
    > > };
    > > volatile struct S_FOO *foo = (struct S_FOO *) address;
    > > if ((foo->bar & 0x000000FF) != 0x10) return FALSE;


    > > VC++'s optimizer is looking at that and seeing that I only
    > > want the lower byte of foo->bar, so it only reads the byte
    > > and skips the AND. However, the hardware that I am reading
    > > from *must* have reads/writes dword aligned and read/write a
    > > dword at a time.


    > > If I change it to


    > > if ((foo->bar & 0xF00000FF) != 0x10) return FALSE;


    > > to make the constant a dword, it reads as expected.


    > > if ((foo->bar & 0x000000FFUL) != 0x10) return FALSE;


    > > Adding the UL suffix doesn't help.


    > > I thought that the volatile keyword would not allow
    > > this to happen.


    > > Am I missing something? Do I need a C/C++ refresher
    > > course?


    > > I know this may not be the right group to post this
    > > question to, but I thought there may be someone in this
    > > group that has come across this before.


    > I don't know if this is correct behaviour or not. Forwarding
    > to comp.lang.c++ and comp.lang.c. Maybe folks there can
    > explain this....


    Well, technically, "What constitutes an access to an object that
    has volatile-qualified type is implementation-defined." (In C;
    in C++, all we have is a non-normative note "In general, the
    semantics of volatile are intended to be the same in C++ as in
    C.") "Implementation-defined" means that the implementation is
    required to document it (but as far as I know, none do---at
    least I've never managed to find such documentation, for any
    compiler I've used); if the implementation defined as read
    access as physically reading one or more bits of the object from
    memory, it's fully conform, although from a QoI point of view,
    it's not really conform with the intent (but that seems usual in
    the case of volatile these days).

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Jan 11, 2009
    #6
  7. James Harris

    Michael Mol Guest

    On Jan 11, 2:23 am, "Benjamin David Lunt" <>
    wrote:
    > I have confirmed that updating to a new version of
    > the compiler generates the 'correct' code.
    >
    > The new version (15.0.30729.1) generates:
    >
    > 00000400 B8000000F0       mov eax,0F0000000h
    > 00000405 8B00             mov eax,[eax]
    > 00000407 33C9             xor ecx,ecx
    > 00000409 3C10             cmp al,10h
    > 0000040B 0F95C1           setnz cl
    > 0000040E 49               dec ecx
    > 0000040F 83E122           and ecx,byte 22h
    > 00000412 8BC1             mov eax,ecx
    > 00000414 C3               ret
    >
    > as it is expected to.
    >
    > However, with the good news of the fix, came a lot of bad news.
    > The new version of the compiler/linker package now included a lot
    > more "baggage" along with my code.  For example, it now generated
    > a _memset() call to clear/set variables were the old compiler/linker
    > package did not.  This particular project, I can not have it
    > changing the way it generates my code.
    >
    > Anyway, since I now know what the fix is, I will have to weigh
    > the differences:  Find a way to keep the same compiler version
    > and get it to read a dword, or update to the new compiler and
    > find a way to make the added baggage work.  Six of one, half
    > a dozen of the other...


    One fix might be to put your read in assembly and either inline it or
    link it separately. This should let you stick with your preferred
    compiler while keeping your desired behavior.
    Michael Mol, Jan 12, 2009
    #7
  8. "Michael Mol" <> wrote in message
    news:...
    On Jan 11, 2:23 am, "Benjamin David Lunt" <>
    wrote:
    > I have confirmed that updating to a new version of
    > the compiler generates the 'correct' code.
    >
    > The new version (15.0.30729.1) generates:
    >
    > 00000400 B8000000F0 mov eax,0F0000000h
    > 00000405 8B00 mov eax,[eax]
    > 00000407 33C9 xor ecx,ecx
    > 00000409 3C10 cmp al,10h
    > 0000040B 0F95C1 setnz cl
    > 0000040E 49 dec ecx
    > 0000040F 83E122 and ecx,byte 22h
    > 00000412 8BC1 mov eax,ecx
    > 00000414 C3 ret
    >
    > as it is expected to.
    >
    > However, with the good news of the fix, came a lot of bad news.
    > The new version of the compiler/linker package now included a lot
    > more "baggage" along with my code. For example, it now generated
    > a _memset() call to clear/set variables were the old compiler/linker
    > package did not. This particular project, I can not have it
    > changing the way it generates my code.
    >
    > Anyway, since I now know what the fix is, I will have to weigh
    > the differences: Find a way to keep the same compiler version
    > and get it to read a dword, or update to the new compiler and
    > find a way to make the added baggage work. Six of one, half
    > a dozen of the other...


    : One fix might be to put your read in assembly and either inline it or
    : link it separately. This should let you stick with your preferred
    : compiler while keeping your desired behavior.

    I was hoping to get away from that. As little a work-around
    as possible. Though I may just have to anyway.

    Thanks,
    Ben
    Benjamin David Lunt, Jan 13, 2009
    #8
  9. James Harris

    James Harris Guest

    Re: hardware access, volatile and optimisations

    On 11 Jan, 00:57, CBFalconer <> wrote:
    > James Harris wrote:
    > > "Benjamin David Lunt" <> wrote:

    >
    > >> I have come across a problem I haven't seen before.
    > >> I have the following code:

    >
    > >>   struct S_FOO {
    > >>     unsigned long bar;
    > >>   };
    > >>   volatile struct S_FOO *foo = (struct S_FOO *) address;
    > >>   if ((foo->bar & 0x000000FF) != 0x10) return FALSE;

    >
    > >> VC++'s optimizer is looking at that and seeing that I only want
    > >> the lower byte of foo->bar, so it only reads the byte and skips
    > >> the AND.  However, the hardware that I am reading from *must*
    > >> have reads/writes dword aligned and read/write a dword at a time.

    >
    > It appears to me that your compiler is not correct for your object
    > hardware.  Are you sure of your facts?  Possibly the i/o system
    > reads into a buffer, and then only one byte is transferred.


    Thanks Chuck. At one point on the original ng the OP included the
    compiler output to show that the compiler was optimising-away the 32-
    bit read into an 8-bit one:

    volatile struct S_FOO *foo = (struct S_FOO *) 0xF0000000;
    if ((foo->bar & 0x000000FF) != 0x10) return 0;

    Produces:

    xxxxxx00 B8000000F0 mov eax,0F0000000h
    xxxxxx05 8A10 mov dl,[eax]

    instead of
    mov eax,0F0000000h
    mov edx,[eax]

    so the compiler was changing the 32-bit read. He tried putting
    volatile on various places and tried other compilers. In the end the
    effect was restricted to just a certain version of one compiler so the
    OP's problem is solved.

    That said I checked the reference manual section of K&R2 it says that
    a compiler may totally ignore the volatile qualifier!

    So, are there really any guarantees when using volatile in C and C++
    or do the responses to volatile depend on the compiler being used?

    James
    James Harris, Jan 15, 2009
    #9
  10. James Harris

    Guest

    Re: hardware access, volatile and optimisations

    James Harris <> wrote:
    >
    > So, are there really any guarantees when using volatile in C and C++
    > or do the responses to volatile depend on the compiler being used?


    No, there aren't any guarantees, it's just a standard way to ask the
    compiler to "do the right things", whatever those may be in its
    environment.
    --
    Larry Jones

    I won't eat any cereal that doesn't turn the milk purple. -- Calvin
    , Jan 15, 2009
    #10
    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. Tom
    Replies:
    3
    Views:
    635
  2. agnivesh

    How to access hardware ports using C ?

    agnivesh, May 9, 2005, in forum: C Programming
    Replies:
    6
    Views:
    1,481
    italy
    May 11, 2005
  3. news reader
    Replies:
    3
    Views:
    308
    Jim Langston
    Jun 30, 2007
  4. James Harris

    Re: hardware access

    James Harris, Jan 10, 2009, in forum: C Programming
    Replies:
    9
    Views:
    268
  5. newbie

    Hardware Access using Ruby?

    newbie, Mar 5, 2008, in forum: Ruby
    Replies:
    0
    Views:
    79
    newbie
    Mar 5, 2008
Loading...

Share This Page