[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[avr-gcc-list] Confusing volatile behaviour with 4.6.2
From: |
Andy Warner |
Subject: |
[avr-gcc-list] Confusing volatile behaviour with 4.6.2 |
Date: |
Sat, 26 Nov 2011 13:11:42 -0600 |
I am seeing some volatile handling behaviour that confuses me, and is
causing problems with some code.
Background: freshly built toolchain (gcc: 4.6.2, binutils 2.21.1,
avr-libc: 1.7.2, linux host.)
Target: Mega128, project is a DMX512 dongle.
DMX512 uses 250Kbaud serial comms, and uses a break to signal the
start of a new frame/packet.
Problem - it appears the compiler is feeling free to optimize/reorder
some register accesses that are marked volatile.
I've checked the archive/google and have found nothing useful -
apologies in advance if I just didn't look hard enough and it's all
been discussed before. I can't remember seeing references to this fly
past on the list recently.
Here is the USART0 rx interrupt handler that demonstrates the problem
(apologies in advance, if gmail mangles this):
#define SEARCHING (-2)
#define BREAK (-1)
#define MAX_DMX (512)
ISR(USART0_RX_vect)
{
unsigned char status = UCSR0A;
unsigned char data = UDR0;
volatile static int slot = SEARCHING;
if (status & 0x10) {
if (slot == SEARCHING) {
slot++;
} else {
goto search;
}
} else {
if ((slot < BREAK) || (++slot > MAX_DMX)) {
goto search;
}
print_h2(0, slot & 0xff);
PORTB = slot & 0x3f;
if ((slot == 0) && (data != 0)) {
goto search;
}
if (slot == wanted) {
level = data;
goto search;
}
}
return;
search:
slot = SEARCHING;
return;
}
Comments on goto > /dev/null.
When compiled with:
$ make test.lst
avr-gcc -mmcu=atmega128 -Wall -O2 -g -c test.c
avr-gcc -mmcu=atmega128 -g -o test.elf test.o
avr-size test.elf
text data bss dec hex filename
1094 22 1 1117 45d test.elf
avr-objdump -h -S test.elf > test.lst
$
The code as posted does not work, and examining test.lst shows why:
...
00000260 <__vector_18>:
#define SEARCHING (-2)
#define BREAK (-1)
#define MAX_DMX (512)
ISR(USART0_RX_vect)
{
260: 1f 92 push r1
262: 0f 92 push r0
264: 0f b6 in r0, 0x3f ; 63
266: 0f 92 push r0
268: 0b b6 in r0, 0x3b ; 59
26a: 0f 92 push r0
26c: 11 24 eor r1, r1
26e: 2f 93 push r18
270: 3f 93 push r19
272: 4f 93 push r20
274: 5f 93 push r21
276: 6f 93 push r22
278: 7f 93 push r23
27a: 8f 93 push r24
27c: 9f 93 push r25
27e: af 93 push r26
280: bf 93 push r27
282: cf 93 push r28
284: ef 93 push r30
286: ff 93 push r31
unsigned char status = UCSR0A;
unsigned char data = UDR0;
288: cc b1 in r28, 0x0c ; 12
volatile static int slot = SEARCHING;
if (status & 0x10) {
28a: 5c 9b sbis 0x0b, 4 ; 11
28c: 23 c0 rjmp .+70 ; 0x2d4 <__vector_18+0x74>
if (slot == SEARCHING) {
28e: 80 91 11 01 lds r24, 0x0111
292: 90 91 12 01 lds r25, 0x0112
296: 2f ef ldi r18, 0xFF ; 255
298: 8e 3f cpi r24, 0xFE ; 254
29a: 92 07 cpc r25, r18
29c: 09 f4 brne .+2 ; 0x2a0 <__vector_18+0x40>
29e: 54 c0 rjmp .+168 ; 0x348 <__vector_18+0xe8>
}
...
Note that it has reordered the read of UCSR0A until after the read of UDR0.
Here is what the preprocessor produced for this code:
$ avr-gcc -mmcu=atmega128 -Wall -O2 -g -E test.c
...
void __vector_18 (void) __attribute__ ((signal,used,
externally_visible)) ; void __vector_18 (void)
{
unsigned char status = (*(volatile uint8_t *)((0x0B) + 0x20));
unsigned char data = (*(volatile uint8_t *)((0x0C) + 0x20));
volatile static int slot = (-2);
if (status & 0x10) {
if (slot == (-2)) {
slot++;
} else {
goto search;
}
} else {
if ((slot < (-1)) || (++slot > (512))) {
goto search;
}
...
Which I _think_ should be telling the compiler that both registers are
volatile, so reordering is forbidden.
If I add some IO pin wiggling for debug, the problem vanishes:
...
ISR(USART0_RX_vect)
{
unsigned char status = UCSR0A;
unsigned char data = UDR0;
volatile static int slot = SEARCHING;
PORTB |= 0x40;
if (status & 0x10) {
if (slot == SEARCHING) {
slot++;
} else {
goto search;
}
} else {
...
Results in:
...
ISR(USART0_RX_vect)
{
260: 1f 92 push r1
262: 0f 92 push r0
264: 0f b6 in r0, 0x3f ; 63
266: 0f 92 push r0
268: 0b b6 in r0, 0x3b ; 59
26a: 0f 92 push r0
26c: 11 24 eor r1, r1
26e: 2f 93 push r18
270: 3f 93 push r19
272: 4f 93 push r20
274: 5f 93 push r21
276: 6f 93 push r22
278: 7f 93 push r23
27a: 8f 93 push r24
27c: 9f 93 push r25
27e: af 93 push r26
280: bf 93 push r27
282: cf 93 push r28
284: ef 93 push r30
286: ff 93 push r31
unsigned char status = UCSR0A;
288: 8b b1 in r24, 0x0b ; 11
unsigned char data = UDR0;
28a: cc b1 in r28, 0x0c ; 12
volatile static int slot = SEARCHING;
PORTB |= 0x40;
28c: c6 9a sbi 0x18, 6 ; 24
if (status & 0x10) {
28e: 84 ff sbrs r24, 4
290: 23 c0 rjmp .+70 ; 0x2d8 <__vector_18+0x78>
if (slot == SEARCHING) {
292: 80 91 11 01 lds r24, 0x0111
296: 90 91 12 01 lds r25, 0x0112
29a: 2f ef ldi r18, 0xFF ; 255
29c: 8e 3f cpi r24, 0xFE ; 254
29e: 92 07 cpc r25, r18
2a0: 09 f4 brne .+2 ; 0x2a4 <__vector_18+0x44>
2a2: 54 c0 rjmp .+168 ; 0x34c <__vector_18+0xec>
}
...
You can see now that the register reads are in the correct order, and
the code works as expected.
Comments/suggestions ?
--
Andy
- [avr-gcc-list] Confusing volatile behaviour with 4.6.2,
Andy Warner <=
- Re: [avr-gcc-list] Confusing volatile behaviour with 4.6.2, Georg-Johann Lay, 2011/11/26
- Re: [avr-gcc-list] Confusing volatile behaviour with 4.6.2, Paulo Marques, 2011/11/28
- Re: [avr-gcc-list] Confusing volatile behaviour with 4.6.2, Andy Warner, 2011/11/28
- Re: [avr-gcc-list] Confusing volatile behaviour with 4.6.2, Wim Lewis, 2011/11/29
- Re: [avr-gcc-list] Confusing volatile behaviour with 4.6.2, Weddington, Eric, 2011/11/29
- Re: [avr-gcc-list] Confusing volatile behaviour with 4.6.2, Andy Warner, 2011/11/29
- Re: [avr-gcc-list] Confusing volatile behaviour with 4.6.2, Weddington, Eric, 2011/11/29
- Re: [avr-gcc-list] Confusing volatile behaviour with 4.6.2, Georg-Johann Lay, 2011/11/29
- Re: [avr-gcc-list] Confusing volatile behaviour with 4.6.2, Weddington, Eric, 2011/11/29
- Re: [avr-gcc-list] Confusing volatile behaviour with 4.6.2, Georg-Johann Lay, 2011/11/29