[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>>
- [avr-libc-dev] Cool, looks like it may work...,
Darcy Watkins <=