Thread: How do I force my compiler to access HW registers as 32 bit instead of bytes?

  1. #1
    Registered User
    Join Date
    Jun 2008
    Posts
    14

    How do I force my compiler to access HW registers as 32 bit instead of bytes?

    I have bit fields in structures to access hw registers. I tested my compiler to see how it reads/writes to the registers and noticed that the compiler is trying to access the registers by bytes. The HW registers only allow 32-bit "words" to be written or read, otherwise it will give a "bus error".

    Is there a way to force the compiler to produce WORD (32bit) accesses for bitfields instead of byte??

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Without specifics, I would ask whether your bitfields are specified as part of a 32-bit object (like a WORD) rather than an 8-bit object (like char).

    Otherwise, perhaps a union of a 32-bit object and your struct may work.

  3. #3
    Registered User
    Join Date
    Jun 2008
    Posts
    14
    A snippet of my code looks like this:

    Code:
    typedef struct {
    
      unsigned reg1 : 25;
      unsigned reg2 : 5;
      unsigned reg3 : 2;
    
    } volatile RegStruct;
    and the compiler is trying to read/write in byte-sizes

  4. #4
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    I'd suggest making each part of your struct have an even number of bytes, and making the entire struct smaller than 32. Structs may have some kind of padding for info on what they contain. Try 28 or 30.

  5. #5
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    $your_compiler may have an option to enforce 32-bit accesses, but you would be just as able to look it up as I.

    If these are one 32-bit register being broken up into fields, then again a union seems like a reasonable way to go here; do all the reads and writes with the 32-bit object, and then interpret via the struct object. (Assuming you even want a struct then, rather than using bitmasks.)

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    Bitfields are useless for mapping to hardware registers.

    I mean, you have this at the moment.
    unsigned reg1 : 25;
    unsigned reg2 : 5;
    unsigned reg3 : 2;

    But following some upgrade (or a port) to a new compiler, you could be editing the code to this
    unsigned reg3 : 2;
    unsigned reg2 : 5;
    unsigned reg1 : 25;

    As you've discovered, you've no control over how the compiler treats memory accesses.

    You need two small access functions, one to write the reg, and another to read it.
    - use bitwise & | >> << etc to pick out bits from a 32-bit word
    - assign the results to your bitfield struct.
    - return the struct
    And a similar thing for reading.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by samdomville View Post
    A snippet of my code looks like this:

    Code:
    typedef struct {
    
      unsigned reg1 : 25;
      unsigned reg2 : 5;
      unsigned reg3 : 2;
    
    } volatile RegStruct;
    and the compiler is trying to read/write in byte-sizes
    I'm not surprised. If we (for the moment) ignore Salem's statement, although he is correct in that statement, and assume that you still want to use a struct with bitfields, then I would recommend that you unionize that with a 32-bit value, eg:
    Code:
    typedef union {
       struct {
    
          unsigned reg1 : 25;
          unsigned reg2 : 5;
         unsigned reg3 : 2;
    
       } bits;
       uint32 word;
    } volatile RegStruct;
    Then write the word to the hardware register, not the bitfields themselves.

    So, let's say you want to modify reg1 to a new value:
    Code:
    // Somewhere global:
    RegStruct *hwReg = (RegStruct *)0x90000000;   // Fictive actual hardware address. 
    ...
    SetNewReg1(unsigned newreg1)
    {
         RegStruct val;
         val.word = hwReg->word;
         val.bits.reg1 = newreg1;
         hwReg->word = val.word
    }
    Salem's suggestion would probably generate exactly the same code, but you would be doing the shifting and masking to set reg1 manually:
    Code:
    volatile uint32 *hwReg = (volatile uint32 *)0x90000000;
    
    #define SHIFT_REG1   7
    #define MASK_REG1    ((~1) << SHIFT_REG1)
    #define SHIFT_REG2   2
    #define MASK_REG2   (((1 << 5) -1)  << SHIFT_REG2)
    #define SHIFT_REG3  0
    #define MASK_REG3   (((1 << 2) -1)  << SHIFT_REG3)
    ... 
    SetNewReg1(unsigned newreg1)
    {
         uint32 val;
         val = *hwReg;
         val = (newreg  << SHIFT_REG1)| (val) & (mask_reg2 | mask_reg3));
         *hwReg = val
    }
    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  8. #8
    Registered User
    Join Date
    Jun 2008
    Posts
    14
    THANKS for all this amazing information! My boss is convinced that we should move away from the bit fields. I just need to know which method requires LESS memory/space? Unionizing the bitfields, or Salem's suggestion?

  9. #9
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by samdomville View Post
    THANKS for all this amazing information! My boss is convinced that we should move away from the bit fields. I just need to know which method requires LESS memory/space? Unionizing the bitfields, or Salem's suggestion?
    Unionizing the bitfields requires 32 bits of space. A register variable and using bitmasks requires 32 bits of space (unless you want to store the values separately from the register-as-a-whole, then that would take 64 bits).

  10. #10
    Registered User
    Join Date
    Jun 2008
    Posts
    14
    Quote Originally Posted by tabstop View Post
    Unionizing the bitfields requires 32 bits of space. A register variable and using bitmasks requires 32 bits of space (unless you want to store the values separately from the register-as-a-whole, then that would take 64 bits).

    I have never used "union" before. What will union do to the struct?

  11. #11
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by samdomville View Post
    I have never used "union" before. What will union do to the struct?
    Nothing.

    union just overlays two variables into the same memory location (broadly speaking). So you would have a union with an int and your struct, and each of them would use the same 32 bits of memory. (But reading/writing the int would force the compiler to read all 32 bits, instead of just 8 sometimes.)

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 16
    Last Post: 11-23-2007, 01:48 PM
  2. Replies: 7
    Last Post: 12-10-2004, 08:18 AM
  3. question about 32 bit addresses??
    By newbie02 in forum C++ Programming
    Replies: 3
    Last Post: 09-12-2003, 02:02 PM
  4. 16 bit or 32 bit
    By Juganoo in forum C Programming
    Replies: 9
    Last Post: 12-19-2002, 07:24 AM