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.

C6747/CCS 3.3 - Problem with Unsigned Int Dereference and Bitmask Operation

We've run into what looks like a compiler issue dealing with a pointer dereference and a bitmask operation on the C6747.

The problem concerns dereferencing an unsigned int pointer that we use to access 32 bit words in memory.  The problem is that if you dereference the pointer and apply a bit mask, the mask is not properly applied.  However, if you include what should be superfluous parentheses in the C statement, the mask is applied properly.  The statement that illustrates the problem is:

unsigned int  *DataOut32;

*DataOut32 = *DataOut32 & 0x001FFFFF;

For example, if *DataOut32 has a value of 0x08400003, the result of the above operation came back as 0x00400003 correctly resetting bit 27 but leaving bit 22 set.

If however, you use the statement:

*DataOut32 = ( (*DataOut32) & 0x001FFFFF );

Then, with *DataOut32 initially equal to 0x08400003, the mask is correctly applied to give a result of 0x00000003.  According to K&R, the precedence of operators should be such that the right side dereference of *DataOut32 occurs first, followed by the bitwise & for the mask followed by the assignment =.  If the processor is truly a 32 bit machine, then this implies that CCS 3.3 does not correctly apply the C rules of operator precedence.

Yes, there is a relatively easy fix for the issue but the question remains: "How extensive is the problem in the code compilation?".  Is the problem only related to bitwise operations or is it necessary to explicitly enforce operator precedence via paranthesis with other variable types?

Mike

 

 

 

  • Hi Mike,

    I could not reproduce the issue. Can you send the exact lines of code you are using to set the value of the pointer and to set the value that the pointer is pointing to? A test case?

    Please see my results below:

     

     

     

     

  • Hi Mariana,

    The following is the subroutine in which we encountered the problem.

    I better give you some background because the code isn't pretty and you'll wonder what in the world we are doing.  Back in July we ran into a problem doing bit shift and masking operations on unsigned long data.  The problem back then was that the "high" bits of the unsigned long did not shift down into the lower 32 bits of the variable.  We reported the problem through our TI sales rep and we were told that the issue was a bug.  To get around the problem we use a "pointer to unsigned int" to reference the high and low bytes of the unsigned long.  In the following code, that variable is "unsigned int *DataOut32".

    I don't have the exact argument values written down, but when we discovered the problem, we were calling the following function with:

    PackedStr[] = { 0x01, 0x00, 0x00, 0x?? 0x??, 0x??, 0x?? 0x??, 0x??, 0x?? 0x??, 0x??, 0x?? 0x??, 0x??  }      There was data in the upper 12 bytes of the PackedStr array but I don't remember what it was.  My bad.

    Length = 3

    UnpackedLong is the output.

     

    void UnpackData64( unsigned char *PackedStr, unsigned long *UnpackedLong, int Length )
    {
      // Local Variable Declarations
      unsigned int  *DataOut32;
     
      //  Point to the lower 32 bits of the value
      DataOut32     = (unsigned int  *)UnpackedLong;
     
      //  Load the lower 32 bits of the value
      *DataOut32 = PackedStr[0];
      *DataOut32 = *DataOut32 | ( (unsigned int)PackedStr[1] << 7 );
      *DataOut32 = *DataOut32 | ( (unsigned int)PackedStr[2] << 14 );
      *DataOut32 = *DataOut32 | ( (unsigned int)PackedStr[3] << 21 );
      *DataOut32 = *DataOut32 | ( (unsigned int)( PackedStr[4] & 0x0F ) << 28 );
     
      //  Check on the length of the input
      if ( 5 < Length )
      {
        //  Increment the pointer to the upper 32 bits of the value
        *DataOut32++;
     
        //  Load the upper 32 bits of the value
        *DataOut32 = ( (unsigned int)( PackedStr[4] >> 4 ) & 0x07 );
        *DataOut32 = *DataOut32 | ( (unsigned int)PackedStr[5] << 3 );
        *DataOut32 = *DataOut32 | ( (unsigned int)PackedStr[6] << 10 );
        *DataOut32 = *DataOut32 | ( (unsigned int)PackedStr[7] << 17 );
        *DataOut32 = *DataOut32 | ( (unsigned int)PackedStr[8] << 24 );
        *DataOut32 = *DataOut32 | ( (unsigned int)( PackedStr[9] & 0x01 ) << 31 );
      }
      //  The input has 5 bytes of data or less
      else
      {
        //  Switch to the appropriate mask
        switch( Length )
        {
        //  Don't retain any bytes
        case 0:
          *DataOut32 = *DataOut32 & 0x00000000;
          break;
       
        //  Retain the first byte
        case 1:
          *DataOut32 = *DataOut32 & 0x0000007F;
          break;
         
        //  Retain the first two bytes
        case 2:
          *DataOut32 = *DataOut32 & 0x00003FFF;
          break;
         
        //  Retain the first three bytes
        case 3:
          *DataOut32 = *DataOut32 & 0x001FFFFF;
          break;
        }
       
        //  Increment the pointer to the upper 32 bits of the value
        *DataOut32++;
     
        //  Zero out the upper bytes of the return
        *DataOut32  = 0;
      }
     
      return;
    }

     

    The code went into the switch statement - case 3 which is where we had the problem. 

    Mike

     

  • HI Mike,

    I need you to send me a working C file where you issue occurs so I can analyze it. I'm not able to reproduce it with the information you are giving me.

    Please also make sure that you have the latest CGT.

  • Hi Marianna,

    What do you mean by CGT?

    I don't believe that we can send you our executable code.  We could probably demonstrate it to someone in our Dallas office if that would help.

    Mike

  • Hi Mike,

    By CGT I mean code generation tools. Please see:

    http://wiki.davincidsp.com/index.php/Compiler_Installation_and_Selection

    The latest CGT have the most updated bug correction. So just updating it might solve the problem if we a lucky.

    Please understand that all I want to do is help. I need to confirm that there is a bug. So far, I did not find any bugs to submit to be corrected. What you claimed that did not work, worked for me. Everything works fine with the information that you gave. Usually this happens when there is something in your particular application that is influencing the result. It might not even be a precedence problem. I put the code you sent me in my program (had to invent UnpackedLong and PackedStr) and the result was correct. I have seem a lot of cases that it looked like a bug and it was actually not, or the symptom was caused by bug elsewhere. Sometimes is a stack problem, heap problem, broken pointer, etc. So I need you to empower me to find the issue and help you.

    You do not need to give me all your code. But just the section that is presenting the problem. If you could send me the UnpackedLong and PackedStr variables it would help (the type -int? long? - and the values). If I have this information and can confirm that it works, it can be something very particular to your application. I can reproduce the issue with just a piece a code, I will submit the bug right away.

    If you prefer not to give more information, then let's see if someone in the community can help you. Or you can send the code to your TI sales rep.

     

  • Hi Mariana,

    Please don't misunderstand, both myself and the guys that I work with greatly appreciate the help that you and the TI Support Team have given us and are giving us.  You've been great over the past few months! 

    I understand that you can't reproduce what we saw yesterday.  The configuration of software and hardware was fairly complicated, involving multiple processors, etc.  Let me see what further information I can get on the problem to pass on to you.

    If you would like to exchange information offline, please e-mail me directly to let me know.

    Thanks again for your help.

    Mike 

  • Hi Mariana,

    We went back this afternoon and attempted to recreate the problem by returning the code to what it was yesterday afternoon.  We were not able to recreate the problem!   We did not take a backup of the code at the time because we were more concerned about debugging our own stuff.  Our bad.  We were adding and deleting LOG_printf statements throughout the afternoon to understand our own bugs.

    Performing a code comparison of a previous backup of the source with what we currently have, the one change that may have occurred since yesterday is that we increased the delay after enabling the UART transmitter prior to disabling it.  We enable and disable with every message to trigger the DMA transfer into the UART's THR.  The delay is implemented by a call to TSK_sleep.  We increased the minimum sleep from 3 clock ticks to 10.  Other than that, I don't see anything that would significantly change the executable image.  The thing is that the call to TSK_sleep occurs in the same context AFTER the call to the UnpackData64 function where we had the problem - they are in the same context.

    Your comment about a stack problem is ringing alarm bells with me because I simply don't know where we are with respect to the stack.  I've pulled a copy of "spra640a" and will try to get information on our stack usage from the system.  We are not performing any dynamic allocation so that argues against it being a heap problem.

    At this point, we are as stymied about what we saw yesterday as you were this morning.   And to reiterate my earlier comment, we do appreciate the tech support that you are giving us.

    Thanks again,

    Mike

  • The issue you saw was probably a symptom from an issue elsewhere that got corrected by chance. I have some suggestions:

    1) One of the things that come to my mind is if you are disabling the UART transmitter by writing to the registers. If you are you could wait until to make sure that the register was written. It takes much more than a cycle to write to a register sometimes. So the best practice is to do something like this:

    register = value;

    while(register != value);

    This way you only keep going if the register has the correct value and prevent problems with inconsistent access to the hardware.

    2) The document you mentioned is a good one to debug your stack. Make sure that you increase the system stack and the tsk stack. Each TSK has it's own stack. The system stack is used by all the other functions (interrupts, swis, etc).

    3) Make sure that you do not have a local variable (specially pointer variables) that should actually be a global (accessed elsewhere).

     

  • Hi Mariana,

    1) Thanks for the tip about watching the register.  It might be a bit more complicated in our application because we are using a DMA transfer to transmit through the UART.

    2) After going through the Programming and Debugging Tips for DSP/BIOS document, we ran the application and the stack sizes are:

         Kernel Stack Size: 0x800   Peak 0x198

        Task Stack Size: 0x400   Peak 0x15C

    There is only one task outside of the ISR's so it doesn't look like we are having stack issues.  At least not in the run scenario that we tested today.

    3) Can you expand your comments on the effect that you are referring to with relation to local pointers that should be global?  In both the task and the ISR's, the code uses a mixture of globally defined pointers to system level data structures and locally defined pointers in functions that manipulate values in those data structures.  The global pointers are loaded in main() and then used by the task and ISR's to select the data structure to manipulate depending on the state of the system.  The local pointers are assigned to elements of the global structures upon entry to the relevant functions.

    You may be onto something in this line of thought.  Would putting the parentheses around the *DataOut32 rvalue force the value to be calculated and placed on the local stack?

    I'm willing to assume that the bitmask operation is parsed correctly by the compiler.  If that is the case, then something had to be overwriting the lvalue of *DataOut32 during the assignment operation.  But that concerns and confuses me because in our current configuration, the only code that could preempt the function in which we had the problem is the CLK_F_isr function.   Can preemptions take place part way through a register write? 

    In the code that we were running the operating scenario was:  1) a message arrives at the UART and the DMA controller raises an interrupt after transferring each byte  2) the ISR processing that event posts a message to a mailbox when the complete message has arrived,  3) the ISR completes, 4) the task wakes up in response to the mailbox message and parses the message received, 5) the task transmits a response.  No new messages are allowed on the link until after the first message has been processed so it is essentially a serial operation.  The only parallelism is the CLK_F_isr function in the background running as HWI_INT15.  As a HWI it can preempt the task but the CLK_F_isr code is independent of our application code.

    It is to all intents a serial operation but we had to introduce the task because it appeared that we were getting timing issues relating to the DMA operations receiving and transmitting the messages in the same context/ISR.  It seemed that we had to release the ISR context before the UART/EDMA transmit operation would work reliably.  Once we made that change, the Tx operation would always start correctly.  By increasing the length of time that the UART transmitter was enabled, we ensured that the transmit completed successfully.

    Thanks again for your suggestions and help.

    Mike