[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[avr-gcc-list] [Bug] Initialization for _delay_loop_2 Optimized Out
From: |
Dave Hansen |
Subject: |
[avr-gcc-list] [Bug] Initialization for _delay_loop_2 Optimized Out |
Date: |
Wed, 23 Jul 2003 18:29:06 -0400 |
This is my first post to the list. Please forgive me if I do something
wrong...
I'm using WinAVR on Win98.
C:\Dave>avr-gcc -v
Reading specs from C:\WINAVR\BIN\..\lib\gcc-lib\avr\3.3\specs
Configured with: ../configure --prefix=/e/avrdev/install --target=avr
--enable-l
anguages=c,c++ --disable-nls
Thread model: single
gcc version 3.3 20030421 (prerelease)
The command line options from my makefile are as follows:
CC = avr-gcc
MCU = atmega32
HZ = 12000000
APPDEFS =
CFLAGS = -mmcu=$(MCU) -D OSC_FREQ=$(HZ) $(APPDEFS) -I.\
-g -Os -funsigned-char -funsigned-bitfields -fpack-struct \
-fshort-enums -Wall -Wstrict-prototypes
-Wa,-ahlms=$(<:.c=.lst)
%.o : %.c
$(CC) -c $(CFLAGS) $< -o $@ 2> $(<:.c=.err)
The bug is demonstrated by the following code:
--- begin included file ---
#include <avr/io.h>
#include <avr/delay.h>
typedef unsigned int U16;
#define CLOCKS_PER_US ((U16)(OSC_FREQ/1000000))
#define CLOCKS_PER_LOOP 4
#define delay_us1(t) do{U16 c = (t)*CLOCKS_PER_US/CLOCKS_PER_LOOP; \
_delay_loop_2(c); }while(0);
static inline void
my_delay_loop(unsigned int __count)
{
if (__count)
{
asm volatile (
"1: sbiw %0,1" "\n\t"
"brne 1b"
: "=w" (__count)
: "0" (__count)
);
}
}
#define delay_us2(t) do{U16 c = (t)*CLOCKS_PER_US/CLOCKS_PER_LOOP; \
my_delay_loop(c); }while(0);
int main(void)
{
PORTA = 0;
DDRA = 1;
while(1)
{
PORTA ^= 1;
delay_us1(1);
delay_us2(1);
}
return 0;
}
--- end included file ---
When compiled, the code for the loop in main looks like this (from the .LSS
file)
--- begin included file ---
while(1)
{
PORTA ^= 1;
9c: 8b b3 in r24, 0x1b ; 27
9e: 91 e0 ldi r25, 0x01 ; 1
a0: 89 27 eor r24, r25
a2: 8b bb out 0x1b, r24 ; 27
/* 16-bit count, 4 cycles/loop */
static inline void
_delay_loop_2(unsigned int __count)
{
asm volatile (
a4: 31 97 sbiw r30, 0x01 ; 1
a6: f1 f7 brne .-4 ; 0xa4
delay_us1(1);
delay_us2(1);
a8: 83 e0 ldi r24, 0x03 ; 3
aa: 90 e0 ldi r25, 0x00 ; 0
ac: 01 97 sbiw r24, 0x01 ; 1
ae: f1 f7 brne .-4 ; 0xac
b0: f5 cf rjmp .-22 ; 0x9c
--- end included file ---
Note that my_delay_loop is a copy of _delay_loop_2 from avr/delay.h, with
the test for __count != 0 added.
Note also that the call to delay_us1 (which uses _delay_loop_2) does not
initialize r30 before decrementing it. Not good. Using delay_us2, which
uses my_delay_loop rather than _delay_loop_2, results in correct code.
I suspect that since __count is not used in _delay_loop_2 other than in the
inline assembly, it is essentially being optimized out, leaving r30
uninitialized. By adding the test for __count != 0 in my_delay_loop, I'm
using the parameter in the C code, so it keeps the initialization. That's
my guess anyway.
My workaround is to use my_delay_loop rather than _delay_loop_2. This
provides the additional benefit that passing zero to the delay function does
not wait the maximum amount of time (about 5.5 ms in my case).
Regards,
-=Dave
_________________________________________________________________
The new MSN 8: advanced junk mail protection and 2 months FREE*
http://join.msn.com/?page=features/junkmail
- [avr-gcc-list] [Bug] Initialization for _delay_loop_2 Optimized Out,
Dave Hansen <=