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

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

[avr-libc-dev] Cool, looks like it may work...


From: Darcy Watkins
Subject: [avr-libc-dev] Cool, looks like it may work...
Date: Tue, 01 Nov 2005 10:42:10 -0800

Hi,

We all encounter cases where we like to wrap our tools in macros.  Sometime
we have to resort to tricks to preserve "C" syntax.  I lick that trick where
a macro wraps something in do { ... } while(0) to ensure that it is
syntactically a single statement.

I sometimes see the use of "prolog" and "epilog" type macros in the context
of customizing naked functions.  Here is a trick that looks like it may be
handy.  I toss it out here since...
 1. You make library tools on this list
 2. If this is flawed say due to compiler optimizations, etc.
    someone is likely to know enough about it and point it out to me.

The example here is to make a context switchable SIGNAL macro, but I imagine
this sort of approach could be used almost anywhere someone finds themselves
having to do anything like...

void myfunction (void) __attribute__ ((naked));

void myfunction (void)
{
        MYPROLOGMACRO();

        // my code inserted here...

        MYEPILOGMACRO();
}


First the prolog and epilog as inline functions (rather than macros since
you can use #ifdef, etc within the inlined code to tailor it to the
different AVR devices).  The example below is only for ATmega128.  No rocket
science here, likely room for improvement, especially other device support.

// Push the AVR GCC volatile registers to stack along with SREG/PSW and
RAMPZ [0x3B]
static void inline push_volatile_regs(void)
{
        asm volatile
        (
                "push    __zero_reg__   \n\t"
                "push    __tmp_reg__    \n\t"
                "in      __tmp_reg__,__SREG__   \n\t"
                "push    __tmp_reg__    \n\t"
                "in      __tmp_reg__,0x3B       \n\t"
                "push    __tmp_reg__    \n\t"
                "push    r18    \n\t"
                "push    r19    \n\t"
                "push    r20    \n\t"
                "push    r21    \n\t"
                "push    r22    \n\t"
                "push    r23    \n\t"
                "push    r24    \n\t"
                "push    r25    \n\t"
                "push    r26    \n\t"
                "push    r27    \n\t"
                "push    r30    \n\t"
                "push    r31    \n\t"
        );
}

// Pop the AVR GCC volatile registers from stack along with SREG/PSW and
RAMPZ [0x3B]
static void inline pop_volatile_regs(void)
{
        asm volatile
        (
                "pop     r31    \n\t"
                "pop     r30    \n\t"
                "pop     r27    \n\t"
                "pop     r26    \n\t"
                "pop     r25    \n\t"
                "pop     r24    \n\t"
                "pop     r23    \n\t"
                "pop     r22    \n\t"
                "pop     r21    \n\t"
                "pop     r20    \n\t"
                "pop     r19    \n\t"
                "pop     r18    \n\t"
                "pop     __tmp_reg__    \n\t"
                "out     0x3B,__tmp_reg__       \n\t"
                "pop     __tmp_reg__    \n\t"
                "out     __SREG__,__tmp_reg__   \n\t"
                "pop     __tmp_reg__    \n\t"
                "pop     __zero_reg__   \n\t"
        );
}

Now for the trick...

// Macro to wrap an ISR providing what appears to the application programmer
as
// a simple language extension.  The { } block after using this macro
becomes
// associated with the inline function declared by this macro.  The content
// is inserted between the prolog and epilog added to an outer "naked"
function.
#define CONTEXT_SWITCHABLE_SIGNAL(name) \
        void name (void) __attribute__ ((naked)) \
                __attribute__ ((signal)); \
                static void inline _inlined_##name##_code(void); \
        void name (void) \
        { \
                push_volatile_regs(); \
                _inlined_##name##_code(); \
                pop_volatile_regs(); \
                asm volatile ( "reti" ); \
        } \
        static void inline _inlined_##name##_code(void)


Now for example of usage....

void test_3 (void) __attribute__ ((naked)) \
    __attribute__ ((signal));

void test_3 (void)
{
        push_volatile_regs();

        // my code goes here... 



        pop_volatile_regs();
        asm volatile ( "reti" );
}

CONTEXT_SWITCHABLE_SIGNAL(SIG_OVERFLOW1)
{
        // my code goes here... 


}

When I look at the listing of test_3 versus test_4, they are identical.  The
token pasting involved appears to be compatible with the ISR macros used for
the SIGNAL macro.

In summary, the trick is to forward declare a static inline function whose {
} code block appears right after the macro is used, and invoke it between
the prolog and epilog code within the body of the function wrapper expanded
within the macro.

Any comments, additions or suggestions?  Am I missing something obvious or
does this scheme show some potential?  Anyone here used this?


 
 
Regards,
 
Darcy
 
--------------------------------------------------------------
Darcy L. Watkins             email: address@hidden
Senior Software Developer++  phone: (604) 455-2000
TASC Systems, Inc.           fax:   (604) 888-2712
9415 - 202 Street,           web:   http://www.tascsystems.com
Langley B.C. Canada V1M 4B5
--------------------------------------------------------------

<<attachment: winmail.dat>>


reply via email to

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