This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

the bitfield of struct in big-endian device

ccsv5 compiler5.0.1 big-edian ARM

Does the compiler5 treat the first member of a struct as the MSB ,diffrent from ccs2 ?

Is there any instruction to make the first member to be LSB?How can I make the "0x0002"match to "Charge = 1",just like the struct is a nomal data?

I tried use RBIT and change the struct define.Any other ways?

  • fan Linlin said:
    Does the compiler5 treat the first member of a struct as the MSB ,diffrent from ccs2 ?

    CCS 2.x is from many years ago.  I take this to mean you are porting code from a very old ARM compiler version to the relatively recent compiler version 5.0.1.  I further presume you have changed ABI from the older ti_arm9_abi to the newer EABI.

    One option for restoring old behavior is to build with --abi=ti_arm9_abi.

    To understand this issue better, please see the appendix titled Bit Fields in the ARM compiler EABI migration document.

    Thanks and regards,

    -George

  • I have read the  EABI migration document,but it just refers to the number of address a struct takes up ,and doesn't refer to the sequens of the bits. The C  compiler user guide describe the struct store in memory,but it's diffrent from my test result.

    example in C  compiler user guide :"Bit fields are packed in memory from most significant byte to least significant byte ."

  • fan Linlin said:
    "Bit fields are packed in memory from most significant byte to least significant byte ."

    That sentence is the specification for the order of the fields.  In big endian mode, the first field starts at the most significant bit in the bit-field, as shown in the figure.  The ARM EABI bit-field layout is dictated by AEABI document produced by ARM.  For further details, see http://infocenter.arm.com -> ARM Software development tools -> Application Binary Interface ... -> ABI for the ARM 32-bit Architecture -> Procedure Call Standard -> Section 7.1.7 "Bit-fields"

    Please show us the definition of your bit-field struct.

    What ARM compiler version are you using in CCS 2?  (It is not the same as the CCS version).

    Which --abi option are you using?

  • I‘m sorry to reply so late.

    I know that the CCS2 and CCS5 use different compiler version.And I really want to know the difference about struct between them.I have read the  Procedure Call Standard document,but I didn't really understand.Can you give me a simple explanation about 7.1.7?

    My bit-filed related with the pictures above is as follow:

    typedef union
    {
    struct
    {
    unsigned int ReadyG : 1; 
    unsigned int SelfCheckPassG : 1; 
    unsigned int Charging : 1; 
    unsigned int Charged : 1; 
    unsigned int Modulating : 1; 
    unsigned int GridDischargeReady : 1; 
    unsigned int FltReptNotRun : 1; 
    unsigned int ReadyR : 1; 
    unsigned int SelfCheckPassR : 1; 
    unsigned int Synchronizing : 1; 
    unsigned int Synchronized : 1;
    unsigned int Connected : 1; 
    unsigned int Stopping : 1; 
    unsigned int Stopped : 1; 
    unsigned int Fault : 1; 
    unsigned int Warning : 1;
    } B;
    unsigned int all;
    }unAppMainStsWordMode4; /* Application fault status word */

    I use eabi.

     

  • Thank you for that information.  However, I still need to know the version of the compiler you used in CCS2, as well as the command-line options used then.  I seriously doubt the compiler you used in CCS2 supported EABI.

  • I'm sorry I didn't make it clear.

    While I use CCS5 for ARM7,I use CCS2 for DSP2808.

    And I think the address allocation of struct members is depend on the version of the compiler which analysis C,isn't it?

    Is it related to the processor core?

    The compiler and linker in CCS2 are as follows:

  • Okay, the bit-field layout is dictated not by the compiler version but by the Application Binary Interface (ABI).  Each processor supports one or more ABIs which dictate things like the size of types and the calling convention.  When compiling in ARM EABI mode, the compiler is obligated to use ARM's AEABI, which spells out precisely how bit-fields are packed.  See the document from ARM infocenter I refer to, above. 

    In brief, in big-endian mode, your 16 bits will occupy the 16 most significant bits of the union, with ReadyG in the most significant bit (MSB).  C2000 has its own ABI, which is not the same as ARM's AEABI.  The most significant difference is that C2000 is a little-endian device, so the bits are packed into the least signficant bits first, which will appear as the mirror-image of the ARM big-endian layout.

    The other major difference is that on ARM, your union is of size 32 bits, whereas on C2000 it will be 16 bits, due to the difference in the size of "unsigned int."  If you inteend the union to be of size 16 bits, use "unsigned short" for both ARM and C2000.

    Is this clear enough?

  • 1.The big-edian talks about bytes,when the bit field talks about bits.Are they  completely independent ?

    2.The followed three points look like incompatible,which make me puzzled:

    first,TMS570 Manual indicate that Big-endian systems store the most-significant byte of a multi-byte data field in the lowest memory address.Writing 0x11223344 to address 0xFFF7F448 shows the following when viewing the memory in 8-bit modes.

    So for a 32bit data,the most-significant byte is discribed as byte3,when the least-significant byte is discribed as byte0.

    second, C compiler user guide indicate that Bit fields are packed in memory from most significant byte to least  significant byte .But it's example indicate the bit field definitions and corresponding bit-field packing as follows:

    my question:in this example,which byte is the significant byte,byte0 or byte3?Is this byte3 also is stored in the lowest memory address?

  • fan Linlin said:

    2.The followed three points look like incompatible,which make me puzzled:

    first,TMS570 Manual indicate that Big-endian systems store the most-significant byte of a multi-byte data field in the lowest memory address.Writing 0x11223344 to address 0xFFF7F448 shows the following when viewing the memory in 8-bit modes.

    So for a 32bit data,the most-significant byte is discribed as byte3,when the least-significant byte is discribed as byte0.

    By "TMS570" manual, I presume you mean the TI document "ARM Optimizing C/C++ Compiler User's Guide."  Is that correct?  Which version, exactly?

    That document talks about storage of bit-fields to memory being done with a byte-by-byte, rather than bit-by-bit, transfer.  You should ignore this for now, because that only makes a difference for little-endian mode.  Focus on the bit layout in a register, which does not refer to bytes.  You only need to know the memory layout if you attempt to read parts of the field directly from memory without going through the C language bit-field access, and only if you are in little-endian mode.

    From the diagram for "Big-endian register", you will see that the fields are indeed packed starting at the Most Signficant (MS) bit, and packed bit-wise.  For a big-endian bit-field, the MS bits will indeed end up in the MS byte.

    Here is a program demonstrating how the bits get packed.  You should study the output of this program, and watch the memory of the object as the program executes.

    #include <stdio.h>
    
    union {
        struct{
            unsigned int A:7;
            unsigned int B:10;
            unsigned int C:3;
            unsigned int D:2;
            unsigned int E:9;
        } x;
        unsigned int whole;
    } u;
    
    int main()
    {
        int i;
        u.whole = 0;
        puts("filling A");
        for(i=0;i<7;i++)
        {
            u.x.A = (1<<i);
            printf("%08x\n", u.whole);
        }
        u.whole = 0;
        puts("filling B");
        for(i=0;i<10;i++)
        {
            u.x.B = (1<<i);
            printf("%08x\n", u.whole);
        }
        u.whole = 0;
        puts("filling C");
        for(i=0;i<3;i++)
        {
            u.x.C = (1<<i);
            printf("%08x\n", u.whole);
        }
        u.whole = 0;
        puts("filling D");
        for(i=0;i<2;i++)
        {
            u.x.D = (1<<i);
            printf("%08x\n", u.whole);
        }
        u.whole = 0;
        puts("filling E");
        for(i=0;i<9;i++)
        {
            u.x.E = (1<<i);
            printf("%08x\n", u.whole);
        }
    }
    
  • third,in my test I defined a struct,

    typedef union
    {
    struct
    {
    uint16 SelfCheckG : 1; 
    uint16 Charge : 1; 
    uint16 Modulate : 1; 
    uint16 DischargeRotor : 1; 
    uint16 Bit4 : 1; 
    uint16 Bit5 : 1; 
    uint16 Bit6 : 1; 
    uint16 Bit7 : 1;
    uint16 SelfCheckR : 1;
    uint16 Synchronize : 1;
    uint16 Connect : 1; 
    uint16 FaultReset : 1; 
    uint16 Bit12 : 1; 
    uint16 Bit13 : 1; 
    uint16 Bit14 : 1; 
    uint16 Bit15 : 1;
    } B;
    uint16 all;
    } unAppMainCtrlWordMode4;

    And in the view of memory,it  shows:

    It shows the first member SelfCheckG as the bit0.And you said that the first member will be the MSB,the same as  C compiler user guide indicate that Bit fields are packed in memory from most significant byte to least  significant byte .It's incompatible that SelfCheckG is bit0 and at the same time MSB.

  • I think I get it!

    Thank you very much for your help and patience!