Big and Little Endian Byte Orderings Big and Little Endian Byte Orderings The MIPS processor and compilers support both the Big Endian and Little Endian byte-ordering conventions. The names Big Endian and Little Endian are used because of the apt analogy to the bloody feud in the classic children's book Gulliver's Travels (quod vide). The feud was between the two mythical islands, Lilliput and Blefescu, over the correct end (big or little) at which to crack an egg. In our case, the issue has to do with the "end" (most significant or least significant) of a multiple-byte data type. With Big Endian ordering, the address of a multiple-byte data type is of its most significant byte (its "big end"), whereas with Little Endian ordering, the address is of its least significant byte (its "little end"). This is shown in Figure A.14. For structures declared in a high-level language, the order of bytes in memory will differ depending on the byte ordering and the particular data type, as shown for a C structure in Figure A.15. ««««««««««««««««««««««««««««««««««««««««»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» Code Big Endian Little Endian Memory Contents Memory Contents ««««««««««««««««««««««««««««««««««««««««»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» struct { long a; short b[2]; char c[4]; } S1 = { /* Big Endian Little Endian */ 0x12345678, /* 12 34 56 78 78 56 34 12 */ 0x1234,0x5678, /* 12 34 56 78 34 12 78 56 */ "ABC" /* 41 42 43 00 41 42 43 00 */ }; ««««««««««««««««««««««««««««««««««««««««»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» Figure A.15 Big and Little Endian Byte-Ordering Example Note that Endianness only affects the operation of the load and store instructions, which means when data is moved between memory or peripheral devices and registers. Except in cases where the host and target have the same byte-ordering convention, you must explicitly define the required Endianness of the target code using the appropriate command-line option (EB or EL). This will override the host's default byte ordering. For example, pmcc -EB -o prog prog.c pmcc -EL -o prog prog.c To write code that can be compiled/assembled to execute correctly in either a Big or a Little Endian target environment, the user must follow one basic rule: either eliminate Endian-specific code or enclose it with #ifdef/else statements, using the appropriate preprocessor flag (MIPSEB or MIPSEL). Endian-specific code is produced whenever the data type implicit in the instruction (e.g., "byte" in load byte) differs from the data type of the accessed data, such as using four load-byte instructions to read a single word or using a store-word instruction to store 4 bytes. I/O addresses are also Endian-specific, because a peripheral device is hardwired to a specific part of the data bus (typically D0-D7). The example programs main.c and asm.s print Endian-sensitive values returned from the functions end1 and end2 and the contents of two Endian-sensitive I/O locations, SIOCNTL and SIODATA. For purposes of illustration, the functions return correct results when passed the value 0 and incorrect results when passed the value 1. The programs are shown in their entirety in the final section of this appendix and are discussed below. The C program defines two base addresses for the peripheral device (SIOBASE) and uses the preprocessor variable MIPSEB (Big Endian) to select between the two byte-ordering conventions. 1 #ifdef MIPSEB 2 #define SIOBASE 0xbe000003 /* Big Endian base address */ 3 #else 4 #define SIOBASE 0xbe000000 /* Little Endian base address */ 5 #endif 6 #define SIOCNTL *((volatile unsigned char *)SIOBASE+4) 7 #define SIODATA *((volatile unsigned char *)SIOBASE+12) The function main prints the results of the functions end1 and end2. Incorrect results are produced by end1 because when the function is passed a 1, it reads the word as a series of 4 bytes, rather than as a single word. Starting at the word address, each byte is read into the variable v, such that the lowest addressed byte ends up in the most significant byte of the variable. This is the correct byte ordering for Big Endian but incorrect for Little Endian: 19 for (i=0;i Incorrect results are produced by end2 because the lwl and lwr instruc- tions are used to access unaligned data; the non-Endian-sensitive solution uses the ulw instruction: 8 end2: la t0,dat2 9 beq a0,zero,1f 10 nop 11 lwl v0,0(t0) 12 lwr v0,3(t0) 13 b 2f 14 nop 15 1: ulw v0,(t0) 16 2: jr ra For Big Endian the program prints: 12345678 12345678 12345678 12345678 00 3b and for Little Endian it prints: 12345678 78563412 12345678 78345612 00 3b Keep in mind that a program's binary cannot be converted from one byte-ordering convention to another by simply swapping all the bytes. This would produce correct results only if all of the program's data were of the same type (size) and the same size as the instructions. To change the byte ordering, programs must be recompiled using the appropriate compiler option. A.7 PROGRAM LISTINGS main.c: 1 #ifdef MIPSEB 2 #define SIOBASE 0xbe000003 /* Big Endian base address */ 3 #else 4 #define SIOBASE 0xbe000000 /* Little Endian base address */ 5 #endif 6 #define SIOCNTL *((volatile unsigned char *)SIOBASE+4) 7 #define SIODATA *((volatile unsigned char *)SIOBASE+12) 8 int dat1 = 0x12345678; 9 end1(n) 10 int n; 11 { 12 int i,v; 13 unsigned char *p; 14 /* set up a pointer into the data */ 15 p = (unsigned char *) 16 if (n==0) v = dat1; 17 else { 18 v = 0; 19 for (i=0;i<4;i++) { 20 v <<= 8; 21 v |= p[i]; 22 } 23 } 24 return(v); 25 } 26 main() 27 { 28 printf("%08x %08x\n"); 29 printf("%08x %08x\n"); 30 printf("%02x %02x\n"); 31 } asm.s: 1 #include "mips.h" 2 .data 3 dat2: .word 0x12345678 4 .text 5 .globl end2 6 .ent end2 7 .set noreorder 8 end2: la t0,dat2 9 beq a0,zero,1f 10 nop 11 lwl v0,0(t0) 12 lwr v0,3(t0) 13 b 2f 14 nop 15 1: ulw v0,(t0) 16 2: jr ra 17 nop 18 .end end2 [EGG] Danny Cohen, "On Holy Wars and a Plea for Peace," IEEE Computer, Oct. 1981, pp. 48-54. ««««««««««««««««««««««««««««««««««««««««»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» This explanation was extracted from Appendix A of The MIPS Programmer's Handbook, by Erin Farquhar and Philip Bunce. ««««««««««««««««««««««««««««««««««««««««»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»» Navigation: Document Home | Document Contents | Document Index