Strange optimisation side effect.

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

Hi,

It has been a while since i posted, but now i'm witness to very strange results with -Os optimisation;

while ((PIND & _BV(D0)) != 0);

When compiling this code snippet with optimisation turned off i get this result;

LDS     R24,0x0030       Load direct from data space
CLR     R25              Clear Register
ANDI    R24,0x04         Logical AND with immediate
ANDI    R25,0x00         Logical AND with immediate
SBIW    R24,0x00         Subtract immediate from word
BREQ    PC+0x02          Branch if equal
RJMP    PC-0x0007        Relative jump

Obviously correct compilation and does the trick with the hardware attached, when optimation turned to -Os the result;

SBIC    0x10,2           Skip if bit in I/O register cleared
RJMP    PC-0x0001        Relative jump

Correct compilation/optimisation but doesn't work with the hardware.

Is there something i'm missing here? Has anyone witnessed the same behaviour before?

BTW. D0 is defined PD2

Thanks for any input...

KK

Assumptio mater errorum est

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

Are you too fast now?

I've once been pulling my few remaining hairs out because right after
an OUT, I was immediately reading an IN that was supposed to depend on
the previously output data. That doesn't work, as the input pin is
sampled before the output port changes. This is a documented
feature... so put an asm("nop") between.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

Jörg,

Thanks for your input, i've looked in to it and must say that this can't be the reason why the optimised code is failing, it's a while loop remember, if it would miss the first time around, it would surely get it the second time.

This is the complete implementation;

DDRD |= _BV(D1); 			
			
loop_until_bit_is_clear (PIND, D0);

DDRD &= ~_BV(D1); 			
loop_until_bit_is_set (PIND, D0);
loop_until_bit_is_set (PIND, D1);

i replaced the original while loops with the macro's since they are reading better, the optimisation effect is the same.

KK.

Assumptio mater errorum est

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

Hi all,

Jörg is as allways right... i replaced the loop_until_bit_is_set and loop_until_bit_is_clear macro's with my homebrew macro with an embedded nop

#define wait_until_bit_set (sfr,bit) 	\
		do {							\
			asm volatile ("nop"::);		\
		} while (bit_is_clear (sfr,bit))

And everything works fine, thanks Jörg.

Assumptio mater errorum est

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

By now i have the problem solved,

void tx_byte (volatile unsigned char data)
{
volatile unsigned char cnt;

for (cnt = 0; cnt < 8; cnt++) 
    { 
        if (data & 0x01) 
        { 
           set_bit (DDRD, D1); 
           wait_until_bit_clear (PIND, D0);
           
           clear_bit (DDRD, D1);
           wait_until_bit_set (PIND, D0);
           wait_until_bit_set (PIND, D1); 
        } else { 
            set_bit (DDRD, D0); 			
            wait_until_bit_clear (PIND, D1);
			
            clear_bit (DDRD, D0);
            wait_until_bit_set (PIND, D1); 
            wait_until_bit_set (PIND, D0); 	
       } 

        data >>= 1; 
    }
}

As you can see i've declared both local variables volatile, thus misleading the optimizer, the macro's use the STS en LDS instructions for reading and writing to the SFR's.

Strange however is that with the previous WinAVR distribution (20050214) this project was working.

Is there an explanation?

KK

Assumptio mater errorum est

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

kkempeneers wrote:
Is there an explanation?

The later version has a better optimiser perhaps?

Cliff