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"); } _______________________________________________ AVR-GCC-list mailing list AVR-GCC-list@nongnu.org http://lists.nongnu.org/mailman/listinfo/avr-gcc-list