gcc compiler and byte / word alignment

Started by Fred October 17, 2005
A newbie question I'm afraid.

LPC2294 ARM

I am trying to read a word, ie a short int, from an ethernet controller. 
It's in 8 but mode and can't do much about it at the moment.

    unsigned short *ptr
//say read from device
    *(ptr + OFFSET)

The BCFG2 is set up 8 bit mode.

When compiled, the value of "OFFSET" is doubled, and the data fetch command 
is "ldrh r3, [r3]".

Why does gcc double "OFFSET"?  There's no need for this even in word 
fetches!

Does "ldrh" expect a word aligned peripheral?  Would there normally be 2 - 
byte fetches or a single erroneous word fetch?

Sorry if this has an obvious answer. 


Fred wrote:
> A newbie question I'm afraid. > > LPC2294 ARM > > I am trying to read a word, ie a short int, from an ethernet controller. > It's in 8 but mode and can't do much about it at the moment. > > unsigned short *ptr > //say read from device > *(ptr + OFFSET) > > The BCFG2 is set up 8 bit mode. > > When compiled, the value of "OFFSET" is doubled, and the data fetch command > is "ldrh r3, [r3]". > > Why does gcc double "OFFSET"? There's no need for this even in word > fetches!
Because it's treating ptr as an array of unsigned shorts. Suppose ptr is 0x1234. If OFFSET is 0, addresses 0x1234 and 0x1235 are accessed for the short. If OFFSET is 1, addresses 0x1236 and 0x1237 are accessed. If OFFSET is 2, addresses 0x1238 and 0x1239 are accessed. Because GCC knows how big a short is (in this case it's two bytes), it will know that the bytes accessed in the C construct "*(ptr + OFFSET)" are located at addresses "ptr + OFFSET * 2" and "ptr + OFFSET * 2 + 1". -- Paul Black mailto:paul.black@oxsemi.com Oxford Semiconductor Ltd http://www.oxsemi.com 25 Milton Park, Abingdon, Tel: +44 (0) 1235 824 909 Oxfordshire. OX14 4SH Fax: +44 (0) 1235 821 141
"Paul Black" <nospam@nospam.oxsemi.com> wrote in message 
news:divrf2$65f$1@jupiter.oxsemi.com...
> Fred wrote: >> A newbie question I'm afraid. >> >> LPC2294 ARM >> >> I am trying to read a word, ie a short int, from an ethernet controller. >> It's in 8 but mode and can't do much about it at the moment. >> >> unsigned short *ptr >> //say read from device >> *(ptr + OFFSET) >> >> The BCFG2 is set up 8 bit mode. >> >> When compiled, the value of "OFFSET" is doubled, and the data fetch >> command >> is "ldrh r3, [r3]". >> >> Why does gcc double "OFFSET"? There's no need for this even in word >> fetches! > > Because it's treating ptr as an array of unsigned shorts. > > Suppose ptr is 0x1234. > If OFFSET is 0, addresses 0x1234 and 0x1235 are accessed for the short. > If OFFSET is 1, addresses 0x1236 and 0x1237 are accessed. > If OFFSET is 2, addresses 0x1238 and 0x1239 are accessed. > > Because GCC knows how big a short is (in this case it's two bytes), it > will know that the bytes accessed in the C construct "*(ptr + OFFSET)" > are located at addresses > "ptr + OFFSET * 2" and "ptr + OFFSET * 2 + 1". > > > --
I see - yes. Thought I might have been a little dense. Can this ARM processor fetch a word in two byte-wide fetches? Just that I know of others which do. Or must word fetches be from word or 32bit wide sources? Conversely, it has byte lanes which can write a single byte in a 32bit wide memory configuration.
> Can this ARM processor fetch a word in two byte-wide fetches? Just > that I know of others which do. Or must word fetches be from word or > 32bit wide sources?
If you disable half-word accesses then the ARM will fetch a half-word as two bytes. Whether you *want* this behaviour is another matter! You want to declare your pointers to hardware registers as volatile too to avoid the compiler optimising away accesses. Andrew
Yep, there are variety of subtle punishments in store for treating the
C compiler as a macro assembler...  at times it can be downright
stubborn about insisting that you don't know the architecture better
than it does - convincing it that you do, to the point of making all
the warnings go away, takes just the right declarations.

"Fred" <fred@nowhere.com> wrote in message 
news:4353956a$0$323$da0feed9@news.zen.co.uk...
> > "Paul Black" <nospam@nospam.oxsemi.com> wrote in message > news:divrf2$65f$1@jupiter.oxsemi.com... >> Fred wrote:
> Can this ARM processor fetch a word in two byte-wide fetches? Just that I > know of others which do. Or must word fetches be from word or 32bit wide > sources?
A word is 32 bits in the ARM world and must be word-aligned. A half-word is 16 bits and must be half-word aligned. The LPC2294 is an ARM7tdmi MCU and thus doesn't support unaligned accesses in hardware. Compilers for ARM typically support unaligned (or packed) pointers which have no alignment requirement. If a CPU doesn't support unaligned accesses directly in hardware, they are split up into a sequence of reads/writes, shifts and masking operations - this is obviously slow and so should avoided as much as possible. Note there is no guarantee compilers produce exactly 2 byte reads for an unaligned half-word access (in the order you wanted) - this means that it is incorrect to use packed pointers on peripherals. So if your peripheral doesn't support aligned halfword accesses the only way to read 2 bytes is to use 2 volatile byte reads and do the masking yourself. However I would be surprised if any peripheral on the LPC was like that... Wilco
On 2005-10-17, Wilco Dijkstra <Wilco_dot_Dijkstra@ntlworld.com> wrote:

>> Can this ARM processor fetch a word in two byte-wide fetches? >> Just that I know of others which do. Or must word fetches be >> from word or 32bit wide sources? > > A word is 32 bits in the ARM world and must be word-aligned. A > half-word is 16 bits and must be half-word aligned. The > LPC2294 is an ARM7tdmi MCU and thus doesn't support unaligned > accesses in hardware. > > Compilers for ARM typically support unaligned (or packed) > pointers which have no alignment requirement. If a CPU doesn't > support unaligned accesses directly in hardware, they are > split up into a sequence of reads/writes, shifts and masking > operations - this is obviously slow and so should avoided as > much as possible.
And remember that this only works when the compiler _knows_ the pointer is misaligned. If you pass a misaligned pointer to a function that was declared as taking a word or half-word pointer, it's not going to work. Been there, done that. :/ -- Grant Edwards grante Yow! I would like to at urinate in an OVULAR, visi.com porcelain pool --
"Andrew Jackson" <alj@nospam.com> wrote in message 
news:Hp6dnbdqWZSsAs7eRVnyjg@eclipse.net.uk...
>> Can this ARM processor fetch a word in two byte-wide fetches? Just >> that I know of others which do. Or must word fetches be from word or >> 32bit wide sources? > > If you disable half-word accesses then the ARM will fetch a half-word as > two > bytes. Whether you *want* this behaviour is another matter! > > You want to declare your pointers to hardware registers as volatile too to > avoid the compiler optimising away accesses. > > Andrew > >
Many thanks. Yes I forgot about volatile variables etc. I would have thought setting the BCFG register to be 8 bit memory width would have inherently forced byte access. What you're suggesting is to use the switch for all half-word accesses, something I really don't want to do. Where is this switch?
"Wilco Dijkstra" <Wilco_dot_Dijkstra@ntlworld.com> wrote in message 
news:iDU4f.2669$WI4.1839@newsfe4-gui.ntli.net...
> > "Fred" <fred@nowhere.com> wrote in message > news:4353956a$0$323$da0feed9@news.zen.co.uk... >> >> "Paul Black" <nospam@nospam.oxsemi.com> wrote in message >> news:divrf2$65f$1@jupiter.oxsemi.com... >>> Fred wrote: > >> Can this ARM processor fetch a word in two byte-wide fetches? Just that >> I know of others which do. Or must word fetches be from word or 32bit >> wide sources? > > A word is 32 bits in the ARM world and must be word-aligned. A half-word > is 16 bits and must be half-word aligned. The LPC2294 is an ARM7tdmi > MCU and thus doesn't support unaligned accesses in hardware. >
The half-word is half-word aligned albeit on an 8 bit bus.
> Compilers for ARM typically support unaligned (or packed) pointers which > have no alignment requirement. If a CPU doesn't support unaligned accesses > directly in hardware, they are split up into a sequence of reads/writes, > shifts and masking operations - this is obviously slow and so should > avoided > as much as possible. Note there is no guarantee compilers produce exactly > 2 byte reads for an unaligned half-word access (in the order you wanted) - > this means that it is incorrect to use packed pointers on peripherals. > > So if your peripheral doesn't support aligned halfword accesses the only > way > to read 2 bytes is to use 2 volatile byte reads and do the masking > yourself. > However I would be surprised if any peripheral on the LPC was like that... >
Temporarily I have used byte access and concatenated the bytes. However this really isn't an ideal and is a slow solution. I've been looking through the datasheets and can't see any proviso that a half-word read won't access a variable on an 8 bit bus.
"Grant Edwards" <grante@visi.com> wrote in message 
news:11l8pinci380ccd@corp.supernews.com...
> On 2005-10-17, Wilco Dijkstra <Wilco_dot_Dijkstra@ntlworld.com> wrote: > >>> Can this ARM processor fetch a word in two byte-wide fetches? >>> Just that I know of others which do. Or must word fetches be >>> from word or 32bit wide sources? >> >> A word is 32 bits in the ARM world and must be word-aligned. A >> half-word is 16 bits and must be half-word aligned. The >> LPC2294 is an ARM7tdmi MCU and thus doesn't support unaligned >> accesses in hardware. >> >> Compilers for ARM typically support unaligned (or packed) >> pointers which have no alignment requirement. If a CPU doesn't >> support unaligned accesses directly in hardware, they are >> split up into a sequence of reads/writes, shifts and masking >> operations - this is obviously slow and so should avoided as >> much as possible. > > And remember that this only works when the compiler _knows_ the > pointer is misaligned. If you pass a misaligned pointer to a > function that was declared as taking a word or half-word > pointer, it's not going to work. > > Been there, done that. :/ > > --
The pointer is definitely half-word aligned.