Historisches

Strukturierte Assembler-Programmierung (14.4.2017)
Ein geschichtlicher Abriss – ohne Anspruch auf Vollständigkeit

Über der Sinn und Zeck von Anweisungen für strukturierte Assembler-Programmierung von Mikroprozessoren und µControllern gibt es immer wieder sehr kontroverse Diskussionen.

Um aufzuzeigen, dass Tools zur Unterstützung strukturierter Methoden bei der Assembler-Programmierung bei namhaften Anbietern bereits in den 80er Jahren gang und gäbe waren, habe ich folgende Informationen anhand von mir zur Verfügung stehenden Unterlagen zusammengestellt (mit einigen Zitaten aus den Handbüchern).

Ich erinnere mich, dass es früher weitere solche Tools gegeben hat, habe aber keine Unterlagen mehr darüber gefunden, so dass ich deren Eigenschaften ebenfalls auflisten könnte.

Allen aufgeführten Tools ist eine Eigenschaft gemeinsam:

    Der Programmierer programmiert mit strukturierten Methoden, aber weiterhin in 100% Assembler-Umgebung, ist also für die Verwendung aller Register und des Speichers des jeweiligen µControllers selbst verantwortlich.

Die Anweisungen für strukturierte Assembler-Programmierung nehmen dem Programmierer Abfragen für Programmverzweigungen, die Schleifenprogrammierung und das Festlegen von Sprungadressen ab (Abdressen werden normalerweise nur noch für Unterprogramme, Interrupt-Routinen und ggf. Sprungtabellen benötigt), wodurch das Assembler-Programm übersichtlicher wird, schneller zu erstellen, weniger fehleranfällig und leichter zu pflegen ist.

Es ist unbestritten, dass diese offensichtlich bewährten Methoden (siehe auch die Zitate) heute noch Gültigkeit haben, nur werden – warum auch immer – kaum mehr Assembler für moderne µController angeboten, die Sprachelemente für strukturierte Programmierung unterstützen.

Ob und wie man solche Software-Tools dann nützt, ist schließlich jedem selbst überlassen. Für mich war und ist es weiterhin durchweg ein großer Gewinn.


Der kurze Weg geht hier entlang:


Motorola[1] (ab 1979)
M68000 Family Resident Structured Assembler

Unterstützte Strukturen (Status 1983, 6. Ausgabe):

  • IF – ELSE – ENDI
  • WHILE – DO – ENDW
  • REPEAT – UNTIL
  • FOR – TO/DOWNTO – ENDF

Der 68000-Assembler von Motorola hat zu jener Zeit bereits die wichtigsten Strukturen unterstützt, allerdings gab es noch kein WHILE – DO – UNTIL und kein REPEAT – ENDR (bzw. LOOP – ENDL).

Statt ELSEIF wurde wegen den möglichen Größenangaben (.b, .w, .l) und unterschiedlichen Sprungweiten (.s, .l) per ELSE – IF – THEN verschachtelt (siehe auch Quelo).

BREAK und BREAK IF (also ein strukturiertes Verlassen der Strukturen) gab es ebenfalls nicht (war wegen einem fehlenden LOOP – ENDL ja auch nicht unbedingt nötig).

Dagegen hat der Motorola-Assembler im Unterschied zum später verfügbaren ziemlich erweiterten 68000-Assembler von Quelo (s.u.) eine FOR-Struktur unterstützt, die ich grundsätzlich für sehr hilfreich halte.

Bei Vergleichen wurden Condition Codes (wie bei Motorola üblich) per <cc> angegeben, also <EQ>, <NE>, <GT>, <GE> etc., die andere Anbieter von strukturierten Assemblern teilweise übernommen haben.

STRUKTA (1983, Rolf-Dieter Klein – "RDK"[2])

Precompiler STRU8080 (für i8080/i8085) bzw. STRUZ80 (für Z80), lauffähig unter CP/M

Unterstützte Strukturen:

  • IF – ELSEIF – ELSE – ENDIF
  • WHILE – ENDWHILE
  • REPEAT – UNTIL
  • LOOP – ENDLOOP
  • DO – ENDDO (entspricht FOR – ENDFOR)

Bei Vergleichen waren logische OR-, AND- und NOT-Verknüpfungen zulässig.

Besonders hilfreich waren Mengenabfragen per IN (wie bei PASCAL), die es bei allen anderen mir bekannten strukturierten Assemblern nicht gibt.

Der Precompiler erzeugte aus dem strukturierten Assembler-Quellprogramm ein "flaches" Assembler-Programm mit (vielen) vom Precompiler erzeugten Sprungadressen. Das erzeugte "flache" Assembler-Programm wurde dann mit den vorhandenen Tools (Assembler, Linker etc.) weiterverarbeitet.

Dasselbe Konzept wird auch bei SXp und s’AVR verwendet (s.u.), allerdings mit ein paar signifikanten Unterschieden.

Interessantes am Rande: Die Precompiler STRU8080 und STRUZ80 waren jeweils in ihrer eigenen Sprache geschrieben.

Ich habe von "RDK" noch ein ausgedrucktes Handbuch mit dem Titel "Ein Precompiler für effiziente Assemblerprogrammierung" und auch den Source-Code in STRUZ80-Sprache.

Diese Precompiler hatten eine kleine Tücke, da vom Precompiler der Stack verwendet wurde, um (ausschließlich) die LOOP-Struktur (die normalerweise endlos ist) per EXIT oder EXITIF zu verlassen.

Diese Methode (Verlassen per Stack-Eintrag) ist m.E. nicht konsistent und wäre auch gar nicht nötig, denn es könnte bei EXIT/EXITIF vom Precompiler genau so gut ein direkter Sprung zu einer Adresse direkt nach der LOOP-Schleife erzeugt werden, ohne den Stack zu belasten (so wie es generell bei SXp und s’AVR implementiert ist).

Die Tücke bei der STRUKTA-Methode: Falls man LOOP nicht "strukturiert" mittels EXIT/EXITIF verlassen hat oder der Stack zwischendurch verändert wurde, hat es zwangsläufig Stack-Probleme gegeben.

Interessant ist, dass Waferscale bei deren PAC1000 ein ähnliches Konzept für einen Schleifenzähler verfolgt hat (s.u.).
Der Hintergrund ist dort aber ein anderer, nämlich ein einziger Hardware-basierender Schleifenzähler.

Anhand des vorliegenden STRUKTA-Source-Codes wäre es ein Leichtes, die Benützung des Stacks bei der LOOP-Schleife durch einen Sprung zu ersetzen (vielleicht hat das später jemand umgesetzt?).

Quelo (1984, Dick Curtiss, USA)
A68K – ein sehr umfangreiches 68000-Macro-Assembler-Paket,
lauffähig unter CP/M und MS-DOS (und anderen Betriebssystemen?).

Unterstützte Strukturen:

  • IF – ELSE IF – ELSE – ENDI
  • WHILE – DO – ENDW
  • WHILE – DO – UNTIL
  • REPEAT – ENDR
  • REPEAT – UNTIL

Strukturen können per BREAK oder BREAK IF verlassen werden.

Statt LOOP – ENDL gibt es REPEAT – ENDR (loop forever).

Eine FOR-Struktur ist leider nicht vorgesehen. Man kann statt dessen z.B. REPEAT – UNTIL nehmen, muss dann eben ein paar zusätzliche Assembler-Befehle für die Initialisierung eines Zählerregisters und für die Schrittoperationen spendieren.

Bei Vergleichen sind die Größen .b, .w und .l zulässig.

Condition Codes werden (wie bei Motorola üblich) per <cc> angegeben, also <EQ>, <NE>, <GT>, <GE> etc.

Bei Vergleichen sind logische OR- und AND-Verknüpfungen zulässig.

Per Anweisungserweiterungen .s und .l kann man bei den Strukturen kurze Branch-Befehle (ggf. während dem Assemblieren reklamiert, falls Sprungweite zu klein) oder lange Sprungbefehle vorgeben.

Hier noch ein lesenswertes Zitat aus dem A68K-Handbuch (Auszug):

"The lack of structuring mechanisms in a programming language almost guarantees that programs written in the language will be difficult to comprehend. The reverse, however, is not true. Obscure programs can be produced in spite of good control structures in a language. A language is nothing more than a tool and, as with most tools, effective use depends on technique. Structured programming techniques may be acquired by the study of programs written by others and by creative imagination.

The point here is that it takes mental effort to create well organized programs. The payoff in structured programming is realized over the lifetime of a program in terms of reliability and maintainability. In the short term, especially when first acquiring technique, structured programming may seem like a burden. Stick with it. Once the skill is acquired, you will wonder how you ever managed without it."

Die Quelo-Assembler für CP/M und MS-DOS (auch lauffähig in einem DOS-Fenster unter Windows) kann man auch heute noch im Internet finden.

Mostek[3] (1984)
Strukturierter Macro-Assembler ASM-68000
, lauffähig auf PDP-11/VAX und unter Unix

Unterstützte Strukturen:

  • IF – ELSE IF – ELSE – ENDI
  • WHILE – DO – ENDW
  • REPEAT – UNTIL
  • LOOP – ENDL
  • FOR – TO/DOWNTO – BY – DO – ENDF

FOR-, LOOP-, REPEAT- und WHILE-Strukturen konnten per EXIT verlassen werden (ggf. auch mit einem Label, um eine mit diesem Label versehene höhere Struktur zu verlassen, offensichtlich jedoch keine IF-Strukturen).

Bei Vergleichen waren die Größen .b, .w und .l zulässig.

Condition Codes wurden (wie bei Motorola üblich) per <cc> angegeben, also <EQ>, <NE>, <GT>, <GE> etc.

Bei Vergleichen waren logische OR- und AND-Verknüpfungen zulässig (.b, .w und .l).

Per Anweisungserweiterungen .s (voreingestellt) und .l konnte man bei den Strukturen kurze Branch-Befehle (ggf. während dem Assemblieren reklamiert, falls Sprungweite zu klein) oder lange Sprungbefehle vorgeben.

Mostek[3] (1984)
ASM-68200
ein strukturierter Macro-Assembler für MK68200,
lauffähig auf PDP-11/VAX und unter Unix

Unterstützte Strukturen ähnlich wie ASM-68000, Vergleiche und logische Verknüpfungen nur .b und .w (16-Bit-µC).

Der "kleine" MK68200-Assembler unter CP/M und MS-DOS hat (leider) keine strukturierte Assembler-Programmierung unterstützt.

Waferscale[4] (1990)
PACSEL – PAC System Entry Language (Macro Assembler), lauffähig unter MS-DOS

Strukturierte Assemblersprache für PAC1000, einem vollintegrierten 16-bit-Bitslice-Controller u.a. mit 32+1 CPU-Registern, EPROM-basierendem Programmspeicher (1024 x 64 Bit) und integrierter Peripherie.

Unterstützte Strukturen:

  • IF – ELSE – ENDIF
  • FOR – ENDFOR (Stack-basierend)
  • SWITCH – CASE – ENDSWITCH
  • PSWITCH – PRIORITY – ENDPSWITCH (Priorität-gesteuert)
  • WHILE – ENDWHILE
  • GOTO – ON (bedingter Sprung)

Für die FOR-Struktur gab es einen separaten 10-bit-Schleifenzähler in Hardware, dessen aktueller Zählerstand vor jedem neuen FOR erst auf dem Stack gespeichert und nach ENDFOR wieder zurückgeholt wurde (dafür gab es extra Assembler-Befehle).

Damit konnte man geschachtelte FOR-Schleifen realisieren.

Allerdings war der Stack (der auch für Call, Push etc. verwendet wurde) nur 15 Ebenen tief.

Jedoch konnten aufgrund der sehr großen Befehlswortbreite mächtige Operationen pro CPU-Zyklus durchgeführt werden, wodurch man seltener Unterprogramme verwenden musste. Und durch die große Anzahl von Registern waren seltener Push/Pop-Befehle nötig. Beides hat den Stack entsprechend geschont.

PACSIM war der zugehörige Simulator unter MS-DOS.

NEC[8] (ab 1990)
RA75
(4-bit-µC) und RL78K (8/16-bit-µC, ALU ähnlich Z80)
Structured Assembler Preprocessor

Wie bei STRUKTA, SXp und s'AVR wird das strukturierte Quellprogramm zunächst separat in ein flaches Assembler-Quellprogramm übersetzt und dann vom nachgeschalteten Assembler/Linker weiter zum eigentlichen Objekt-Code verarbeitet.

Unterstützte Strukturen:

  • IF – ELSEIF – ELSE – ENDIF
  • WHILE – ENDW
  • REPEAT – UNTIL
  • FOR – NEXT
  • SWITCH – CASE – DEFAULT – ENDS

Für Bit-Abfragen standen die Varianten IF_bit, ELSEIF_bit, WHILE_bit und UNTIL_bit zur Verfügung.

FOR, REPEAT, WHILE und SWITCH konnten per BREAK abgebrochen werden (in eine Strukturebene zurück).

Per CONTINUE wurde bei WHILE und REPEAT der nächste Schleifendurchgang durchgeführt und per FOREVER war bei FOR, WHILE und REPEAT eine endlose Schleife möglich.

FOR-Schleifen erlaubten wahlweise eine Schrittgröße von +1 und -1 und eine Endebedingung.

Schließlich war noch ein nicht strukturierter "Rettungssprung" per GOTO-Anweisung möglich.

Die unterstützten Strukturen waren für beide µC-Familien dieselben, wobei die offensichtlich etwas neuere RL78K-Version erlaubte, die Sprungweite per Groß/Kleinschreibung (nur der erste Buchstabe war relevant) der strukturierten Anweisungen zu beeinflussen (auch gemischt innerhalb einer Struktur), wodurch unterschiedliche Assembler-Befehle erzeugt wurden.

Dies entspricht den sonst verwendeten Anweisungserweiterungen .l (long), .m (medium, nur bei s'AVR) und .s (short).

Die strukturierten Anweisungen konnten nur maximal 31 Ebenen tief verschachtelt werden.

IAR (1996)
Hitachi[8] H8 Assembler, Linker, and Librarian

Unterstützte Strukturen:

  • IFS – ELSEIFS – ELSES – ENDIFS
  • WHILE – ENDW
  • REPEAT – UNTIL
  • FOR – TO/DOWNTO – DO – ENDF
  • SWITCH – CASE – DEFAULT – ENDS

Da im Assembler Macros per IF – ELSE – END ohne vorangestelltes # o.ä. erlaubt waren, wurden die IF-Anweisungen für strukturierte Assembler-Programmierung per angehängten "S" unterschieden.

Schleifen und SWITCH konnten per BREAK verlassen werden.

Bei Vergleichen waren die Größen .b, .w und .l zulässig.

Condition Codes waren ähnlich wie bei Motorola per <cc>.

Bei Vergleichen waren logische OR- und AND-Verknüpfungen zulässig (.b, .w und .l).

Auch hier ein Auszug aus dem Handbuch:

"The H8 Assembler includes a versatile range of directives for structured assembly, to make it easier to implement loops and control structures at assembly level.

The advantage of using the structured assembly directives is that the resulting programs are clearer, and their logic is easier to understand.

The directives are designed to generate simple, predictable code so that the resulting program is as efficient as if it were programmed by hand."

Und: "IFS blocks can be nested to any level." – bis halt irgendwann der Programmspeicher überläuft ...

Zu den anderen Strukturen wird bezüglich zulässiger Verschachtelungstiefe keine Angabe gemacht.

Die Eigenschaft "to any level" bezüglich IFS galt im Unterschied zur bedingten Assemblierung, die maximal 50 Ebenen tief geschachtelt werden konnte. Ob aber dann (im Unterschied zur strukturierten Programmierung) noch die Übersicht über das jeweils assemblierte Programm bewahrt blieb?

IAR (2000, 2003)
Der Atmel AVR Assembler, Linker, and Librarian scheint keine Anweisungen für strukturierte Assembler-Programmierung zu unterstützen. Gibt es andere Versionen?

SXp-Lite und SXp-Full (2000, Eberhard Haug)

Precompiler für SX-µController von Scenix/Ubicom (später Parallax),
lauffähig unter Windows und Wine (Windows-Layer unter Linux).

Unterstützte Strukturen:

  • IF – ELSEIF – ELSE –ENDI
  • WHILE – ENDW
  • REPEAT – UNTIL
  • LOOP – ENDL
  • FOR – ENDF

Logische Verknüpfungen wurden nicht unterstützt, nur (mehrfaches) NOT (und gleichwertig die Negierung per !).

Verlassen einer Struktur per EXIT oder EXITIF in die nächst höhere Struktur.

Ein absoluter Sprung aus einer Struktur heraus war per EXITIF – TO zulässig (ein bedingtes GOTO).

SXp-Lite hat nur Strukturen innerhalb von (sehr kleinen) SX-Pages unterstützt, SXp-Full dagegen den gesamten Speicherbereich. Der (extrem kleine) Stack wurde von SXp nicht verwendet, allerdings notgedrungen das W-Register, um Rechenoperationen durchzuführen.

Aufgrund von vielen verfügbaren Skip-Befehlen konnte mit SXp ein sehr effektiver Code erzeugt werden (nahezu identisch mit reiner SX-Assembler-Programmierung).
Lediglich die kleinen Programmspeicher-Pages waren sehr hinderlich, aber per SXp-Full voll unter Kontrolle.

Da die SX-µController pin- und code-kompatiblel zur PIC16C5x-Serie von Microchip waren (bei gleicher Taktfrequenz jedoch 4x schneller), konnten mit SXp auch Programme für die PIC16C5x-Serie geschrieben werden, allerdings dann mit der (m.E. vorteilhaften) SX-Assembler-Syntax.

EASy68K (ca. 2004 ff, Prof. Charles Kelly, USA)
Editor/Assembler/Simulator for the 68000,
lauffähig unter Windows und Wine (Windows-Layer unter Linux).

Unterstützte Strukturen:

  • IF – ELSE – ENDI
  • WHILE – DO - ENDW
  • REPEAT – UNTIL
  • FOR – TO/DOWNTO – BY – DO – ENDF
  • DBLOOP – UNLESS

Die DBLOOP-Struktur ist eine Kombination aus FOR und REPEAT.

Bei Vergleichen sind die Größen .b, .w und .l zulässig.

Condition Codes werden (wie bei Motorola üblich) per <cc> angegeben, also <EQ>, <NE>, <GT>, <GE> etc.

Bei Vergleichen sind logische OR- und AND-Verknüpfungen zulässig.

Per Anweisungserweiterungen .s und .l kann man bei den Strukturen kurze Branch-Befehle oder lange Sprungbefehle vorgeben.

EASy68k enthält auch einen Simulator und ist heute noch kostenlos erhältlich.

s’AVR-Lite (2016, Eberhard Haug)

Precompiler für 8-Bit-AVR-µController von Atmel/Microchip,
lauffähig unter Windows und Wine (Windows-Layer unter Linux).

Unterstützte Strukturen:

  • IF – ELSEIF – ELSE –ENDI
  • WHILE – ENDW
  • REPEAT – UNTIL
  • LOOP – ENDL
  • FOR – ENDF

Logische Verknüpfungen werden derzeit nicht unterstützt, nur (mehrfaches) NOT (und gleichwertig die Negierung per "!").

Verlassen einer Struktur per EXIT oder EXITIF in die nächst höhere Struktur.

Bei Schleifen (FOR, LOOP, REPEAT, WHILE) kann die nächste Schleifen-Iteration vorzeitig per CONT oder CONTIF fortgesetzt werden (ab s’AVR 2.33, siehe hier).

Ein absoluter Sprung aus einer Struktur heraus ist per EXITIF – TO zulässig (ein bedingtes GOTO). Der Stack wird von s’AVR nicht verwendet.

Schmerzfrei oder sehr effizient

Da es bei den 8-Bit-AVR-µControllern (im Unterschied zu einigen anderen µControllern) nur sehr wenige Status-Register-abhängige Skip-Befehle gibt, ist ein maximal effizienter Code eigentlich nur realisierbar, wenn man jeweils die benötigte Sprungweite bei Programmverzweigungen weiß, was aber bei einem Precompiler prinzipbedingt normalerweise nicht der Fall ist.

Die anfangs verfügbare s’AVR-Lite-Version 1.x verwendet als "schmerzfreien" Kompromiss meist eine Kombination aus Branch-Befehlen (BRcc) mit RJMP (statt ausschließlich BRcc-Befehle), so dass immer Sprungweiten von bis zu +/- 2k Worten innerhalb einer Struktur möglich sind und es somit nicht die Einschränkung auf maximal +64/-63 Worte mit ausschließlich BRcc-Befehlen gibt, die man mit etwas komplexeren Programmstrukturen schnell erreicht hat.

s'AVR  Version 2 (23.7.2017)

Inzwischen gibt es einige Erweiterungen, u.a. kann nun mit s’AVR wahlweise auch Code für die effizientere BRcc-Methode generiert werden, dann aber eben mit der Einschränkung bzgl. +64/-63 Worten maximaler Sprungweite innerhalb einer Struktur, es sei denn, die größere Sprungweite wird per (neuer) s’AVR-Anweisungserweiterung .m (für medium) erzwungen.

Mehr dazu siehe ein paar Zeilen weiter unten oder ausführlicher hier.

 

Weitere Entwicklungs-Tools für strukturierte Assembler-Programmierung:

  • Zilog Z80?
  • Hitachi/Renesas?
  • IAR (weitere)?
  • Weitere?

Falls jemand hierzu Angaben machen kann, bitte ich um eine Mitteilung an nebenstehende E-Mail-Adresse (dann bitte die Quelle angeben und ob der Name mit veröffentlicht werden darf/soll) - vielen Dank!

nach oben


Schmerzfrei ist auch effizient (2.6.2017)

Nun wollte ich es doch noch etwas genauer wissen und habe mich an s’AVR Version 2.0 gemacht. Der Aufwand war etwas größer als gedacht ...

Diese Version erzeugt wahlweise entweder immer den bisherigen "schmerzfreien" Code der Version 1.x mit überwiegend BRcc/RJMP oder nun auch immer "effizienten" Code mit überwiegend BRcc - mit der bekannten Einschränkung bezüglich maximaler Sprungweite.

Falls s’AVR 2.0 nicht in Atmel-Studio eingebunden, sondern separat aufgerufen wird, erkennt man die zusätzlichen Möglichkeiten[9] bereits am Programmfenster:

sAVR2.0_Window


Für beide Optionen lässt sich im strukturierten Quellprogramm bei Bedarf zusätzlich eine individuelle Sprungweite per .s- und .m-Erweiterung ("m" für Medium) bei einigen der s’AVR-Anweisungen vorgeben (wie bei den oben beschriebenen Sprachen), so dass man nicht sehr umständlich im kompilierten Assembler-Programm per geänderten Abfragen mit RJMP-Befehlen eingreifen muss.

Wird kein .s oder .m an die betreffenden s’AVR-Anweisungen angehängt (wie z.B. bei einem für s’AVR 1.x geschriebenen Programm), gilt die per Radio-Button (siehe Bild) oder per Kommandozeilen-Parameter voreingestellte Sprungweite ("Default Structure Segment Range").

Die sonstigen Eigenschaften von s’AVR 2.0 sind wie hier beschrieben und ein Handbuch gibt es inzwischen auch (sowohl deutsch als auch englisch).

Der Unterschied im Ergebnis

Bei einem mit dem neuen "effizienten" Code untersuchten sehr umfangreichen s’AVR-Programm mit mehr als 1.000 Quellprogrammzeilen sind schnell - wie nicht anders zu erwarten - nach Reklamation des AVR-Assemblers bei einigen größeren s’AVR-Strukturen einige einmalige Eingriffe per .m-Erweiterung[5] nötig (wohlgemerkt im komfortablen s’AVR-Quellprogramm und nicht im kompilierten flachen Assembler-Programm).

Das untersuchte s’AVR-Programm hat aufgrund von vielen verschachtelten FOR/IF-Schleifen[6] eine sehr große Laufzeit (deshalb wurde es für den Vergleich ausgewählt).

Fazit für das untersuchte Programm:

  • Interessanterweise ist der Laufzeitgewinn zwischen "schmerzfrei" und "effizient" nur ca. 6%.
     
  • Andererseits ist die Programmspeicherbelegung der etwas schnelleren "effizienten" Variante um nahezu denselben Betrag von ca. 6% (ca. 50 Speicherworte) kleiner als bei der "schmerzfreien" Variante.
     
  • Dieses Ergebnis bestätigt zumindest bei dem überprüften Programm, dass der ursprüngliche "schmerzfreie" Ansatz per überwiegend BRcc/RJMP-Code immer noch akzeptabel effizient ist, auch wenn er streckenweise (wegen seiner Universalität) etwas eigenwillig generierte Assembler-Befehlsfolgen hat.

Bei anderen s’AVR-Programmen wird der Unterschied zwischen den beiden voreingestellten Optionen "schmerzfrei" und "effizient" (ggf. mit individuellen .m-Sprungweiteneingriffen) je nach Größe und Anzahl der s’AVR-Strukturen bestimmt ein anderer sein.

Noch effizienter?

Spannend wäre schließlich der Vergleich des untersuchten Programms (dessen Funktion schnell beschrieben ist) mit einer äquivalenten Version eines AVR-Assembler-Gurus, wobei ich aber keinen allzu großen Unterschied zur "effizienten" s’AVR-Variante erwarten würde.

Das Erstellen des reinen AVR-Assembler-Programms[7] ist auf jeden Fall deutlich mühsamer und fehleranfälliger.

Die Ackermann-Funktion (28.1.2019)

Einen umfangreichen Vergleich der Effizienz diverser CPUs auf Basis der Ackermann-Funktion gibt es inzwischen hier (Assembler, s’AVR, C und Pascal)

Berechnung der Fakultät großer Zahlen (10.6.2019)

Und hier werden AVR GCC und s’AVR in Bezug auf die Berechnung von Fakultäten großer Zahlen auf einem ATmega1284 verglichen - mit einem spannenden Ergebnis.

AVR-Tipps (9.12.2019)

Um einigen Stolperfallen vorzubeugen, sind hier Tipps rund um AVR und s’AVR zusammengestellt.
Weiterhin sind noch funktionelle Ergänzungen von s’AVR beschrieben und einige Beispiele dazu.

Wurzelberechnungen (3.8.2021)

Ein größerer Abschnitt ist der ganzzahligen Berechnung von Quadratwurzeln und dem Vergleich mit Programmbeispielen in C gewidmet.

nach oben


[1] Motorola > später Freescale, heute NXP

[2] RDK dürfte bei einigen "älteren Semestern" noch bekannt sein.
Er hat damals beim Norddeutschen Rundfunk viele TV-Computer-Sendungen gemacht und auch einige Bücher zum Thema Mikrocomputer und Programmiersprachen geschrieben (bei mir stehen ein paar davon im Bücherregal).

[3] Mostek wurde 1985 von Thomson-CSF (heute ST) übernommen.

[4] Waferscale wurde 2000 von ST übernommen.

[5] Das Quellprogramm benötigt im effizienten Mode vier .m-Erweiterungen bei FOR-Strukturen und eine .m-Erweiterung bei einer IF-Struktur, um ausreichend Sprungweite per RJMP- statt per BRcc-Befehlen zu erreichen.

[6] Aus der typischen Endlos-LOOP des Hauptprogramms heraus wird ein Unterprogramm mit neun verschachtelten FOR/IF-Strukturen aufgerufen und es ergibt sich eine Strukturtiefe des s’AVR-Unterprogramms von maximal 17.

Jede FOR-Schleife wird neunmal durchlaufen, woraus sich insgesamt
9^9 = 387.420.489 FOR-Durchläufe ergeben, die aber per IF-Abfragen vorzeitig abgebrochen werden (mehr Details inzwischen hier).

Schließlich ergeben sich aber immer noch mehrere Millionen sehr komplexe Operationen, die zu einer relativ großen Gesamtlaufzeit des Programms im Minutenbereich führen (natürlich abhängig von der Taktfrequenz des verwendeten AVR).

Meine Untersuchungen wurden mit einem ATmega328P und einem angeschlossenen LCD durchgeführt. Der Stack-Bedarf des Programms ist sehr gering, lediglich im SRAM werden einige Daten gewälzt, so dass man durchaus kleinere ATmegas und sogar ATtinys mit wenigstens 256 Byte SRAM und ausreichend I/O-Pins für das LCD verwenden kann.

[7] Das von s’AVR erzeugte "effektive" flache Assembler-Programm hat ca. 400 mehr Zeilen als das ursprüngliche s’AVR-Programm (s’AVR-Zeilen als Kommentar belassen, sonst ca. 270 Zeilen Unterschied).

Beim "schmerzfreien" Programm sind es sogar ca. 500 bzw. ca. 360 Zeilen Unterschied zwischen s’AVR-Programm und kompiliertem Assembler-Programm.

[8] Hitachi ist seit 2003 Teil von Renesas, NEC seit 2010.

[9] Weitere Möglichkeiten wurden im Laufe der Zeit dazugefügt, siehe u.a. hier.