1. This forum section is a read-only archive which contains old newsgroup posts. If you wish to post a query, please do so in one of our main forum sections (here). This way you will get a faster, better response from the members on Motherboard Point.

Endianness macros

Discussion in 'Embedded' started by Noob, Nov 27, 2009.

  1. Noob

    Noob Guest

    [ NB: cross-posted to comp.lang.c and comp.arch.embedded ]

    Hello everyone,

    I'm having trouble understanding some endianness-related macros
    provided on my platform.

    <quote>

    typedef volatile U32 FOOBA_MU32;
    typedef volatile U16 FOOBA_MU16;
    typedef volatile U8 FOOBA_MU8;

    /* ------------------------------------------------------- */
    /* void FOOBA_WriteRegMem32BE(void *Address_p, U32 Value); */
    /* ------------------------------------------------------- */
    #ifndef FOOBA_MEMORY_ACCESS_NO_OPTIMIZATION /* optimized */
    #ifndef FOOBA_MEMORY_ACCESS_BIG_NOT_LITTLE /* little endian CPU */
    #define FOOBA_WriteRegMem32BE(Address_p, Value) \
    { \
    *((FOOBA_MU32 *) (Address_p)) = (U32) ((((Value) & 0xFF000000) >> 24) | \
    (((Value) & 0x00FF0000) >> 8 ) | \
    (((Value) & 0x0000FF00) << 8 ) | \
    (((Value) & 0x000000FF) << 24)); \
    }
    #else /* big endian CPU */
    #define FOOBA_WriteRegMem32BE(Address_p, Value) \
    { \
    *((FOOBA_MU32 *) (Address_p)) = (U32) (Value); \
    }
    #endif /* _BIG_NOT_LITTLE */
    #else /* not optimized */
    #define FOOBA_WriteRegMem32BE(Address_p, Value) \
    { \
    *(((FOOBA_MU8 *) (Address_p)) ) = (U8) ((Value) >> 24); \
    *(((FOOBA_MU8 *) (Address_p)) + 1) = (U8) ((Value) >> 16); \
    *(((FOOBA_MU8 *) (Address_p)) + 2) = (U8) ((Value) >> 8 ); \
    *(((FOOBA_MU8 *) (Address_p)) + 3) = (U8) ((Value) ); \
    }
    #endif /* _NO_OPTIMIZATION */

    /* ------------------------------------------------------- */
    /* void FOOBA_WriteRegMem32LE(void *Address_p, U32 Value); */
    /* ------------------------------------------------------- */
    #ifndef FOOBA_MEMORY_ACCESS_NO_OPTIMIZATION /* optimized */
    #ifndef FOOBA_MEMORY_ACCESS_BIG_NOT_LITTLE /* little endian CPU */
    #define FOOBA_WriteRegMem32LE(Address_p, Value) \
    { \
    *((FOOBA_MU32 *) (Address_p)) = (U32) (Value); \
    }
    #else /* big endian CPU */
    #define FOOBA_WriteRegMem32LE(Address_p, Value) \
    { \
    *((FOOBA_MU32 *) (Address_p)) = (U32) ((((Value) & 0xFF000000) >> 24) | \
    (((Value) & 0x00FF0000) >> 8 ) | \
    (((Value) & 0x0000FF00) << 8 ) | \
    (((Value) & 0x000000FF) << 24)); \
    }
    #endif /* _BIG_NOT_LITTLE */
    #else /* not optimized */
    #define FOOBA_WriteRegMem32LE(Address_p, Value) \
    { \
    *(((FOOBA_MU8 *) (Address_p)) ) = (U8) ((Value) ); \
    *(((FOOBA_MU8 *) (Address_p)) + 1) = (U8) ((Value) >> 8 ); \
    *(((FOOBA_MU8 *) (Address_p)) + 2) = (U8) ((Value) >> 16); \
    *(((FOOBA_MU8 *) (Address_p)) + 3) = (U8) ((Value) >> 24); \
    }
    #endif /* _NO_OPTIMIZATION */


    </quote>

    (As far as I understand, registers are memory-mapped, but this should
    not matter (or does it?) for this discussion.)

    Suppose I want to write the *value* 259 to address "addr"
    259(base 10) = 0x00000103(base 16)

    I shouldn't have to care whether the data is stored least-significant
    octet first or most-significant octet first, right?

    I'd just write:

    FOOBA_WriteRegMem32(addr, 259);

    As far as I understand, endianness only matters when considering a
    number's representation, not when considering a number's value?

    Whether a system is big-endian, little-endian, or weird-endian,
    value & 0xff gives the number's least-significant octet, right?

    So, in my case, should I write
    FOOBA_WriteRegMem32LE(addr, 259);
    or
    FOOBA_WriteRegMem32BE(addr, 259);
    ??

    And if I change to a different platform, do I have to change all
    my calls? (That would not make sense, I must've missed something.)

    ....

    I've been discussing this issue with a colleague, and he suggested that perhaps
    many differing components' registers may be mapped in the address space, some
    big-endian, other little-endian, thus the programmer must know what kind of
    register he is accessing. Would that be a plausible explanation?

    Regards.
     
    Noob, Nov 27, 2009
    #1
    1. Advertisements

  2. Yes, one doe not usually have to care.
    In fact, one normally writes *addr = 259; because addr will have the
    I'd want to know why you have write either. These macros did not just
    appear -- they must be part of some other code that you are using to
    solve some problem. Knowing why they were written, might make their
    purpose clearer, but it must have something to do with writing data
    that is not "native". Something in what you are doing would seem to
    need writing data in a format that specified not by the machine's
    addressing but by something else.
    No, that does not seem to be the purpose.
    That sounds more like it. It's hard to say with so little
    information, but there seems to be a need to write data in a
    representation that must be explicit in the program and which may or
    may not be the native format for the machine. Some file formats are
    like that, for example, as are many protocols.
     
    Ben Bacarisse, Nov 27, 2009
    #2
    1. Advertisements

  3. Noob

    larwe Guest

    Reading the sample code, it seems very likely that you've got a bus
    that runs in one particular endianness (say PCI) and a processor core
    that lives in the opposite endianness, and you are trying to keep your
    internal representation of the contents of these device registers
    consistent with the datasheets.
     
    larwe, Nov 27, 2009
    #3
  4. Noob

    Mel Guest

    Also very common when you've got a buffer full of binary stuff read in from
    some other medium -- file, Internet packet, EEPROM, etc. -- which was
    created with a different convention from yours.

    Mel.
     
    Mel, Nov 27, 2009
    #4
  5. Totally irrelevant.
    I assume that the target address is external to the MCU.
    It depends. If the data bus you're talking to is 8 bits, then it might
    matter, depending on whether your MCU has an appropriately configured
    external bus controller peripheral. If the data bus is 32 bits, then you
    should only care if it isn't wired correctly. For a 16-bit bus, both
    considerations apply.
    Only if that different platform has its external bus wired or configured
    differently for the address space you're talking to.
    Yes. But changing a component's endianness in hardware is usually very
    easy, so I guess this is for a low-cost device.
     
    Boudewijn Dijkstra, Nov 27, 2009
    #5
  6. Noob

    D Yuniskis Guest

    Actually, I suspect that is a big part of the problem!
    It implies that the "device" (addresses) being accessed is
    external to the processor itself (you haven't mentioned
    specifics -- processor, device, etc.).

    A Little Endian processor stores LSB at lower address
    and MSB at next higher address (I make no claims yet about the
    TIME SEQUENCE ORDERING in which this occurs -- MSB, LSB vs.
    LSB, MSB). The reverse is true for Big Endian processors.

    (pretend we're just dealing with a 16 bit value, here.
    And, that the data bus is 8 bits wide. You can extend
    the concept to wider words and busses)

    If the device you are talking to occupies multiple
    (consecutive) addresses, then the relationship of
    LSB & MSB to address X & address X+1 will differ
    depending on the Endianess of the processor.

    For example, assume you have a UART with data register
    at X and control at X+1. The value 0x3100 would write
    an ASCII '1' (0x31) to the data register (causing the
    character to be transmitted, for example) and a "00"
    to the control register FOR A BIG ENDIAN processor.

    OTOH, you would end up writing a 0x00 to the data register
    and a 0x31 to the control register in a Little Endian
    architecture. Quite different results. :>

    This is often encountered in network drivers where the
    data is sent in "network byte order" (which must be
    "universal") but must be interpreted in *host* byte order.
     
    D Yuniskis, Nov 27, 2009
    #6
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.