[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c++

bit fields and data structure

ma740988

11/17/2008 1:53:00 AM


I often peruse source that use memory mapped registers as a
configuration and/or command and status interface between embedded
software and FPGA logic. In doing so you're given a register name
accompanied by descriptions and a location in memory for reading/
writing data.

For ex:.

Revision Register - Location 0x0000
[31...15] spare
[14...00] number


Control Register - Location 0x0001
[31..3] -- Spare
[2] -- Address Line 3
[1] -- Address Line 2
[0] -- Address Line 1

To describe these registers in source one could do:

struct RevisionRegister {
unsigned short number : 16;
unsigned short spare : 16;
};

struct ControlRegister {
unsigned int Spare : 29;
unsigned short AddressLine3 : 1;
unsigned short AddressLine2 : 1;
unsigned short AddressLine1 : 1 ;
} ;

The trouble with the composite type ControlRegister is sizeof
(ControlRegister) is not 32 bits. That said, its not possible to
receive ControlRegister in it's current form from an end user and
overlay it at the appropriate location. The fundamental issue
surrounds the use of bitfields and implementation defined nature of
POD types. The question: What are some of the - if you will - tips
for dealing with this issue?

Would it make sense to eliminate the fields ... so now:

struct ControlRegister {
unsigned int Spare ;
unsigned int AddressLine3 ;
unsigned int AddressLine2 ;
unsigned int AddressLine1 ;
} ;

Upon receipt of the type layout ContolRegister (something I have to do
anyways) according to the needs of the memory mapped location.

Trouble with this is you give the end user free reign to put in
values outside of the bit range.


7 Answers

Maxim Yegorushkin

11/17/2008 9:49:00 AM

0

On Nov 17, 1:53 am, ma740988 <ma740...@gmail.com> wrote:
> I often peruse source that use memory mapped registers as a
> configuration and/or command and status interface between embedded
> software and FPGA logic.  In doing so you're given a register name
> accompanied by descriptions and a location in memory for reading/
> writing data.
>
> For ex:.
>
> Revision Register  - Location 0x0000
> [31...15]    spare
> [14...00]    number
>
> Control Register - Location 0x0001
> [31..3] -- Spare
> [2]  -- Address Line 3
> [1]  -- Address Line 2
> [0]  -- Address Line 1
>
> To describe these registers in source one could  do:
>
>   struct RevisionRegister {
>     unsigned short  number      :  16;
>     unsigned short  spare         :  16;
>   };
>
> struct ControlRegister {
>   unsigned int      Spare              :  29;
>   unsigned short AddressLine3 :  1;
>   unsigned short AddressLine2 :  1;
>   unsigned short AddressLine1  : 1 ;
>
> } ;
>
> The trouble with the composite type ControlRegister is sizeof
> (ControlRegister) is not 32 bits.

It is because bit-fields of different type can not be merged. Fix:

struct ControlRegister {
unsigned Spare : 29;
unsigned AddressLine3 : 1;
unsigned AddressLine2 : 1;
unsigned AddressLine1 : 1 ;
} ;

> That said, its not possible to
> receive ControlRegister in it's current form from an end user and
> overlay it at the appropriate location.   The fundamental issue
> surrounds the use of bitfields and implementation defined nature of
> POD types.  The question:  What are some of the - if you will - tips
> for dealing with this issue?

Another issue is that bit-field bit order can be little or big-endian
depending on the platform and the compiler. A portable way to read
mapped registers is to read the register, convert it from the byte
order of the hardware that exposes that register into the byte order
of the cpu (if byte orders are the same this is a noop), and then
apply mask by using bitwise and operator to extract the interesting
bits. This way you don't depend on the bit-field bit order.

--
Max




ma740988

11/17/2008 7:43:00 PM

0

On Nov 17, 4:48 am, Maxim Yegorushkin <maxim.yegorush...@gmail.com>
wrote:
> On Nov 17, 1:53 am, ma740988 <ma740...@gmail.com> wrote:
>
>
>
> > I often peruse source that use memory mapped registers as a
> > configuration and/or command and status interface between embedded
> > software and FPGA logic.  In doing so you're given a register name
> > accompanied by descriptions and a location in memory for reading/
> > writing data.
>
> > For ex:.
>
> > Revision Register  - Location 0x0000
> > [31...15]    spare
> > [14...00]    number
>
> > Control Register - Location 0x0001
> > [31..3] -- Spare
> > [2]  -- Address Line 3
> > [1]  -- Address Line 2
> > [0]  -- Address Line 1
>
> > To describe these registers in source one could  do:
>
> >   struct RevisionRegister {
> >     unsigned short  number      :  16;
> >     unsigned short  spare         :  16;
> >   };
>
> > struct ControlRegister {
> >   unsigned int      Spare              :  29;
> >   unsigned short AddressLine3 :  1;
> >   unsigned short AddressLine2 :  1;
> >   unsigned short AddressLine1  : 1 ;
>
> > } ;
>
> > The trouble with the composite type ControlRegister is sizeof
> > (ControlRegister) is not 32 bits.
>
> It is because bit-fields of different type can not be merged. Fix:
>
>     struct ControlRegister {
>       unsigned Spare :  29;
>       unsigned AddressLine3 : 1;
>       unsigned AddressLine2 : 1;
>       unsigned AddressLine1 : 1 ;
>     } ;
>
> > That said, its not possible to
> > receive ControlRegister in it's current form from an end user and
> > overlay it at the appropriate location.   The fundamental issue
> > surrounds the use of bitfields and implementation defined nature of
> > POD types.  The question:  What are some of the - if you will - tips
> > for dealing with this issue?
>
> Another issue is that bit-field bit order can be little or big-endian
> depending on the platform and the compiler. A portable way to read
> mapped registers is to read the register, convert it from the byte
> order of the hardware that exposes that register into the byte order
> of the cpu (if byte orders are the same this is a noop), and then
> apply mask by using bitwise and operator to extract the interesting
> bits. This way you don't depend on the bit-field bit order.
>
I think I understand what you're alluding to on reads (didn't complete
the sample code based on your description so i could post it), what
about write operations?

James Kanze

11/18/2008 9:14:00 AM

0

On Nov 17, 10:48 am, Maxim Yegorushkin <maxim.yegorush...@gmail.com>
wrote:
> On Nov 17, 1:53 am, ma740988 <ma740...@gmail.com> wrote:
> > I often peruse source that use memory mapped registers as a
> > configuration and/or command and status interface between
> > embedded software and FPGA logic. In doing so you're given
> > a register name accompanied by descriptions and a location
> > in memory for reading/ writing data.

> > For ex:.

> > Revision Register - Location 0x0000
> > [31...15] spare
> > [14...00] number

> > Control Register - Location 0x0001
> > [31..3] -- Spare
> > [2] -- Address Line 3
> > [1] -- Address Line 2
> > [0] -- Address Line 1

> > To describe these registers in source one could do:

> > struct RevisionRegister {
> > unsigned short number : 16;
> > unsigned short spare : 16;
> > };

> > struct ControlRegister {
> > unsigned int Spare : 29;
> > unsigned short AddressLine3 : 1;
> > unsigned short AddressLine2 : 1;
> > unsigned short AddressLine1 : 1 ;
> > } ;

Maybe. How a compiler lays out bitfields is implementation
defined.

> > The trouble with the composite type ControlRegister is sizeof
> > (ControlRegister) is not 32 bits.

It is with my compilers. But it definitely depends on the
compiler; a compiler for a 16 bit machine is likely to
systematically put any bit field greater or equal to 16 bits in
a separate word.

> It is because bit-fields of different type can not be merged.

Since when? Both g++ and Sun CC merge them, under Solaris.

> Fix:

> struct ControlRegister {
> unsigned Spare : 29;
> unsigned AddressLine3 : 1;
> unsigned AddressLine2 : 1;
> unsigned AddressLine1 : 1 ;
> } ;

It would be a pretty poor implementation which generated a
different layout for these two. I'm not even sure it's legal.
(The actual layout is implementation defined, and the standard
isn't really clear about the restrictions, if any. But laying
out these two differently certainly violates the spirit of the
standard, if not the actual wording.)

> > That said, its not possible to receive ControlRegister in
> > it's current form from an end user and overlay it at the
> > appropriate location. The fundamental issue surrounds the
> > use of bitfields and implementation defined nature of POD
> > types. The question: What are some of the - if you will -
> > tips for dealing with this issue?
>
> Another issue is that bit-field bit order can be little or
> big-endian depending on the platform and the compiler.

The layout is implementation defined, with very few
restrictions. But if you're reading and writing memory mapped
registers, portability is presumably not a concern. And
implementation defined means documented, so you know what the
compiler does. For any one particular version of the compiler,
of course, but from a QoI point of view, no reasonable compiler
will change the basic principles from one version to the next.
(Although... I've seen changes more radical than that, like the
byte order in a long. From a QoI point of view, the quality
wasn't there, but it was still the compiler we had to use.)

> A portable way to read mapped registers is to read the
> register, convert it from the byte order of the hardware that
> exposes that register into the byte order of the cpu (if byte
> orders are the same this is a noop), and then apply mask by
> using bitwise and operator to extract the interesting bits.
> This way you don't depend on the bit-field bit order.

"A portable way to read mapped registers"? Sounds like an
oxymoron to me.:-)

Seriously, of course, such problems don't affect just mapped
registers, and this is the way to solve them portably in other
cases (transmission protocols, etc.). The register is slightly
different, in that you can (maybe) read and write words, and not
just bytes, but other than that, the principles are the same.
Using bit fields results in less and cleaner code, but it only
works for mapped registers, and only then if your compiler does
something reasonable, and documents it. (If it doesn't, he
might want to consider changing compilers; under Windows, VC++
is more or less broken with regards to bit fields, but g++ works
fine.)

--
James Kanze (GABI Software) email:james.kanze@gmail.com
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

11/18/2008 9:24:00 AM

0

On Nov 17, 8:42 pm, ma740988 <ma740...@gmail.com> wrote:
> On Nov 17, 4:48 am, Maxim Yegorushkin
> <maxim.yegorush...@gmail.com> wrote:

[...]
> > Another issue is that bit-field bit order can be little or
> > big-endian depending on the platform and the compiler. A
> > portable way to read mapped registers is to read the
> > register, convert it from the byte order of the hardware
> > that exposes that register into the byte order of the cpu
> > (if byte orders are the same this is a noop), and then apply
> > mask by using bitwise and operator to extract the
> > interesting bits. This way you don't depend on the bit-field
> > bit order.

> I think I understand what you're alluding to on reads (didn't
> complete the sample code based on your description so i could
> post it), what about write operations?

Same principle. Basically:

enum ControlRegisterMasks
{
spareMask = 0x1FFFFFFF,
addressLine3Mask = 0x20000000,
addressLine2Mask = 0x40000000,
addressLine1Mask = 0x80000000
} ;

enum ControlRegisterShiftCounts
{
spareShiftCount = 0,
addressLine3ShiftCount = 29,
addressLine2ShiftCount = 30,
addressLine1ShiftCount = 31
} ;

typedef unsigned int /* or uint32_t */ ControlRegister ;

int
getAddressLine1(
ControlRegister reg )
{
return (reg & addressLine1Mask) >> addressLine1ShiftCount ;
}

void
setAddressLine1(
ControlRegister& reg,
int value )
{
reg = (reg & ~addressLine1Mask)
| ((value << addressLine1ShiftCount) & addressLine1Mask) ;
}

// ...

--
James Kanze (GABI Software) email:james.kanze@gmail.com
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

ma740988

12/28/2008 3:09:00 AM

0

On Nov 18, 4:24 am, James Kanze <james.ka...@gmail.com> wrote:
>
> Same principle.  Basically:
>
>     enum ControlRegisterMasks
>     {
>         spareMask        = 0x1FFFFFFF,
>         addressLine3Mask = 0x20000000,
>         addressLine2Mask = 0x40000000,
>         addressLine1Mask = 0x80000000
>     } ;
>
>     enum ControlRegisterShiftCounts
>     {
>         spareShiftCount        =  0,
>         addressLine3ShiftCount = 29,
>         addressLine2ShiftCount = 30,
>         addressLine1ShiftCount = 31
>     } ;
>
>     typedef unsigned int /* or uint32_t */ ControlRegister ;
>
>     int
>     getAddressLine1(
>         ControlRegister     reg )
>     {
>         return (reg & addressLine1Mask) >> addressLine1ShiftCount ;
>     }
>
>     void
>     setAddressLine1(
>         ControlRegister&    reg,
>         int                 value )
>     {
>         reg = (reg & ~addressLine1Mask)
>             | ((value << addressLine1ShiftCount) & addressLine1Mask) ;
>     }
>
>     //  ...
>

Hows this link (http://www.open-std.org/jtc1/sc22/wg14...
n929.pdf) for an idea. I like the concept in the document.

So given a register layout:
destination : 7 bits
source : 7 bits
enable_this : 1 bit
enable_that : 1 bit
spare : 16 bits

One option I'm experimenting with surrounds the use of access types
(borrowed from Ada's access types )

struct some_hw_register {
bool enable_that ; // : 1
bool enable_this ; // : 1
unsigned int source ; // : 7
unsigned int destination ; // : 7
};

class HW_Map : public Access_Register {
public :
Access_Hw_Reg < unsigned int, 0 > enable_that;
Access_HW_Reg < unsigned int, 1 > enable_that;
Access_HW_Reg < unsigned int, 2, 7 > source; // bit
position 2, 7 bits
Access_HW_Reg < unsigned int, 9, 7 > destination; // bit
position 9, 7 bits
HW_Map ( void* ptr ) : Access_Register ( ptr ) {}

inline void Read ( some_hw_register& hw ) {
hw.enable_that = Access_Register::Read ( enable_that ) ;
hw.enable_this = Access_Register::Read ( enable_this ) ;
hw.source = Access_Register::Read ( source) ;
hw.destination = Access_Register::Read ( destination ) ;
}
inline void Write ( some_hw_register& hw ) {
Access_Register::Write( enable_that, hw.enable_that ) ;
Access_Register::Write( enable_this, hw. enable_this ) ;
Access_Register::Write( source, hw.source ) ;
Access_Register::Write( destination, hw.destination ) ;
}
};

Option 2:
Now page 8 of the attached provides a cool idea. I suspect I could
do:
HW_MEMORY < read_method, write_method, addr_const, addr_range >
MEM1 ;
Later in read_method and write_method, I could access the individual
variables. Not sure how to structure this one. I'm lost :)

I understand that there's portability issues here and such there's no
clean way to deal with bit field manipulations except avoid them.
Thats nice, however, in the REAL world - a world that deals with
signal processing applications executing on DSPs (the world I live
in), a world that deals with mobile phones etc. etc. there's no way
around this.


James Kanze

12/28/2008 1:29:00 PM

0

On Dec 28, 4:08 am, ma740988 <ma740...@gmail.com> wrote:
> On Nov 18, 4:24 am, James Kanze <james.ka...@gmail.com> wrote:
> > Same principle. Basically:

> > enum ControlRegisterMasks
> > {
> > spareMask = 0x1FFFFFFF,
> > addressLine3Mask = 0x20000000,
> > addressLine2Mask = 0x40000000,
> > addressLine1Mask = 0x80000000
> > } ;

> > enum ControlRegisterShiftCounts
> > {
> > spareShiftCount = 0,
> > addressLine3ShiftCount = 29,
> > addressLine2ShiftCount = 30,
> > addressLine1ShiftCount = 31
> > } ;

> > typedef unsigned int /* or uint32_t */ ControlRegister ;

> > int
> > getAddressLine1(
> > ControlRegister reg )
> > {
> > return (reg & addressLine1Mask) >> addressLine1ShiftCount ;
> > }

> > void
> > setAddressLine1(
> > ControlRegister& reg,
> > int value )
> > {
> > reg = (reg & ~addressLine1Mask)
> > | ((value << addressLine1ShiftCount) & addressLine1Mask) ;
> > }

> > // ...

> Hows this link (http://www.open-std.org/jtc1/sc22/wg14... n929.pdf)
> for an idea. I like the concept in the document.

I haven't studied it in detail, but it looks like a proposal for
something to add to the standard. Which I don't think was
accepted. In some ways, it is a solution looking for a
problem. It certainly provides something more directly readable
than the current situation, and it provides a portable syntax.
But hardware I/O registers are by their very nature unportable,
so the portable syntax doesn't buy you much. And it's not as if
bit shifting etc. cause any real problems.

--
James Kanze (GABI Software) email:james.kanze@gmail.com
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

ma740988

12/28/2008 5:41:00 PM

0

On Dec 28, 8:29 am, James Kanze <james.ka...@gmail.com> wrote:

> In some ways, it is a solution looking for a
> problem.  It certainly provides something more directly readable
> than the current situation, and it provides a portable syntax.
> But hardware I/O registers are by their very nature unportable,
> so the portable syntax doesn't buy you much.  And it's not as if
> bit shifting etc. cause any real problems.
>
Fair enough! I was headed down the path with sets_this_variable and
gets_this_variable with the bit fiddling done within the methods. At
some point I thought there has to be a better way :) then I ran across
this article:

http://www.artima.com/cppsource/safel...
A novel idea with regards to individual bits but it doesn't appear to
address a range of bits.

Oh well
Thanks