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.

C2000 Compiler wrongly handles 64-bit variables declared in the STACK

Other Parts Discussed in Thread: TMS320F28335

Hello, I've just run into a problem I believe is due to the wrong way the compiler handles 64-bit variables when they are declared locally within a function (STACK).

In particular I have the following sample code that gives different results depending on whether TestFunction1() or TestFunction2() get called:

Assuming OSDC__s32Time_Error = 0x24F235C2, OSDC__s16ProportionalGain = 0x5000 and OSDC__s16LoopGain = 0x0028,

void TestFunction1(void)
{
  s64Time_Error       = (S64)OSDC__s32Time_Error;
  s64ProportionalGain = (S64)OSDC__s16ProportionalGain;
  s64LoopGain         = (S64)OSDC__s16LoopGain;
  
  s64PropComponent          = s64Time_Error * s64ProportionalGain;
  OSDC__s64IntegratorState += s64Time_Error * s64LoopGain;
}

void TestFunction2(void)
{
  S64 s64Time_Error__STACK;
  S64 s64ProportionalGain__STACK;
  S64 s64LoopGain__STACK;
  
  s64Time_Error__STACK       = (S64)OSDC__s32Time_Error;
  s64ProportionalGain__STACK = (S64)OSDC__s16ProportionalGain;
  s64LoopGain__STACK         = (S64)OSDC__s16LoopGain;
  
  s64PropComponentTest          = s64Time_Error__STACK * s64ProportionalGain__STACK;
  OSDC__s64IntegratorStateTest += s64Time_Error__STACK * s64LoopGain__STACK;
}

In particular, TestFunction2() yields:

s64PropComponentTest = 0x00000B8BB0CCA000 <-- volatile global variable in external RAM

OSDC__s64IntegratorStateTest = 0x000000084D3797E0 <-- volatile global variable in external RAM

while TestFunction1() yields:

s64PropComponent = 0x00000B8BB0CCA000 <-- global variable in internal RAM

OSDC__s64IntegratorState = 0xFFFFFAF737754650 <-- global variable in internal RAM

Any idea of what's happening?

Thanks a lot.

Paolo

  • I apologize for taking so long to reply. 

    I am unable to reproduce your result.  Please post the exact compiler version and build options you are using.

    Thanks and regards,

    -George

  • Hello George, the compiler revision is 5.2.1 but apparently (as per release notes) even newer versions don't seem to address or mention this problem.

    My build options are:

    CCFLAGS = '-v28 -g -k -ss -pm -al -os -on2 -op0 -o3 -fr"/Product/build/obj" -fs"/Product/build/asm" -ft"/Product/build/temp" -fb"/Product/build/abs" -d"_DEBUG" -d"LARGE_MODEL" -b -ma -mf -ml -mt -pdsw225 --printf_support=nofloat'.

    The processor is a TMS320F28335.

    Hope this helps.

    Paolo

  • I am still unable to reproduce the error.  I am using those options and compiler version 5.2.1.  

    I suggest you make sure you are not running out of stack or heap.  

    In case it matters, here the source code I am running.  I am running it under a test harness we have which can support printf.  Your system may or may not be able to run it.

    #include <stdint.h>
    #include <stdio.h>
    
    typedef int64_t S64;
    typedef int32_t S32;
    typedef int16_t S16;
    
    S32 OSDC__s32Time_Error;
    S16 OSDC__s16ProportionalGain, OSDC__s16LoopGain;
    S64 s64Time_Error, s64ProportionalGain, s64LoopGain;
    S64 s64PropComponent, OSDC__s64IntegratorState;
    S64 s64PropComponentTest, OSDC__s64IntegratorStateTest;
    
    void init()
    {
      OSDC__s32Time_Error = 0x24F235C2;
      OSDC__s16ProportionalGain = 0x5000;
      OSDC__s16LoopGain = 0x0028;
    }
    
    void TestFunction1(void)
    {
      s64Time_Error       = (S64)OSDC__s32Time_Error;
      s64ProportionalGain = (S64)OSDC__s16ProportionalGain;
      s64LoopGain         = (S64)OSDC__s16LoopGain;
       
      s64PropComponent          = s64Time_Error * s64ProportionalGain;
      OSDC__s64IntegratorState += s64Time_Error * s64LoopGain;
    }
     
    void TestFunction2(void)
    {
      S64 s64Time_Error__STACK;
      S64 s64ProportionalGain__STACK;
      S64 s64LoopGain__STACK;
       
      s64Time_Error__STACK       = (S64)OSDC__s32Time_Error;
      s64ProportionalGain__STACK = (S64)OSDC__s16ProportionalGain;
      s64LoopGain__STACK         = (S64)OSDC__s16LoopGain;
       
      s64PropComponentTest          = s64Time_Error__STACK * s64ProportionalGain__STACK;
      OSDC__s64IntegratorStateTest += s64Time_Error__STACK * s64LoopGain__STACK;
    }
    
    
    void main()
    {
       init();
    
       TestFunction1();
       puts("After TestFunction1");
       printf("s64PropComponent: 0x%llx, expected 0xB8BB0CCA000\n",
                  s64PropComponent);
       printf("OSDC__s64IntegratorState: 0x%llx, expected 0x5C5D86650\n",
                  OSDC__s64IntegratorState);
    
       TestFunction2();
       puts("After TestFunction2");
       printf("s64PropComponentTest: 0x%llx, expected 0xB8BB0CCA000\n",
                  s64PropComponentTest);
       printf("OSDC__s64IntegratorStateTest: 0x%llx, expected 0x5C5D86650\n",
                  OSDC__s64IntegratorStateTest);
    }

    Thanks and regards,

    -George

  • Well, don't know what to say but I believe there's nothing wrong with the stack.

    Also, I'm experiencing another problem still with 64-bit variables.

    The following code is not working as it should:

    #define S32_MAX (2147483647L)
    #define S32_MIN (-2147483648L)
    volatile S64 s64debugVar;
    
    void main(void)
    {
      if (s64debugVar < S32_MIN)
      {
        s64debugVar = S32_MIN;
      }
      else if (s64debugVar > S32_MAX)
      {
        s64debugVar = S32_MAX;
      }
    }
    

    Now, if I set (using my JTAG emulator) s64debugVar = 0, the final number stored into s64debugVar is 2147483648 which is wrong, of course. Besides, I can't even understand where that number comes from!

    Regards,

    Paolo

  • The first bullet in this wiki article applies with regard to S32_MIN.  It is viewed as the unsigned value 2147483648.  s64debugVar is less than that, so it is assigned S32_MIN.  To make this work the way you expect, you need to change the suffix on the constants from "L" to "LL".  This tells the compiler the type of the constants is long long.  

    Thanks and regards,

    -George

  • No it doesn't. The example is totally different. Sorry George but you're wrong.

    In a 32-bit 2s representation, a "signed long" number N is within the range:  [-231, 231 - 1]. This means its minimum value is -231 = -2147483648.

    Please see below, what the compiler User's Guide (page 92) says:

    Attached the mentioned User's Guide.

    Even casting to S64 does not solve the problem:

    void main(void)
    {
      if (s64debugVar < (S64)S32_MIN)
      {
        s64debugVar = (S64)S32_MIN;
      }
      else if (s64debugVar > (S64)S32_MAX)
      {
        s64debugVar = (S64)S32_MAX;
      }
    }

     

    Where S64 stands for (long long).

    Actually I've been able to make it work casting the S32_MIN to S32 (i.e. "long") explicitly: (S32)S32_MIN. Since S32_MIN is a perfectly acceptable S32 negative value, at this point I still believe the Compiler has a bug. Casting to S64 should never cause a 32-bit negative number to be converted into a positive one.

    Regards,

     

    Paolo

    TMS320C28x_C_Compiler_v6.pdf
  • I'm sorry, but George is correct.  In C89, the language version the TI compiler supports, the expression -2147483648L is of type "unsigned int." That's because (according to ANSI 3.1.3.2 "Integer Constants"), "The type of an integer constant is the first of the corresponding list in which its value can be represented. [..] suffixed by the letter l or L: long int, unsigned long int.[..]" The value 2147483648L does not fit in a 32-bit long int, so it must be treated as unsigned long int, and therefore the negation operation is an unsigned negation. If you want an expression which represents the minimum value of a long int, either include limits.h and use LONG_MIN, or use (-2147483647L-1)