[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [avr-gcc-list] Strange inline asm bug or silly user?
From: |
Georg Lay |
Subject: |
Re: [avr-gcc-list] Strange inline asm bug or silly user? |
Date: |
Tue, 20 Jul 2010 10:04:14 +0200 |
User-agent: |
Thunderbird 2.0.0.24 (X11/20100302) |
David Carr schrieb:
> I'm just learning to use inline assembly with avr-gcc, and I've
> encountered what seems to me to be a very strange bug (but may be user
> silliness).
>
> In the test case below, I repeatedly change the first entry of the data
> array between 0xFF and 0x00. A short piece of assembly then moves
> data[0] into r0 and pushes it out to PORTB. This causes an LED to
> flash. This works.
>
> However, when I change:
>
> "ldd r0, %a1+0 \n\t"
> "out %0, r0 \n\r"
>
> to:
>
> ldd r1, %a1+0 \n\t"
> "out %0, r1 \n\r"
>
> IE: replace r0 with r1, the LED just stays lit continuously.
>
> Fine, so I look at the assembly listing generated by avr-objdump -h -S
> ads-tx.elf > ads-tx.lst
> This is the diff between the working and non-working versions:
>
> 99,102c99,102
> < ae: 10 80 ld r1, Z
> < b0: 15 b8 out 0x05, r1 ; 5
> < "ldd r1, %a1+0 \n\t"
> < "out %0, r1 \n\r"
> ---
>> ae: 00 80 ld r0, Z
>> b0: 05 b8 out 0x05, r0 ; 5
>> "ldd r0, %a1+0 \n\t"
>> "out %0, r0 \n\r"
> 170,171c170,171
> < e4: 10 80 ld r1, Z
> < e6: 15 b8 out 0x05, r1 ; 5
> ---
>> e4: 00 80 ld r0, Z
>> e6: 05 b8 out 0x05, r0 ; 5
> 188,189c188,189
> < f0: 10 80 ld r1, Z
> < f2: 15 b8 out 0x05, r1 ; 5
> ---
>> f0: 00 80 ld r0, Z
>> f2: 05 b8 out 0x05, r0 ; 5
>
> It looks to me like the only thing that has changed is R0/R1.
>
> Even more strange is that using R2, R3, R13 all work. Just R1 fails. I
> am baffled.
>
> Test code:
>
> #include <stdint.h>
> #include <avr/io.h>
>
> #define F_CPU 8000000UL
> #include <util/delay.h>
>
> void send_packet(volatile uint8_t* data)
> {
> asm volatile(
> //first load data in to RX
> "ldd r0, %a1+0 \n\t"
> "out %0, r0 \n\r"
> :
> :"I" (_SFR_IO_ADDR(PORTB)), "e" (data)
> : "r0", "r1", "r2", "r3", "r13");
> }
Note that clobbering R0 and R1 is pretty much useless.
These registers are used implicitely by the compiler. In other words:
you have to restore their contents by hand. For R0 there is nothing to do
(except, of cource in ISR code) because it is just a temporary register whose
value is valid for one insn (insns are one of gcc's internal representations).
For R1 you have to add a CLR R1 at the end of each inline asm snippet.
Also note that it's often preferable to let the compiler chose the reg as in
void send_packet(volatile uint8_t* data)
{
uint8_t value;
asm volatile(
//first load data in to RX
"ld %0, %a2 \n\t"
"out %1, %0"
: "=r" (value)
: "I" (_SFR_IO_ADDR(PORTB)), "e" (data)
: "memory");
}
I wrote ld instead of ldd ...+0 because ldd is not available for X but X is
element of "e".
Or even better
static inline void send_packet (volatile uint8_t* data)
{
uint8_t value = *data;
asm volatile(
"out %0, %1"
:
: "I" (_SFR_IO_ADDR(PORTB)), "r" (value)
: "memory");
}