Poofjunior
Posts: 35
Joined: Tue May 15, 2012 5:27 pm
Location: Claremont California

Defining addresses and bit-fields with structs

Mon Feb 10, 2014 7:55 am

Hi everyone,

I recently stumbled upon this book:
http://books.google.com/books?id=i62vDV ... on&f=false

It discusses defining bit-fields of an address with a structure using the ':' operator.

With a header file of structs like these, writing code for peripheral programming becomes quite nice!

We can write:

Code: Select all

    while ( !(UART_RIS.RXRIS) );                                                
    return UART_DR.DATA;
with a header file under the covers that has this:

Code: Select all

                                                                                 
typedef struct                                                                  
{                                                                               
    unsigned int RIRMIS     : 1;                                                
    unsigned int CTSRMIS    : 1;                                                
    unsigned int DCDRMIS    : 1;                                                
    unsigned int DSRRMIS    : 1;                                                
    unsigned int RXRIS      : 1;                                                
    unsigned int TXRIS      : 1;                                                
    unsigned int RTRIS      : 1;                                                
    unsigned int FERIS      : 1;                                                
    unsigned int PERIS      : 1;                                                
    unsigned int BERIS      : 1;                                                
    unsigned int OERIS      : 1;                                                
    unsigned int RESERVED   : 21;                                               
} uart_ris;                                                                     
#define UART_RIS (* (uart_ris*) 0x2020103c)    

typedef struct                                                                  
{                                                                               
    unsigned int DATA       : 8;                                                
    unsigned int FE         : 1;                                                
    unsigned int PE         : 1;                                                
    unsigned int BE         : 1;                                                
    unsigned int OE         : 1;                                                
    unsigned int RESERVED   : 20;                                               
} uart_dr;                                                                      
#define UART_DR (* (uart_dr*) 0x20201000)  

Assuming I'm willing to write out the header file to get that kind of syntax, is there any reason why I should not do something like this?

Thanks!

dom
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 5708
Joined: Wed Aug 17, 2011 7:41 pm
Location: Cambridge

Re: Defining addresses and bit-fields with structs

Mon Feb 10, 2014 11:58 am

Poofjunior wrote:Hi everyone,
Assuming I'm willing to write out the header file to get that kind of syntax, is there any reason why I should not do something like this?
It's not portable. C makes no guarantees about the order of the bits in the bitfields. A different compiler may not work with the same code.

Also hardware may require a certain width access (typically 32-bit) to talk to peripherals.
The C compiler may decide the bitfield access can be done more efficiently with a 16 or 8-bit access which probably won't do the right thing.

dwelch67
Posts: 1002
Joined: Sat May 26, 2012 5:32 pm

Re: Defining addresses and bit-fields with structs

Mon Feb 10, 2014 2:28 pm

Never use bitfields...ever...period. It is as simple as that. One of the two K or R regretted it later, I dont have a link to a reference of that though.

Obviously the compiler is going to generate masking and shifting, basically you can implement the same yourself but instead have maintainable and portable (and usable) code. Even where the instruction set has a bit set or bit clear the optimizer will figure that out.

David

Poofjunior
Posts: 35
Joined: Tue May 15, 2012 5:27 pm
Location: Claremont California

Re: Defining addresses and bit-fields with structs

Mon Feb 10, 2014 9:32 pm

Thanks for the replies.

When you mention "not portable," does that mean that the C code can't be used by others systems? If that's the case, then it makes sense that bit fields wouldn't be portable, but I think they also may make sense for this particular application. In this case, the code works only in a bare-metal context and only for a Pi.

Right now, I'm using bit fields to access the actual bit fields in hardware addresses. In the example above, DATA is a bit field in the UART_DR register taken from the datasheet. While that example isn't very evocative of how using bit fields could be advantageous, other situations could be advantageous where a number of settings can be changed from a single address by toggling multiple bit fields.

If possible, I'd like to know more why this is such bad practice before shunning myself from doing so. :D

User avatar
joan
Posts: 15372
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Defining addresses and bit-fields with structs

Mon Feb 10, 2014 9:56 pm

Non-portable means the program may not work on a machine other than the Pi and also may not work on the Pi if you change compiler.

I can't see either of those being a problem for what you are planning.

dwelch67
Posts: 1002
Joined: Sat May 26, 2012 5:32 pm

Re: Defining addresses and bit-fields with structs

Tue Feb 11, 2014 3:13 am

Code: Select all

struct hello
{
    unsigned int a 1;
    unsigned int b 1;
    unsigned int c 2;
    unsigned int d 4;
};
...
hello.a=1;
On the same machine or different machines

Sometimes will set bit 7, sometimes will set bit 0. Or it may instead set bit 31. Or bit 15, even bit 63. That is essentially what it means to use bitfields. There is nothing in the standard and nothing in your code that you can do to make it predictable (other than to never use bitfields).

Now the same compiler the same day with no other changes will produce the same code over and over again and modify the same bit. But if you change compiler options, upgrade or change the compiler, or use a different compiler even on the same machine there is no reason to expect that it will behave the same, it can choose any one of the above possibilities.

Of course what you could have done instead was:

Code: Select all

hello|=(1<<7);
EXTREMELY portable, certainly significantly more portable than bitfields. And at least on this platform, same machine any compiler it will produce the same results.

Now try this

Code: Select all

struct hello
{
    unsigned int a 1;
    unsigned int c 2;
    unsigned int d 4;
};
hello.a = 1;
and it gets much worse that can set bit 7 or 6 or 0 or 1 or 63 or 62 or 31 or 30 or 15 or 14 and all be completely compatible to the C standards.

My personal rule that you are violating here is you are crossing compile boundaries with a struct, whenever you do something like this and point a struct at hardware (use it as an address on an address bus, use it for a field in a register, pass the struct to memory and pick it up by separately compiled code (even with the same compiler against different code with different compile options)), that is using a struct across a compile boundary and it is nothing but a headache. bitfields or not. Actually any time you assign the address of a struct or struct generated in this case at anything you violate that with the exception of struct=malloc();

Now some folks prefer to use a different margin, keeping to a simple middle ground and having their code run, predictably, on more platforms and for longer periods of time without maintenance or modification. bbut you are limited to less language features. Other folks prefer more freedom and prefer to touch their code every re-compile or every compiler change or every platform so that they can use more language features and/or dont have to learn how the language or tools work.

If you have not figured it out bitfields is like religion or politics, something that is backed by very very strong feelings...Almost always results in a flame war.

David

findx
Posts: 29
Joined: Mon Jul 29, 2013 7:52 pm

Re: Defining addresses and bit-fields with structs

Tue Feb 11, 2014 6:22 am

There are also instances where bitfields are unable to set individual bits. For example, you have to feed password bits at the same time you set other the bits on the RPi GPIO pads control register:

http://www.scribd.com/doc/101830961/GPIO-Pads-Control2

So you're back to or'ing together bits for a single write, unless the compiler happens to combine multiple bitfield lines with the password into one write, which I don't think should happen for a volatile hardware register.

hermanhermitage
Posts: 65
Joined: Sat Jul 07, 2012 11:21 pm
Location: Zero Page

Re: Defining addresses and bit-fields with structs

Tue Feb 11, 2014 7:40 am

Apart from the portability issues, bitfields can make program logic rather unclear by hiding the sequence of read-modify-write involved. When accessing hardware registers you usually want transparency on the bus traffic. Hardware level programming you tend to want things clear and explicit.

Where bitfields are useful is for when you want to keep tightly packed memory resident internal data structures and
(1) you aren't worried about layout/data portability/exchange, or stability between compilers.
(2) you want a simple notation to access the fields.

User avatar
chrisryall
Posts: 155
Joined: Wed Nov 27, 2013 11:45 am
Location: Wirral UK
Contact: Website

Re: Defining addresses and bit-fields with structs

Tue Feb 11, 2014 9:01 am

Thanks, exemplary clear laying out of the issues. I'd wondered about all those bit shifts in constants and they make sense now.

Poofjunior
Posts: 35
Joined: Tue May 15, 2012 5:27 pm
Location: Claremont California

Re: Defining addresses and bit-fields with structs

Tue Feb 11, 2014 11:01 pm

Thanks everyone.

The reason I asked is because I've seen syntax style similar to the one I'm proposing implemented in PIC32 development with MPLabs' IDE and compiler. A quick peek at their header file shows similar definitions, so that the programmer can access the individual bitfields.

https://code.google.com/p/pinguino32/so ... 12l.h?r=95

They seem to "ensure" that the compiler allocates bit fields in the right location by stuffing empty bits in between bit fields. However, for a single register, I don't see how they ensure that the compiler guarantees that the order they declare the bits is from LSbit to MSbit and not MSbit to LSbit.

For other embedded-systems development, I haven't seen this style elsewhere; in those cases, I've only seen the traditional bit-masking and shifting in a read-modify-write style.

I really appreciate all of the replies!

valtonia
Posts: 26
Joined: Wed Jul 04, 2012 9:09 pm

Re: Defining addresses and bit-fields with structs

Fri Feb 14, 2014 10:28 pm

As DWelch pointed out, this is probably flame-bait, but here's my experience of bit-fields;

I used to work for a company producing digital set-top boxes (and other related products). All coding was in C and based on both MIPS and ARM processors - not even a hint of Intel in embedded systems back then (around Y2K). We used bit-fields extensively to make controlling all of the various hardware not only manageable, but achievable. Never once did we have issues where the compiler suddenly changed it's mind about which way around the bit order was (endianness?).

In our code, we tended to define a struct for the particular group of registers, then inside that declare a union for each word, that contained a struct for the bit-fields and word or byte or whatever for the whole register. That way, you could read/write all the bits in one go or address individual bits as required. These structs where then mapped with pointers to the appropriate memory addresses. [ I expect DWelch has probably passed out by now! :D ] Without this system in place I can tell that setting up the hardware and working with it would've been a nightmare. Perhaps it was that the compilers were written specifically for the processors we were using - i.e. NOT GCC, but the bit ordering was absolutely predictable.

Now, in this case, I'd say portability is not an issue. Are you really going to port this code run on anything other than the Pi? My advice would be to write your code in the way that makes the most sense to you and makes your life easier. If this were a commercial venture I might say differently, but for personal projects it's not so important. Remember, coding for the Pi is meant to be fun!

dwelch67
Posts: 1002
Joined: Sat May 26, 2012 5:32 pm

Re: Defining addresses and bit-fields with structs

Sat Feb 15, 2014 1:00 am

valetonia...no explosions here..If you want to play the spec angle, the spec makes this an implementation defined thing. As with the unions, from a spec perspective you were doing something bad by using unions like that. I would expect that there are compilers out there that do the same thing for every platform and are very predictable. doesnt mean they wont be tomorrow, but so long as you dont get one of those surprises that usually happens after testing and right after a big release goes out...

I would have argued you could have done all the same thing, maintanable, using code that is more portable, less risky within and across compilers.

If it worked for you hey great. bitfields is one of those religion and politics topics, I see so many people doing things with structs and bitfields that I have been burned by many times, but at the end of the day it is your code. Furthermore I encourage anyone still listening to go out and try this for yourself. Dont take my word or anyone elses as gospel. Try it yourself, try to do the things we claim work or dont work.

David

User avatar
jojopi
Posts: 3424
Joined: Tue Oct 11, 2011 8:38 pm

Re: Defining addresses and bit-fields with structs

Sat Feb 15, 2014 1:58 am

dwelch67 wrote:If you want to play the spec angle, the spec makes this an implementation defined thing.
It does. But I think it should be pointed out that in this case the definition is really made in the ABI, not the compiler.

If you had to compile every binary with the same version of the compiler as every shared library it links, then nothing would ever work. So struct layout has to be completely standardised, at least on each distinct platform that supports linking.

I do agree that bitfields are not the best way to access hardware, however, even on a specific platform. They hide important details in the ABI, outside the program.

Return to “Bare metal, Assembly language”