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.

Wrong variable placement by compiler CCS 4.1.2.027

Other Parts Discussed in Thread: MSP430F248

I have met strange behaviour of CCS C compiler for my MSP430F248.

It's use the same registers inside C-function as local variable or input variable has. I can see it in several functions.

Some times i see the loop variable placed in the same register as input parameter and code run in a wrong way.

What's going on?

This is a part of C-source code

#define TO_HIGH(b) (b >> 3)
#define TO_LOW(b,p) ( ( (b<<13) | (p<<8) ) &0x1F00 )

#define clear_CLE   P5OUT &= ~BIT5
#define set_CLE     P5OUT |= BIT5
#define clear_nCE   P5OUT &= ~BIT4
#define set_nCE     P5OUT |= BIT4
#define clear_nWE   P6OUT &= ~BIT2
#define set_nWE     P6OUT |= BIT2

#define clear_ALE   P6OUT &= ~BIT1
#define set_ALE     P6OUT |= BIT1
#define clear_nRE   P5OUT &= ~BIT3
#define set_nRE     P5OUT |= BIT3
#define clear_nWP   P6OUT &= ~BIT3
#define set_nWP     P6OUT |= BIT3

#define switchOUT   P4DIR=0xFF
#define switchIN    { P4DIR=0; P4OUT=0xFF; }

...

#define setIOx(s)   P4OUT = (s)
#define getIOx(s)   (s) = P4IN

...

#define NAND_LatchCmd(cmd) \
{ set_CLE; clear_nWE; setIOx(cmd); set_nWE; clear_CLE; }

void NAND_LatchBlockAddr( U16 hi_addr, U16 lo_addr )
{
  set_ALE;
  clear_nWE;
  setIOx( (lo_addr>>8) & 0xFF );
  set_nWE;
  clear_nWE;
  setIOx( hi_addr & 0xFF );
  set_nWE;
  clear_nWE;
  setIOx( (hi_addr>>8) & 0x1 );
  set_nWE;
  clear_ALE;
}

U8 NAND_StatusRead( void )
{
  U8 status;
  switchOUT;
  NAND_LatchCmd( NAND_CMDSTATUS );
  clear_nRE;
  switchIN;
  getIOx( status );
  set_nRE;
  return status;
}

U8 NAND_BlockErase( U16 block, U16 page )
{
  volatile U8 status;
  set_nWP;
  switchOUT;
 
  NAND_LatchCmd( NAND_ERASESET );
  NAND_LatchBlockAddr( TO_HIGH(block), TO_LOW( block, page ) );
  NAND_LatchCmd( NAND_ERASEDO );

  do
  {
    status = NAND_StatusRead( );
  } while( (status & BIT6) == 0 );
 
  clear_nWP;

  if( (status & BIT0) == 0)
    return 0;  //successful erase
  else
    return 1;                    //error
}

------------------- asm generated code

DECD.W  SP
BIS.B   #8,&Port_5_6_P6OUT
MOV.B   #-1,&Port_3_4_P4DIR
BIS.B   #0x0020,&Port_5_6_P5OUT
BIC.B   #4,&Port_5_6_P6OUT
MOV.B   #0x0060,&Port_3_4_P4OUT
BIS.B   #4,&Port_5_6_P6OUT
AND.B   #0x00df,&Port_5_6_P5OUT
CALL    #I_LSR_3
AND.W   #0x001f,R13
MOV.B   R13,R13                <---------------------------- it's seems very strange, because there's input var in R13, so input var is changed.

SWPB    R13

CALL    #NAND_LatchBlockAddr
BIS.B   #0x0020,&Port_5_6_P5OUT
BIC.B   #4,&Port_5_6_P6OUT
MOV.B   #0x00d0,&Port_3_4_P4OUT
BIS.B   #4,&Port_5_6_P6OUT
AND.B   #0x00df,&Port_5_6_P5OUT

        C$DW$L$NAND_BlockErase$2$B, C$L6:

CALL    #NAND_StatusRead
MOV.B   R12,0x0000(SP)
BIT.B   #0x0040,0x0000(SP)
JEQ     (C$L6)

        C$DW$L$NAND_BlockErase$2$E:

BIC.B   #8,&Port_5_6_P6OUT
MOV.W   #1,R12
AND.B   @SP,R12
INCD.W  SP
RET

  • Can you specify more clearly how it is not running correctly?  (i.e. what are you seeing that is different to what you expected?)

     

    Tim Karaldin said:
    it's seems very strange, because there's input var in R13, so input var is changed

    Yes there is input in R13 but "page" is only used as an input to NAND_LatchBlockAddr(); as it is not required later the compiler is free to manipulate the value into the argument for the function call

     

    In the command you have highlighted note the ".B" part of the command - this is effectively masking off the most significant byte (similar to "var &= 0x00FF" ).  It is a valid operation and more efficient than using the AND -masking.  It looks like the compiler has made some optimisations: rather than shifting "page" up by 8bits and then performing the AND 0x1F00 operation it instead performs an AND.W #0x001f on the lower byte, the SWPB operation then effectively shifts the result up 8bits.  What is strange to me is that I can't see where "block" is incorporated in the compiled TO_LOW macro.  Is this all the disassembly?  Perhaps I am missing something...

     

  • Chris_m thanks for your reply,

    You are right, in this source's part everything is ok ( I didn't understand that mov.b clear high byte), execept mistake in logic. ( left shift by 13 is outside of 0x1F00 mask, so compiler trought out the "OR" operation ).

    Unfortunatelly i have changed code with wrong variable placement by changing "inline" functions to "define" to solve problems, so now i cann't reproduce it. I'll try to get wrong behaviour again but now with define every thing is ok.

     

     

**Attention** This is a public forum