s'AVR Precompiler

 

Strukturierte Assembler-Programmierung für Atmel® AVR®
(31.3.2016)

Nachdem ich in jüngeren Jahren für diverse Mikroprozessoren auch reichlich komplexe Programme in Assembler-Sprache mit Sprachelementen für strukturierte Assembler-Programmierung[1] programmiert hatte und diese Tools zu schätzen wusste, habe ich mir neuerdings wieder eine solche Möglichkeit auch für modernere µController und Windows®-Umgebung gewünscht.

Dieses Konzept ist schon Jahrzehnte alt (und bewährt), wird aber "dank" Hochsprachen leider nur noch selten für aktuelle µController angeboten und wenn, dann für reichlich viel Geld.

Bereits im Jahr 2000 habe ich mich deshalb selbst ans (Pascal-) Programmieren gemacht und für die sehr schnellen SX-Mikrocontroller von Scenix/Ubicom[2] einen Precompiler (damals SXp genannt) erstellt.

Für die SX-µController war es auch noch wichtig, mit deren sehr kleinem Programmspeicher sparsam umzugehen und natürlich das Maximum an Ausführungsgeschwindigkeit heraus zu holen.

C-basierende und damit programmspeicherfressende Programme waren damals für diesen Zweck nicht wirklich eine Alternative (auch wenn es für SX bereits C-Compiler gab).

Außerdem waren (und sind auch heute teilweise immer noch) Hochsprachen zum Programmieren von kleinen Mikrocontrollern nicht jedermanns Sache.

Oder man muss aus Speicher- oder Geschwindigkeitsgründen oder man will für Ausbildungszwecke bewusst auf Assemblersprache zurückgreifen.


Der kurze Weg geht hier entlang:


s'AVR  Version 1 (31.3.2016)

Da ich vor Kurzem für verschiedene Projekte einen etwas aktuelleren und preisgünstigen µC benötigt hatte und immer noch gerne maschinennah in Assembler-Sprache programmiere, habe ich das bewährte Konzept des Precompilers für strukturierte Assembler-Programmierung für die AVR-Mikrocontroller von Atmel umgeschrieben (und den Precompiler nun s'AVR genannt),

    mit dem sich AVR-Assembler-Programme nicht nur deutlich schneller, sondern auch noch sehr viel übersichtlicher und auf Anhieb zuverlässiger erstellen lassen.

Und mehr AVR-Programmierspaß macht es auch!

Precompiler

Da das Programm aus dem s'AVR-Quellprogramm nicht direkt einen Maschinen-Code (also z.B. eine HEX- oder OBJ-Datei) erzeugt, sondern zunächst ein strukturloses (und deutlich längeres) "flaches" AVR-Assembler-Quellprogramm, ist es kein echter Compiler sondern ein Precompiler.

Es handelt sich bei s'AVR auch nicht um Assembler-Macro-Befehle, womit sich ein strukturiertes Assembler-Programm ebenfalls realisieren lassen würde, aber bei Weitem nicht so elegant (und ziemlich mühsam).

Das erzeugte "flache" Assembler-Quellprogramm wird (ohne dass man es überhaupt anschauen müsste) mit dem bisherigen AVR-Assembler anschließend in Maschinen-Code assembliert und dann wie gewohnt mit einem geeigneten Programmier-Tool in den AVR-µC programmiert.

Das hört sich alles vielleicht etwas kompliziert an, ist es aber nicht. Man muss einfach nur einmal damit gearbeitet haben und will dann strukturierte Assembler-Programmierung nicht mehr missen.

nach oben


s'AVR-Anweisungen

Hinweis:
Bei Ansicht auf Smartphones werden Zeilen umgebrochen, so dass die Strukturierung der s’AVR-Programme teilweise verloren geht.

Das sind die derzeit von s'AVR unterstützten Anweisungen zur strukturierten AVR-Assembler-Programmierung in aller Kürze:

---------------------------------------------------------------------------
IF Bedingung [THEN]         ; erste Abfrage (THEN ist nicht zwingend nötig)
    BefehlsFolge
ELSEIF Bedingung [THEN]     ; weitere Abfrage(n), mehrfach optional
    BefehlsFolge
ELSE                        ; letzte Verzweigung, optional
    BefehlsFolge
ENDI                        ; Ende der IF-Struktur
---------------------------------------------------------------------------
LOOP                        ; Endlosschleife
    BefehlsFolge            ; verlassen der LOOP-Schleife nur mittels EXIT,
                            ; EXITIF, Assembler-Sprung- und Branch-
                            ; Befehlen, RET, Interrupt oder Reset
ENDL                        ; Ende der LOOP-Schleife
---------------------------------------------------------------------------
WHILE Bedingung             ; Abfrage zu Beginn der WHILE-Schleife
    BefehlsFolge
ENDW                        ; Ende der WHILE-Schleife
---------------------------------------------------------------------------
REPEAT                      ; Beginn der Schleife
    BefehlsFolge
UNTIL Bedingung             ; Abfrage am Ende der REPEAT-Schleife
---------------------------------------------------------------------------
FOR RegisterZuweisung       ; Schleife mit Register-Initialisierung
    BefehlsFolge
ENDF                        ; dekrementieren des Schleifenzählers und
                            ; überprüfen auf den Wert Null
---------------------------------------------------------------------------
EXIT                        ; verlassen einer Strukturebene
EXITIF Bedingung            ; bedingtes Verlassen einer Strukturebene
EXITIF Bedingung TO Adresse ; bedingter Sprung aus einer Struktur-
                            ; ebene heraus
---------------------------------------------------------------------------
 

CONTINUE (26.1.2022)

 

Für alle Schleifen (also FOR, LOOP, REPEAT und WHILE) wird in einer neueren s’AVR-Version (ab s’AVR 2.33) inzwischen auch CONTINUE unterstützt, ab dem vorzeitig die nächste Schleifen-Iteration durchgeführt wird, noch bevor das eigentliche Ende der jeweiligen Schleife erreicht ist.

 

---------------------------------------------------------------------------
CONT                        ; Fortsetzung einer FOR-, LOOP, REPEAT- oder WHILE-Schleife
                            ; für die nächste Schleifen-Iteration
CONTIF Bedingung            ; bedingtes CONT für die nächste Schleifen-Iteration
---------------------------------------------------------------------------
 

s’AVR verwendet dafür die verkürzten Anweisungen CONT und CONTIF, wobei letztere ein bedingtes CONTINUE ist, welches sonst umständlich und weniger übersichtlich in einer zusätzlichen IF-Struktur untergebracht sein muss. Mehr dazu siehe hier.

 

"BefehlsFolge" sind entweder reine AVR-Assembler-Befehle oder weitere s'AVR-Anweisungen, die beliebig tief geschachtelt werden können - bis dass der Programmspeicher überläuft.

Das (nahezu) beliebig tiefe Schachteln von solchen Anweisungen ist natürlich eine wichtige Anforderung an eine strukturierte Programmierung.

"Bedingung" steht für Vergleiche (mindestens ein AVR-Register), Register- und Port-Bit-Abfragen oder Statusregister-Flag-Abfragen.

"RegisterZuweisung" gibt die Zahl der FOR-Schleifendurchgänge an.

Das spezifizierte FOR-Schleifenregister kann bereits vorher (bei Erreichen der FOR-Schleife) geladen sein oder die Zuweisung ist Teil des Befehls. Das FOR-Schleifenregister kann entweder mit einer Konstanten oder dem Inhalt eines anderen AVR-Registers geladen werden.

Beta-Version verfügbar

Im Moment gibt es eine Beta-Version von s'AVR für Windows®, die von mir bereits ausgiebig getestet wurde und auch laufend für aktuelle AVR-Projekte verwendet wird.

Damit lassen sich ohne Einschränkungen auch für ATtiny strukturierte Assembler-Programme erstellen. Für alle anderen 8-Bit-AVR-µC gilt das natürlich ebenso.

Handbuch

Ein ausführliches Handbuch mit einigen s’AVR-Beispielen und vielen Tipps steht ebenfalls zur Verfügung[3], nämlich hier zum Download.

Die wichtigsten Dinge sind im Help-Menü des Programms zusammengefasst.

Ausprobieren?

Interessierte AVR-Assembler-Programmierer mögen sich gerne bei mir mit einer kurze E-Mail an nebenstehene E-Mail-Adresse melden, damit ich ihnen das (mit ca. 600 kByte sehr kompakte) Programm zum eigenen Test zukommen lassen kann (bitte angeben, ob als ZIP- oder als 7Z-Datei) - kostenlos versteht sich. Lediglich um einen Erfahrungsbericht würde ich bitten.

Umstieg = Aufstieg

Bereits bestehende AVR-Assembler-Quellprogramme können nachträglich  (auch nur teilweise) sehr einfach mit s'AVR-Befehlsstrukturen erweitert werden. Das macht den Umstieg - oder besser den Aufstieg - zu s'AVR besonders einfach.

Der vorsichtige Programmierer fängt bei der Umstellung auf s’AVR mit ein paar wenigen Strukturen an und lässt die bisherigen Assembler-Befehle als Kommentar im Quellprogramm stehen. Außerdem legt er eine Sicherungskopie des ursprünglichen Programms an.

Anhand der von s’AVR erzeugten Ausgabedatei (*.asm) kann man dann direkt eventuelle Unterschiede (wenn überhaupt) zwischen dem ursprünglichen Assembler-Programm und dem von s’AVR erzeugten erkennen.

Natürlich ist es deutlich einfacher, ein s’AVR-Programm von Anfang an strukturiert zu schreiben anstatt ein bestehendes AVR-Assembler-Programm mühsam umzuschreiben.

Als Entwicklungsumgebung kann Atmel®-Studio dienen (im s’AVR-Handbuch ist das Einbinden ausführlich beschrieben), muss aber nicht.

Bei Bedarf ist selbst ein Programmaufruf per DOS-Kommandoschnittstelle nebst Übergabe von Parametern möglich. Diese wird aber eigentlich nur zum Einbinden in andere Programme (wie z.B. Atmel®-Studio) verwendet.

Und schließlich läuft s’AVR auch mit Wine unter Linux.

Bin gespannt, ob es bei den Lesern meiner Website Interesse an einem solchen Programmier-Tool gibt. Ich selbst erstelle meine AVR-Assembler-Programme inzwischen ausschließlich strukturiert für s’AVR.

Schmerzfrei und effizient (2.6.2017)

Hier vorab das Ergebnis eines Vergleichs mit s’AVR Version 2 (mit erweiterten Funktionen), die inzwischen auch weiter unten vorgestellt wird.

nach oben


s’AVR-Beispiel (Auszug)

Hier ist ein sehr einfacher Auszug aus einem größeren s'AVR-Testprogramm - in der strukturierten Form kurz und übersichtlich:

LOOP                  ; main loop

    .

    .

    .

    ; Test FOR, WHILE and REPEAT

    clr rval          ; test value zero

    ldi rtst,0xB0     ; start B.0 test

    FOR rchk := #16   ; loop 16 times

        rcall chkok

    ENDF

    ldi rtst,0xC0     ; start C.0 test

    ldi rchk,1

    WHILE rchk <= #16 ; count from 1 through 16

        rcall chkok

        inc rchk

    ENDW

    ldi rtst,0xD0     ; start D.0 test

    REPEAT            ; continue counting from 17 until 32

        rcall chkok

        inc rchk

    UNTIL rchk == #32

ENDL                  ; main loop (forever)

 

Alles was in diesem Beispiel nicht rot markiert ist, ist reine AVR-Assemblersprache und wird von s’AVR nicht angetastet!

 

Die blauen Markierungen der Assembler-Befehle stammen von Visual Assist des Atmel-Studio 7.

 

In dem aufgerufenen Unterprogramm werden Details des jeweiligen Tests dynamisch (abhängig von den jeweiligen Schleifenparametern) auf einem LCD angezeigt.

 

Und hier folgt, was s'AVR 1.x beim Compilieren (das geht schneller als ein Mausklick) daraus erzeugt[4] hat:

 

    ;01// LOOP        ; main loop

_L1:

    .

    .

    .

_L231:

    ; Test FOR, WHILE and REPEAT

    clr   rval         ; test value zero

    ldi   rtst,0xB0    ; start B.0 test

    ;02// FOR rchk := #16 ; loop 16 times

    LDI   rchk,16

_L289:

    rcall chkok

    ;02// ENDF

    DEC   rchk

    BREQ  _L290

    RJMP  _L289

_L290:

    ldi   rtst,0xC0    ; start C.0 test

    ldi   rchk,1

    ;02// WHILE rchk <= #16; count from 1 through 16

_L292:

    CPI   rchk,16

    BRLO  _L293

    BREQ  _L293

    RJMP  _L294

_L293:

    rcall chkok

    inc   rchk

    ;02// ENDW

    RJMP  _L292

_L294:

    ldi   rtst,0xD0   ; start D.0 test

    ;02// REPEAT      ; continue counting from 17 until 32

_L296:

    rcall chkok

    inc   rchk

    ;02// UNTIL rchk == #32

    CPI   rchk,32

    BREQ  _L297

    RJMP  _L296

_L297:

    ;01// ENDL        ; main loop (forever)

    RJMP  _L1

 

Die Befehlszeilen in schwarzer Schrift wurden von s’AVR 1.x in der Ausgabedatei erzeugt. Der Rest sind die ursprünglichen AVR-Assembler-Befehle, die unangetastet blieben.

 

Die ursprünglichen s’AVR-Anweisungen sind in der Ausgabedatei optional als Kommentar erhalten (oben rot markiert), können aber bei Bedarf in der Ausgabedatei unterdrückt werden.

 

Anhand der Angaben 01//, 02// etc. in den auskommentierten s’AVR-Anweisungen erkennt man die augenblickliche Strukturebene des Programms bzw. die absolute Verschachtelungstiefe, die man im "flachen" Assemblerprogramm sonst nicht erkennen kann.

 

Warum manche der AVR-Assembler-Befehle von s’AVR 1.x genau so und nicht anders (möglicherweise etwas optimaler) generiert wurden, steht im Handbuch beschrieben.

 

Auffallend an diesem einfachen (und in kürzester Zeit geschriebenen Testprogramm) ist, dass s'AVR allein im Hauptprogramm (also innerhalb der LOOP/ENDL-Schleife) aufgrund von vielen IF-Abfragen nahezu 300 Sprungzieladressen erzeugt hat, wogegen das s’AVR-Hauptprogramm aufgrund der strukturierten Programmierung überhaupt keine Adressen benötigt - wenn das keine Erleichterung ist!

 

In den aufgerufenen Unterprogrammen (natürlich ebenfalls mit s'AVR-Anweisungen geschrieben) kommen in diesem Beispiel nochmals weitere ca. 30 von s'AVR erzeugte Sprungzieladressen dazu.

 

nach oben


s'AVR  Version 2 (23.7.2017)

Mit dem Essen bzw. mit dem s’AVR-Programmieren kommt der Appetit, und deshalb gibt es nun s’AVR Version 2 mit einigen Verbesserungen.

Wie an verschiedenen Stellen erklärt, wird bei s’AVR  Version 1 immer mit der entspannten "schmerzfreien" ("no pain") Methode compiliert, sprich statt geeigneten (bei AVR meist fehlenden) Skip-Befehlen werden zum Überspringen BRcc-Befehle erzeugt und der eigentliche "weite" Sprung wird per RJMP durchgeführt.

Das ergibt einerseits zwar einen universellen Code ("schmerzfrei" eben), der bezüglich Sprungweite normalerweise keinen Eingriff durch den Programmierer erfordert, ist aber andererseits nicht maximal effizient - und manchmal (bedingt durch den AVR-Befehlssatz) auch nicht sehr elegant, siehe obiges Beispiel mit s’AVR Version 1.

Dieser kleine Schönheitsfehler ist mit der s’AVR  Version 2 beseitigt, indem der Anwender wahlweise zum Compilieren des s’AVR-Quellprogramms entweder die bisherige "schmerzfreie" Betriebsart, aber neuerdings auch eine "effiziente" Betriebsart wählen kann (letztere ist nun voreingestellt).

Da die "effiziente" Betriebsart wegen Verwendung von meist BRcc-Befehlen bei größeren Strukturen aber einen (kleinen) Eingriff durch den Programmierer erfordert, mussten einige der s’AVR-Anweisungen durch eine Sprungweite .m erweitert werden, die bei Bedarf bei der betroffenen Anweisung im s’AVR-Quellprogramm angehängt wird.

Die Erweiterung "m" steht für "medium" und RJMP-Befehle im Unterschied zu "long" (.l), das für JMP-Befehle reserviert ist.

Beispiel für größere Sprungweite

Zum besseren Verständnis hier ein Auszug aus einem konkreten und sauber strukturiert geschriebenen s’AVR-Programm mit vielen verschachtelten FOR/IF-Schleifen[5]
(auf kleinen SmartPhone-Bildschirmen schaut das wegen automatischen Zeilenumbrüchen möglicherweise nicht ganz so schön aus)
:

Unterprogramm:

 FOR r2 := neun                 ; Index i = 9...1

  einige Assembler-Befehle

  ...

  FOR r3 := neun                ; Index j = 9...1

   einige weitere Assembler-Befehle

   ...

   IF.m NZ                      ; sonst next j,

                                ; größere Sprungweite per IF.m

    FOR r4 := neun              ; Index k

     einige weitere Assembler-Befehle

     ...

     IF NZ                      ; sonst next k

      FOR r5 := neun            ; Index l

       einige weitere Assembler-Befehle

       ...

       IF NZ                    ; sonst  next l

        FOR r6 := neun          ; Index m

         einige weitere Assembler-Befehle

         ...

         IF NZ                  ; sonst next m

          FOR r7 := neun        ; Index n

           einige weitere Assembler-Befehle

           ...

           IF NZ                ; sonst next n

            FOR r8 := neun      ; Index o

             einige weitere Assembler-Befehle

             ...

             IF NZ              ; sonst next o

              FOR r9 := neun    ; Index p

               einige weitere Assembler-Befehle

               ...

               IF NZ            ; sonst next p

                FOR r10 := neun ; Index q

                 einige weitere Assembler-Befehle

                 ...

                 IF NZ          ; sonst next q

                  rcall pruefen

                 ENDI

                ENDF    ; next q

               ENDI

              ENDF    ; next p

             ENDI

            ENDF     ; next o

           ENDI

          ENDF     ; next n

         ENDI

        ENDF      ; next m

       ENDI

      ENDF      ; next l

     ENDI

    ENDF.m     ; next k, ENDF.m für größere Sprungweite

   ENDI       ; für größere Sprungweite .m bei IF (s.o.)

  ENDF.m     ; next j, ENDF.m für größere Sprungweite

 ENDF.m     ; next i, FOR-Schleife für Index i = 9...1

            ; ENDF.m für größere Sprungweite

ret


Wie man aufgrund von insgesamt vielen Assembler-Befehlen (nämlich jeweils 4 bis 5 nach den FOR-Anweisungen) vermuten kann, ist bei den vier äußeren Schleifen (also 3x FOR und 1x IF) die Sprungweite mittels BRcc zu gering[6], so dass im erzeugten Assembler-Programm mittels RJMP gesprungen werden muss - natürlich wegen der bei IF bzw. ENDF angehängten Sprungweiten-Erweiterung .m automatisch von s’AVR generiert.

Und hier ein Auszug des compilierten flachen "effizienten" ASM-Programms einmal bei der betroffenen IF.m-Struktur am Anfang mit einem RJMP _L22 ans Ende der IF-Struktur (nicht so bei Index k, siehe BREQ _L29):

 ...

 ;03// IF.m NZ        ; sonst next j, größere Sprungweite per IF.m

 BRNE _L23

 RJMP _L22

_L23:

 ;04// FOR r4 := neun ; Index k

 MOV r4,neun

_L26:

 einige weitere Assembler-Befehle

 ...

 ;05// IF NZ             ; sonst next k

 BREQ _L29

_L30:

 ;06// FOR r5 := neun    ; Index l

 MOV r5,neun

_L33:

 ...


und dann noch am Ende bei den FOR-Strukturen von i, j und k (aber noch nicht bei l, siehe BRNE _L33) jeweils mit einem RJMP zurück an den zugehörigen Anfang:

 ...

_L36:

 ;06// ENDF       ; next l

 DEC r5

 BRNE _L33

 ;05// ENDI

_L31:

_L29:

 ;04// ENDF.m     ; next k, ENDF.m für größere Sprungweite

 DEC r4

 BREQ _L27

 RJMP _L26

_L27:

 ;03// ENDI       ; für größere Sprungweite .m bei IF (s.o.)

_L24:

_L22:

 ;02// ENDF.m     ; next j, ENDF.m für größere Sprungweite

 DEC r3

 BREQ _L20

 RJMP _L19

_L20:

 ;01// ENDF.m     ; next i, FOR-Schleife für Index i = 9...1

                  ; ENDF.m für größere Sprungweite

 DEC r2

 BREQ _L17

 RJMP _L16

_L17:

 ret


D.h., s’AVR generiert durch die erzwungene Sprungweite .m (und nur an diesen Stellen!) den "schmerzfreien" Code per kombinierten BRcc und RJMP.

Würden die 8-Bit-AVR-µC auch Skip-Befehle abhängig von Status-Bits unterstützen ("SKcc"), könnte man damit die BRcc-Befehle ersetzen, um über den folgenden RJMP-Befehl zu springen und es müssten keine zusätzlichen Labels nach diesen RJMP-Befehlen erzeugt werden.

Wegen der gewählten s’AVR-Option "effizient" sind es bei diesem Unterprogramm sonst ausschließlich BRcc-Befehle.

Ich möchte behaupten: Effizienter bekommt das auch ein routinierter AVR-Assembler-Programmierer nicht hin, sofern er einen einigermaßen übersichtlichen Programmierstil hat. Um das etwas allgemeiner vergleichen zu können, müsste man jedoch noch andere und komplexere s’AVR-Strukturen im "effizienten" Mode untersuchen. Daran soll es nicht scheitern.

Ein erster Erfahrungsbericht bezüglich Geschwindigkeits- und Code-Gewinn bei "effizienter" Compilierung mit s’AVR Version 2 wurde bereits früher veröffentlicht.

An obigem Beispiel sieht man auch sehr schön die Verschachtelungstiefe[7]  z.B. per
;06// ENDF angezeigt, sofern die ursprünglichen s’AVR-Zeilen nicht bei der Ausgabe als Kommentarzeile unterdrückt wurden.

Ein interessanter Effizienz-Vergleich zwischen s’AVR und C findet sich inzwischen hier. (28.1.2019)

Und hier gibt es einen Vergleich zwischen s’AVR und AVR-GCC anhand der (deutlich komplexeren) Berechnung großer Fakultäten mit einem ATmega1284. (10.6.2019)

Und hier werden schließlich sehr flott Quadratwurzeln gezogen. (3.8.2021)

Label-Prefix

Eine weitere Verbesserung bei s’AVR  Version 2 ist die wahlweise Erzeugung von Labels im Format _Axxxx bis _Zxxxx (jeweils einheitlich für eine Compilierung).

Das Label-Prefix kann entweder als Option per Maus im s’AVR-Fenster ausgewählt werden ...

sAVR2.2

... oder z.B. bei Einbindung in Atmel-Studio auch per Parameter über das Command-Line-Interface.

Das bei s’AVR Version 1 verwendete _Lxxxx ist nun vorbelegt.

Diese Möglichkeit ist zwingend nötig, falls mehrere s’AVR-Quellprogramme separat compiliert und dann per .INCLUDE zu einem Programm zusammengeführt und assembliert werden.

Ein konkretes (sehr umfangreiches!) s’AVR-Beispiel hierzu gibt es inzwischen hier.
Dabei geht es zur Abwechslung auch mal wieder um LEDs ...

Weitere Details und Feinheiten sind im völlig überarbeiteten s’AVR-Handbuch für die Version 2 beschrieben - ab der Ausgabe 2.2 nun auch in Englisch.

Flott alle Quellprogramme eines Verzeichnisses mit einem Mausklick compiliert (8.4.2020)

Ab s’AVR Version 2.3 lassen sich alle *.s-Quellprogramme in einem gemeinsamen Verzeichnis per Kommandozeilen-Parameter /label_al (für ein Label-Prefix _ALxxxx) unter Atmel-Studio 7 mit einem einzigen Mausklick compilieren, so dass sich s’AVR nun genau so einfach und schnell bedienen lässt wie bei der Programmentwicklung in der C-Umgebung.

s’AVR sogar unter AVR Studio 4 (23.4.2021)

Mit dem neuen Kommandozeilen-Parameter /label_al war der Weg nicht mehr weit, um mit einem Trick auch unter dem ca. 20 Jahre alten AVR Studio 4 elegant s’AVR-Programme zu compilieren (s’AVR Version 2.34) und zwar per weiterem Kommandozeilen-Parameter /as4, womit ebenfalls alle *.s-Quellprogramme eines Verzeichnisses compiliert werden, denn wegen einer sehr eingeschränkten Parameterübergabe ist es bei AVR Studio 4 nicht möglich, dynamisch Datei- und Verzeichnis-Informationen zu übergeben.

nach oben


s’AVR Version 2 unter Linux (10.8.2017)

Vorab muss ich erwähnen, dass Ralf Jardon[8] als erfahrener Linuxaner s’AVR unter die Lupe genommen und mir eine Menge Inputs gegeben hat, damit für einen einfachen und reibungslosen Betrieb unter Linux noch einige Verbesserungen in s’AVR einfließen konnten - herzlichen Dank, Ralf!

Der Grundgedanke dabei war, s’AVR in der vorliegenden Windows-Version mittels Linux-Programm Wine auszuführen und zwar per Script, so dass die ganze Pre-Compiler- und Assembler-Lauf-Prozedur mehr oder weniger per einem einzigen Mausklick erfolgen kann.

Eine größere Unschönheit war zunächst, dass bei Textdateien unter Linux die einzelnen Textzeilen per Line-Feed (LF) abgeschlossen werden anstatt per Carriage-Return + Line-Feed (CRLF), wie unter Windows üblich.

s’AVR hatte (als Windows-Programm) ursprünglich nur Zeilen mit CRLF korrekt gelesen und compiliert.

Bei Linux-Dateien wurde das gesamte Quellprogramm dagegen als eine einzige Quellprogrammzeile gelesen und schlicht uncompiliert wieder ausgegeben, da am Anfang normalerweise keine s’AVR-Anweisung steht.

Ein einfaches (aber für mich nicht befriedigendes) Workaround war die Vorschaltung des Linux-Konvertierungsprogramms unix2dos (dann im Script enthalten), womit schließlich alles reibungslos klappte.

Natürlich konnte ich das nicht auf sich beruhen lassen und habe s’AVR erweitert[9], so dass nun sowohl Windows- als auch Linux-Textdateien mit ein- und derselben Version korrekt gelesen werden können.

Eine andere kleine Hürde war noch, einen Weg zu finden, wie man denn das Linux-Script einfach abbrechen könnte, falls beim Compilieren (insbesondere von mehreren Dateien nacheinander) von s’AVR ein Fehler erkannt wird.

Für diesen Zweck erzeugt s’AVR nun eine separate Datei *.err, in der ausschließlich die Fehlermeldungen zeilenweise aufgelistet werden.
Und wenn keine Fehler aufgetreten sind, ist diese Datei einfach nicht vorhanden.

Diese Tatsache lässt sich per Linux-Script feststellen, das dann die Fehlermeldungen ausgibt und den Rest des Compiler/Assembler-Vorgangs abbricht, so dass keine weiteren Quellprogramme compiliert oder gar assembliert werden (wodurch es zu weiteren Fehlermeldungen kommen würde).

Und so schaut Ralfs EasyBuild-Script in einem Inline-Frame aus, das zunächst ein ausgewähltes Verzeichnis nach Quellprogrammdateien *.s durchscannt, diese automatisch mit fortlaufenden Label-Prefixes übersetzt und anschließend alles assembliert:

Ralfs E-Mail-Adresse habe ich vorsichtshalber ausgeixt, damit die Robots sie nicht finden. In seiner TM1638-Library[8] ist sie aber enthalten.

nach oben


Erweiterung für Atmel Studio: Indent Guides (25.1.2019)

 

Eine hilfreiche Erweiterung für Atmel Studio namens Indent Guides möchte ich meinen Lesern nicht vorenthalten.

 

Man kann diese Erweiterung innerhalb von Atmel Studio unter "Tools/Extensions and Updates/Online" finden und installieren.

 

Sie markiert Programmstrukturen durch senkrechte gestrichelte Linien z. B. wie folgt (je nach Setup unter "Tools/Options").

 

Hier ein einfaches Beispiel (Senden von 8 Bits per SPI-Bit-Banging aus der TM1638-Library):

 

Indent Guides_s

 

Das ist recht praktisch bei sehr großen und vielen verschachtelten Strukturen und klappt unabhängig von der jeweiligen Programmiersprache, also auch für s’AVR.

 

Mit der von s’AVR erzeugten strukturlosen (flachen) Assembler-Datei schaut es dann innerhalb von Atmel Studio so aus:

 

Indent Guides_asm

 

Diese senkrechten Strukturmarkierungen sind aber nicht in den Dateien selbst enthalten, sondern werden nur im jeweils aktiven Fenster von Atmel Studio dargestellt (und deshalb ist der Code hier als Grafik wiedergegeben).

 

Per "Edit/Advanced" lassen sich diese Hilfslinien ein- und ausschalten.

 

nach oben


Warenzeichen:


[2] Ubicom wurde 2012 von Qualcomm übernommen.
Die SX-Bausteine sind inzwischen nicht mehr verfügbar.

[3] Handbuch für s’AVR  Version 1 nur in Deutsch.
Für s’AVR Version 2 gibt es eine deutsche und eine eine englische Ausgabe, siehe Downloads.

[4] Die erzeugte Ausgabedatei schaut man normalerweise nur im Fehlerfall an, da in dieser für den Assembler erzeugten Assembler-Quelldatei (*.asm) ggf. auch Fehlermeldungen und andere Hinweise enthalten sind, aber vielleicht auch zum Debuggen, was dank s'AVR dann vermutlich nicht mehr so oft nötig ist.

[5] Die Konstante 9 ist in einem Register namens "neun" hinterlegt, so dass man auch die unteren AVR-Register R0-R15 für FOR-Schleifen mit Initialisierung per Zuweisung verwenden kann, dann aber zwangsläufig über ein Register und nicht über eine Konstante.

[6] Spätestens der AVR-Assembler bringt es per Fehlermeldung an den Tag.

[7] Die größte Verschachtelungstiefe beträgt bei diesem Beispiel 17 bei Index q.

Eine Begrenzung für die Verschachtelungstiefe gibt es bei s’AVR nicht. Die Grenze ist einzig der AVR-Programmspeicher (keinesfalls der AVR-Stack, der von s’AVR nicht angetastet wird).

[8] Hier ein Link zu einer Library von Ralf, die als s’AVR-Version hier besprochen wird.

[9] Im WWW gibt es unendlich viele Abhandlungen und seitenweise Programmvorschläge, wie man Textdateien von Windows, Unix/Linux und MacOS denn unter einen Hut bringen könnte - oder auch nicht.

Nach einigen Stunden Recherche wollte ich mich schon geschlagen geben (es gab ja die unix2dos-Lösung), habe aber dann doch spontan eine einfache Lösung für mein Uralt-Delphi 5 gefunden, die nur sehr wenige Delphi-Programmzeilen benötigt.