EmbeddedRelated.com
Forums
The 2024 Embedded Online Conference

Endianness of Data...

Started by julvr November 11, 2008
Forgive me if this is a noob question, but this is my first chip
bringup from scratch.  I'm trying to bring up an ARM7 (ADuC7021), and
am having a problem with the endianness of data, and I'm not sure how
to fix it.

My problem is this:  if I call an internal function
SD_OutputString("Bootloader.."), I get the following output on my
serial port:  "tooBdaol..re".  In other words, it seems to be storing
the string in reverse endian format.


The code in question is very simple:

void SD_OutputString(const char *pTxt)
{
   while (*pTxt != 0)
   {
       SD_OutputChar(*pTxt);
       pTxt++;
   }
}

main()
{
   SD_OutputString("Bootloader..");
}


I'm using arm-elf-gcc / arm-elf-ld to compile and link the code.  My
Makefile has the following lines:

CPPFlags = -Wall -mcpu=arm7tdmi -mbig-endian
LDFlags = -T ld_flash.cmd -nostartfiles -mbig-endian



Does anyone know why my data is being stored in reverse order?



John
julvr wrote:
> Forgive me if this is a noob question, but this is my first chip > bringup from scratch. I'm trying to bring up an ARM7 (ADuC7021), and > am having a problem with the endianness of data, and I'm not sure how > to fix it. > > My problem is this: if I call an internal function > SD_OutputString("Bootloader.."), I get the following output on my > serial port: "tooBdaol..re". In other words, it seems to be storing > the string in reverse endian format. > > > The code in question is very simple: > > void SD_OutputString(const char *pTxt) > { > while (*pTxt != 0) > { > SD_OutputChar(*pTxt); > pTxt++; > } > } > > main() > { > SD_OutputString("Bootloader.."); > } > > > I'm using arm-elf-gcc / arm-elf-ld to compile and link the code. My > Makefile has the following lines: > > CPPFlags = -Wall -mcpu=arm7tdmi -mbig-endian > LDFlags = -T ld_flash.cmd -nostartfiles -mbig-endian > > > > Does anyone know why my data is being stored in reverse order? > > > > John
Interesting ... the code seems to work. Please compile again with the added switch -Wa,-ahlms=myfile.lst to get assembly listings. It seems that the compiled code accesses the string in word-size pieces instead of byte loads. The listing will also show if the compiler or assembler mis-switches the string contents when translating. -- Tauno Voipio tauno voipio (at) iki fi
The dissasembly (did an objdump -D) is as follows:


00000000 <.rodata>:
   0:	5b504420 	blpl	1411088 <.rodata+0x1411088>
   4:	426f6f74 	rsbmi	r6, pc, #464	;    "Boot"
   8:	6c6f6164 	stfvse	f6, [pc], #-400    ;    "load"
   c:	65725d0a 	ldrvsb	r5, [r2, #-3338]!  ;    "er"
  10:	00000000 	andeq	r0, r0, r0

where 426f6f74 ==> "Boot"
where 6c6f6164 ==> "load"

etc, so it seems that the data is in fact stored in the correct order.


000100c8 <SD_OutputString>:
   100c8:	e1a0c00d 	mov	ip, sp
   100cc:	e92dd800 	stmdb	sp!, {fp, ip, lr, pc}
   100d0:	e24cb004 	sub	fp, ip, #4	; 0x4
   100d4:	e24dd004 	sub	sp, sp, #4	; 0x4
   100d8:	e50b0010 	str	r0, [fp, #-16]
   100dc:	e51b3010 	ldr	r3, [fp, #-16]
   100e0:	e5d33000 	ldrb	r3, [r3]
   100e4:	e3530000 	cmp	r3, #0	; 0x0
   100e8:	0a000007 	beq	1010c <SD_OutputString+0x44>
   100ec:	e51b3010 	ldr	r3, [fp, #-16]
   100f0:	e5d33000 	ldrb	r3, [r3]
   100f4:	e1a00003 	mov	r0, r3
   100f8:	ebffffdd 	bl	10074 <SD_OutputChar>
   100fc:	e51b3010 	ldr	r3, [fp, #-16]
   10100:	e2833001 	add	r3, r3, #1	; 0x1
   10104:	e50b3010 	str	r3, [fp, #-16]
   10108:	eafffff3 	b	100dc <SD_OutputString+0x14>
   1010c:	e89da808 	ldmia	sp, {r3, fp, sp, pc}


I'm not fluent in assembler though, so I'm not sure exactly what it's
doing here.  The C code is pretty straight forward though -- I'm not
sure how it can misinterpret it.

John






julvr wrote:
> The dissasembly (did an objdump -D) is as follows: > > > 00000000 <.rodata>: > 0: 5b504420 blpl 1411088 <.rodata+0x1411088> > 4: 426f6f74 rsbmi r6, pc, #464 ; "Boot" > 8: 6c6f6164 stfvse f6, [pc], #-400 ; "load" > c: 65725d0a ldrvsb r5, [r2, #-3338]! ; "er" > 10: 00000000 andeq r0, r0, r0 > > where 426f6f74 ==> "Boot" > where 6c6f6164 ==> "load" > > etc, so it seems that the data is in fact stored in the correct order.
> > I'm not fluent in assembler though, so I'm not sure exactly what it's > doing here. The C code is pretty straight forward though -- I'm not > sure how it can misinterpret it. > I'll comment the code:
> 000100c8 <SD_OutputString>: > 100c8: e1a0c00d mov ip, sp > 100cc: e92dd800 stmdb sp!, {fp, ip, lr, pc} > 100d0: e24cb004 sub fp, ip, #4 ; 0x4 > 100d4: e24dd004 sub sp, sp, #4 ; 0x4
The above code creates a stack frame and sets fp to top of it
> 100d8: e50b0010 str r0, [fp, #-16]
This stores pTxt from r0 to a local word in stack
> 100dc: e51b3010 ldr r3, [fp, #-16] > 100e0: e5d33000 ldrb r3, [r3]
This loads the byte *pTxt into r3
> 100e4: e3530000 cmp r3, #0 ; 0x0 > 100e8: 0a000007 beq 1010c <SD_OutputString+0x44>
This tests the byte for '\0' and jumps to exit if yes
> 100ec: e51b3010 ldr r3, [fp, #-16] > 100f0: e5d33000 ldrb r3, [r3] > 100f4: e1a00003 mov r0, r3
This loads *ptxt again and sets it up as argument to SD_OutputChar
> 100f8: ebffffdd bl 10074 <SD_OutputChar>
Here we call the output function
> 100fc: e51b3010 ldr r3, [fp, #-16] > 10100: e2833001 add r3, r3, #1 ; 0x1 > 10104: e50b3010 str r3, [fp, #-16]
Bump pTxt
> 10108: eafffff3 b 100dc <SD_OutputString+0x14>
Loop back to while at 100dc
> 1010c: e89da808 ldmia sp, {r3, fp, sp, pc}
Tear down the stack frame, return ---- As far as I see, the code is correct. I'm still suspicious on the set up of the data section. Is this a ROM/RAM system where the initialization code sets up the .data section in RAM? How do you get the code and data to the target system? Can it be that you have the endianess crossed? An ARM core has an input which tells the endianess of the data bus. -- Tauno
I'm loading the data through a JTAG debugger.  Currently everything is
in RAM.  (The goal is to get to a point where I can write the code
into flash through the serial port, but I'm not there yet).  The code
runs, which means that the endianess is correct for the code at
least...  However, now that you mention it, it may be that the
debugger is switching the endian when loading (and that I should be
compiling little endian).  I'll look into the debugger manual to see
if I can find anything.

Thank you very much for your time.  I really appreciate it.  These
things can be very frustrating if you don't know what you're doing.

julvr <nospam@ulvr.com> writes:

> Forgive me if this is a noob question, but this is my first chip > bringup from scratch. I'm trying to bring up an ARM7 (ADuC7021), and > am having a problem with the endianness of data, and I'm not sure how > to fix it. > > My problem is this: if I call an internal function > SD_OutputString("Bootloader.."), I get the following output on my > serial port: "tooBdaol..re". In other words, it seems to be storing > the string in reverse endian format. > > The code in question is very simple: > > void SD_OutputString(const char *pTxt) > { > while (*pTxt != 0) > { > SD_OutputChar(*pTxt); > pTxt++; > } > } > > main() > { > SD_OutputString("Bootloader.."); > } > > I'm using arm-elf-gcc / arm-elf-ld to compile and link the code. My > Makefile has the following lines: > > CPPFlags = -Wall -mcpu=arm7tdmi -mbig-endian > LDFlags = -T ld_flash.cmd -nostartfiles -mbig-endian > > Does anyone know why my data is being stored in reverse order?
Isn't it so much fun to work with Little-Endian processors?!? ----------------------------------------------------------------------- "Big-Endian byte order is known as 'normal', 'intuitive', or 'obvious'. Little-Endian is sometimes called 'perverse', 'annoying', 'dysfunctional', or 'stupid'. These designations do not, of course, imply any bias or preference." Christopher R. Hertel, "Implementing CIFS" 2004
On Nov 11, 3:38=A0pm, julvr <nos...@ulvr.com> wrote:
> Forgive me if this is a noob question, but this is my first chip > bringup from scratch. =A0I'm trying to bring up an ARM7 (ADuC7021), and > am having a problem with the endianness of data, and I'm not sure how > to fix it.
<snip>
> CPPFlags =3D -Wall -mcpu=3Darm7tdmi -mbig-endian > LDFlags =3D -T ld_flash.cmd -nostartfiles -mbig-endian
Are you sure it's big endian? The data sheet at http://www.analog.com/static/imported-files/data_sheets/ADUC7019_7020_7021_= 7022_7024_7025_7026_7027_7028.pdf says it's little endian. -- Paul
julvr wrote:
> However, now that you mention it, it may be that the > debugger is switching the endian when loading (and that I should be > compiling little endian). I'll look into the debugger manual to see > if I can find anything.
Not so fast. The program is obviously compiled correctly, and you have a pure byte-wise output loop, so here endianness does not matter. The output you see is typical for data written into memory with the wrong endianness and in four-byte chunks (=using 32bit accesses). To fix this, when you download your string data with the JTAG debugger, (a) either the debugger must be set to byte-transfer mode, (b) or it must be configured to the correct endianness. As Paul Black already stated, your processor memory is organized little-endian. If you plan to define String constants or other data in your C program, you must definitely set the correct endianness. BTW, there is no "right" or "proper" endianness. For the machine and proper function of a program is in the end completely irrelevant -- you just need to make sure your compiler and processor use the same. Some processors (e.g. see PowerPC, PowerISA 2.05, Book III-S) can even be configured at run-time to access memory big-endian (PPC native mode) or little-endian (e.g. for PCI address space), this is set with a flag in the memory descriptor or the machine state register.
"Hagen Patzke" <hpatzke@hotmail.com> wrote in message news:gfd2j8$51j$1@aioe.org...
> julvr wrote: >> However, now that you mention it, it may be that the >> debugger is switching the endian when loading (and that I should be >> compiling little endian). I'll look into the debugger manual to see >> if I can find anything. > > Not so fast. The program is obviously compiled correctly, and you have a pure byte-wise output loop, so here > endianness does not matter.
The key question is whether the processor used has been configured to be big-endian - I bet it hasn't (assuming the device even allows it - if it doesn't then there is no way you can run big-endian code). ARM7 uses word-invariant endianness, which means that the endian of word accesses is unchanged between little and big-endian. Therefore an ARM program compiled for big-endian will run in little endian as it uses 32-bit instructions, but all 8- and 16-bit accesses will be incorrect, like the OP noticed. Wilco

The 2024 Embedded Online Conference