1
\$\begingroup\$

WinAVR seems to produce a lot of useless code, e.g. for following C method

ISR(INT0_vect) {
    TCCR1B = 0x09;
}

it produces (-Os)

PUSH      R1             Push register on stack
PUSH      R0             Push register on stack
IN        R0,0x3F        In from I/O location
PUSH      R0             Push register on stack
CLR       R1             Clear Register
PUSH      R24            Push register on stack
LDI       R24,0x09       Load immediate
STS       0x0081,R24     Store direct to data space
POP       R24            Pop register from stack
POP       R0             Pop register from stack
OUT       0x3F,R0        Out to I/O location
POP       R0             Pop register from stack
POP       R1             Pop register from stack
RETI                     Interrupt return

although

PUSH      R0            Push register on stack
LDI       R0,0x09       Load immediate
STS       0x0081,R0     Store direct to data space
POP       R0            Pop register from stack
RETI                    Interrupt return

should be sufficient. Because these extra commands take time, my question: how to tell the compiler to produce only the required code? Or is there a tool which can optimize the byte code directly?

UPDATE: I've tried

ISR(INT0_vect, ISR_NAKED) {
    asm volatile(
    "push r0             \n\t"
    "ldi  r0, %[value]   \n\t"
    "sts  %[ioReg], r0   \n\t"
    "pop  r0             \n\t"
    "reti                \n\t"
    : // output
    : // input
       [ioReg] "M" (_SFR_IO_ADDR(TCCR1B)),
       [value] "M" (0 << ICNC1
                  | 0 << ICES1 
                  | 0 << WGM13 
                  | 1 << WGM12
                  | 0 << CS12
                  | 0 << CS11 
                  | 1 << CS10)
    );
}

but the compiler complains:

c:\temp/ccjBxDFz.s: Assembler messages:
c:\temp/ccjBxDFz.s:30: Error: register number above 15 required

I've read a lot of AVR inline assembler documentation/tutorials, but can't get it to compile.

\$\endgroup\$

3 Answers 3

2
\$\begingroup\$

Why not use an inline assembly statement to do what you want?

See the inline assembler cookbook

A simple (readable) multiline example from there (a very short delay) which can go right into your AVR-GCC program:

asm volatile("nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" ::);

Since you seem to know your assembly, you should be good ready to rock with inline assembly as well.

\$\endgroup\$
2
\$\begingroup\$

I think that GCC's naked attribute does what you want. It skips generating any function header or footer, so you need to do your own reti.

void INT0_vect(void) __attribute__ ((signal, naked)); 

void INT0_vect(void) 
{
    TCCR1B = 0x09;
    asm volatile("reti"); 
} 

FreeRTOS uses this scheme for context switching on AVR, they explicitly store all registers. You may only want a subset:

    #define portSAVE_CONTEXT()      \
    asm volatile (  "push   r0                                              \n\t"   \
                                    "in             r0, __SREG__                    \n\t"   \
                                    "cli                                                    \n\t"   \
                                    "push   r0                                              \n\t"   \
                                    "push   r1                                              \n\t"   \
                                    "clr    r1                                              \n\t"   \
                                    "push   r2                                              \n\t"   \
                                    "push   r3                                              \n\t"   \
                                    "push   r4                                              \n\t"   \
                                    "push   r5                                              \n\t"   \
                                    "push   r6                                              \n\t"   \
                                    "push   r7                                              \n\t"   \
                                    "push   r8                                              \n\t"   \
                                    "push   r9                                              \n\t"   \
                                    "push   r10                                             \n\t"   \
                                    "push   r11                                             \n\t"   \
                                    "push   r12                                             \n\t"   \
                                    "push   r13                                             \n\t"   \
                                    "push   r14                                             \n\t"   \
                                    "push   r15                                             \n\t"   \
                                    "push   r16                                             \n\t"   \
                                    "push   r17                                             \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   r28                                             \n\t"   \
                                    "push   r29                                             \n\t"   \
                                    "push   r30                                             \n\t"   \
                                    "push   r31                                             \n\t"   \
                                    "lds    r26, pxCurrentTCB               \n\t"   \
                                    "lds    r27, pxCurrentTCB + 1   \n\t"   \
                                    "in             r0, 0x3d                                \n\t"   \
                                    "st             x+, r0                                  \n\t"   \
                                    "in             r0, 0x3e                                \n\t"   \
                                    "st             x+, r0                                  \n\t"   \
                            );

#define portRESTORE_CONTEXT()                                                           \
    asm volatile (  "lds    r26, pxCurrentTCB               \n\t"   \
                                    "lds    r27, pxCurrentTCB + 1   \n\t"   \
                                    "ld             r28, x+                                 \n\t"   \
                                    "out    __SP_L__, r28                   \n\t"   \
                                    "ld             r29, x+                                 \n\t"   \
                                    "out    __SP_H__, r29                   \n\t"   \
                                    "pop    r31                                             \n\t"   \
                                    "pop    r30                                             \n\t"   \
                                    "pop    r29                                             \n\t"   \
                                    "pop    r28                                             \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    r17                                             \n\t"   \
                                    "pop    r16                                             \n\t"   \
                                    "pop    r15                                             \n\t"   \
                                    "pop    r14                                             \n\t"   \
                                    "pop    r13                                             \n\t"   \
                                    "pop    r12                                             \n\t"   \
                                    "pop    r11                                             \n\t"   \
                                    "pop    r10                                             \n\t"   \
                                    "pop    r9                                              \n\t"   \
                                    "pop    r8                                              \n\t"   \
                                    "pop    r7                                              \n\t"   \
                                    "pop    r6                                              \n\t"   \
                                    "pop    r5                                              \n\t"   \
                                    "pop    r4                                              \n\t"   \
                                    "pop    r3                                              \n\t"   \
                                    "pop    r2                                              \n\t"   \
                                    "pop    r1                                              \n\t"   \
                                    "pop    r0                                              \n\t"   \
                                    "out    __SREG__, r0                    \n\t"   \
                                    "pop    r0                                              \n\t"   \
                            );
\$\endgroup\$
3
  • \$\begingroup\$ I've tried that, but it destroys r0. \$\endgroup\$
    – Mike L.
    Jul 11, 2011 at 20:17
  • \$\begingroup\$ I think you need to do something like this: codesearch.google.com/#Pnoc7erC9_w/trunk/Micropendous/libs/… \$\endgroup\$ Jul 11, 2011 at 20:37
  • \$\begingroup\$ @Joby - I get Sorry, this content is currently unavailable. Our engineers are working to resolve this issue. Please try again in a few minutes. Can you drop that sample into your answer? \$\endgroup\$ Jul 11, 2011 at 21:16
1
\$\begingroup\$

The problem was the usage of r0. With r16 it works:

ISR(INT0_vect, ISR_NAKED) {
    asm volatile(
    "push r16             \n\t"
    "ldi  r16, %[value]   \n\t"
    "sts  %[ioReg], r16   \n\t"
    "pop  r16             \n\t"
    "reti                 \n\t"
    : // output
    : // input
       [ioReg] "M" (_SFR_IO_ADDR(TCCR1B)),
       [value] "M" (0 << ICNC1
                  | 0 << ICES1 
                  | 0 << WGM13 
                  | 1 << WGM12
                  | 0 << CS12
                  | 0 << CS11 
                  | 1 << CS10)
    );
}
\$\endgroup\$
1
  • \$\begingroup\$ With the AVR only registers 16 and above can be used for the "ldi" instruction. \$\endgroup\$
    – MattyZ
    Jul 13, 2011 at 0:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.