Switch statement goes wrong unless optimisation is -O0

Go To Last Post
15 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This has drivent me somewhat crazy - a whole program module that worked - when optimisation was globally at -O1, now fails - badly - jumping to address 0xFFFF instead of the correct case statement.

Compiling this module at -O0 then the program works.

The switch parameter is taken from the first byte of a buffer .. other than that I see nothin wrong -- because it works - and has worked.

Single stepping through the switch sees the z vector loaded with FFFF before the indexed jump ..into oblivion!

Sorry for a long post - if it helps then here is the code fragment.
Assume the first bits work - it's the actual switch that fails.
Any ideas anyone? GCC Bug?

void action_command(void)
{

   byte  i;
   byte  ret;
   byte  cmd_OK;

   cmd_OK = 0;

   i = 0;
   ret = 1;

   do
   {
      temp = bgetc();
      if( (temp == 0x0D) || (temp == 0x0A) )
      {
         command[i++] = 0;             // Terminate the string
         ret = 0;
      }
      else
      {
         if(temp >= 'a' && temp <= 'z')
            temp = temp - 0x20;           // Convert to uppercase

         command[i++] = temp;             // Save the character
      }

   } while(bkbhit && ret && i < CMD_BUF_SIZE);

   length = i - 1;

   if( (!ret) && length)
   {
      //
      // Action the Command  (i contains the length of the string)
      //

      cmd_OK = 1;

  	cmmdvalue = command[0];
      switch(cmmdvalue)
      {

         case 'A':
		 	command_A ();



            break;


         case 'B':      // Battery Voltage

            send_ACK();
            TX_battery_voltage();
            break;


The assembley code generated is:

+00001EB2:   91DF        POP       R29            Pop register from stack
+00001EB3:   91CF        POP       R28            Pop register from stack
+00001EB4:   911F        POP       R17            Pop register from stack
+00001EB5:   90FF        POP       R15            Pop register from stack
+00001EB6:   90EF        POP       R14            Pop register from stack
+00001EB7:   9508        RET                      Subroutine return
@00001EB8: action_command
552:      {
+00001EB8:   92AF        PUSH      R10            Push register on stack
+00001EB9:   92BF        PUSH      R11            Push register on stack
+00001EBA:   92CF        PUSH      R12            Push register on stack
+00001EBB:   92DF        PUSH      R13            Push register on stack
+00001EBC:   92EF        PUSH      R14            Push register on stack
+00001EBD:   92FF        PUSH      R15            Push register on stack
+00001EBE:   930F        PUSH      R16            Push register on stack
+00001EBF:   931F        PUSH      R17            Push register on stack
+00001EC0:   93CF        PUSH      R28            Push register on stack
+00001EC1:   93DF        PUSH      R29            Push register on stack
552:      {
+00001EC2:   EDCA        LDI       R28,0xDA       Load immediate
+00001EC3:   E2D8        LDI       R29,0x28       Load immediate
+00001EC4:   E001        LDI       R16,0x01       Load immediate
+00001EC5:   E011        LDI       R17,0x01       Load immediate
568:               command[i++] = 0;             // Terminate the string
+00001EC6:   24EE        CLR       R14            Clear Register
579:         } while(bkbhit && ret && i < CMD_BUF_SIZE);
+00001EC7:   2E0F        MOV       R0,R31         Copy register
+00001EC8:   E5F5        LDI       R31,0x55       Load immediate
+00001EC9:   2ECF        MOV       R12,R31        Copy register
+00001ECA:   E2F5        LDI       R31,0x25       Load immediate
+00001ECB:   2EDF        MOV       R13,R31        Copy register
+00001ECC:   2DF0        MOV       R31,R0         Copy register
+00001ECD:   0156        MOVW      R10,R12        Copy register pair
+00001ECE:   9408        SEC                      Set Carry
+00001ECF:   1CA1        ADC       R10,R1         Add with carry
+00001ED0:   1CB1        ADC       R11,R1         Add with carry
552:      {
+00001ED1:   2EF1        MOV       R15,R17        Copy register
+00001ED2:   94FA        DEC       R15            Decrement
565:            temp = bgetc();
+00001ED3:   940E03FA    CALL      0x000003FA     Call subroutine
+00001ED5:   93802559    STS       0x2559,R24     Store direct to data space
566:            if( (temp == 0x0D) || (temp == 0x0A) )
+00001ED7:   308D        CPI       R24,0x0D       Compare with immediate
+00001ED8:   F011        BREQ      PC+0x03        Branch if equal
+00001ED9:   308A        CPI       R24,0x0A       Compare with immediate
+00001EDA:   F419        BRNE      PC+0x04        Branch if not equal
568:               command[i++] = 0;             // Terminate the string
+00001EDB:   8218        STD       Y+0,R1         Store indirect with displacement
+00001EDC:   2D0E        MOV       R16,R14        Copy register
+00001EDD:   C009        RJMP      PC+0x000A      Relative jump
573:               if(temp >= 'a' && temp <= 'z')
+00001EDE:   5681        SUBI      R24,0x61       Subtract immediate
+00001EDF:   318A        CPI       R24,0x1A       Compare with immediate
+00001EE0:   F418        BRCC      PC+0x04        Branch if carry cleared
574:                  temp = temp - 0x20;           // Convert to uppercase
+00001EE1:   5B8F        SUBI      R24,0xBF       Subtract immediate
+00001EE2:   93802559    STS       0x2559,R24     Store direct to data space
576:               command[i++] = temp;             // Save the character
+00001EE4:   91802559    LDS       R24,0x2559     Load direct from data space
+00001EE6:   8388        STD       Y+0,R24        Store indirect with displacement
579:         } while(bkbhit && ret && i < CMD_BUF_SIZE);
+00001EE7:   01F6        MOVW      R30,R12        Copy register pair
+00001EE8:   8190        LDD       R25,Z+0        Load indirect with displacement
+00001EE9:   01F5        MOVW      R30,R10        Copy register pair
+00001EEA:   8180        LDD       R24,Z+0        Load indirect with displacement
+00001EEB:   1798        CP        R25,R24        Compare
+00001EEC:   F041        BREQ      PC+0x09        Branch if equal
+00001EED:   2300        TST       R16            Test for Zero or Minus
+00001EEE:   F409        BRNE      PC+0x02        Branch if not equal
+00001EEF:   C13F        RJMP      PC+0x0140      Relative jump
+00001EF0:   5F1F        SUBI      R17,0xFF       Subtract immediate
+00001EF1:   9621        ADIW      R28,0x01       Add immediate to word
+00001EF2:   3210        CPI       R17,0x20       Compare with immediate
+00001EF3:   F6E9        BRNE      PC-0x22        Branch if not equal
+00001EF4:   C137        RJMP      PC+0x0138      Relative jump
581:         length = i - 1;
+00001EF5:   92F028D9    STS       0x28D9,R15     Store direct to data space
583:         if( (!ret) && length)
+00001EF7:   2300        TST       R16            Test for Zero or Minus
+00001EF8:   F009        BREQ      PC+0x02        Branch if equal
+00001EF9:   C138        RJMP      PC+0x0139      Relative jump
+00001EFA:   20FF        TST       R15            Test for Zero or Minus
+00001EFB:   F409        BRNE      PC+0x02        Branch if not equal
+00001EFC:   C135        RJMP      PC+0x0136      Relative jump
591:        	cmmdvalue = command[0];
+00001EFD:   91800000    LDS       R24,0x0000     Load direct from data space
+00001EFF:   938028D8    STS       0x28D8,R24     Store direct to data space
592:            switch(cmmdvalue)
+00001F01:   E090        LDI       R25,0x00       Load immediate
+00001F02:   01FC        MOVW      R30,R24        Copy register pair
+00001F03:   54E1        SUBI      R30,0x41       Subtract immediate
+00001F04:   40F0        SBCI      R31,0x00       Subtract immediate with carry
+00001F05:   31E8        CPI       R30,0x18       Compare with immediate
+00001F06:   05F1        CPC       R31,R1         Compare with carry
+00001F07:   F008        BRCS      PC+0x02        Branch if carry set
+00001F08:   C129        RJMP      PC+0x012A      Relative jump
+00001F09:   50EC        SUBI      R30,0x0C       Subtract immediate
+00001F0A:   4FFF        SBCI      R31,0xFF       Subtract immediate with carry
+00001F0B:   0FEE        LSL       R30            Logical Shift Left
+00001F0C:   1FFF        ROL       R31            Rotate Left Through Carry
+00001F0D:   9005        LPM       R0,Z+          Load program memory and postincrement
+00001F0E:   91F4        LPM       R31,Z          Load program memory
+00001F0F:   2DE0        MOV       R30,R0         Copy register
+00001F10:   9409        IJMP                     Indirect jump to (Z)
596:      		 	command_A ();
+00001F11:   940E1D28    CALL      0x00001D28     Call subroutine
+00001F13:   C11E        RJMP      PC+0x011F      Relative jump
606:                  TX_battery_voltage();
+00001F14:   940E14AC    CALL      0x000014AC     Call subroutine
+00001F16:   C11B        RJMP      PC+0x011C      Relative jump
612:                  TX_temperature_reading();
+00001F17:   940E149F    CALL      0x0000149F     Call subroutine
+00001F19:   C118        RJMP      PC+0x0119      Relative jump
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

try adding a (extern?) declaration for command[]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Which AVR target was used?

I would suggest use only -Os always, it gives the smallest and mostly also the fastest code.
Then e.g. 8 bit calculations are done without expanding to 16 bit.

You should also use avr-objdump.exe to generate the list file.
Then the source code was included and jump destinations are named as comment.

To detect why the jump fail, we must see the jump table and on which address it was.

Maybe, we must see also a complete function, not interrupted in between.
We should also see the type definition of all global variables, used in this function.

You schould better use local variables, whenever applicable.
E.g. storing "cmmdvalue" into SRAM seems unneeded.
If needed from a called function, it may be passed as argument.

Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The jumptable is apparently located from address 0x00f4. Show us that, too.

What is the value for which you experience the failure? What is in that table for that value?

JW

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

rowifi wrote:
This has drivent me somewhat crazy - a whole program module that worked - when optimisation was globally at -O1, now fails - badly - jumping to address 0xFFFF instead of the correct case statement.

I don't see the declaration for command[] or commdvalue.

I'd like to know which version of gcc you are using.

If you want old-style c behaviour, you should probably be using
-fno-strict-aliasing
and
-fno-move-loop-invariants

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well thanks for the info everyone.
Target is XMEGA64 A3

Using Winavr 20100110

I've attached the screen shots of the code just at the end point of the switch where it's going to jump to FFFF.
Included are the screen shots of the other info requested.

The code fails on a switch with 'A' as the parameter, as shown in the command buffer[0]. I haven't forced any other value here yet to see what effect it has.

I've reverted to the original switch (command[0]) statement but it makes no difference. to the outcome.

I've just tried compiling the project with an earlier version of the module with this switch in it, in case added code had done something - but exactly the same happens.

I'm still very stuck to cure it apart from removing the optimisation and I'd like to understand in case there's a deeper problem lurking.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Do the screen shots show the simulator, or a debugging session on the chip?

The ijmp address is loaded from 0x00f4 (word address). On the memory dump screen shot you can see that there is no 0xffff at that address. Instead there is 0x1f0f, which is the address right behind the ijmp and therefore seems to be correct. So it looks like a bug of the simulator/debugger.

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

So it looks like a bug of the simulator

Wow! Now THAT would be SO unusual.
[/sarcastic]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Stefan
This is from a debug session on the chip.
I see that just before the LPM executes that the Z register ( R30,R31) is loaded with 0xE8 0x01, which is the shifted 0xF4,0x00. The LPM then loads 0xFF which looks wrong.
This is the only place in the code where LPM exists - but it looks like it executes incorrectly.

If left to free run - the program crashes - so I don't think its a single step error.
There are issues with the XmegaA3 in WritingFlash and EEprom but nothing mentioned about reading using the LPM instruction.

I may have to try a different CPU as that is the only new difference from a working unit to this faulty one.
( Can't try this code in an earlier PCB as the IO has all changed )

Thanks for helping.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I never looked at a data sheet of a XMega so far. Perhaps there is a lock bit that prevents reading the Flash (even at run time by lpm).

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, I would never rely on the debug stuff - couldn't you perform a simple minimal test with reading a piece of FLASH using pgm_read_byte() and send it out somehow?

JW

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I made a simple loop to read from Flash to Ram.

Output code shown:

:              CCPWrite(&MCU.MCUCR, MCU_JTAGD_bm);
+00000165:   E986        LDI       R24,0x96       Load immediate
+00000166:   E090        LDI       R25,0x00       Load immediate
+00000167:   E061        LDI       R22,0x01       Load immediate
+00000168:   940E2712    CALL      0x00002712     Call subroutine
+0000016A:   E080        LDI       R24,0x00       Load immediate
+0000016B:   E090        LDI       R25,0x00       Load immediate
76:       	rambuf[i] =	pgm_read_byte(test[i]);
+0000016C:   EE48        LDI       R20,0xE8       Load immediate
+0000016D:   E051        LDI       R21,0x01       Load immediate
+0000016E:   E62B        LDI       R18,0x6B       Load immediate
+0000016F:   E235        LDI       R19,0x25       Load immediate
+00000170:   01FA        MOVW      R30,R20        Copy register pair
+00000171:   0FE8        ADD       R30,R24        Add without carry
+00000172:   1FF9        ADC       R31,R25        Add with carry
+00000173:   81E0        LDD       R30,Z+0        Load indirect with displacement
+00000174:   E0F0        LDI       R31,0x00       Load immediate
+00000175:   91E4        LPM       R30,Z          Load program memory
+00000176:   01D9        MOVW      R26,R18        Copy register pair
+00000177:   0FA8        ADD       R26,R24        Add without carry
+00000178:   1FB9        ADC       R27,R25        Add with carry
+00000179:   93EC        ST        X,R30          Store indirect
+0000017A:   9601        ADIW      R24,0x01       Add immediate to word
73:       	for (i = 0; i<20 ;i++)
+0000017B:   3184        CPI       R24,0x14       Compare with immediate
+0000017C:   0591        CPC       R25,R1         Compare with carry
+0000017D:   F791        BRNE      PC-0x0D        Branch if not equal
+0000017E:   E184        LDI       R24,0x14       Load immediate
+0000017F:   9380255A    STS       0x255A,R24     Store direct to data space
88:       	PMIC_SetVectorLocationToApplication();

It always reads from Flash location 0000 and fills the buffer with that '0c' - part of the vector data.
The test buffer exists correctly in Flash at location 0x01E8 and the ram buffer is at 0x256B

Seems like this fails also.
I FEEL LIKE i'M DOING SOMETHING CRAZY BUT CAN'T PUT MY FINGER ON IT.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1,

rowifi wrote:

76:       	rambuf[i] =	pgm_read_byte(test[i]);


This is incorrect use of pgm_read_byte. Instead of reading from FLASH address where test[] is, you read from RAM from the same address (where there are presumably unitialised data), and take the value read from there as the address to FLASH.
You should use:
rambuf[i] =	pgm_read_byte(&test[i]);

2.
What is

 CCPWrite(&MCU.MCUCR, MCU_JTAGD_bm);

?

JW

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, JW.

Thanks - having just made a blank project to try it - I realise the mistake.
It seems that the LPM works in this instance when I fix the code, but I've yet to understand why the device reads incorectly in my optimised switch statement.

I'll keep trying things.

The other funciotn is just code that disables the JTAG port.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

rowifi wrote:
Yes, JW.

but I've yet to understand why the device reads incorectly in my optimised switch statement.

So you should try

-fno-strict-aliasing

and you should show us how command[] and cmmdvalue are declared.