AVR GCC Inline Assembler - Cookbook.PDF

(52 KB) Pobierz
305453302 UNPDF
GCC-AVR
Inline Assembler
Cookbook
Version 1.6
About this Document
Maintanance of this document has stopped. Most parts have been integrated
into the AVR Libc User's Manual, which can be downloaded from
The GNU C compiler for Atmel AVR RISC processors offers, to embed assembly language code into
C programs. This cool feature may be used for manually optimizing time critical parts of the software
or to use specific processor instruction, which are not available in the C language.
Because of a lack of documentation, especially for the AVR version of the compiler, it may take some
time to figure out the implementation details by studying the compiler and assembler source code.
There are also a few sample programs available in the net. Hopefully this document will help to
increase their number.
It's assumed, that you are familiar with writing AVR assembler programs, because this is no AVR
assembler programming tutorial. It's no C language tutorial either.
Copyright (C) 2001-2002 by egnite Software GmbH
Permission is granted to copy and distribute verbatim copies of this manual provided that the copyright
notice and this permission notice are preserved on all copies. Permission is granted to copy and
distribute modified versions of this manual provided that the entire resulting derived work is distributed
under the terms of a permission notice identical to this one.
This document describes version 3.2 of the compiler. There may be some parts, which hadn't been
completely understood by the author himself and not all samples had been tested so far. Because the
author is German and not familiar with the English language, there are definitely some typos and
syntax errors in the text. As a programmer the author knows, that a wrong documentation sometimes
might be worse than none. Anyway, he decided to offer his little knowledge to the public, in the hope
to get enough response to improve this document.
Herne, 22 nd of August 2002
Harald Kipp
GCC-AVR Inline Assembler Cookbook
1/13
Contents
History
05/07/01 V 1.1: Output and input lists sequence corrected in chapter 1. Multibyte operands added.
Index added. Some typos corrected.
05/07/01 V 1.2: subi replaced by inc in clobber samples. Pointer type is mandantory.
05/07/01 V 1.3: Pointer register modifier added.
05/16/02 V 1.4: Fixed the funny "risk" typo. New chapters C Names, FAQ and Links added.
08/10/02 V 1.5: Fixed vairable name in clobber section. New chapter C stub functions added.
08/22/02 V 1.6: Added a note about integration into the official AVR Libc.
GCC-AVR Inline Assembler Cookbook
2/13
1 GCC Statement asm
Let's start with a simple example of reading a value from port D:
asm("in %0, %1" : "=r" (value) : "I" (PORTD) : );
Each asm statement is devided by colons into four parts:
1. The assembler instructions, defined as a single string constant:
"in %0, %1"
2. A list of output operands, separated by commas. Our example uses just one:
"=r" (value)
3. A comma separated list of input operands. Again our example uses one operand only:
"I" (PORTD)
4. Clobbered registers, left empty in our example.
You can write assembler instructions in much the same way like normal assembler programs.
However, registers and constants are used in a different way, if they refer to expressions of your C
program. The connection between registers and C operands is specified in the second and third part
of the asm instruction, resp. the list of input and output operands. The general form is
asm(code : output operand list : input operand list : clobber list);
In the code section operands are refered by a percent sign followed by a single digit. %0 refers to the
first %1 to the second operand and so forth. In example above
%0 refers to "=r" (value) and
%1 refers to "P" (port) .
This may still look a little odd now, but the syntax of an operand list will be explained soon. Let us first
look to that part of a compiler listing, which may have been generated from our example:
lds r24,value
/* #APP */
in r24, 12
/* #NOAPP */
sts value,r24
The comments have been added by the compiler to inform the assembler, that the included code has
not been generated by the compilation of C statements, but by inline assembler statements. The
compiler selected r24, to get the value. It may have selected any other register, though. It may not
explicitely load or store the value and it may even decide not to include your assembler code at all. All
these decisions are part of the compiler's optimization strategie. For example, if you never use the
variable value in the remaining part of the C program, the compiler will most likely remove your code,
unless you switched off optimization. To avoid this, you can add the volatile attribute to the asm
statement:
asm volatile("in %0, %1" : "=r" (value) : "I" (PORTD) : );
The last part of the asm instruction, the clobber list, is mainly used to tell the compiler about
modifications done by the assembler code. This part may be omitted, all other parts are required, but
may be left empty. If your assembler routine won't use any input or output operand, still two colons
must follow the assembler code string. A good example is a simple statement to disable interrupts:
asm volatile("cli"::);
GCC-AVR Inline Assembler Cookbook
3/13
2 Assembler Code
You can use the same assembler instruction mnemonics, as you'd use with any other AVR assembler.
And you can write as many assembler statements into one code string as you like and your flash
memory is able to hold.
To make it more readable, you should put each statement on a seperate line:
asm volatile("nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
::);
The linefeed and tab characters will make the assembler listing generated by the compiler more
readable. It may look a bit odd for the first time, but that's the way the compiler creates it's own
assembler code.
You may also make use of some special registers.
Symbol Register
__SREG__ Status register at address
0x3F
__SP_H__ Stack pointer high byte at
address 0x3E
__SP_L__ Stack pointer low byte at
address 0x3D
__tmp_reg__ Register r0, used for
temporary storage
__zero_reg__ Register r1, always zero
_PC_
Register r0 may be freely used by your assembler code and need not to be restored at the end of your
code. It's a good idea to use __tmp_reg__ and __zero_reg__ instead of r0 or r1, just in case a new
compiler version might change the register definitions.
GCC-AVR Inline Assembler Cookbook
4/13
Program counter
305453302.001.png
3 Input and Output Operands
Each input and output operand is described by a constraint string followed by a C expression in
parantheses. GCC-AVR 2.9.5.2 knows the following constraint characters:
Constrain
t
Used for
Range
a
Simple upper registers
r16 to r23
b
Base pointer registers pairs y,z
d
Upper register
r16 to r31
e
Pointer register pairs
x,y,z
G
Floating point constant
0.0
I
6-bit positive integer
constant
0 to 63
J
6-bit negative integer
constant
-63 to 0
K
Integer constant
2
L
Integer constant
0
l
Lower registers
r0 to r15
M
8-bit integer constant
0 to 255
n
16-bit integer constant?
N
Integer constant
-1
O
Integer constant
8, 16, 24
P
Integer constant
1
q
Stack pointer register
SPH:SPL
r
Any register
r0 to r31
t
Temporary register
r0
v
32-bit integer constant?
w
Special upper register pairs r24, r26, r28, r30
x
Pointer register pair X
x (r27:r26)
y
Pointer register pair Y
y (r29:r28)
z
Pointer register pair Z
z (r31:r30)
These definitions seem not to fit properly to the AVR instruction set. The author's assumption is, that
this part of the compiler has never been really finished in this version, but that assumption may be
wrong. The selection of the proper contraint depends on the range of the constants or registers, which
must be acceptable to the AVR instruction they are used with. The C compiler doesn't check any line
of your assembler code. But it is able to check the constraint against your C expression. However, if
you specify the wrong constraints, then the compiler may silently pass wrong code to the assembler.
And, of course, the assembler will fail with some cryptic output or internal errors. For example, if you
specify the constraint "r" and you are using this register with an "ori" instruction in your assembler
code, then the compiler may select any register. This will fail, if the compiler chooses r2 to r15. (It will
never choose r0 or r1, because these are uses for special purposes.) That's why the correct constraint
in that case is "d". On the other hand, if you use the constraint "M", the compiler will take care, that
you don't pass anything else but an 8-bit value. Later on we will see, how to pass multibyte expression
results to the assembler code.
The following table shows all AVR assembler mnemonics, which require operands, and the related
contraints. Because of the improper constraint definitions in version 2.9.5.2, they aren't strict enough.
There is, for example, no constraint, which restricts integer constants to the range 0 to 7 for bit set and
bit clear operations.
Mnemo Constraint
s
adc r,r
add r,r
adiw w,I
and r,r
andi d,M
asr r
bclr I
bld r,I
brbc I,label
brbs I,label
bset I
bst r,I
cbi I,I
cbr d,I
com r
cp r,r
cpc r,r
cpi d,M
cpse r,r
dec r
elpm t,z
eor r,r
in r,I
inc r
ld r,e
ldd r,b
ldi d,M
lds r,label
lpm t,z
lsl r
lsr r
mov r,r
mul r,r
neg r
or r,r
ori d,M
out I,r
pop r
push r
rol r
ror r
sbc r,r
sbci d,M
sbi I,I
sbic I,I
sbiw w,I
sbr d,M
sbrc r,I
sbrs r,I
ser d
st e,r
std b,r
sts label,r
sub r,r
subi d,M
swap r
GCC-AVR Inline Assembler Cookbook
5/13
305453302.002.png
Zgłoś jeśli naruszono regulamin