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.

TMS320F28027: Compiler adding blank address in a struct

Part Number: TMS320F28027

Hello,

The problem arise only using an unsigned long in a struct and only with a struct size greater than a specific threashold ( 9? ) 

Compilers tested

16.9.10 LTS
20.2.5 LTS

example:

in the working code, outsideVar has address:   0x00008306
This is correct, since the previus variable w3 has address: 0x00008305   

In the code with bug, outsideVar has address:   0x00008320
This is not correct, since the previus variable w10 has address: 0x0000831E
So compier let 0x0000831F blank. However you can see this address in the variable "all", so this behavior can be dangerus for memcopy routine

Code working fine

typedef union _TMP
{
    struct
    {
        union
        {
            struct
            {
                unsigned short w0;
                unsigned short w1;
                unsigned short w2;
                unsigned short w3;
            } EXPANDED;
            struct
            {
                unsigned long w0_w1;
                unsigned short w2_w3[2];
            } COMPRESSED;
            unsigned short all[4];
        } SUBSYSTEM;
        unsigned short outsideVar;
    }expand;
    unsigned short all[5];
} TMP;

Code with bug:

typedef union _TMP
{
    struct
    {
        union
        {
            struct
            {
                unsigned short w0;
                unsigned short w1;
                unsigned short w2;
                unsigned short w3;
                unsigned short w4;
                unsigned short w5;
                unsigned short w6;
                unsigned short w7;
                unsigned short w8;
                unsigned short w9;
                unsigned short w10;
            } EXPANDED;
            struct
            {
                unsigned long w0_w1;
                unsigned short w2_w18[9];
            } COMPRESSED;
            unsigned short all[11];
        } SUBSYSTEM;
        unsigned short outsideVar;
    }expand;
    unsigned short all[12];
} TMP;

  • Hello Nicola,

    To clarify, do both compiled codes function the same? I'm curious why the first situation would be okay, considering outsideVar and all[4] are pointing to the exact same address, whereas in the compiled code with a 'bug', they don't overlap. Is this intentional? How are you defining a variable/its fields with this struct? It's difficult for me to understand the issue since I don't see how this struct gets used (i.e. are all the fields supposed to be pointing to the same array/variable addresses?). Please provide some example code on how you're using the struct.

  • Hi Omer, this is a running example. I don't use this struct, it's just wrote to be tested

    typedef union _TMP
    {
        struct
        {
            union
            {
                struct
                {
                    unsigned short w0;
                    unsigned short w1;
                    unsigned short w2;
                    unsigned short w3;
                    unsigned short w4;
                    unsigned short w5;
                    unsigned short w6;
                    unsigned short w7;
                    unsigned short w8;
                    unsigned short w9;
                    unsigned short w10;
                } EXPANDED;
                struct
                {
                    unsigned long w0_w1;
                    unsigned short w2_w10[9];
                } COMPRESSED;
                unsigned short all[11];
            } SUBSYSTEM;
            unsigned short outsideVar;
        }expand;
        unsigned short all[12];
    } TMP;
    
    TMP test;
    
    while (1)
    {
        test.expand.SUBSYSTEM.EXPANDED.w0 = 0;
        test.expand.SUBSYSTEM.EXPANDED.w1 = 1;
        test.expand.SUBSYSTEM.EXPANDED.w2 = 2;
        test.expand.SUBSYSTEM.EXPANDED.w3 = 3;
        test.expand.SUBSYSTEM.EXPANDED.w4 = 4;
        test.expand.SUBSYSTEM.EXPANDED.w5 = 5;
        test.expand.SUBSYSTEM.EXPANDED.w6 = 6;
        test.expand.SUBSYSTEM.EXPANDED.w7 = 7;
        test.expand.SUBSYSTEM.EXPANDED.w8 = 8;
        test.expand.SUBSYSTEM.EXPANDED.w9 = 9;
        test.expand.SUBSYSTEM.EXPANDED.w10 = 10;
        test.expand.outsideVar = 11;
    }

    Please note that if I change

    unsigned long w0_w1; 

    to

    unsigned short w0_w1[2];

    everything works fine

  • Hi dev123 - Omer,

    There is some oddness around arrays and longs. The C2000 compiler guide Optimizing-C gives clues, by default bytes are 16 bit and seemingly w0_w1[2] is actually 32 bit long. Oddly longs do not behave well in C lib arrays data often has random breaks. Reported similar behavior some time ago casting 32 bits into functions using arrays as storage is a bit touchy. Imagine the same is true of nested structs with arrays in your test code. 

     /cfs-file/__key/communityserver-discussions-components-files/171/TI_2D00_C2000-Optimizing-C_2C00_C_2B002B00_-Compilers-spru514y.pdf

  • The compiler is working as designed.  For a general introduction to the concepts involved, please see this FAQ (not from TI).  

    Here are some facts about the C2000 architecture that are relevant.

    • Each address corresponds to a 16-bit word, and not an 8-bit byte
    • The type long is 32-bits wide, and must be a aligned on a 2-word boundary
    • The type short is 16-bits wide, and has no alignment requirement

    This structure ...

                struct
                {
                    unsigned long w0_w1;
                    unsigned short w2_w18[9];
                } COMPRESSED;

    ... contains a long.  Thus, it must be aligned to a 2-word boundary, and must contain an even number of words.  The total size of the members in this struct is 11 words.  Thus, a word of padding is added to the end for a total length of 12 words.  This alignment and padding requirement propagates out, and causes the struct member outsideVar to always be on an even address.

    if I change

    Fullscreen
    1
    unsigned long w0_w1;
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    to

    Fullscreen
    1
    unsigned short w0_w1[2];
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    everything works fine

    Because you removed the long, the padding and alignment are not needed.

    Thanks and regards,

    -George