Union of bitfields and larger type on ARM

Does anyone know if the following "naughty" (implementation dependent) construct would work "correctly" on the ARM Cortex M4, compiled with arm-gcc-embedded?

typedef union { uint32_t phase_accumulator_full; struct { uint8_t integer_high : 8, integer_low : 8, frac_high : 8, frac_low : 8;

}; } phase_accumulator;

Reply to
bitrex
Loading thread data ...

Den tirsdag den 23. februar 2016 kl. 20.18.11 UTC+1 skrev bitrex:

that would depend on what you mean by correctly and what endianness you have

-Lasse

Reply to
Lasse Langwadt Christensen

I am not an expert (ask on comp.arch.embedded) but my understanding is that this sort of thing is guaranteed by the EABI (bugs aside).

--

John Devereux
Reply to
John Devereux

Oh yes CM4 is generally little endian, and that does not seem to match the struct!

--

John Devereux
Reply to
John Devereux

I'm new to coding for the processor, and I had been having a little trouble determining what the endianness of the thing actually _is_...

Reply to
bitrex

Well, I'd like to be able to increment the uint32_t, and then access the individual bytes through the union such that say if we have 0xAABBCCDD in the uint32_t, I'll have 0xAA in integer_high, 0xBB in integer_low, etc.

Reply to
bitrex

At least those Cortexes I have used, (Atmel, Philips, STM) are definitively little-endian.

--

-TV
Reply to
Tauno Voipio

the bytes are in the wrong order for a little-endian cpu, don't know of any M4 that isn't little-endian

And it don't think it'll compile unless you name the struct

-Lasse

Reply to
Lasse Langwadt Christensen

I can't even figure out why it would be considered "naughty" at all. The only implementation-dependent aspects I can see are the alignment of the parts (on the ARM, 8-bit, 16-bit and 32-bit types all have "natural" alignments), and the ordering of the bitfields (which is low bits first

- guaranteed by the ARM EABI, and thus consistent across compilers).

Reply to
David Brown

"Naughty" if one wants to port the code as-is to another architecture, I guess.

Reply to
bitrex

I believe ISO C11 permits anonymous structs in general, and gcc supports them now in C++, C99, everything...

Reply to
bitrex

First:

Yes, it'll work as long as you want the least significant byte to be named "integer_high" and the most significant byte to be named "frac_low".

Second:

You need to name the bitfield. I'll assume you've named it "bits" -- i.e., phase_accumulator.bits.frac_high.

Third:

It should be just as fast to use:

uint32_t phase_accumulator;

static inline uint8_t integer_high(uint32_t x) {return (x >> 24) & 0xff;} static inline uint8_t integer_low (uint32_t x) {return (x >> 16) & 0xff;} static inline uint8_t frac_high (uint32_t x) {return (x >> 8) & 0xff;} static inline uint8_t frac_low (uint32_t x) {return (x >> 0) & 0xff;}

This will be portable, and integer_high(phase_accumulator) should read as easily (or more so) as phase_accumulator.bits.integer_high.

--

Tim Wescott 
Wescott Design Services 
http://www.wescottdesign.com
Reply to
Tim Wescott

you are right, the anonymous struct does compile with the version of arm-none-eabi-gcc I have here

-Lasse

Reply to
Lasse Langwadt Christensen

Does it complain if you do -pedantic?

Reply to
bitrex

I would say "non-portable" rather than "naughty". "Naughty" implies that this might not work in some circumstances, or perhaps depends on undefined behaviour. This is merely non-portable and relies on implementation-dependent behaviour (which happens to be defined by the ARM EABI, and thus should apply to all ARM compilers).

Reply to
David Brown

I get a warning that ISO C99 doesn't support unnamed structs/unions

and about a trillion warning from cmsis code

-Lasse

Reply to
Lasse Langwadt Christensen

True.

Not necessary true, assuming you are using C11 (rather than C++), or gcc or clang, or any other compiler that supports anonymous structs as an extension. Since this is specifically for the ARM, and not meant to be portable, it is perhaps not unreasonable to use an extension that is available the most common tools for that target. But that's a decision for the OP to make.

No, these functions are not a good substitute. First, they do not do the same thing if "phase_accumulator" is used as a volatile - and such bitfield structures are usually used for hardware registers where volatile is relevant. Using the bitfields, accesses to the separate fields will be done as 8-bit accesses - using the functions, they will be 32-bit accesses.

Second, your functions give read-only access, not read-write access - another set is needed for writing. Those are messy.

static inline uint32_t set_integer_low (uint32_t x, uint8_t y) { return (x & 0xff00ffff) | ((uint32_t) y

Reply to
David Brown

sumg ting does not look correct? Assuming I understand what you're after.

struct _phase_acc { union { uint32_t phase_accumulator_full }; union { uint_8 integer_high:8, integer_low:8, frac_high:8, frc_low : 8; }; } phase_accumulator;

You can include a condition to test for the second union to determine the endious of the platform to correctly compile the code for the bit field order. The above struct should overlay to generate a single 32 bit image.

Jamie

Reply to
M Philbrook

typo..

typo..

No, it won't. You have two 32 bit unions members of a struct, witch gives a 64 bit struct.

--
Ian Collins
Reply to
Ian Collins

In that case you have the ordering wrong. The Cortex M devices are all strictly little-endian, and the EABI requires little-endian bitfield order too (it is possible for the bitfields to be in a different endian order than multi-byte data - the bitfield endianness is a choice for the ABI and/or compiler).

Reply to
David Brown

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.