Pfad: Home => AVR-Assembler gavrasm => Einführung    (This page in English: Flag EN) Logo
Logo

Einführung in Gerd's AVR Assembler

Hier werden die besonderen Features des gavrasm-Assemblers vorgestellt. Die Beispiele compilieren nicht unbedingt auch auf anderen Assemblern. Im einzelnen werden vorgestellt:
  1. 1 Aufruf des Assemblers auf der Kommandozeile
  2. 2 Aufruf des Assemblers mit einer Batch oder in einer Shell
  3. 3 Hilfsprogramm zum Aufruf unter Windows
  4. 4 Verwendung von IF-ELSE-ENDIF
  5. 5 Verwendung von EXIT
  6. 6 Verwendung von Makros
  7. 7 Verwendung von besonderen literalen Konstanten
  8. 8 Verwendung von Trennzeichen in Konstanten

1 Aufruf des Assemblers auf der Kommandozeile

Beim Aufruf in einer Kommandozeile geht man am besten so vor:
  1. Man öffnet eine Kommandozeile (Win: meistens unter Start/Programme/Zubehör/Eingabeaufforderung) oder Shell (Linux-KDE) und wechselt mit cd [Pfad] in das Verzeichnis mit dem Quelltext.
  2. Das Assemblieren wird mit [gavrasm-pfad]gavrasm -optionen quelltext[.asm] gestartet.
Befinden sich alle verwendeten INCLUDE-Dateien im Pfad des Quelltextes, dann braucht man nur den Namen der Include-Dateien (z.B. "8515def.inc") anzugeben. Andernfalls muss dem Namen der korrekte Pfad hinzugefügt werden (z.B. "C:\avrtools\appnotes\8515def.inc" oder "/home/gerd/avrasm/def/8515def.inc").

Die Parameteroptionen sind in der Datei Liesmich.Txt generell aufgelistet. Hier einige ausführlichere Erläuterungen:

An den Seitenanfang

2 Aufruf des Assemblers mit einer Batch oder in einer Shell

Um sich die wiederholte Prozedur der Eingabe von Pfadnamen zu ersparen, kann der Assembler-Aufruf in einer Batchdatei erfolgen. Das geht bei Windows und Linux unterschiedlich.

2.1 Windows-Batch

Unter Windows wird dazu eine neue Textdatei angelegt, in Assemble_de.bat umbenannt (und ja: dadurch ändert sich der Dateityp!), mit der rechten Maustaste im Kontextmenue "Bearbeiten" im Editor geöffnet und mit folgenden Zeilen versehen:

REM Batch-Aufrufdatei
[Laufwerk]:
CD [Pfad-zur-Sourcedatei]
[gavrasm-pfad\]gavrasm [-optionen] quelldatei[.asm]
PAUSE

Batchscript

Die Textdatei wird mit der Endung ".bat" in einem beliebigen Verzeichnis gespeichert. Wer mag, kann eine Verknüpfung auf diese Batchdatei auf den Desktop legen. Sie kann durch Anklicken gestartet werden und steuert den Assemplierprozess. Die Pause-Anweisung am Ende bewirkt, dass sich das Fenster erst nach Drücken einer Taste schließt, damit wir die wertvollen Infos von gavrasm auch sehen können.

2.1.1 Windows-Batch mit Errorlevel-Auswertung

Seit gavrasm-Version 3.4 gibt der Assembler beim Beenden den Fehlerstatus zurück. Dieser kann mit der Variable errorlevel ausgewertet werden. Der Code in der Batch kann so aussehen:

REM
REM Testet Rueckgabewert vom Assembler
REM
[Laufwerk]
CD [Pfad zur Sourcedatei]
[gavrasm-pfad\]gavrasm -optionen Quelldatei[.asm]
If errorlevel 1 Goto Fehler
REM Kein Fehler, weitere Instruktionen hierhin
goto ende
:Fehler
REM Fehler aufgetreten, weitere Instruktionen hierhin
echo Fehlerbehandlung!
notepad.exe Quelldatei.err
:ende
pause



Batchdatei Fehlerbehandlung

Nach dem Klicken auf die Batchdatei assembliert gavrasm die angegebene Quelldatei und kehrt mit errorlevel 1 zurück.

Batchdatei-Ablauf

Da beim Assemblieren ein Fehler gefunden wurde, öffnet die Batchdatei den Editor mit der .err-Datei. Mit deren Hilfe kann man jetzt Fehler im Quellcode ausbessern.

Notepad mit err-Datei

Natürlich kann man auch jeden anderen Editor aufrufen.

An den Seitenanfang

2.2 Linux-Shell

Unter Linux schreiben wir folgendes Shell-Script:

#!/bin/bash
cd [Pfad-zur-Sourcedatei]
[Pfad-zu-gavrasm/]gavrasm [-optionen] Quelldatei[.asm]
read key

Shell-Script

und speichern es mit der Endung .sh irgendwo ab. Wer mag, kann sich eine Verknüpfung zu dieser Shelldatei auf dem KDE-Desktop erzeugen (Neu erstellen/Verknüpfung mit Programm, dabei Ausführung in einem Terminalprogramm wählen) und anschließend die Ausführungrechte setzen. Die Zeile mit read key bewirkt, dass man die Ausgabe im Terminal verfolgen kann, bevor sich das Terminal schließt.

2.2.1 Linux-Shell mit Fehlerauswertung

Seit Version 3.4 von gavrasm gibt der Assembler beim Beenden den Fehlerstatus zurück. Das kann dazu genutzt werden um in der Shell zu verzweigen. Der Code kann so aussehen:

#!/bin/bash
# Diese Batch ruft gavrasm auf und verzweigt
cd [Pfad-zur-Sourcedatei]
[Pfad-zu-gavrasm/]gavrasm [-optionen] Quelldatei[.asm]
if [ "$?" = "0" ]; then
  # Dieser Zweig wird ausgeführt wenn kein Fehler auftritt
  echo "Shell: Kein Fehler beim Assemblieren"
else
  # Dieser Zweig wird ausgeführt wenn ein Fehler auftritt
  echo "Shell: Fehler beim Assemblieren"
  # Aufruf des Editors mit der Fehlerdatei von gavrasm
  kwrite "fehler.err"
fi

Batch fuer Auswertung

Im Beispiel ruft die Shell eine fehlerhafte Assemblerdatei auf. Die Ausgabe der Shell sieht dann so aus:

Fehler ausgeloest

Statt des Zweigs mit ohne Fehler wird jetzt der Editor KWrite aufgerufen und die Fehlerdatei Quellcode.err angezeigt.

KWrite mit .err

Natürlich kann auch jeder andere vorhandene Editor aufgerufen werden.

An den Seitenanfang

3 Window Caller - Werkzeug für den Aufruf unter Windows

Wenn Du in einer Fensterumgebung arbeitest, könntest Du müde werden beim Schreiben von Batchdateien. Hier ist was einfaches als Ersatz.
Auf vielfachen Wunsch habe ich ein Windows-Programm geschrieben, das menuegesteuert Batchdateien erzeugt, den Assembler aufruft und in einem Editorfenster Dateien anzeigen kann. Einige neue Schmankerl sind: Mehr über die Features und über die Bedienung gibt es in der Lies-Mich-Datei.
Das Programm läuft nur unter Windows (sorry, Linuxer) und steht gepackt unter diesem Link zum Download zur Verfügung.

An den Seitenanfang

4 Verwendung von IF-ELSE-ENDIF

Die zusätzlichen Direktiven .IF, .ELSE und .ENDIF ermöglichen es, je nach den Einstellungen im Kopf einer Quelldatei oder nach festgestellten Rechenergebnissen Programmteile zu kompilieren oder nicht. Die IF-Bedingung wird während der Kompilation geprüft. Ist sie erfüllt, wird der folgende Quellcode assembliert. Wenn nicht, wird die Kompilierung des Quellcodes erst nach der .ELSE- oder der .ENDIF-Direktive wieder fortgesetzt. Achtung: Fehlen beide Anweisungen, wird der Rest des gesamten Quelltextes nicht mehr kompiliert!

Als Anwendungsbeispiel:

.EQU taktfrequenz=40000000
.IF taktfrequenz>4000000
.EQU teiler=4
.ELSE
.EQU teiler=2
.ENDIF

Ein Blick auf die Symbolliste zeigt, dass Teiler nach dem Kompilieren auf 2 gesetzt ist. Wird die Taktfrequenz im Kopf z.B. auf 10.000.000 umdefiniert, wird der Teiler auf 4 gesetzt. Allgemein vermeidet man dadurch, dass für jede Änderung von minimalen Parametern eigene Änderungen im Quelltext, außer im Kopf, vorgenommen werden müssen.

Als typische Anwendung kann ein Quelltext z.B für verschiedene Typen von AVRs geschrieben werden. Weil sich die Interruptvektoren bei jedem Typ an einer anderen Stelle befinden, kann der Vektorbereich spezifisch kompiliert werden.

;
; Definiere Prozessor im Kopf
;
.EQU aTyp=2313 ; Prozessor ist ein 2313
;
.EQU aTyp=2323 ; Prozessor wäre ein 2323
;
.EQU aTyp=8515 ; Prozessor wäre ein 8515
;
; Abschnitt mit den Int-Vektoren
;
.CSEG
.ORG $0000
	rjmp Main ; für alle Typen gleich
	rjmp IntVecInt0 ; External Int Vector, wird verwendet
; Int-Vektoren für 2313
.IF aTyp == 2313
	reti ; IntVecInt1 ; External Int Vector, nicht verwendet
	reti ; Timer1Capt, nicht verwendet
	reti ; Timer1/Comp, nicht benutzt
	reti ; Timer1/Ovf, nicht benutzt
	rjmp IntVecTC0Ovf ; TC0-Overflow, verwendet
	reti ; UartRX, nicht benutzt
	reti ; UartUdre, nicht benutzt
	reti ; UartTx, nicht verwendet
.ENDIF
; Int-Vektoren für 2323
.IF aTyp == 2323
	rjmp IntVecTC0Ovf ; TC0-Overflow, verwendet
.ENDIF
; Int-Vektoren für 8515
.IF aTyp == 8515
	reti ; IntVecInt1 ; External Int Vector, nicht verwendet
	reti ; Timer1Capt, nicht verwendet
	reti ; Timer1/CompA, nicht benutzt
	reti ; Timer1/CompB, nicht benutzt
	reti ; Timer1/Ovf, nicht benutzt
	rjmp IntVecTC0Ovf ; TC0-Overflow, verwendet
	reti ; SpiStc, nicht verwendet
	reti ; UartRX, nicht benutzt
	reti ; UartUdre, nicht benutzt
	reti ; UartTx, nicht verwendet
	reti ; AnaComp, nicht verwendet
.ENDIF
;
; Interrupt-Service-Routine INT0
;
IntVecInt0:
	[...]
	reti
;
; Interrupt-Service-Routine TC0-Overflow
;
IntVecTC0Ovf:
	[...]
	reti
;
; Hauptprogramm
;
Main:
	[...]

Es ist klar ersichtlich, dass bei einer Umstellung des Quellcodes für einen anderen Prozessor alle Änderungen sehr umfangreich und deshalb fehlerträchtig sind. Vergisst man die Sache mit den unterschiedlichen Interruptvektoren, ergibt sich ein nettes Fehlersuch-Problem. Mit dem dargestellten Quellcode ist die Umstellung des Programmes für einen anderen Typ ein Leichtes.

Selbstverständlich können die Bedingungen der .IF-Direktive auch komplexer formuliert sein, wie z.B. hier:

.IF (aTyp == 2313) || (aTyp == 8515)

Verschaltelte IF-Direktiven sind wegen der Unübersichtlichkeit und wegen möglicher Fehlerquellen allerdings nicht implementiert.

An den Seitenanfang

5 Verwendung von EXIT

Überschreitet eine Größe einen zulässigen Wertebereich, dann bricht man die Assemblierung mit einer Fehlermeldung gerne ab, damit kein Unsinn auf den AVR losgelassen wird. Mit der Direktive .EXIT kann man das erreichen:

.EQU taktfrequenz=4000000
.EQU teiler=64
.EXIT (taktfrequenz/teiler)>65535

Damit ist z.B. sichergestellt, dass auch bei anderen Taktfrequenzen kein 16-Bit-Zählerüberlauf zu befürchten ist, ohne dass es der Assemblerprogrammierer merkt.

An den Seitenanfang

6 Verwendung von Makros

Makros werden vom Assembler gespeichert und erst beim Aufruf ihres Namens in den Code eingefügt, z.B. so

.MACRO mtest
  nop
.ENDM
;
; Hier wird das Makro eingefügt
;
	mtest

Der Code im Makro ist mittels übergebenen Parametern variierbar. Die Parameter heißen @0 bis @9. Z.B. so

;
; Register global definieren
;
.DEF rmp,R16
.MACRO mtest
	ldi @0,@1 ; Erwartet Register als ersten Param, Konstante als zweiten
	clr @0
.ENDM
;
; Makro einfügen
;
	mtest rmp,50

Die Verwendung von Makros weist bei diesem Assembler die Besonderheit auf, dass alle im Makro definierten Marken nur innerhalb des entsprechenden Makros gültig sind. Das verhindert, dass bei mehrfacher Verwendung des Makros Konfusion auftritt. Global definierte Symbole sind von innerhalb des Makros zugänglich, daher darf auch bei allen Makro-internen Symbolen kein Namenskonflikt auftreten. Wegen der lokalen Definition von Marken innerhalb des Makros ist es normalerweise nicht möglich, interne Marken außerhalb des Makros zu verwenden. Um dennoch eine Exportmöglichkeit zu haben, kann man mit der Direktive
.SETGLOBAL Marke1[, Marke2, ...]
den Wert nach außerhalb des Makros exportieren. Die so gebildete Variable wird zu Beginn jedes Aufrufs des Makros jeweils auf den aktuellen Wert gesetzt.

Mit diesem Instrumentarium ist die Möglichkeit gegeben, umfangreiche Bibliotheken für immer wiederkehrende Aufgaben zu schreiben. Weil der Code nur dann eingefügt wird, wenn das Makro auch tatsächlich im Code aufgerufen wird, wird kein Platz verschwendet.

An den Seitenanfang

7 Verwendung von besonderen literalen Konstanten

gavrasm ermölicht die Verwendung von ASCII-Kontrollzeichen in Zeichenkonstanten, also z.B.

.DB "Dies ist die erste Zeile.\m\jDies ist die zweite Zeile."

Ein '\'-Zeichen wird mit zwei '\' eingefügt. Im Gegensatz zu anderen Assemblern werden ';' in Zeichenketten richtig erkannt und behandelt.

An den Seitenanfang

8 Trennzeichen in Binär- und Hex-Konstanten

Der Assembler erlaubt die Verwendung des Punktes als Trennzeichen in Konstanten, wie z.B.

.EQU abc = 0b0001.0010
.EQU def = 0x0FFF.FFFF

Versuchen Sie diesen Quellcode niemals mit einem anderen Assembler zu assemblieren!

An den Seitenanfang

©2003-2014 by http://www.avr-asm-tutorial.net