473,383 Members | 1,980 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,383 software developers and data experts.

Taking advantage of cotiguous bytes in struct = portable?

In embedded systems (programmed in C), often times structure
declarations are used to group together several status/control/data
registers of external hardware (or even internal registers). The
example below (from GBD's THE C BOOK) uses this. Is this a portable
method? [Note, there is no issue with structure "padding" because no
structure object is defined, only a declaration is used to access
existing hardware].


/*
* Declare the device registers
* Whether to use int or short
* is implementation dependent
*/

struct devregs{
unsigned short volatile csr;
unsigned short const volatile data;
};
/* bit patterns in the csr */
#define ERROR 0x1
#define READY 0x2
#define RESET 0x4

/* absolute address of the device */
#define DEVADDR ((struct devregs *)0xffff0004)

/* number of such devices in system */
#define NDEVS 4

/*
* Busy-wait function to read a byte from device n.
* check range of device number.
* Wait until READY or ERROR
* if no error, read byte, return it
* otherwise reset error, return 0xffff
*/
unsigned int read_dev(unsigned devno){

struct devregs * const dvp = DEVADDR + devno;

if(devno >= NDEVS)
return(0xffff);

while((dvp->csr & (READY | ERROR)) == 0)
; /* NULL - wait till done */

if(dvp->csr & ERROR){
dvp->csr = RESET;
return(0xffff);
}

return((dvp->data) & 0xff);
}

Any portability issues? At first sight this looks like an awesome
technique!

Nov 14 '05 #1
5 2366
REH

"Kobu" <ko********@gmail.com> wrote in message
news:11**********************@z14g2000cwz.googlegr oups.com...
[Note, there is no issue with structure "padding" because no
structure object is defined, only a declaration is used to access
existing hardware].


How does mapping the structure directly over that hardware registers'
address space, and not creating an object of the type, alleviate there being
any issues with the layout of the structure?

Nov 14 '05 #2


Kobu wrote:
In embedded systems (programmed in C), often times structure
declarations are used to group together several status/control/data
registers of external hardware (or even internal registers). The
example below (from GBD's THE C BOOK) uses this. Is this a portable
method? [Note, there is no issue with structure "padding" because no
structure object is defined, only a declaration is used to access
existing hardware].
That's a non sequitur. The struct declaration defines
a memory layout; that memory layout may contain padding; if
you use the padded layout with un-padded hardware things
may not line up correctly. For a particular compiler on a
particular piece of hardware things may work just fine --
but portability problems loom, and you'll need to re-verify
every time you change compiler or machine.

A few other points:
/* absolute address of the device */
#define DEVADDR ((struct devregs *)0xffff0004)
Conversion between integers and pointers is allowed
(in both directions), but the results are implementation-
defined and thus not portable. A construct like the one
you've written will probably work just fine on most "flat
address" machines, but embedded systems are perhaps more
likely than most to have "crinkly" address spaces. This
is another non-portability you'll need to re-verify each
time out.
struct devregs * const dvp = DEVADDR + devno;
Here's where you impose the possibly-padded struct's
memory layout on whatever actually lives at the desired
location. Note that if the struct is padded (and hence
larger than you want), the location will be mis-calculated
if `devno' is non-zero.
if(devno >= NDEVS)
return(0xffff);
It would be better to make this test before trying
to initialize `dvp'. On many systems it's harmless to
generate a bogus pointer value (provided you never use
it), but in principle the mere act of "thinking about"
an illegal address can be a mortal sin. Besides (sigh),
it's "more efficient" to avoid the erroneous calculation
whose result you'll never use anyhow.
Any portability issues?


As noted. However, it might not be worth while to
worry about them overmuch; what you're trying to do is
inherently non-portable, so you're forced to walk on the
wild side. Try to find ways to get the compiler to verify
your non-portable assumptions -- for example, here's an
ugly hack that will generate a compile error if `struct
devregs' contains any padding:

/* Message To Those Who Come After Me: I don't
* really care about this array type, and I'll
* never actually use it for anything; it's just
* here to make the compiler whine if there's any
* padding in a `struct devregs'. If you get a
* complaint about an invalid array size or some
* such thing, it's not really about this array
* at all: it just means that `struct devregs'
* isn't laid out the way I want, and that code
* using `struct devregs' won't work with this
* compiler. Too bad -- but at least you found
* out at compile time, instead of by trying to
* debug some mysterious misbehavior.
*/
typedef char bogus_array_type[
sizeof(struct devregs) == 2 * sizeof(short) ];

(When using such a hack, the long-winded comment is an
essential component; don't omit it.)

--
Er*********@sun.com

Nov 14 '05 #3
In article <11**********************@z14g2000cwz.googlegroups .com>,
"Kobu" <ko********@gmail.com> wrote:
In embedded systems (programmed in C), often times structure
declarations are used to group together several status/control/data
registers of external hardware (or even internal registers). The
example below (from GBD's THE C BOOK) uses this. Is this a portable
method? [Note, there is no issue with structure "padding" because no
structure object is defined, only a declaration is used to access
existing hardware].


/*
* Declare the device registers
* Whether to use int or short
* is implementation dependent
*/

struct devregs{
unsigned short volatile csr;
unsigned short const volatile data;
};
/* bit patterns in the csr */
#define ERROR 0x1
#define READY 0x2
#define RESET 0x4

/* absolute address of the device */
#define DEVADDR ((struct devregs *)0xffff0004)

/* number of such devices in system */
#define NDEVS 4

/*
* Busy-wait function to read a byte from device n.
* check range of device number.
* Wait until READY or ERROR
* if no error, read byte, return it
* otherwise reset error, return 0xffff
*/
unsigned int read_dev(unsigned devno){

struct devregs * const dvp = DEVADDR + devno;

if(devno >= NDEVS)
return(0xffff);

while((dvp->csr & (READY | ERROR)) == 0)
; /* NULL - wait till done */

if(dvp->csr & ERROR){
dvp->csr = RESET;
return(0xffff);
}

return((dvp->data) & 0xff);
}

Any portability issues? At first sight this looks like an awesome
technique!


Best to throw that book away before it does any more damage.

The code will crash with any modern operating system that will
absolutely refuse to let you access hardware directly. And rightfully
so. Device drivers access hardware, maybe code running on some
embededded systm, but nothing else does.
Nov 14 '05 #4
On Wed, 16 Feb 2005 23:07:57 +0000, Christian Bau
<ch***********@cbau.freeserve.co.uk> wrote:
In article <11**********************@z14g2000cwz.googlegroups .com>,
"Kobu" <ko********@gmail.com> wrote:
In embedded systems (programmed in C), often times structure <snip>
Any portability issues? At first sight this looks like an awesome
technique!


Best to throw that book away before it does any more damage.

The code will crash with any modern operating system that will
absolutely refuse to let you access hardware directly. And rightfully
so. Device drivers access hardware, maybe code running on some
embededded systm, but nothing else does.


See the OP's first line.

--
Al Balmer
Balmer Consulting
re************************@att.net
Nov 14 '05 #5
Kobu wrote:
In embedded systems (programmed in C), often times structure
declarations are used to group together several status/control/data
registers of external hardware (or even internal registers). The
example below (from GBD's THE C BOOK) uses this. Is this a portable
method? [Note, there is no issue with structure "padding" because no
structure object is defined, only a declaration is used to access
existing hardware].
/*
* Declare the device registers
* Whether to use int or short
* is implementation dependent
*/

struct devregs{
unsigned short volatile csr;
unsigned short const volatile data;
};

As others have pointed out, structure padding can still bite you,
because it could cause devregs.data to refer to the wrong memory
location in the first structure if there are padding bytes between csr
and data. Also later structures (DEVADDR + n) might not line up with
the hardware if the first has some tail packing bytes.

Also, I don't like using structures like this for i/o, because some
platforms may need special instructions to do the access - e.g. x86
with IN and OUT, or Risc chips which need memory barrier instructions.
Having said that, it's a popular technique if you develop for something
where neither of these apply.

I usually use something like this

/* Structure packing for ARMCC */
#ifdef __arm
#define PACKED_STRUCT __packed
#else
#define PACKED_STRUCT
/* check the structure size for compilers other than ARMCC!
build with DEBUG defined, check the printfs. Also check Ux types! */
#endif

typedef unsigned char U8;
typedef unsigned short U16;
typedef unsigned int U32;

typedef PACKED_STRUCT struct {
U16 abc;
U16 def;
} HW_STRUCT;

I'd at least do a debug check that the sizeof the structure is what you
expect - e.g

#ifdef DEBUG
if (sizeof(U16) != 2 )
printf ("Fix U16 typedef!\n" );
if (sizeof(HW_STRUCT) !=4))
printf ("Fix packing\n" );
#endif

E.g. for GCC on Arm the the types would be the same, but structure
packing is done with __attribute__ ((packed)) on the elements. IIRC you
can use this in a macro too - e.g.

#ifdef __GNUC__
#define PACKED_ELEM __attribute__ ((packed))
#endif

typedef struct
{
U8 xyz;
U32 abc PACKED_ELEM;
U32 def PACKED_ELEM;
} struct;

You're better off asking this sort of question in comp.arch.embedded
BTW - I've set the follow ups.

Zog.

Nov 14 '05 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

15
by: Reid Nichol | last post by:
Hello, I was wondering if I could control how many bytes are in an int and the byte order. In C/C++ I can use int32 but how do I do this in python? How can I control byte order?
27
by: Daniel Lidström | last post by:
Hello! I want to work with individual bytes of integers. I know that ints are 32-bit and will always be. Sometimes I want to work with the entire 32-bits, and other times I want to modify just...
19
by: becte | last post by:
I need to use three bytes to store four 6-bit integers (4 * 6 = 3 * 8) like this 11111122|22223333|33444444 Suppose the input is, int c1, c2, c3, c4, range 0 .. 2^6 -1 and the output is int...
16
by: Raj Kotaru | last post by:
Hello all, I recently came across the following segment of code that defines a C struct: typedef struct { unsigned char unused_bits:4; unsigned char wchair_state:2; } xyz;
19
by: James Harris | last post by:
My K&R 2nd ed has in the Reference Manual appendix, A7.4.8 sizeof yields the number of BYTES required to store an object of the type of its operand. What happens if C is running on a machine that...
4
by: Everton | last post by:
The task at hand is to initialize a variable of type "struct in6_addr" in a portable way. For instance: /* NetBSD - /usr/include/netinet6/in6.h */ struct in6_addr { union { __uint8_t ...
30
by: junky_fellow | last post by:
I was looking at the source code of linux or open BSD. What I found that lots of typedefs were used. For example, consider the offset in a file. It was declared as off_t offset; and off_t is...
20
by: William Ahern | last post by:
Thoughts, comments? #ifdef HAVE_TYPEOF /* * Can use arbitrary expressions */ #define alignof(t) \ ((sizeof (t) > 1)? offsetof(struct { char c; typeof(t) x; }, x) : 1)
32
by: r.z. | last post by:
class vector3 { public: union { float data; struct { float x, y, z; };
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.