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

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

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


From: Paulo Marques
Subject: Re: [avr-libc-dev] New Atomic.h header?
Date: Mon, 08 Jan 2007 19:19:09 +0000
User-agent: Thunderbird 1.5.0.7 (X11/20060909)

Dean wrote:
Hi guys!

Hi, Dean.

[...]
My macro allows for both atomic (interrupts disabled) and non-atomic
(interrupts enabled) blocks of code to be easily made. Unlike
conventional methods these macros are quite foolproof - the epilogue for
each is run automatically on block exit regardless of the exit path.
When compiled with -Os, it results in the smallest possible code.

First of all, I would like to say that I agree that we should improve the way that atomic blocks are handled in avr-gcc, but I've found a few problems with your solution, though.

The main problem is that the generated code doesn't always do what is expected. Something like:

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;
}

compiles to (using gcc 4.2.0):

        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

As you can see, the 'a' and 'b' loads are not atomic as expected, because the compiler doesn't know about side effects and reorders the loads around the flags restore operation.

To avoid this there must be some way to tell the compiler that everything inside the block must be treated as volatile.

Anyway, I usually don't need a lot of code to be atomic. My problem is the other way around: I only need to access multi-byte variables in an atomic way, while keeping the interrupt latency as small as possible.

That is why a while ago I suggested creating an atomic.h with special accessor functions atomic_read/write_16/32(uint16/32_t *ptr) that used the same "restore flags one instruction earlier" trick that we also use to update the stack pointer in function prologues.

This only solves the problem of multi-byte variables though. For more complex interactions, we need something like your solution, but we have to solve the reordering problem :(

BTW, your atomic.h also forces the code to use -std=c99. I don't know if this will be a problem, though, but I thought I should mention it.

--
Paulo Marques - www.grupopie.com

"The face of a child can say it all, especially the
mouth part of the face."




reply via email to

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