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.

Void pointer optimization problem

Genius 5910 points

 The compile I'm using: V6.4.6 With Optimization 2.

This code is from Intraspin Lab13b:

The Call:

  obj->pwmHandle[0] = PWM_init((void *)PWM_ePWM1_BASE_ADDR,sizeof(PWM_Obj));

 The function:

PWM_Handle PWM_init(void *pMemory,const size_t numBytes)
{
  PWM_Handle pwmHandle;


  if(numBytes < sizeof(PWM_Obj))
    return((PWM_Handle)NULL);


  // assign the handle
  pwmHandle = (PWM_Handle)pMemory;

  return(pwmHandle);
} // end of PWM_init() function

The disassembler:

        PWM_init():
3e87c1:   1EA6        MOVL         @XAR6, ACC
 332        return((PWM_Handle)NULL);
3e87c2:   023A        MOVB         ACC, #58
3e87c3:   0FA6        CMPL         ACC, @XAR6
3e87c4:   56C90003    BF           C$L1, LOS
3e87c6:   D400        MOVB         XAR4, #0x0
        C$L1:
3e87c7:   0006        LRETR  

The disassembler with Optimization  off:

        PWM_init():
3e81ba:   FE06        ADDB         SP, #6
3e81bb:   1E44        MOVL         *-SP[4], ACC
3e81bc:   A842        MOVL         *-SP[2], XAR4
 331      if(numBytes < sizeof(PWM_Obj))
3e81bd:   023A        MOVB         ACC, #58
3e81be:   0F44        CMPL         ACC, *-SP[4]
3e81bf:   56C90004    BF           C$L1, LOS
 332        return((PWM_Handle)NULL);
3e81c1:   D400        MOVB         XAR4, #0x0
3e81c2:   6F03        SB           C$L2, UNC
 336      pwmHandle = (PWM_Handle)pMemory;
        C$L1:
3e81c3:   0642        MOVL         ACC, *-SP[2]
3e81c4:   1E46        MOVL         *-SP[6], ACC
 339    } // end of PWM_init() function
        C$L2:
3e81c5:   FE86        SUBB         SP, #6
3e81c6:   0006        LRETR  

  And works correctly.

The output of the compiler optimization is not constant if I play with the order of the code the result will change.

So can you please tell me how to solve this problem.  Or better how to disable void pointer optimization.

 Thanks

  • Which optimizations are you using?

    Out of context, the optimized version doesn't look obviously wrong. PWM_ePWM1_BASE_ADDR is stored in XAR4, and XAR4 is only modified if numBytes >= sizeof(PWM_Obj). Can you post the disassembly of the function call?

    Thanks,
  • Adam Haun said:
    Which optimizations are you using?

    Out of context, the optimized version doesn't look obviously wrong. PWM_ePWM1_BASE_ADDR is stored in XAR4, and XAR4 is only modified if numBytes >= sizeof(PWM_Obj). Can you post the disassembly of the function call?

    Thanks,

     I'm using optimalization 2:  I don't see where where XAR4 is filed with PWM_ePWM1_BASE_ADDR. I "solved" it by making everything volatile.

  • I'll ask the compiler team about this.
  • I agree with Adam's analysis.  The disassembly for the optimized version is correct.  I suspect you overlook the initial conditions.  When PWM_init starts, the argument pMemory is in XAR4 and the argument numBytes is in the lower half of ACC.  The function result is returned in XAR4.  Thus, if numBytes is >= sizeof(PWM_Obj), then nothing needs to be done to assign pMemory to pwmHandle, and then return it.

    Thanks and regards,

    -George

  • George and Adam,

    Thanks for this insightful answer. I understand now.

     Thanks!

     

  • Today again I have a problem with different results with optimization off and 2.

     I think the problem is I2Handle->I2CFFTX.bit.TXFFST  is only read once and not at every time. SO the i2c data is overwriten in the hardware buffer.

     See this assembly code:

    104            for(i=0; i<(No_of_databytes ) ;i++){
    3e8ce0:   5300        CMPB         AH, #0x0
    3e8ce1:   EC2A        SBF          C$L7, EQ
    3e8ce2:   D020        MOVB         XAR0, #0x20    /// <--- Register offset Offset  XAR4 is the base register of I2C
    3e8ce3:   CC941F00    AND          AL, *+XAR4[AR0], #0x1f00  // Register offset is copied to AL
    3e8ce5:   88A8        MOVZ         AR6, @AH  
    3e8ce6:   D500        MOVB         XAR5, #0x0
    3e8ce7:   3B01        SETC         SXM
    3e8ce8:   FFC7        LSR          AL, 8
    3e8ce9:   2FA9        MOV          PH, @AL        /// Copy Memory location value to PH  (value in AL is( 0x7820 => I2CFFTX )
    3e8cea:   DE81        SUBB         XAR6, #1
            C$L4:                                                             /// Loop restart point
    3e8ceb:   92AA        MOV          AL, @PH       // Copy memory location of result of      MOV          PH, @AL  ???
    105             while ((I2Handle->I2CFFTX.bit.TXFFST ==  4) && (I2Handle->I2CSTR.bit.ARDY == 0));    // TXFifo is full wait
    3e8cec:   5204        CMPB         AL, #0x4    // Bit check.  But checks the result of line 3e8ce9 and not at pointer location.
    3e8ced:   ED03        SBF          C$L5, NEQ
    3e8cee:   42AB        TBIT         @PL, #0x2
    3e8cef:   EFFC        SBF          C$L4, NTC
    106             if ( I2Handle->I2CSTR.bit.NACK == 1)    // Nack error
            C$L5:
    3e8cf0:   41AB        TBIT         @PL, #0x1
    3e8cf1:   EF11        SBF          C$L6, NTC
    108                 I2Handle->I2CFFTX.bit.TXFFRST = 0;     // Empty fifo.
    3e8cf2:   C5A4        MOVL         XAR7, @XAR4
    109                 I2Handle->I2CMDR.bit.STP = 1; // send STP to end transfer
    3e8cf3:   C4A4        MOVL         XAR6, @XAR4
    112                 I2Handle->I2CFFTX.bit.TXFFRST = 1;     // Empty fifo.
    3e8cf4:   83A4        MOVL         XAR5, @XAR4
    110                 I2Handle->I2CSTR.bit.NACK = 1;    // clear NACK bit
    3e8cf5:   1AD40006    OR           *+XAR4[2], #0x0006
    113                 return I2C_NACK_ERROR;
    3e8cf7:   9A02        MOVB         AL, #0x2
    108                 I2Handle->I2CFFTX.bit.TXFFRST = 0;     // Empty fifo.
    3e8cf8:   DF20        ADDB         XAR7, #32
    109                 I2Handle->I2CMDR.bit.STP = 1; // send STP to end transfer
    3e8cf9:   DE09        ADDB         XAR6, #9
    112                 I2Handle->I2CFFTX.bit.TXFFRST = 1;     // Empty fifo.
    3e8cfa:   DD20        ADDB         XAR5, #32
    108                 I2Handle->I2CFFTX.bit.TXFFRST = 0;     // Empty fifo.
    3e8cfb:   18C7DFFF    AND          *+XAR7[0], #0xdfff
    109                 I2Handle->I2CMDR.bit.STP = 1; // send STP to end transfer
    3e8cfd:   1AC60800    OR           *+XAR6[0], #0x0800
    112                 I2Handle->I2CFFTX.bit.TXFFRST = 1;     // Empty fifo.
    3e8cff:   1AC52000    OR           *+XAR5[0], #0x2000
    113                 return I2C_NACK_ERROR;
    3e8d01:   6F0B        SB           C$L8, UNC
    115             I2Handle->I2CDXR = Write_Array[i]; //Next data byte
            C$L6:
    3e8d02:   ABA9        MOVL         @ACC, XT
    3e8d03:   81A5        ADD          ACC, @AR5
    104            for(i=0; i<(No_of_databytes ) ;i++){
    3e8d04:   1EA7        MOVL         @XAR7, ACC
    115             I2Handle->I2CDXR = Write_Array[i]; //Next data byte
    3e8d05:   D008        MOVB         XAR0, #0x8
    104            for(i=0; i<(No_of_databytes ) ;i++){
    3e8d06:   DD01        ADDB         XAR5, #1
    115             I2Handle->I2CDXR = Write_Array[i]; //Next data byte
    3e8d07:   92C7        MOV          AL, *+XAR7[0]
    3e8d08:   9694        MOV          *+XAR4[AR0], AL
    104            for(i=0; i<(No_of_databytes ) ;i++){
    3e8d09:   000EFFE2    BANZ         65506,AR6--

    I spend a really lot of time tracking such problems and it is a bit frustration. So I really hope you can tell me what is or what  i'm doing  wrong? I think there maybe an issue with the compiler. See Bold. I hope I made it clear.

     Thanks.

  • evs said:
     I think the problem is I2Handle->I2CFFTX.bit.TXFFST  is only read once and not at every time.

    Is this field marked volatile?

    Thanks and regards,

    -George

  • I thought I understand it. But unfortunately don't.

     I made everything volatile in i2c.h

     But I still got different results with optimization off and 2, It doesn't work anymore with optimization 2 . Any more suggestions?

     

    Can you help me explain this piece of code:

            C$L12:
    3e87cd:   761F01E4    MOVW         DP, #0x1e4   // What is purpose of this instruction for this loop
    144            while(I2caRegs.I2CSTR.bit.XRDY == 0){};
    3e87cf:   4402        TBIT         @0x2, #0x4   // So where is bit 4 test against? address 2? 
    3e87d0:   EFFD        SBF          C$L12, NTC

  • The register structure is declared volatile at the bottom of the header file, so all of its members are volatile too:

    extern volatile struct I2C_REGS I2caRegs;

    What do you mean by "it doesn't work"? What exactly is the failing behavior? Going from optimizations off to level 2 is expected to change the assembly no matter what.
  • I did not noted that volatile and that is a part of my problem. Thanks!
    The problem is I try to get some hardware running. I got it working at runlevel 0 and at runlevel 2 it doesn't. In this case I2C read. So Please tell me how to debug that. Because I got 3 black boxes the compiler and the controller and this case also an external IC.
    I think it is still strange how non-volatile variables are Handled by the compiler and how it is impossible to verify that the compiler handled it as intended.
    So please tell me how I can solve this?

    Thanks.
  • evs said:
    Can you help me explain this piece of code:

    Not really.  Lots of useful context is missing.  This isn't the best way to understand compiler generated assembly.  Instead, use the build option --src_interlist.  This causes the compiler to not delete the auto-generated assembly file and insert useful comments in it.  From my_source.c, the file my_source.asm is created.  The screen shot below shows how to set the option.

    I can partially explain this one instruction.

    evs said:
    MOVW   DP, #0x1e4   // What is purpose of this instruction for this loop

    A global variable is accessed with a sequence similar to this ...

            MOVW      DP,#_global
            MOV       AL,@_global

    The upper bits of the address of the global variable come from the DP register (DP stands for data page).  The lower bits are encoded in the instruction.  Thus, from time to time, the DP register is loaded with the upper address bits of a symbol.  This illustrates one disadvantage of looking at disassembly.  It cannot show you the name of the global variable the compiler is accessing.

    Thanks and regards,

    -George