<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
		<id>https://rn-wissen.de/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Rdiez</id>
		<title>RN-Wissen.de - Benutzerbeiträge [de]</title>
		<link rel="self" type="application/atom+xml" href="https://rn-wissen.de/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Rdiez"/>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Spezial:Beitr%C3%A4ge/Rdiez"/>
		<updated>2026-04-12T07:17:25Z</updated>
		<subtitle>Benutzerbeiträge</subtitle>
		<generator>MediaWiki 1.25.1</generator>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Inline-Assembler_in_avr-gcc&amp;diff=17581</id>
		<title>Inline-Assembler in avr-gcc</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Inline-Assembler_in_avr-gcc&amp;diff=17581"/>
				<updated>2011-07-20T09:45:19Z</updated>
		
		<summary type="html">&lt;p&gt;Rdiez: Beispiel &amp;quot;Multiplikation 16x16 auf 32 von .S ins Inline-Assembler übersetzt&amp;quot; eingefügt.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In C versteht man unter '''Inline Assembler''' die Möglichkeit, direkt Assembler-Befehle in den Code einzufügen bzw. die eingefügten Assembler-Befehle selbst. &lt;br /&gt;
&lt;br /&gt;
Neben den einzufügenden Befehlen muss beschrieben werden, welche Nebeneffekte die Befehle auf die Maschine haben und wo/wie Parameter übergeben werden, bzw. wie die Zuordnung von Variablen zu den Registern ist. Diese Beschreibung ist notwendig weil der [[Compiler]] keine Vorstellung davon hat, welche Effekte und Nebenwirkungen die Assembler-Kommandos auf Register, Variablen und Speicher haben, denn der Assembler-Schnippsel ist für den Compiler lediglich eine &amp;quot;Black Box&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Obgleich das dazu verwendete Schlüsselwort &amp;lt;tt&amp;gt;__asm&amp;lt;/tt&amp;gt; zum ANSI-C-Standard gehört, ist dies in jedem C-Compiler anders implementiert. Das gilt insbesondere für die Schnittstellenbeschreibung Variablen/Register. Dieser Artikel bezieht sich auf den Inline Assembler von [[avr-gcc]]. &lt;br /&gt;
Viele Erklärungen aus diesem Artikel sind auch gültig für Inline-Assembler anderer C-Compiler der  [[gcc]]-Familie. Instruktionen und Registerklassen werden sich aber unterscheiden, weil diese natürlich abhängig sind vom verwendeten Controller bzw. der Controller-Familie.&lt;br /&gt;
&lt;br /&gt;
=Assembler oder Inline-Assembler?=&lt;br /&gt;
;Assembler: Längere und komplexere Code-Stücke sind komfortabler direkt in Assembler auszudrücken. Dazu schreibt man Assembler-Funktionen und ruft diese von C aus auf. Natürlich können auch C-Funktionen von Assembler aus aufgerufen werden. Zudem kann man im Assembler den C-Präprozessor nutzen, was bei Inline-Assembler nur auf C-Ebene geht. Der Build-Prozess wird allerdings komplizierter, da extra asm-Dateien übersetzt werden müssen. Ein typischer Fall ist es, eine komplette ISR in Assembler zu schreiben.&lt;br /&gt;
;Inline-Assembler: Mit Inline-Assembler kann man kleine Assembler-Stückchen direkt in den C-Code einbetten. Es muss dann keine Assembler-Funktion aufgerufen werden. Dies kann von der Registerverwendung her deutlich günstiger sein, da [[gcc]] genau weiß, welche Register gebraucht werden und welche nicht. &lt;br /&gt;
:Eine (Assembler-)Funktion ist hingegen eine Black Box, bei der von der Standard-[[avr-gcc/Interna#Registerverwendung|Registerverwendung]] ausgegangen werden muss, auch wenn weniger Register in der Funktion verwendet werden. Ein Funktionsaufruf bedeutet also meistens einen Laufzeit-Overhead im Vergleich zu einem Inline-Code. &lt;br /&gt;
:Bei mehrfacher Verwendung einer längeren Codesequenz ist eine Funktion jedoch sparsamer im [[Flash]]-Verbrauch. Legt man eine Funktion als C-Funktion an und ihren Body als Inline-Assembler (eine s.g. Stub-Funktion, von engl. ''Stub'' = Stumpf), dann übernimmt gcc das Verwalten von Funktions-Argumenten, return-Wert, etc. und man brauch sich nicht selber um die Aufruf-Konvention zu kümmern. Auch innerhalb einer Funktion kann C mit Assembler gemischt werden.&lt;br /&gt;
:Ein Vorteil von Inline-Assembler ist, daß eine C-Funktion, die Inline-Assembler enthält, vom C-Compiler [[C-Tutorial#Inlining|geinlinet]] werden kann. Dies ist mit einer reinen Assembler-Funktion nicht möglich.&lt;br /&gt;
&lt;br /&gt;
=Begriffe=&lt;br /&gt;
;Assembler-Template: Das Template (''Schablone'') ist ein statischer, konstanter String im Sinne von C. Es enthält die Assembler-Befehle sowie Platzhalter, in deren Stelle später die Operanden treten&lt;br /&gt;
;Constraint: Die Constraints (''Nebenbedingungen'') beschreiben Einschränkungen an die zu verwendeten Register. Dies ist notwendig, da nicht alle Maschinenbefehle auf alle Register anwendbar sind&lt;br /&gt;
;Clobber-List: Das ist eine Liste von Registern, deren Inhalt durch den Inline-Assembler zerstört wird&lt;br /&gt;
&lt;br /&gt;
=Syntax und Semantik=&lt;br /&gt;
Das Schlüsselwort, um eine Inline-Assembler Sequenz einzuleiten, ist &amp;lt;tt&amp;gt;__asm&amp;lt;/tt&amp;gt; (ANSI). Oft ist auch &amp;lt;tt&amp;gt;asm&amp;lt;/tt&amp;gt; oder &amp;lt;tt&amp;gt;__asm__&amp;lt;/tt&amp;gt; verwendbar. Um zu kennzeichnen, daß die Sequenz keinesfalls wegoptimiert werden darf &amp;amp;ndash; etwa dann, wenn der Assembler keine Wirkung auf C-Variablen hat &amp;amp;ndash; wird dem &amp;lt;tt&amp;gt;asm&amp;lt;/tt&amp;gt; ein &amp;lt;tt&amp;gt;volatile&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;__volatile&amp;lt;/tt&amp;gt; nachgestellt. Danach folgen in runden Klammern die durch &amp;lt;tt&amp;gt;''':'''&amp;lt;/tt&amp;gt; getrennten Abschnitte des Inline-Assemblers:&lt;br /&gt;
 asm volatile ([[#Assembler-Template|asm-template]] : [[#Operanden und Constraints|output-operand-list]] : [[#Operanden und Constraints|input-operand-list]] : [[#Clobbers|clobber-list]]);&lt;br /&gt;
&lt;br /&gt;
Abschnitte, die leer sind, können auch weggelassen werden, wenn dahinter kein weiterer Abschnitt folgt:&lt;br /&gt;
 asm volatile (asm-template);&lt;br /&gt;
&lt;br /&gt;
Oder, wenn weder Input- noch Output-Operanden gebraucht werden, aber Register oder Speicher verändert werden:&lt;br /&gt;
 asm volatile (asm-template ::: clobber-list);&lt;br /&gt;
&lt;br /&gt;
{{FarbigerRahmen |&lt;br /&gt;
Aus Compiler-Sicht werden die Assembler-Befehle im Template parallel, also ''gleichzeitig'' ausgeführt! Dies ist zu bedenken, wenn Register sowohl als Input als auch als Output verwendet werden.&lt;br /&gt;
}} &lt;br /&gt;
&lt;br /&gt;
==Assembler-Template==&lt;br /&gt;
&lt;br /&gt;
Im Template stehen die durch Zeilenumbrüche getrennten Assembler-Befehle. Das Template kann zudem &amp;lt;tt&amp;gt;%&amp;lt;/tt&amp;gt;-Ausdrücke als Platzhalter enthalten, welche durch die Operanden ersetzt werden. Dabei bezieht sich &amp;lt;tt&amp;gt;%0&amp;lt;/tt&amp;gt; auf den ersten Operanden, &amp;lt;tt&amp;gt;%1&amp;lt;/tt&amp;gt; auf den zweiten Operanden, etc. Die Operanden selbst werden im zweiten und dritten Abschnitt des Templates als Komma-getrennte Liste angegeben.&lt;br /&gt;
&lt;br /&gt;
Ein Platzhalter kann zusätzlich einen einbuchstabigen Modifier enthalten, um ein Register in einem speziellen Format darzustellen. Wird z.B. ein Wert ab Register &amp;lt;tt&amp;gt;r28&amp;lt;/tt&amp;gt; (dem Y-Register) gehalten, dann wären folgende Ersetzungen denkbar (als erstes Argument):&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;tt&amp;gt;%0&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;rarr;&amp;amp;nbsp;&amp;amp;nbsp;r28&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;tt&amp;gt;%A0&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;rarr;&amp;amp;nbsp;&amp;amp;nbsp;r28&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;tt&amp;gt;%B0&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;rarr;&amp;amp;nbsp;&amp;amp;nbsp;r29&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;tt&amp;gt;%C0&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;rarr;&amp;amp;nbsp;&amp;amp;nbsp;r30&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;tt&amp;gt;%D0&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;rarr;&amp;amp;nbsp;&amp;amp;nbsp;r31&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;tt&amp;gt;%a0&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;rarr;&amp;amp;nbsp;&amp;amp;nbsp;y&amp;amp;nbsp;&amp;amp;nbsp;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im einfachsten Falle enthält das Templater nur einen Befehl:&lt;br /&gt;
 &amp;quot;nop&amp;quot;&lt;br /&gt;
oder sogar garkeinen Befehl und lediglich einen Kommentar:&lt;br /&gt;
 &amp;quot;; ein Kommentar&amp;quot;&lt;br /&gt;
&lt;br /&gt;
:{| {{Blauetabelle}}&lt;br /&gt;
|+ '''Tabelle: asm-Platzhalter und ihre Modifier, Sonderzeichen'''&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! Platzhalter || wird ersetzt durch&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;%''n''&amp;lt;/tt&amp;gt; || Wird ersezt durch Argument &amp;lt;tt&amp;gt;''n''&amp;lt;/tt&amp;gt; mit &amp;lt;tt&amp;gt;''n''&amp;lt;/tt&amp;gt; = 0...9&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;%A''n''&amp;lt;/tt&amp;gt; || das erste (untere) Register des Arguments &amp;lt;tt&amp;gt;''n''&amp;lt;/tt&amp;gt; (Bits 0...7)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;%B''n''&amp;lt;/tt&amp;gt; || das zweite Register des Arguments &amp;lt;tt&amp;gt;''n''&amp;lt;/tt&amp;gt; (Bits 8...15)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;%C''n''&amp;lt;/tt&amp;gt; || das dritte Register des Arguments &amp;lt;tt&amp;gt;''n''&amp;lt;/tt&amp;gt; (Bits 16...23)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;%D''n''&amp;lt;/tt&amp;gt; || das vierte Register des Arguments &amp;lt;tt&amp;gt;''n''&amp;lt;/tt&amp;gt; (Bits 24...31)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;%a''n''&amp;lt;/tt&amp;gt; || Ausgabe des Arguments als Adress-Register,&amp;lt;br/&amp;gt;also als &amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;y&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;z&amp;lt;/tt&amp;gt;. Erlaubt zusammen mit Constraint &amp;lt;tt&amp;gt;b&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;e&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;y&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;z&amp;lt;/tt&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;%~&amp;lt;/tt&amp;gt; || wird auf AVR mit Flash bis max. 8kByte durch ein &amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt; ersetzt, ansonsten bleibt es leer.&amp;lt;br/&amp;gt;Zum Aufbau von Sprungbefehlen, etwa &amp;quot;&amp;lt;tt&amp;gt;%~call foo&amp;lt;/tt&amp;gt;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;%=&amp;lt;/tt&amp;gt; || eine für dieses asm-Template und die Übersetzungseinheit eindeutige Zahl.&amp;lt;br/&amp;gt;Zum Aufbau  lokaler Sprungmarken.&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! Sequenz || wird ersetzt durch Sonderzeichen&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;%%&amp;lt;/tt&amp;gt; || das &amp;lt;tt&amp;gt;%&amp;lt;/tt&amp;gt;-Zeichen selbst&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;\n&amp;lt;/tt&amp;gt; || ein Zeilenumbruch&amp;lt;br/&amp;gt;zum Trennen mehrerer asm-Befehle/Zeilen&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;\t&amp;lt;/tt&amp;gt; || ein TAB, zur Übersichtlichkeit im erzeugten asm&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;\&amp;quot;&amp;lt;/tt&amp;gt; || ein &amp;lt;tt&amp;gt;&amp;quot;&amp;lt;/tt&amp;gt; wird eingefügt&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;\\&amp;lt;/tt&amp;gt; || das &amp;lt;tt&amp;gt;\&amp;lt;/tt&amp;gt;-Zeichen selbst&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! Kommentar || Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;; ''Text''&amp;lt;/tt&amp;gt; || einzeiliger Kommentar bis zum Ende des Templates bzw. nächsten Zeilenumbruch&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;/* ''Text'' */&amp;lt;/tt&amp;gt; || mehrzeiliger Kommentar wie in C&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Operanden und Constraints==&lt;br /&gt;
&lt;br /&gt;
Ein Operand besteht aus der Angabe des Constraint-Strings (also der Registerklasse und Kennzeichnung, ob es sich um einen Output-Operanden handelt) und dahinter in runden Klammern der C-Ausdruck, der in Register der angegebenen Klasse geladen werden soll. Die Operanden werden mit 0 beginnend von links nach rechts durchnumeriert und über diese Nummer angesprochen, um sie ins Assembler-Schnippsel einzufügen.&lt;br /&gt;
&lt;br /&gt;
Mehrere Input- bzw. Output-Operanden werden durch Komma getrennt.&lt;br /&gt;
&lt;br /&gt;
:{| {{Blauetabelle}}&lt;br /&gt;
|+ '''Tabelle: Constraints und ihre Bedeutung'''&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! Constraint || Register || Wertebereich&lt;br /&gt;
|rowspan=&amp;quot;14&amp;quot;|&amp;amp;nbsp;&lt;br /&gt;
! Constraint || Konstante || Wertebereich&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;a&amp;lt;/tt&amp;gt;||einfache obere Register||&amp;lt;tt&amp;gt;r16&amp;lt;/tt&amp;gt;...&amp;lt;tt&amp;gt;r23&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;G&amp;lt;/tt&amp;gt;||Floatingpoint-Konstante ||&amp;lt;tt&amp;gt;0.0&amp;lt;/tt&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;b&amp;lt;/tt&amp;gt;||Pointer-Register ||&amp;lt;tt&amp;gt;y&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;z&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;i&amp;lt;/tt&amp;gt;||Konstante ||&amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;d&amp;lt;/tt&amp;gt;||obere Register ||&amp;lt;tt&amp;gt;r16&amp;lt;/tt&amp;gt;...&amp;lt;tt&amp;gt;r31&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;I&amp;lt;/tt&amp;gt;||positive 6-Bit-Konstante ||0...63&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;e&amp;lt;/tt&amp;gt;||Pointer-Register ||&amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;y&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;z&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;J&amp;lt;/tt&amp;gt;||negative 6-Bit Konstante ||&amp;lt;tt&amp;gt;-&amp;lt;/tt&amp;gt;63...0&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;l&amp;lt;/tt&amp;gt;||untere Register ||&amp;lt;tt&amp;gt;r0&amp;lt;/tt&amp;gt;...&amp;lt;tt&amp;gt;r15&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;M&amp;lt;/tt&amp;gt;||8-Bit Konstante ||0...255&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;q&amp;lt;/tt&amp;gt;||Stack-Pointer ||&amp;lt;tt&amp;gt;SPH:SPL&amp;lt;/tt&amp;gt;&lt;br /&gt;
|colspan=&amp;quot;3&amp;quot; |&amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt;||ein Register ||&amp;lt;tt&amp;gt;r0&amp;lt;/tt&amp;gt;...&amp;lt;tt&amp;gt;r31&amp;lt;/tt&amp;gt;&lt;br /&gt;
!{{Hintergrund1}}| Constraint ||{{Hintergrund1}}| Memory ||{{Hintergrund1}}| Wertebereich&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt;||Scratch-Register ||&amp;lt;tt&amp;gt;r0&amp;lt;/tt&amp;gt;&lt;br /&gt;
|&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;|| Memory || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;||obere Register-Paare ||&amp;lt;tt&amp;gt;r24&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;r26&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;r28&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;r30&amp;lt;/tt&amp;gt;&lt;br /&gt;
|colspan=&amp;quot;3&amp;quot; rowspan=&amp;quot;5&amp;quot;|&amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt;||Pointer-Register X ||&amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;r27:r26&amp;lt;/tt&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;y&amp;lt;/tt&amp;gt;||Pointer-Register Y ||&amp;lt;tt&amp;gt;y&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;r29:r28&amp;lt;/tt&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;z&amp;lt;/tt&amp;gt;||Pointer-Register Z ||&amp;lt;tt&amp;gt;z&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;r31:r30&amp;lt;/tt&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;0&amp;lt;/tt&amp;gt;...&amp;lt;tt&amp;gt;9&amp;lt;/tt&amp;gt;||colspan=&amp;quot;2&amp;quot;|Identisch mit dem angegebenen Operanden&amp;lt;br/&amp;gt;Wird verwendet, wenn ein Operand sowohl als Input&amp;lt;br/&amp;gt;als auch als Output dient, um sich auf diesen&amp;lt;br/&amp;gt;Operanden zu beziehen&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:{| {{Blauetabelle}}&lt;br /&gt;
|+ '''Tabelle: Constraint Modifier'''&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
!Modifier || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;=&amp;lt;/tt&amp;gt; || der Operand ist Output-Operand&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;&amp;amp;&amp;lt;/tt&amp;gt; || diesen Operanden ''nicht'' als Input-Operanden verwenden,&amp;lt;br/&amp;gt;sondern nur als Output-Operand&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;+&amp;lt;/tt&amp;gt; || dieser Operanden ist Input- und Output-Operand&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ein Input-Operand könnte also so aussehen, wobei &amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt; eine C-Variable ist. Als Register dient ein (je nach Typ von &amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt; auch mehrere) obere Register, irgendwo von &amp;lt;tt&amp;gt;r16&amp;lt;/tt&amp;gt; bis &amp;lt;tt&amp;gt;r31&amp;lt;/tt&amp;gt; (Constraint &amp;lt;tt&amp;gt;&amp;quot;d&amp;quot;&amp;lt;/tt&amp;gt;):&lt;br /&gt;
 &amp;quot;d&amp;quot; (foo)&lt;br /&gt;
&lt;br /&gt;
In den Klammern kann ein beliebiger, gültiger C-Ausdruck stehen, der beim folgenden Beispiel in irgendeinem Register landet (Constraint &amp;lt;tt&amp;gt;&amp;quot;r&amp;quot;&amp;lt;/tt&amp;gt;), ohne weitere Einschränkung an das Register:&lt;br /&gt;
 &amp;quot;r&amp;quot; ((foo &amp;gt;= 0) ? foo : -foo)&lt;br /&gt;
&lt;br /&gt;
Um einen Operanden als Output-Operanden zu kennzeichnen, wird dem Constraint ein &amp;lt;tt&amp;gt;&amp;quot;=&amp;quot;&amp;lt;/tt&amp;gt; vorangestellt.&lt;br /&gt;
Soll &amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt; ein Output-Operand sein, der in den Registern &amp;lt;tt&amp;gt;r0&amp;lt;/tt&amp;gt;...&amp;lt;tt&amp;gt;r15&amp;lt;/tt&amp;gt; landen soll (Constraint &amp;lt;tt&amp;gt;&amp;quot;l&amp;quot;&amp;lt;/tt&amp;gt;, sieht es so aus. Dabei muss &amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt; ein sogenannter Lvalue sein, also ein Wert, dem etwas zugewiesen werden kann:&lt;br /&gt;
 &amp;quot;=l&amp;quot; (foo)&lt;br /&gt;
&lt;br /&gt;
Ist &amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt; sowohl Input als auch Output, schreibt man &amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt; als Output- und als Input-Operand hin. In der Input-Constraint bezieht man sich dann auf die Operanden-Nummer von &amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt;. Hier ein komplettes Beispiel, das die Nibbles von &amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt; tauscht. Weil &amp;lt;tt&amp;gt;swap&amp;lt;/tt&amp;gt; auf alle Register anwendbar ist, kann als Registerklasse &amp;lt;tt&amp;gt;&amp;quot;r&amp;quot;&amp;lt;/tt&amp;gt; genommen werden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
unsigned char foo;&lt;br /&gt;
...&lt;br /&gt;
asm volatile (&amp;quot;swap %0&amp;quot; : &amp;quot;=r&amp;quot; (foo) : &amp;quot;0&amp;quot; (foo));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt; als Input-Operand soll im gleichen Register liegen wie &amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt; als Output-Operand. Daher wird als Constraint &amp;lt;tt&amp;gt;&amp;quot;0&amp;quot;&amp;lt;/tt&amp;gt; angegeben, d.h. es wird ins gleiche Register geladen wie der Operand Numero&amp;amp;nbsp;0 &amp;lt;tt&amp;gt;&amp;quot;r&amp;quot; (foo)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Benannte Constraints ===&lt;br /&gt;
&lt;br /&gt;
Um das Assembler-Schnippsel besser lesbar zu halten, kann man Constraints einen Namen geben:&lt;br /&gt;
 asm volatile (&amp;quot;swap %[bar]&amp;quot; : [bar] &amp;quot;+r&amp;quot; (foo));&lt;br /&gt;
Damit ist der Assembler auch unabhängig von der Reihenfolge der Operanden. Das macht die Anpassung, wenn ein neuer Operand hinzukommt, wesentlich einfacher und den Schnippsel zudem besser lesbar. &lt;br /&gt;
&lt;br /&gt;
Hier wird &amp;lt;tt&amp;gt;bar&amp;lt;/tt&amp;gt; als Alias für die C-Variable &amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt; benutzt; es könnte aber auch jeder andere gültige C-Bezeichner sein, also insbesondere auch &amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Instruktionen und Constraints===&lt;br /&gt;
Die folgende Tabelle enhält eine Auflistung von AVR-Instruktionen und dazu passende Argumente bzw. Constraints. Nicht alle Shorthands sind in der Tabelle enthalten, so ist &amp;quot;&amp;lt;tt&amp;gt;clr Rn&amp;lt;/tt&amp;gt;&amp;quot; nur eine Abkürzung für &amp;quot;&amp;lt;tt&amp;gt;eor Rn, Rn&amp;lt;/tt&amp;gt;&amp;quot;, ähnliches gilt für den Zoo von Instruktionen rund um das SREG wie  branch, bit set, bit clear, etc., die im Endeffekt auf nur vier Instruktionen abbilden. Instruktionen wie &amp;lt;tt&amp;gt;nop&amp;lt;/tt&amp;gt;, die keine Argumente brauchen, sind ebenfalls nicht in der Tabelle enthalten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;quot;load&amp;quot;&amp;lt;/tt&amp;gt; ist ein &amp;lt;tt&amp;gt;&amp;quot;load from SRAM&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;&amp;quot;store&amp;quot;&amp;lt;/tt&amp;gt; ist &amp;lt;tt&amp;gt;&amp;quot;store to SRAM&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
:{| {{Blauetabelle}}&lt;br /&gt;
|+'''Tabelle: Übersicht AVR-Instruktionen und passende Constraints'''&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
!Mnemonic || Constraint ||Bedeutung ||rowspan=&amp;quot;32&amp;quot;|&amp;amp;nbsp;&lt;br /&gt;
!Mnemonic || Constraint ||Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;adc&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt;  || add with carry&lt;br /&gt;
| &amp;lt;tt&amp;gt;add&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt;  || add&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;adiw&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;w,I&amp;lt;/tt&amp;gt; || add immediate to word&lt;br /&gt;
| &amp;lt;tt&amp;gt;and&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt;  || and&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;andi&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;d,M&amp;lt;/tt&amp;gt; || and with immediate &lt;br /&gt;
| &amp;lt;tt&amp;gt;asr&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt;    || arithmetic shift right&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;bclr&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;I&amp;lt;/tt&amp;gt;   || bit clear in SREG&lt;br /&gt;
| &amp;lt;tt&amp;gt;bld&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,I&amp;lt;/tt&amp;gt;  || bit load from T&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;brbc&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;I,label&amp;lt;/tt&amp;gt; || branch if bit in SREG clear&lt;br /&gt;
| &amp;lt;tt&amp;gt;brbs&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;I,label&amp;lt;/tt&amp;gt; || branch if bit in SREG set&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;bset&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;I&amp;lt;/tt&amp;gt;  || bit set in SREG&lt;br /&gt;
| &amp;lt;tt&amp;gt;bst&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,I&amp;lt;/tt&amp;gt; || bit store from T&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;cbi&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;I,I&amp;lt;/tt&amp;gt; || clear bit in I/O&lt;br /&gt;
| &amp;lt;tt&amp;gt;com&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt;   || complement&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;cp&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt;  || compare&lt;br /&gt;
| &amp;lt;tt&amp;gt;cpc&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt; || compare with carry&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;cpi&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;d,M&amp;lt;/tt&amp;gt; || compare against immediate&lt;br /&gt;
| &amp;lt;tt&amp;gt;cpse&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt;|| compare, skip if equal&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;dec&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt;   || decrement&lt;br /&gt;
| &amp;lt;tt&amp;gt;elpm&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;t,z&amp;lt;/tt&amp;gt;|| extern: load from prog mem&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;eor&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt; || exclusive-or&lt;br /&gt;
| &amp;lt;tt&amp;gt;fmul*&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;a,a&amp;lt;/tt&amp;gt; || fractional multiply&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;in&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,I&amp;lt;/tt&amp;gt;  || input from I/O&lt;br /&gt;
| &amp;lt;tt&amp;gt;inc&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt;   || increment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;ld&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,e&amp;lt;/tt&amp;gt;  || load indirect&lt;br /&gt;
| &amp;lt;tt&amp;gt;ld&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,e+&amp;lt;/tt&amp;gt;  || load indirect, post-increment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;ld&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,-e&amp;lt;/tt&amp;gt;  || load indirect, pre-decrement&lt;br /&gt;
| &amp;lt;tt&amp;gt;ldd&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,b+I&amp;lt;/tt&amp;gt; || load indirect with displacement&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;ldi&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;d,M&amp;lt;/tt&amp;gt; || load immediate&lt;br /&gt;
| &amp;lt;tt&amp;gt;lds&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,label&amp;lt;/tt&amp;gt; || load direct from SRAM&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;lpm&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;t,z&amp;lt;/tt&amp;gt;     || load from prog mem&lt;br /&gt;
| &amp;lt;tt&amp;gt;lsr&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt;    || logical shift right&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;mov&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt;  || move&lt;br /&gt;
| &amp;lt;tt&amp;gt;movw&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt; || move word&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;mul&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt;  || multiply unsigned&lt;br /&gt;
| &amp;lt;tt&amp;gt;muls&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;d,d&amp;lt;/tt&amp;gt;  || multiply signed &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;mulsu&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;a,a&amp;lt;/tt&amp;gt;  || multiply signed/unsigned &lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;| &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;neg&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt;    || negate&lt;br /&gt;
| &amp;lt;tt&amp;gt;or&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt;   || or&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;ori&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;d,M&amp;lt;/tt&amp;gt;  || or with immediate&lt;br /&gt;
| &amp;lt;tt&amp;gt;out&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;I,r&amp;lt;/tt&amp;gt;  || output to I/O&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt;    || pop from Stack&lt;br /&gt;
| &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt;   || push to Stack&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;ror&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt;    || rotate right&lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;| &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;sbc&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt;  || subtract with carry&lt;br /&gt;
| &amp;lt;tt&amp;gt;sbci&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;d,M&amp;lt;/tt&amp;gt; || subtract with carry immediate&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;sbic&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;I,I&amp;lt;/tt&amp;gt; || skip if bit in I/O clear&lt;br /&gt;
| &amp;lt;tt&amp;gt;sbis&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;I,I&amp;lt;/tt&amp;gt; || skip if bit in I/O set&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;sbi&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;I,I&amp;lt;/tt&amp;gt;  || set Bit in I/O&lt;br /&gt;
| &amp;lt;tt&amp;gt;sbiw&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;w,I&amp;lt;/tt&amp;gt; || subtract immediate from word&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;sbrc&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,I&amp;lt;/tt&amp;gt; || skip if bit in register clear&lt;br /&gt;
| &amp;lt;tt&amp;gt;sbrs&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,I&amp;lt;/tt&amp;gt; || skip if bit in register set&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;st&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;e,r&amp;lt;/tt&amp;gt;  || store indirect&lt;br /&gt;
| &amp;lt;tt&amp;gt;st&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;e+,r&amp;lt;/tt&amp;gt;  || store indirect, post-increment&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;st&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;-e,r&amp;lt;/tt&amp;gt;  || store indirect, pre-decrement&lt;br /&gt;
| &amp;lt;tt&amp;gt;std&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;b,r&amp;lt;/tt&amp;gt; || store indirect with displacement&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;sts&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;label,r&amp;lt;/tt&amp;gt; || store direct&lt;br /&gt;
| &amp;lt;tt&amp;gt;sub&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r,r&amp;lt;/tt&amp;gt;  || subtract&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;subi&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;d,M&amp;lt;/tt&amp;gt; || subtract immediate&lt;br /&gt;
| &amp;lt;tt&amp;gt;swap&amp;lt;/tt&amp;gt;||&amp;lt;tt&amp;gt;r&amp;lt;/tt&amp;gt;   || swap nibbles&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
|-&lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|&amp;amp;nbsp;&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hier noch ein paar der gebräuchlichsten Shorthands und deren Abbildung auf &amp;quot;Basis&amp;quot;-Instruktionen:&lt;br /&gt;
&lt;br /&gt;
:{| {{Blauetabelle}}&lt;br /&gt;
|+'''Tabelle: Shorthands'''&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
!Shorthand || gleichbedeutend mit || Bedeutung ||rowspan=&amp;quot;5&amp;quot;|&amp;amp;nbsp;&lt;br /&gt;
!Shorthand || gleichbedeutend mit || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;asl r&amp;lt;/tt&amp;gt;   || &amp;lt;tt&amp;gt;addc r,r&amp;lt;/tt&amp;gt;    || arithmetic shift left&lt;br /&gt;
| &amp;lt;tt&amp;gt;cbr r,M&amp;lt;/tt&amp;gt; || &amp;lt;tt&amp;gt;andi  r, ~M&amp;lt;/tt&amp;gt; || clear bits in reg&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;clr r&amp;lt;/tt&amp;gt;   || &amp;lt;tt&amp;gt;eor  r,r&amp;lt;/tt&amp;gt;   || clear reg to zero &lt;br /&gt;
| &amp;lt;tt&amp;gt;lsl r&amp;lt;/tt&amp;gt;   || &amp;lt;tt&amp;gt;add  r,r&amp;lt;/tt&amp;gt;   || logical shift left&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;sbr d,M&amp;lt;/tt&amp;gt; || &amp;lt;tt&amp;gt;ori  d, M&amp;lt;/tt&amp;gt; || set bits in reg&lt;br /&gt;
| &amp;lt;tt&amp;gt;ser d&amp;lt;/tt&amp;gt;   || &amp;lt;tt&amp;gt;ldi  d, 0xff&amp;lt;/tt&amp;gt; || set all bits in reg&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;tst r&amp;lt;/tt&amp;gt;   || &amp;lt;tt&amp;gt;and  r,r&amp;lt;/tt&amp;gt;   || test against zero&lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|&amp;amp;nbsp;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Clobbers==&lt;br /&gt;
&lt;br /&gt;
In der Komma-getrennten Clobber-Liste kann man angeben, welche Register durch den Inline-Assembler ihren Wert ändern. Ändern z.B. &amp;lt;tt&amp;gt;r2&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;r3&amp;lt;/tt&amp;gt; ihre Werte, dann ist die Clobber-Liste&lt;br /&gt;
 &amp;quot;r2&amp;quot;, &amp;quot;r3&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Wird schreibend auf das RAM zugegriffen, dann muss man das auch mitteilen, damit RAM-Inhalte, die sich evtl. in Registern befinden, nach dem Inline-Assembler neu gelesen werden. Der Clobber dafür ist:&lt;br /&gt;
 &amp;quot;memory&amp;quot;&lt;br /&gt;
&lt;br /&gt;
'''Beispiel:'''&lt;br /&gt;
&lt;br /&gt;
Es soll ein Inline-Assembler geschrieben werden, das den Inhalt zweier aufeinanderfolgender Speicherstellen austauscht. Die Adresse soll in &amp;lt;tt&amp;gt;addr&amp;lt;/tt&amp;gt; stehen. Sie ist Input-Operand und muss in Register X, Y oder Z stehen, um den &amp;lt;tt&amp;gt;ld&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;st&amp;lt;/tt&amp;gt;-Befehl anwenden zu können. Die passende Constraint ist also &amp;lt;tt&amp;gt;&amp;quot;e&amp;quot;&amp;lt;/tt&amp;gt;. Nach der Sequenz liegt &amp;lt;tt&amp;gt;addr&amp;lt;/tt&amp;gt; unverändert vor.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   asm volatile (&lt;br /&gt;
      &amp;quot;ld r2,  %a0+&amp;quot;   &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;ld r3,  %a0&amp;quot;    &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;st %a0,  r2&amp;quot;    &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;st -%a0, r3&amp;quot;&lt;br /&gt;
         : /* keine Output-Operanden */&lt;br /&gt;
         : &amp;quot;e&amp;quot; (addr)&lt;br /&gt;
         : &amp;quot;r2&amp;quot;, &amp;quot;r3&amp;quot;, &amp;quot;memory&amp;quot;&lt;br /&gt;
   );&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
avr-gcc entscheidet sich dazu, das Z-Register für &amp;lt;tt&amp;gt;addr&amp;lt;/tt&amp;gt; zu verwenden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	ld r2,  Z+&lt;br /&gt;
	ld r3,  Z&lt;br /&gt;
	st Z,  r2&lt;br /&gt;
	st -Z, r3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Günstiger ist es jedoch, dem Compiler auch die Entscheidung zu überlassen, welche(s) Register als Hilfsregister verwendet werden sollen. Ein Register kann &amp;lt;tt&amp;gt;__tmp_reg__&amp;lt;/tt&amp;gt; sein, für das zweite  legen wir eine lokale 8-Bit-Variable &amp;lt;tt&amp;gt;hilf&amp;lt;/tt&amp;gt; an:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   {&lt;br /&gt;
      char hilf;&lt;br /&gt;
	&lt;br /&gt;
      asm volatile (&lt;br /&gt;
         &amp;quot;ld __tmp_reg__,  %a1+&amp;quot;           &amp;quot;\n\t&amp;quot;&lt;br /&gt;
         &amp;quot;ld %0,           %a1&amp;quot;            &amp;quot;\n\t&amp;quot;&lt;br /&gt;
         &amp;quot;st %a1,          __tmp_reg__&amp;quot;    &amp;quot;\n\t&amp;quot;&lt;br /&gt;
         &amp;quot;st -%a1,         %0&amp;quot;&lt;br /&gt;
            : &amp;quot;=&amp;amp;r&amp;quot; (hilf)&lt;br /&gt;
            : &amp;quot;e&amp;quot;   (addr)&lt;br /&gt;
            : &amp;quot;memory&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
   }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;tt&amp;gt;__tmp_reg__&amp;lt;/tt&amp;gt; (also &amp;lt;tt&amp;gt;r0&amp;lt;/tt&amp;gt;) brauch nicht in die Clobber-Liste aufgenommen zu werden. Um das zweite benötigte Register (hier &amp;lt;tt&amp;gt;r24&amp;lt;/tt&amp;gt;, in dem &amp;lt;tt&amp;gt;hilf&amp;lt;/tt&amp;gt; lebt) kümmert sich avr-gcc und sichert es, falls nötig&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
       	ld	r0, Z+&lt;br /&gt;
       	ld	r24, Z&lt;br /&gt;
       	st	Z, r0&lt;br /&gt;
       	st	-Z, r24&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{FarbigerRahmen |&lt;br /&gt;
Falls das Register &amp;lt;tt&amp;gt;r1&amp;lt;/tt&amp;gt; verändert wird &amp;amp;ndash; was z.B. geschieht, wenn man Multiplikationsbefehle verwendet &amp;amp;ndash; dann muss am Ende des Templates das Register wieder auf&amp;amp;nbsp;0 gesetzt werden, denn bei avr-gcc enthält dieses Register immer den Wert&amp;amp;nbsp;0.&lt;br /&gt;
Das Register in die Clobber-Liste aufzunehen bleibt wirkungslos. Hat man es zerstört,&lt;br /&gt;
dann schreibt man ans Ende des Templates ein&lt;br /&gt;
 clr __zero_reg__&lt;br /&gt;
und stellt es dadurch wieder her.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=Vordefinierte Bezeichner und Makros=&lt;br /&gt;
Je nach Assembler, für den avr-gcc Code erzeugt, gibt es unterschiedliche vordefinierte Funktionen/Makros, die von Inline-Assembler aus verwendbar sind.&lt;br /&gt;
&lt;br /&gt;
== GNU-Assembler ==&lt;br /&gt;
&lt;br /&gt;
:{| {{Blauetabelle}}&lt;br /&gt;
|+ '''Tabelle: vordefinierte Bezeichner/Makros&lt;br /&gt;
|- {{Hintergrund1}}&lt;br /&gt;
! Bezeichner || Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;__SP_L__&amp;lt;/tt&amp;gt; || unteres Byte des Stack-Pointers, für &amp;lt;tt&amp;gt;in&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;out&amp;lt;/tt&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;__SP_H__&amp;lt;/tt&amp;gt; || oberes Byte des Stack-Pointers, für &amp;lt;tt&amp;gt;in&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;out&amp;lt;/tt&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;__SREG__&amp;lt;/tt&amp;gt; || Status-Register, für &amp;lt;tt&amp;gt;in&amp;lt;/tt&amp;gt; bzw. &amp;lt;tt&amp;gt;out&amp;lt;/tt&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;__tmp_reg__&amp;lt;/tt&amp;gt; || ein Register zur temporären Verwendung (&amp;lt;tt&amp;gt;r0&amp;lt;/tt&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;__zero_reg__&amp;lt;/tt&amp;gt; || ein Register, das 0 enthält (&amp;lt;tt&amp;gt;r1&amp;lt;/tt&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;lo8(''const'')&amp;lt;/tt&amp;gt; || die unteren 8 Bit der Konstanten &amp;lt;tt&amp;gt;''const''&amp;lt;/tt&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;hi8(''const'')&amp;lt;/tt&amp;gt; || Bits 8...15 der Konstanten &amp;lt;tt&amp;gt;''const''&amp;lt;/tt&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;hlo8(''const'')&amp;lt;/tt&amp;gt; || Bits 16...23 der Konstanten &amp;lt;tt&amp;gt;''const''&amp;lt;/tt&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;hhi8(''const'')&amp;lt;/tt&amp;gt; || Bits 24...31 der Konstanten &amp;lt;tt&amp;gt;''const''&amp;lt;/tt&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;tt&amp;gt;pm(''const'')&amp;lt;/tt&amp;gt; || Konstante &amp;lt;tt&amp;gt;''const''&amp;lt;/tt&amp;gt; durch 2 geteilt,&amp;lt;br/&amp;gt;zur Berechnung von Flash-Adressen für &amp;lt;tt&amp;gt;icall&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;lpm&amp;lt;/tt&amp;gt; etc.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Beispiele=&lt;br /&gt;
&lt;br /&gt;
==nop==&lt;br /&gt;
Mit den bisherigen Vorkenntnissen ist zu &amp;lt;tt&amp;gt;nop&amp;lt;/tt&amp;gt; nicht viel zu sagen:&lt;br /&gt;
 asm volatile (&amp;quot;nop&amp;quot;);&lt;br /&gt;
Oder als C-Makro:&lt;br /&gt;
 #define nop() \&lt;br /&gt;
    asm volatile (&amp;quot;nop&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;nop&amp;lt;/tt&amp;gt; hat weder Input- noch Output-Operanden, und Register/RAM ändern sich natürlich nicht. Bei der Makro-Definition ist lediglich darauf zu achten, daß das Makro nicht mit einem&amp;amp;nbsp;&amp;lt;tt&amp;gt;;&amp;lt;/tt&amp;gt; endet, damit man den C-Code wie gewohnt mit&amp;amp;nbsp;&amp;lt;tt&amp;gt;;&amp;lt;/tt&amp;gt; schreiben kann:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (x)&lt;br /&gt;
   nop();&lt;br /&gt;
else&lt;br /&gt;
   ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==swap Nibbles==&lt;br /&gt;
Ein einfaches Beispiel für &amp;lt;tt&amp;gt;swap&amp;lt;/tt&amp;gt; haben wir bereits oben kennen gelernt. Der Inline-Assembler dreht die Nibbles von &amp;lt;tt&amp;gt;foo&amp;lt;/tt&amp;gt; um:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
unsigned char foo;&lt;br /&gt;
...&lt;br /&gt;
asm volatile (&amp;quot;swap %0&amp;quot; : &amp;quot;=r&amp;quot; (foo) : &amp;quot;0&amp;quot; (foo));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wünschenswert wäre eher, &amp;lt;tt&amp;gt;swap&amp;lt;/tt&amp;gt; wie eine normale C-Funktion verwenden zu können und hinzuschreiben:&lt;br /&gt;
 a = swap(b);&lt;br /&gt;
ohne daß &amp;lt;tt&amp;gt;b&amp;lt;/tt&amp;gt; seinen Wert ändert. Soll &amp;lt;tt&amp;gt;b&amp;lt;/tt&amp;gt; geswappt werden, dann via&lt;br /&gt;
 b = swap(b);&lt;br /&gt;
zudem soll das Argument ein Ausdruck sein können:&lt;br /&gt;
 if (b == swap (b+1))&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
Dazu verwenden wir eine lokale Variable &amp;lt;tt&amp;gt;__x__&amp;lt;/tt&amp;gt;, in die der ursprüngliche Wert &amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt; gesichert wird:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#define swap(x)                                            \&lt;br /&gt;
 ({                                                        \&lt;br /&gt;
    unsigned char __x__ = (unsigned char) x;               \&lt;br /&gt;
    asm volatile (&amp;quot;swap %0&amp;quot; : &amp;quot;=r&amp;quot; (__x__) : &amp;quot;0&amp;quot; (__x__)); \&lt;br /&gt;
    __x__;                                                 \&lt;br /&gt;
  })&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
alternativ könnten wir eine inline-Funktion definieren:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
static inline unsigned char swap (unsigned char x)&lt;br /&gt;
{&lt;br /&gt;
    asm volatile (&amp;quot;swap %0&amp;quot; : &amp;quot;=r&amp;quot; (x) : &amp;quot;0&amp;quot; (x));&lt;br /&gt;
    return x;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==swap Bytes==&lt;br /&gt;
Werden Zahlen zwischen verschiedenen Plattformen übertragen, kann es sein, daß diese unterschiedlich dargestellt werden: Das low-Byte kann in sich im unteren Byte befinden (AVR), es kann aber auch im oberen Byte sein. Ist das so, dann müssen die Werte beim Senden/Empfang umgewandelt werden, indem die Bytes getauscht werden. Liegt der 16-Bit-Wert in &amp;lt;tt&amp;gt;x_in&amp;lt;/tt&amp;gt; und soll der konvertierte Wert nach &amp;lt;tt&amp;gt;x_out&amp;lt;/tt&amp;gt; gespeichert werden, dann könnte man auf die Idee kommen, so etwas zu schreiben:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   asm volatile (&lt;br /&gt;
      &amp;quot;mov %A0, %B1&amp;quot;   &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;mov %B0, %A1&amp;quot;&lt;br /&gt;
         : &amp;quot;=r&amp;quot; (x_out)&lt;br /&gt;
         : &amp;quot;r&amp;quot;  (x_in)&lt;br /&gt;
   );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Daraus könnte folgender Code entstehen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     mov    r24, r25&lt;br /&gt;
     mov    r25, r24&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Das ist offenbar Käse! Was ist passiert? &lt;br /&gt;
&lt;br /&gt;
avr-gcc hat sich dazu entschieden, &amp;lt;tt&amp;gt;x_in&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;r25:r24&amp;lt;/tt&amp;gt; anzulegen. Auch &amp;lt;tt&amp;gt;x_out&amp;lt;/tt&amp;gt; wird in diesen Registern angelegt. Das ist erst mal in Ordnung, wenn &amp;lt;tt&amp;gt;x_in&amp;lt;/tt&amp;gt; nach dem Inline nicht mehr gebraucht wird. &lt;br /&gt;
&lt;br /&gt;
Allerdings wird das Inline nicht en bloc &amp;amp;mdash; also nicht zeitparallel &amp;amp;mdash; ausgeführt, sondern sequenziell. Bei ''gleichzeitiger'' Ausführung der beiden &amp;lt;tt&amp;gt;mov&amp;lt;/tt&amp;gt;-Instruktionen wäre auch nichts dagegen zu sagen! Ein &amp;lt;tt&amp;gt;swap&amp;lt;/tt&amp;gt;-Kommando z.B. tauscht die Nibbles ''gleichzeitig'', und der Input-Operand kann im gleichen Register leben wie der Output-Operand, wenn der Input nicht weiter verwendet wird. &lt;br /&gt;
&lt;br /&gt;
Mit den beiden Bytes geht es aber nicht. Wir müssen daher kennzeichnen, daß sich &amp;lt;tt&amp;gt;x_out&amp;lt;/tt&amp;gt; in einem Register befindet, das ''nur'' als Output dient, was durch das &amp;lt;tt&amp;gt;&amp;amp;&amp;lt;/tt&amp;gt; in der Output-Constraint erreicht wird:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   asm volatile (&lt;br /&gt;
      &amp;quot;mov %A0, %B1&amp;quot;   &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;mov %B0, %A1&amp;quot;&lt;br /&gt;
         : &amp;quot;=&amp;amp;r&amp;quot; (x_out)&lt;br /&gt;
         : &amp;quot;r&amp;quot;   (x_in)&lt;br /&gt;
   );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Damit erfolgt eine korrekte Registerzuordnung. &amp;lt;tt&amp;gt;x_out&amp;lt;/tt&amp;gt; steht jetzt in &amp;lt;tt&amp;gt;r19:r18&amp;lt;/tt&amp;gt; und überschneidet nich nicht mehr mit &amp;lt;tt&amp;gt;x_in&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
       	mov	r18, r25&lt;br /&gt;
       	mov	r19, r24&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alternativ können wir wie bei [[#swap Nibbles|swap Nibbles]] eine lokale Variable verwenden, und alles als (inline-)Funktion machen. In dem folgenden Beispiel wird ein etwas anderer Code zum Tauschen verwendet:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
static inline unsigned short swap_16 (unsigned short x_in)&lt;br /&gt;
{&lt;br /&gt;
   asm volatile (&lt;br /&gt;
      &amp;quot;eor %A0, %B0&amp;quot;   &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;eor %B0, %A0&amp;quot;   &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;eor %A0, %B0&amp;quot;&lt;br /&gt;
         : &amp;quot;=r&amp;quot; (x_in)&lt;br /&gt;
         : &amp;quot;0&amp;quot;  (x_in)&lt;br /&gt;
   );&lt;br /&gt;
	&lt;br /&gt;
   return x_in;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Die &amp;lt;tt&amp;gt;eor&amp;lt;/tt&amp;gt;-Sequenz tauscht die Inhalte von &amp;lt;tt&amp;gt;r24&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;r25&amp;lt;/tt&amp;gt;. Sie ist genauso schnell und knapp wie ein &amp;quot;Dreiecks-Tausch&amp;quot;, kommt aber ohne Hilfsregister aus. Nachrechnen, es stimmt!&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
       	eor	r24, r25&lt;br /&gt;
       	eor	r25, r24&lt;br /&gt;
       	eor	r24, r25&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Multiplikation 16x16 auf 32 von .S ins Inline-Assembler übersetzt ==&lt;br /&gt;
&lt;br /&gt;
Das ist die ursprüngliche Routine mul16x16_32 from Atmel's avr201.asm file, see also Atmel's document &amp;quot;AVR201: Using the AVR Hardware Multiplier&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
;******************************************************************************&lt;br /&gt;
;*&lt;br /&gt;
;* FUNCTION&lt;br /&gt;
;*	mul16x16_32&lt;br /&gt;
;* DECRIPTION&lt;br /&gt;
;*	Unsigned multiply of two 16bits numbers with 32bits result.&lt;br /&gt;
;* USAGE&lt;br /&gt;
;*	r19:r18:r17:r16 = r23:r22 * r21:r20&lt;br /&gt;
;* STATISTICS&lt;br /&gt;
;*	Cycles :	17 + ret&lt;br /&gt;
;*	Words :		13 + ret&lt;br /&gt;
;*	Register usage: r0 to r2 and r16 to r23 (11 registers)&lt;br /&gt;
;* NOTE&lt;br /&gt;
;*	Full orthogonality i.e. any register pair can be used as long as&lt;br /&gt;
;*	the 32bit result and the two operands does not share register pairs.&lt;br /&gt;
;*	The routine is non-destructive to the operands.&lt;br /&gt;
;*&lt;br /&gt;
;******************************************************************************&lt;br /&gt;
&lt;br /&gt;
mul16x16_32:&lt;br /&gt;
	clr	r2&lt;br /&gt;
	mul	r23, r21		; ah * bh&lt;br /&gt;
	movw	r19:r18, r1:r0&lt;br /&gt;
	mul	r22, r20		; al * bl&lt;br /&gt;
	movw	r17:r16, r1:r0&lt;br /&gt;
	mul	r23, r20		; ah * bl&lt;br /&gt;
	add	r17, r0&lt;br /&gt;
	adc	r18, r1&lt;br /&gt;
	adc	r19, r2&lt;br /&gt;
	mul	r21, r22		; bh * al&lt;br /&gt;
	add	r17, r0&lt;br /&gt;
	adc	r18, r1&lt;br /&gt;
	adc	r19, r2&lt;br /&gt;
	ret&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das ist hier eine Übersetzung für den avr-gcc. Der größte Vorteil besteht darin, dass der avr-gcc die Benutzung von den Registern an den umliegenden C Code anpassen kann. Daher müssen gegebenenfalls keine Register umkopiert werden, um diese Routine aufzurufen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
static __inline__ uint32_t mul_unsigned_16x16_32 ( const uint16_t operand_1, const uint16_t operand_2 )&lt;br /&gt;
{&lt;br /&gt;
    uint32_t return_value;&lt;br /&gt;
&lt;br /&gt;
    asm  // No &amp;quot;asm volatile&amp;quot;, so that the compiler can optimize the whole lot away&lt;br /&gt;
    (    // if the result is not used.&lt;br /&gt;
    &lt;br /&gt;
        // The code here is based on routine mul16x16_32 from Atmel's avr201.asm file,&lt;br /&gt;
        // see also Atmel's document &amp;quot;AVR201: Using the AVR Hardware Multiplier&amp;quot;.&lt;br /&gt;
        &lt;br /&gt;
        &amp;quot;clr    r2   ; r1/__zero_reg__ gets clobbered by mul, and we need          \n\t&amp;quot; \&lt;br /&gt;
        &amp;quot;            ; some register to hold a zero value later, see below.        \n\t&amp;quot; \&lt;br /&gt;
        &amp;quot;                                                                          \n\t&amp;quot; \&lt;br /&gt;
        &amp;quot;mul    %B[operand_1], %B[operand_2]  ; high(operand_1) * high(operand_2)  \n\t&amp;quot; \&lt;br /&gt;
        &amp;quot;movw   %C[return_value], r0          ; 16-bit move: r1:r0 -&amp;gt; rD+1:rD      \n\t&amp;quot; \&lt;br /&gt;
        &amp;quot;                                                                          \n\t&amp;quot; \&lt;br /&gt;
        &amp;quot;mul    %A[operand_1], %A[operand_2]  ; low(operand_1) * low(operand_2)    \n\t&amp;quot; \&lt;br /&gt;
        &amp;quot;movw   %A[return_value], r0          ; 16-bit move: r1:r0 -&amp;gt; rD+1:rD      \n\t&amp;quot; \&lt;br /&gt;
        &amp;quot;                                                                          \n\t&amp;quot; \&lt;br /&gt;
        &amp;quot;mul    %B[operand_1], %A[operand_2]  ; high(operand_1) * low(operand_2)   \n\t&amp;quot; \&lt;br /&gt;
        &amp;quot;add    %B[return_value], r0                                               \n\t&amp;quot; \&lt;br /&gt;
        &amp;quot;adc    %C[return_value], r1                                               \n\t&amp;quot; \&lt;br /&gt;
        &amp;quot;adc    %D[return_value], r2                                               \n\t&amp;quot; \&lt;br /&gt;
        &amp;quot;                                                                          \n\t&amp;quot; \&lt;br /&gt;
        &amp;quot;mul    %B[operand_2], %A[operand_1]  ; high(operand_2) * low(operand_1)   \n\t&amp;quot; \&lt;br /&gt;
        &amp;quot;add    %B[return_value], r0                                               \n\t&amp;quot; \&lt;br /&gt;
        &amp;quot;adc    %C[return_value], r1                                               \n\t&amp;quot; \&lt;br /&gt;
        &amp;quot;adc    %D[return_value], r2                                               \n\t&amp;quot; \&lt;br /&gt;
        &amp;quot;                                                                          \n\t&amp;quot; \&lt;br /&gt;
        &amp;quot;clr __zero_reg__      ; r1/__zero_reg__ gets clobbered by mul             \n\t&amp;quot;&lt;br /&gt;
        &lt;br /&gt;
        : [return_value] &amp;quot;=&amp;amp;r&amp;quot; (return_value)                       // output operands&lt;br /&gt;
        : [operand_1] &amp;quot;r&amp;quot; (operand_1), [operand_2] &amp;quot;r&amp;quot; (operand_2)  // input  operands&lt;br /&gt;
        :  &amp;quot;r2&amp;quot; // clobbered registers (&amp;quot;r1/__zero_reg__&amp;quot; here would have no effect)&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    return return_value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Zugriff auf SFRs ==&lt;br /&gt;
Um auf SFRs zuzugreifen, können im asm-Template keine Defines aus &amp;lt;tt&amp;gt;avr/io.h&amp;lt;/tt&amp;gt; verwendet werden, weil der Präprozessor nicht mehr über den erzeugten Assembler-Code läuft (er läuft vor dem Compilieren). Um nicht die hex-Codes des SFRs angeben zu müssen, kann man dem Inline die Adressen als Konstanten übergeben. Weil die Adressen RAM-Adressen sind, müssen sie in das &amp;lt;tt&amp;gt;_SFR_IO_ADDR&amp;lt;/tt&amp;gt; Makro verpackt werden, um den Offset für den I/O-Bereich abzuziehen. &amp;lt;tt&amp;gt;tcnt1&amp;lt;/tt&amp;gt; wird auf den Inhalt von &amp;lt;tt&amp;gt;TCNT1&amp;lt;/tt&amp;gt; gesetzt:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#include &amp;lt;avr/io.h&amp;gt;&lt;br /&gt;
   ... &lt;br /&gt;
   uint16_t tcnt1;&lt;br /&gt;
&lt;br /&gt;
   asm volatile (&lt;br /&gt;
      &amp;quot;in %A0, %1&amp;quot;    &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;in %B0, %1+1&amp;quot;&lt;br /&gt;
         : &amp;quot;=r&amp;quot; (tcnt1)&lt;br /&gt;
         : &amp;quot;M&amp;quot; (_SFR_IO_ADDR (TCNT1))&lt;br /&gt;
   );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
wird umgesetzt zu&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	in r24, 44&lt;br /&gt;
	in r25, 44+1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Das nur als Beispiel. Von C aus geht das natürlich auch mit&lt;br /&gt;
 uint16_t tcnt1 = TCNT1;&lt;br /&gt;
&lt;br /&gt;
== Zugriff aufs SRAM ==&lt;br /&gt;
Auf bekannte globale Symbole kann man direkt von Assembler aus zugreifen:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   extern int einInt;&lt;br /&gt;
&lt;br /&gt;
   asm volatile (&lt;br /&gt;
      &amp;quot;lds %A0, einInt&amp;quot;   &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;lds %B0, einInt+1&amp;quot;&lt;br /&gt;
         : &amp;quot;=r&amp;quot; (...)&lt;br /&gt;
   );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
ergibt&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	lds r24, einInt&lt;br /&gt;
	lds r25, einInt+1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
alternativ ginge&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   asm volatile (&lt;br /&gt;
      &amp;quot;lds %A0, %A1&amp;quot;   &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;lds %B0, %B1&amp;quot;&lt;br /&gt;
         : &amp;quot;=r&amp;quot; (...)&lt;br /&gt;
         : &amp;quot;m&amp;quot; (einInt)&lt;br /&gt;
   );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls die Adresse eines Objekts zur Compilezeit bekannt ist, kann man auch die Adresse von C aus übergeben:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct foo_t {&lt;br /&gt;
   int a[2], b[2];&lt;br /&gt;
} foo;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
{&lt;br /&gt;
   asm volatile (&lt;br /&gt;
      &amp;quot;lds %A0, %1&amp;quot;    &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;lds %B0, %1+1&amp;quot;&lt;br /&gt;
         : &amp;quot;=r&amp;quot; (...)&lt;br /&gt;
         : &amp;quot;i&amp;quot; (&amp;amp; foo.b[1])&lt;br /&gt;
   );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
ergibt&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	lds r24, einStruct+6&lt;br /&gt;
	lds r25, einStruct+6+1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls die Adresse zur Compilezeit nicht bekannt ist, muss sie natürlich in einem Adress- oder Basisregister übergeben werden:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
void blah (struct foo_t * pfoo)&lt;br /&gt;
{&lt;br /&gt;
   asm volatile (&lt;br /&gt;
      &amp;quot;ld  %A0, %a1&amp;quot;    &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;ldd %B0, %a1+1&amp;quot;&lt;br /&gt;
         : &amp;quot;=&amp;amp;r&amp;quot; (...)&lt;br /&gt;
         : &amp;quot;b&amp;quot; (&amp;amp; pfoo-&amp;gt;b[1])&lt;br /&gt;
   );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
ergibt&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	ld  r24, Z&lt;br /&gt;
	ldd r25, Z+1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Auch hier muss der Output-Operand mit einem&amp;amp;nbsp;&amp;lt;tt&amp;gt;&amp;amp;&amp;lt;/tt&amp;gt; gekennzeichnet werden, damit er nicht ins gleiche Register geladen wird wie die Adresse.&lt;br /&gt;
&lt;br /&gt;
= Labels und Schleifen =&lt;br /&gt;
Für Labels in Sprüngen und Schleifen können keine festen Bezeichner verwendet werden, weil ein Label, der via Makro oder inline-Funktion in den Code eingefügt wird, nicht mehrfach vorkommen darf. Dazu kann man sich durch Einfügen von &amp;lt;tt&amp;gt;&amp;quot;%=&amp;quot;&amp;lt;/tt&amp;gt; Labels zusammenbauen, etwa &amp;lt;tt&amp;gt;L_a%=&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;L_b%=&amp;lt;/tt&amp;gt;, etc. Das &amp;lt;tt&amp;gt;&amp;quot;%=&amp;quot;&amp;lt;/tt&amp;gt; wird durch eine für die Übersetzungseinheit und den Code-Schnippsel eindeutige Zahl ersetzt. Die obigen Sequenzen könnten also z.B. umgesetzt werden als &amp;lt;tt&amp;gt;L_a14&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;L_b14&amp;lt;/tt&amp;gt;, wenn sie im gleichen Schnippsel stehen.&lt;br /&gt;
&lt;br /&gt;
Etwas bequemer ist die Verwendung einer Ziffer als Label. Beim Sprung gibt man direkt hinter der Ziffer an, in welche Richtung das Label gesucht wird. Ist das Label &amp;lt;tt&amp;gt;''n''&amp;lt;/tt&amp;gt;, dann sucht und springt&lt;br /&gt;
*&amp;lt;tt&amp;gt;''n''b&amp;lt;/tt&amp;gt; zurück (backward)&lt;br /&gt;
*&amp;lt;tt&amp;gt;''n''f&amp;lt;/tt&amp;gt; nach vorne (forward)&lt;br /&gt;
&lt;br /&gt;
Es wird zum nächsten auffindbaren Label in der angegebenen Richtung gesprungen.&lt;br /&gt;
&lt;br /&gt;
==Bits zählen==&lt;br /&gt;
&lt;br /&gt;
Dieses Assembler-Schnippsel zählt die Anzahl der gesetzten Bits in einem Byte &amp;lt;tt&amp;gt;eingabe&amp;lt;/tt&amp;gt;. Die Eingabe wird nach rechts ins Carry geschoben, und das Carry zum Ergebnis dazu addiert.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
static inline unsigned char count_bits (unsigned char eingabe)&lt;br /&gt;
{                                              &lt;br /&gt;
   unsigned char count;&lt;br /&gt;
&lt;br /&gt;
   asm volatile ( &lt;br /&gt;
      &amp;quot;clr %0&amp;quot;                &amp;quot;\n&amp;quot;&lt;br /&gt;
      &amp;quot;0:&amp;quot;                    &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;lsr %1&amp;quot;                &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;adc %0, __zero_reg__&amp;quot;  &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;tst %1&amp;quot;                &amp;quot;\n\t&amp;quot;&lt;br /&gt;
      &amp;quot;brne 0b&amp;quot;&lt;br /&gt;
         : &amp;quot;=&amp;amp;r&amp;quot; (count), &amp;quot;+r&amp;quot; (eingabe)&lt;br /&gt;
   );&lt;br /&gt;
&lt;br /&gt;
   return count;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Damit kann man sich ein Parity bauen:&lt;br /&gt;
 #define parity(x) (count_bits(x) &amp;amp; 1)&lt;br /&gt;
und hätte eine schlankere (aber etwas langsamere) Parity-Implementierung als in &amp;lt;tt&amp;gt;avr/parity.h&amp;lt;/tt&amp;gt;. Ein &lt;br /&gt;
 if (parity(foo))&lt;br /&gt;
    ...&lt;br /&gt;
wird in Assembler dann zu (&amp;lt;tt&amp;gt;r24 = eingabe&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;r25 = count&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	lds r24,foo&lt;br /&gt;
/* #APP */&lt;br /&gt;
	clr r25&lt;br /&gt;
0:&lt;br /&gt;
	lsr r24&lt;br /&gt;
	adc r25, __zero_reg__&lt;br /&gt;
	tst r24&lt;br /&gt;
	brne 0b&lt;br /&gt;
/* #NOAPP */&lt;br /&gt;
	sbrs r25,0&lt;br /&gt;
	rjmp .L1&lt;br /&gt;
        ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Bugs=&lt;br /&gt;
* Um die Sonderzeichen &amp;lt;tt&amp;gt;&amp;quot;%~&amp;quot;&amp;lt;/tt&amp;gt; und &amp;lt;tt&amp;gt;&amp;quot;%=&amp;quot;&amp;lt;/tt&amp;gt; benutzen zu können, muss bei parameterlosen Inline Assembler dem Template ein Doppelpunkt folgen:&lt;br /&gt;
:&amp;lt;pre&amp;gt;asm volatile (&amp;quot;%~call some_function&amp;quot; :);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Quellen=&lt;br /&gt;
* Doku zur avr-libc&lt;br /&gt;
* Doku zu avr-gcc&lt;br /&gt;
* Quellen von gcc&lt;br /&gt;
&lt;br /&gt;
=Siehe auch=&lt;br /&gt;
* [[AVR Assembler Einführung]]&lt;br /&gt;
* [[:Kategorie:Quellcode Assembler_AVR|Quellcode Assembler]]&lt;br /&gt;
* [[Sourcevergleich#GCC (Assembler einfügen)]]&lt;br /&gt;
* [[avr-gcc]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Kategorie:Grundlagen]]&lt;br /&gt;
[[Kategorie:Quellcode_Assembler_AVR]]&lt;br /&gt;
[[Kategorie:Quellcode C]]&lt;/div&gt;</summary>
		<author><name>Rdiez</name></author>	</entry>

	</feed>