avr-gcc-list
[Top][All Lists]
Advanced

[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");
}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]