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.

signed to unsigned int devision



Hello,
customer step over a signed/unsigned int devision which blow up his power supply. Can you check if below compiler behaviour is correct or a bug. There was no compiler warning during compilation.

Result of CAL_mg_s16TestRes1  = CAL_mg_s16TestNom / 4u; is 16379 which is not correct.

Correct behaviour of positive division:

Compiler: ti-cgt-c2000_18.12.8.LTS

#--- Compiler settings --------------------------------------------------------
compiler_flags =  \
                  --silicon_version=28                         \
                  --unified_memory                             \
                  --opt_level=3                                \
                  --opt_for_speed=4                            \
                  --opt_for_space                              \
                  --c99                                        \
                  --single_inline                              \
                  --cla_support=cla2                           \
                  --float_support=fpu32                        \
                  --tmu_support=tmu0                           \
                  --vcu_support=vcu0                           \
                  --fp_mode=relaxed                            \
                  $(subst -I,--include_path=,$(includes))      \
                  --symdebug:dwarf                             \
                  --define=CPU1                                \
                  --define=_FLASH                              \
                  --quiet                                      \
                  --verbose_diagnostics                        \
                  --diag_warning=225                           \
                  --diag_suppress=10063                        \
                  --issue_remarks                              \
                  --preproc_with_compile                       \
                  --gen_data_subsections=off                   \
                  --advice:performance=all                     \
                  --pp_directory="$(pp_path)"                  \
                  --obj_directory="$(obj_path)"                \
                  --temp_directory="$(tmp_path)"               \
                  --asm_directory="$(asm_path)"                \
                  --list_directory="$(lst_path)"

static int16   CAL_mg_s16TestRes1;
static int16   CAL_mg_s16TestRes2;
static int16   CAL_mg_s16TestRes3;
static int16   CAL_mg_s16TestRes4;
static int16   CAL_mg_s16TestNom;
static int16   CAL_mg_s16TestDenom;
static Uint16  CAL_mg_u16TestDenom;


     /* TEST TEST */
     CAL_mg_s16TestRes1    = 0;
     CAL_mg_s16TestRes2    = 0;
     CAL_mg_s16TestRes3    = 0;
     CAL_mg_s16TestNom     = 20;
     CAL_mg_s16TestDenom   = 4;
     CAL_mg_u16TestDenom   = 4u;

     CAL_mg_s16TestRes1  = CAL_mg_s16TestNom / 4u;
     CAL_mg_s16TestRes2  = CAL_mg_s16TestNom / 4;
     CAL_mg_s16TestRes3  = CAL_mg_s16TestNom / CAL_mg_s16TestDenom;
     CAL_mg_s16TestRes4  = CAL_mg_s16TestNom / CAL_mg_u16TestDenom;

Uncorrect behaviour of negativ division:

     /* TEST TEST */
     CAL_mg_s16TestRes1    = 0;
     CAL_mg_s16TestRes2    = 0;
     CAL_mg_s16TestRes3    = 0;
     CAL_mg_s16TestNom     = -20;
     CAL_mg_s16TestDenom   = 4;
     CAL_mg_u16TestDenom   = 4u;

     CAL_mg_s16TestRes1  = CAL_mg_s16TestNom / 4u;
     CAL_mg_s16TestRes2  = CAL_mg_s16TestNom / 4;
     CAL_mg_s16TestRes3  = CAL_mg_s16TestNom / CAL_mg_s16TestDenom;
     CAL_mg_s16TestRes4  = CAL_mg_s16TestNom / CAL_mg_u16TestDenom;

Regards, Holger

  • What device is this for?

  • Hello Nima,
    it is F280049. Compiler version: ti-cgt-c2000_18.12.8.LTS

    Regards, Holger

  • Few questions:

    1. What is the Pinmux image you have attached? Is there a relevance between that image and the failure.

    2. Do you have a ZIPPED project file that we can test out on our launchpads?

    3. How did single stepping over the instruction blow up the power supply?

  • Hi Nima,

    1. sorry I posted the wrong images. Now corrected.

    2. no need for .zip project. You can easily test the c code in the thread above.

    3. this is only test code to show the fault, in the application the values is calculated in the algorithm and the failure was difficult to find

    Regards, Holger

  • Okay thank you. It is thanksgiving holiday so the responses may be delayed but I will connect you to the right SW/compiler person.

  • check if below compiler behaviour is correct or a bug

    It is correct.

    The expression ...

    int16_variable / 4u

    ... is evaluated by first converting all the operands to a common type.  In this case, that common type is unsigned 16-bit integer.  Then unsigned 16-bit division is performed.  Since this is unsigned division by 4, it is changed to unsigned right shift by 2.  So, it is the same as if you wrote ...

    (uint16_t) int16_variable >> 2

    In this case, int16_variable contains the value -20.  When changed to 16-bit unsigned, it is the value 0xffec.  0xffec >> 2 is 0x3ffb.  Written in decimal, that is 16379.

    Thanks and regards,

    -George

  • Hello George,

    customer checked with GCC compiler which behaves different from our:

    static int16_t   CAL_mg_s16TestRes1;
    static int16_t   CAL_mg_s16TestRes2;
    static int16_t   CAL_mg_s16TestRes3;
    static int16_t   CAL_mg_s16TestRes4;
    static int16_t   CAL_mg_s16TestNom;
    static int16_t   CAL_mg_s16TestDenom;
    static uint16_t  CAL_mg_u16TestDenom;

    /* TEST TEST */
    CAL_mg_s16TestRes1    = 0;
    CAL_mg_s16TestRes2    = 0;
    CAL_mg_s16TestRes3    = 0;
    CAL_mg_s16TestNom     = -20;
    CAL_mg_s16TestDenom   = 4;
    CAL_mg_u16TestDenom   = 4u;

    CAL_mg_s16TestRes1  = CAL_mg_s16TestNom / 4u;
    CAL_mg_s16TestRes2  = CAL_mg_s16TestNom / 4;
    CAL_mg_s16TestRes3  = CAL_mg_s16TestNom / CAL_mg_s16TestDenom;
    CAL_mg_s16TestRes4  = CAL_mg_s16TestNom / CAL_mg_u16TestDenom;

    printf("CAL_mg_s16TestRes1 = %i \n", CAL_mg_s16TestRes1);
    printf("CAL_mg_s16TestRes2 = %i \n", CAL_mg_s16TestRes2);
    printf("CAL_mg_s16TestRes3 = %i \n", CAL_mg_s16TestRes3);
    printf("CAL_mg_s16TestRes4 = %i \n", CAL_mg_s16TestRes4);

    Regards, Holger

  • customer checked with GCC compiler which behaves different

    Yes, it does.  Because on a host GCC system, the type int is 32-bits.  On C2000, int is 16-bits.

    Consider the description I wrote in my previous post.

    The expression ...

    int16_variable / 4u

    ... is evaluated by first converting all the operands to a common type.  In this case, that common type is unsigned 16-bit integer.  Then unsigned 16-bit division is performed.  Since this is unsigned division by 4, it is changed to unsigned right shift by 2.  So, it is the same as if you wrote ...

    (uint16_t) int16_variable >> 2

    In this case, int16_variable contains the value -20.  When changed to 16-bit unsigned, it is the value 0xffec.  0xffec >> 2 is 0x3ffb.  Written in decimal, that is 16379.

    It is correct in general form.  But, on a system where int is 32-bit, some details are different.  Here is how it works on such a system.

    The expression ...

    int16_variable / 4u

    ... is evaluated by first converting all the operands to a common type. In this case, that common type is unsigned 32-bit integer.  Then unsigned 32-bit division is performed.  Since this is unsigned division by 4, it is changed to unsigned right shift by 2.  So, it is the same as if you wrote ...

    (uint32_t) int16_variable >> 2

    In this case, int16_variable contains the value -20.  When changed to 32-bit unsigned, it is the value 0xffffffec.  0xffffffec >> 2 is 0x3ffffffb.  Written in decimal, that is 1073741819.

    Except printf writes -5, and not 1073741819.  Why?  Because before printing that expression out, it is first assigned to a int16_t variable.  Call it int16_result.  When that happens, only the lower 16-bits are kept.  So, int16_result is assigned 0xfffb.  When printf does the %i conversion of a 16-bit wide signed variable that contains 0xfffb, it writes out -5.  

    If this is the behavior you want on C2000, one way to get it is to use a cast to force the division to be performed as 32-bit unsigned.  For instance ...

    CAL_mg_s16TestRes1  = (int32_t) CAL_mg_s16TestNom / 4u;

    Thanks and regards,

    -George