avr-libc-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[avr-libc-dev] Re: New Atomic.h header?


From: Dean
Subject: [avr-libc-dev] Re: New Atomic.h header?
Date: Tue, 9 Jan 2007 22:34:39 +1100

Hi all,

Sorry for the lateness of this, I've been away for the past two days. 

Joerg: If eventually accepted I will of course ask the original author for 
permission, and add him to the copyright. I hope I don't get too annoying here 
bouncing my ideas off you all; I tend to get over-enthusiastic about the 
simplest of things.

Paulo Marques raised two good issues with me via email about my atomic macros, 
one of which is serious.

First of all, my macros require compilation in GNU99 standards mode. I can't 
see why people don't do this all the time anyway, but since the rest of AVRLibC 
is ANSI compliant (IIRC) this may cause some concern with users.

Second is the serious one. GCC4.1 may re-order the block and move out access to 
variables. In Paulo's test case:

#include <avr/io.h>
#include <avr/interrupt.h>
#include "Atomic.h"

uint16_t counter1, counter2;

int main(void)
{
 uint16_t a, b;
 
 ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
 {
  a = counter1;
  b = counter2;
 }
 
 PORTB = a;
 PORTC = b;
 
 return 0;
}

The resulting ASM produced is:

> ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
>   64: 8f b7       in r24, 0x3f ; 63
>   66: f8 94       cli
>   68: 8f bf       out 0x3f, r24 ; 63
> a = counter1;
> b = counter2;
> }
> 
> PORTB = a;
>   6a: 80 91 60 00 lds r24, 0x0060
>   6e: 88 bb       out 0x18, r24 ; 24
> PORTC = b;
>   70: 80 91 62 00 lds r24, 0x0062
>   74: 85 bb       out 0x15, r24 ; 21

Which is no good. Unless anyone can think of a way to force the compiler to not 
re-order the code, then this macro won't be suitable for general use. It still 
behaves correctly on code that does more than just global manipulation, however.


As for the requirements of the NON_ATOMIC block, someone on 'Freaks wanted code 
inside the atomic block that was non-atomic. Using a cli(); in the block is of 
course fine, however if the nested non-atomic code was non trivial and used the 
break; statement the sei(); afterwards might not be executed, in the same 
manner than the sei(); may not be executed with Ron's macros.


The FORCE modes are useful where the current interrupt state is a known 
constant, for example inside a nested interrupt. I myself use it for this 
purpose; some of my interrupts are normally non-blocking but require atomic 
code.

- Dean


reply via email to

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