9 Replies Latest reply on Aug 31, 2020 5:15 AM by YuAr_3514996

    PSoC 4 Compiler optimization problem

    YuAr_3514996

      Hi,

       

      I'm using PSoC 4 in a BLE application. The specific device is CY8C4247LQI-BL473.

       

      I have the following piece of code:

       

      int32 passwd;
      uint8 cypher[16];
      
      /*
           some code here, cypher buffer is loaded
      */
      
      passwd= cypher[0] + cypher[1]*0x100 + cypher[2]*0x10000 + cypher[3]*0x1000000;
      
      if(passwd < (int32) 0)
      {
           passwd = passwd * (int32)(-1);
      }
      

       

      I'm facing the following issue: depending on the optimization level I choose, the test at 10th line is always false.

       

      Optimization levels None, Debug and Minimal work fine. But with level High, Speed and Size the "if" command result is always false, even with valid values.

       

      I'm setting the optimization level via "Build -> Build Settings -> Configuration: Release -> ARM GCC 5.4-2016-q2-update -> Optimization -> Optimization Level".

       

      Can someone please help me understand what is going on here? Is there something I'm missing?

       

      Here follows some further details:

       

      Environment:
      PSoC Creator  4.3 (4.3.0.1445)
      Culture: Portuguese (Brazil)
      OS Version: Microsoft Windows NT 10.0.18362.0
      CLR Version: 4.0.30319.42000
      
      Installed CyInstaller Products:
      Peripheral Driver Library 3.0.1
      Peripheral Driver Library 3.1.1
      PSoC Programmer 3.28.7
      PSoC Creator 4.3
      
      Loaded Plugins:
      Name: Toolchain Manager
      Version: 4.3.0.1445
      Company: Cypress Semiconductor
      Description: PSoC Creator Toolchain Manager
      
      Name: ARM GCC Generic
      Version: 4.3.0.1445
      Company: Cypress Semiconductor
      Description: ARM GNU Generic
      
      Name: ARM MDK Generic
      Version: 4.3.0.1445
      Company: Cypress Semiconductor
      Description: ARM MDK Generic
      
      Name: ARM IAR Generic
      Version: 4.3.0.1445
      Company: Cypress Semiconductor
      Description: ARM IAR Generic
      
      Name: DP8051 Keil Generic
      Version: 4.3.0.1445
      Company: Cypress Semiconductor
      Description: DP8051 Keil Generic
      
      
      
      

       

      Thank you very much.

       

      Cheers,

       

      Yuri

        • 1. Re: PSoC 4 Compiler optimization problem
          RakshithM_16

          Hi YuAr_3514996,

           

          I modified your code slightly to test it. I added an LED pin and if the 'if condition' is true, I toggle the LED. Please let me know if there is any issue with the test code.

           

              int32 passwd;  
              uint8 cypher[16];  
          
              cypher[0] = 0xFF;
              cypher[1] = 0xFF;
              cypher[2] = 0xFF;
              cypher[3] = 0xFF;
              
              passwd= cypher[0] + cypher[1]*0x100 + cypher[2]*0x10000 + cypher[3]*0x1000000;  
              
              for(;;)
              {
                  /* Place your application code here. */
                  if(passwd < (int32) 0)  
                  {  
                      LED_Write(1);
                      CyDelay(500);
                      LED_Write(0);
                      CyDelay(500);
                      LED_Write(1);
                      CyDelay(500);
                      LED_Write(0);
                      CyDelay(500);
                  }  
                  else
                  {
                      LED_Write(1);
                  }
              }
          

           

          I programmed this code using all optimization levels and irrespective of the optimization level the LED was toggling. Could it be possible that the issue is with other code in your project? If I am missing something, please let me know.

           

          Thanks and Regards,

          Rakshith M B

          • 2. Re: PSoC 4 Compiler optimization problem
            MoTa_728816

            Hi,

             

            I'm just curious, but I wonder if you add volatile to passwd, will it help?

             

            > int32 passwd

            < volatile int32 passwd

             

            moto

            • 3. Re: PSoC 4 Compiler optimization problem
              YuAr_3514996

              Hi! Declaring "int32 passwd" as volatile works fine. Thank you.

              • 4. Re: PSoC 4 Compiler optimization problem
                YuAr_3514996

                Hi RakshithM_16! Thank you for the help.

                 

                The piece of code I've posted it's part of a pretty straight forward function. It just generates a random password based on some input parameters.

                 

                I just made some testing and figured out that if I load "cypher" array manually as you did the code works fine for any optimization level.

                 

                In my original code, "cypher" array is loaded by an AES encrpytion function. Depending on the optimization level, even with the encryption value loaded into "cypher[3:0]" being negative the test "passwd < (int32) 0" returns always FALSE. The odd thing here is if I get the value returned by the AES function and recompile the code loading it manually into "cypher", the code then works.

                 

                Here follows the actual code I'm running:

                 

                uint32 bleGeneratePasskey(uint8 random, uint8 *addr1, uint8 *addr2)
                {
                    uint8 key[16];
                    uint8 plain[16];
                    uint8 cypher[16];
                    int32 passwd;
                   
                    /* init KEY array with constant values and "random" var at one position */
                   
                    /* init PLAIN array with both "addr1[6]" and "addr2[6]" content plus 4 constants */
                   
                    CyBle_AesEncrypt(plain, key, cypher);
                
                    passwd = cypher[0] + cypher[1]*0x100 + cypher[2]*0x10000 + cypher[3]*0x1000000;
                   
                    #ifdef DEBUG_PRINT
                        char temp[128];
                        uint8 i;
                       
                        sprintf(temp, "-> P: ");
                        for(i = 0; i < 16; i++)
                            sprintf(temp, "%s%02X ", temp, plain[i]);
                        debugPrint(temp);
                       
                        sprintf(temp, "-> K: ");
                        for(i = 0; i < 16; i++)
                            sprintf(temp, "%s%02X ", temp, key[i]);
                        debugPrint(temp);
                       
                        sprintf(temp, "-> C: ");
                        for(i = 0; i < 16; i++)
                            sprintf(temp, "%s%02X ", temp, cypher[i]);
                        debugPrint(temp);
                       
                        sprintf(temp, "-> 1: %ld (0x%08lX)", passwd, passwd);
                        debugPrint(temp);
                       
                    #endif
                       
                    if(passwd < (int32) 0)
                    {
                        passwd = passwd * (int32)(-1);
                       
                        #ifdef DEBUG_PRINT
                            sprintf(temp, "******** < 0 ********\n");
                            debugPrint(temp);
                        #endif
                    }
                       
                    #ifdef DEBUG_PRINT
                        sprintf(temp, "-> 2: %ld (0x%08lX)", passwd, passwd);
                        debugPrint(temp);
                    #endif
                   
                    if(passwd > (int32)999999)
                        passwd &= 0x7FFFF;
                       
                    #ifdef DEBUG_PRINT
                        sprintf(temp, "-> 3: %ld (0x%08lX)", passwd, passwd);
                        debugPrint(temp);
                    #endif
                   
                    return ((uint32) passwd);   
                }
                

                 

                 

                And here some outputs I got from my debug terminal:

                 

                Optimization level: SIZE, loading CYPHER from AES

                [07388] -> C: 88 59 94 A2 FA 86 56 A4 5C 9C A9 BF F5 72 FA D2 
                [07396] -> 1: -1567336056 (0xA2945988)
                [07400] -> 2: -1567336056 (0xA2945988)
                [07404] -> 3: -1567336056 (0xA2945988)
                [07408] -> PASSKEY: 2727631240
                

                 

                Optimization level: SIZE, loading CYPHER manually

                [09731] -> C: 88 59 94 A2 FA 86 56 A4 5C 9C A9 BF F5 72 FA D2 
                [09739] -> 1: -1567336056 (0xA2945988)
                [09743] ******** < 0 ********
                [09746] -> 2: 1567336056 (0x5D6BA678)
                [09750] -> 3: 239224 (0x0003A678)
                [09753] -> PASSKEY: 239224
                

                       

                Optimization level: SIZE, loading CYPHER from AES

                [36946] -> C: D3 F1 4F FB 73 AF E9 3D CA B6 C2 92 FA 06 97 2D 
                [36954] -> 1: -78646829 (0xFB4FF1D3)
                [36958] -> 2: -78646829 (0xFB4FF1D3)
                [36962] -> 3: -78646829 (0xFB4FF1D3)
                [36966] -> PASSKEY: 4216320467
                

                 

                Optimization level: SIZE, loading CYPHER manually

                [03803] -> C: D3 F1 4F FB 73 AF E9 3D CA B6 C2 92 FA 06 97 2D 
                [03811] -> 1: -78646829 (0xFB4FF1D3)
                [03815] ******** < 0 ********
                [03818] -> 2: 78646829 (0x04B00E2D)
                [03822] -> 3: 3629 (0x00000E2D)
                [03825] -> PASSKEY: 3629
                

                 

                Optimization level: MINIMAL, loading CYPHER from AES

                [08129] -> C: 84 89 FF BA A0 1F 2A 43 90 0A 28 1F AB D7 A3 85 
                [08137] -> 1: -1157658236 (0xBAFF8984)
                [08141] ******** < 0 ********
                [08144] -> 2: 1157658236 (0x4500767C)
                [08148] -> 3: 30332 (0x0000767C)
                [08151] -> PASSKEY: 30332
                

                 

                Optimization level: MINIMAL, loading CYPHER manually

                [06334] -> C: 84 89 FF BA A0 1F 2A 43 90 0A 28 1F AB D7 A3 85 
                [06342] -> 1: -1157658236 (0xBAFF8984)
                [06346] ******** < 0 ********
                [06349] -> 2: 1157658236 (0x4500767C)
                [06353] -> 3: 30332 (0x0000767C)
                [06356] -> PASSKEY: 30332
                

                 

                 

                I could workaround this in other ways, like declaring "passwd" as volatile as MoTa_728816 suggested. But I'd like to know why this is happening.

                 

                Cheers,

                 

                Yuri

                • 5. Re: PSoC 4 Compiler optimization problem
                  RakshithM_16

                  Hi Yuri,

                   

                  Would it be okay for you to share the entire project or at least a minimalistic version of your project in which you are facing the issue so that we can test it out?

                  Also, can you try changing the datatype of cypher from uint8 to int16 and let me know if that makes any difference?

                   

                  Thanks and Regards,

                  Rakshith M B

                  • 6. Re: PSoC 4 Compiler optimization problem
                    YuAr_3514996

                    Hi Rakshith,

                     

                    I've made a minimal project with the problem still going on. I removed all my source code and all componentes not needed to show the problem.

                     

                    It just initializes the BLE stack to use the encryption function and calls my password function once in a second.

                     

                    With optimization enabled, the above mentioned test returns always false. Without optimizations it works well.

                     

                    By the way, changing "uint8" arrays to "uint16" was of no success.

                     

                    Cheers,

                     

                    Yuri

                    • 7. Re: PSoC 4 Compiler optimization problem
                      RakshithM_16

                      Hi Yuri,

                       

                      We tried debugging and placing a breakpoint to check the result of the if condition and with high optimization the if statement was skipped. So, we believe the compiler is optimizing out the if condition.

                       

                      One thought was that, because the cypher is an unsigned int and the passwd is a sum of unsigned int the compiler might be assuming that passwd will not be less than 0. So, we tried declaring cypher as int8 and typecasting it as shown and this worked. We had to typecast it while printing too.

                      CyBle_AesEncrypt(plain, key, (uint8*) cypher);  
                      

                       

                      Can you please let me know if this works?

                      I think using volatile as suggested by MoTa_728816-san is a better solution in this case.

                       

                      Thanks and Regards,

                      Rakshith M B

                      • 8. Re: PSoC 4 Compiler optimization problem
                        NoTa_4591161

                        Hi Yuri,

                         

                        I don't know if it applies to your program, but I'll talk about optimization in general.

                         

                        An ANSI C compliant compiler compiles with optimization options to eliminate unnecessary code and data. The compiler deletes all variables except those related to I/O. The input and output variables here are global variables, function arguments and return value variables. The compiler considers removing local variables by optimization. To prevent this, the programmer must explicitly declare "This variable is necessary". It consists in using global variables and arguments. Even local variables can be survived from optimization if they have a relationship with them. Conversely, if you create a function with only local variables, a function with no contents will be created.

                         

                        In addition to this, if optimization progresses, variables located in memory will be replaced by registers inside the CPU, and it will become impossible to access peripheral registers.  "volatile" is declared to mean that the specified address is always accessed.

                         

                        You can get more detailed information by searching for "gcc optimization option" on the Web.

                         

                        I hope this information is useful for you.

                         

                        Best Regards,

                        Kenshow

                        • 9. Re: PSoC 4 Compiler optimization problem
                          YuAr_3514996

                          Hi,

                           

                          Thank you MoTa_728816 and RakshithM_16 for the help.

                           

                          I knew basically how optimization works in microcontrollers. Very often when using a debugger (mostly in other architechtures), if I place a breakpoint in some lines it just doesn't stop because of the optimization (usually when the variable being loaded in that line is not used anymore inside the same function). To workaround that, I just declare the related variable as "volatile" (telling the compiler "compile this line, no matter what"). This works fine for my debugging purposes.

                           

                          In this case, I didn't think it would be a problem because after the variable "passwd" being loaded first time, it is tested, modified and returned as function value. I thought this process would be considered "important enough" by the compiler.

                           

                          Anyway, I'll stick with the volatile solution (it works fine for me). I'd like to understand what happens under the hood of gcc, but to really clear this out I'd had to go through compiler's internals and that should not be my focus by now.

                           

                          Thank you guys!

                           

                          Cheers,

                           

                          Yuri