Aus RN-Wissen.de
Wechseln zu: Navigation, Suche


Compiler

Das, was letzlich ein Micro-Controller tut, wird ausschließlich durch das bestimmt, was wir in den Program-Flash reinladen. Üblicherweise ist das eine "*.HEX" Datei, die in etwas seltsamer Form doch nur ein 1:1 Bild der Bits und Bytes ist, wie sie dann im Speicher stehen. Und das sind feststehende Daten (wie z.B. Umrechnungs-Tabellen), und das übersetzte Programm.

Compiler1.png
Schematischer Ablauf der Compilerung anhand der Beispiele BASCOM, FASTAVR und GCC

Die Code-Erzeugung geschieht meistens in mehreren Schritten, die oft auch explizit in einem sogenannten "makefile" stehen können.

Precompilerung
Es werden die Anweisung aufgelöst, mit denen der Sourcecode eigentlich erst vollständig wird, wie Makros und symbolische Namen. Meistens sind solche Anweisungen an bestimmten vorangestellten Zeichen erkennbar, wie z.B. "#" (C/C++) und "$" (BasCom).
Compilierung
Der eigentliche Compile-Vorgang, bei dem oft erstmal nur "Objects" erzeugt werden (Das ist zwar schon Maschinencode, aber noch mit vorläufigen Sprung- und Datenadressen).
Linken
bindet diese Objekte zusammen und ersetzt die verschieblichen Adressen durch absolute Werte

Und eventuell noch

Konvertieren
um die endgültige "HEX" File zu erhalten

Varianten der Programmentwicklung

"Echte" Compiler

Das sind zum Beispiel Assembler, Bascom, GCC. Die verhalten sich genau so wie in der Darstellung und erzeugen mehr oder weniger direkt den Maschinen-code für einen ganz konkreten Controller. "FastAVR", den ich aber mangels besserer Kenntnis hier nur erwähnen will, ist wohl eher ein Programm-Generator.

Program-Generator

Es gibt auch die Gruppe der "Programm-Generatoren". Die erstellen als Ergebnis einen Source-Code eine anderen Sprache, den man dann nochmals übersetzen muß. Bei einigen Micro-Controller-Compilern ist es auch so, daß die als Zwischen- oder Nebenprodukt Assemblercode herstellen, den man noch überarbeiten könnte, wenn man das will. Die Tücke dabei ist, daß das aber nicht umgekehrt geht, d.h. bei jeder Änderung der ursprünglichen Source muß man solche Anpassungen nochmal machen.

Virtual Machines

Compiler dieser Kategorie (JAVA) erzeugen ebenfalls Maschinencode, aber für eine Maschine, die es eigentlich garnicht gibt. Auf dem Zielsystem (Prozessor, Controller) läuft dann ein Programm, daß diesen Code zum Laufzeitpunkt auf den realen Maschinencode umsetzt. Der Gedanke ist ja nicht schlecht: Ich kann für alle möglichen Rechner EINE Applikation entwickeln, daß dann ohne weiteres auf jedem x-beliebigen Computer ablaufen kann, für den es dieses "Umsetz"-Programm gibt.

"Basic" Controller

(PICAXE) Auch hier wird in zwei Teilen kompiliert /übersetzt: Erstmal ein Basic-Dialekt in eine Art "Token"-Format (kann man als "Kürzel" bezeichnen). Dieses Format wird dann auf den Controller geladen und hier läuft dann als "Firmware" ein Interpreter, der diese Token dann für den RISC-Controller aufbereitet.

Source Code

Recht grob, aber doch, besteht jedes Programm für jeden Compiler (mit unterschiedlicher Gewichtung) aus drei Teilen:

Definition des Zielsystems

Man muß dem Compiler sagen, für welchen Controller er den Code generieren soll. Meistens durch "Kommandozeilen-Parameter" (GCC) oder "$Regfile= xxx " (Bascom). Die Absicht ist, daß man den restlichen Source-Code nicht ändern muß, wenn man einen anderen Controller verwenden will. Das ist aber schon recht theoretisch, denn so standardisiert, wie es bei den PCs ist (durch das Betriebssystem), sind die Microcontroller beileibe nicht.

Deklaration der Daten

Bekanntmachung, welche Daten/Funktionen verwendet werden, um andere Module darüber in Kenntnis zu setzen. Eine Deklaration ist zu unterscheiden von einer Definition.

Definition der Daten

Hier wird definiert, mit welchen Daten das Programm arbeiten soll. Beim Assembler kann man das auch bleibenlassen, der ist da nicht so heikel, im anderen Extrem, bei den ++ Objekt-orientierten Sprachen, muß hier bereits recht detailliert beschrieben werden, was man braucht und wie man mit diesen Daten im restlichen Programm denn umgehen will.

  • Elementare Datentypen: Typen, die zum Sprachumfang gehören
  • Einzelfelder: eines oder mehrere Byte, die zusammen eine bestimmten Datentyp bilden
  • Arrays: das sind ein- oder mehrdimensionale Tabellen, wobei die Elemente Einzelfelder, aber auch Strukturen sein können
  • Strukturen: Zusammenfassung von Einzelfeldern oder anderen Strukturen zu zusammenhängenden Einheiten

Adressierung der Daten

  • direkt

Das Datum wird direkt mit seiner Adresse angesprochen, meist symbolisch durch einen eindeutigen Namen.

  • indirekt

Die Datenadresse steht in einem Pointer (Zeiger), und dieser Pointer wird im Programm angegeben. (Das geht bei vielen Sprachen auch mehrstufig, d.h. die adresse der adresse).

Befehle

Das eigentliche Programm in Form von mehr oder weniger symbolischen und/oder abstrakten Anweisungen. Auch hier gibt es Unterscheidungen

Anweisungen
  • Zuweisungen
Variable = ausdruck
  • Funktionsdefinitionen
Variable = funktion (argument)

Dabei ist "argument" eine Liste von Ausdrücken (die aber auch leer sein kann)

Anweisungsblöcke

Mehrere Anweisungen werden als "Block" zusammengefaßt, das ist vor allem für die folgenden Ablauf-Kontrollbefehle relevant.

Kontrollstrukturen
  • Unbedingte Verzweigung
GOTO 
CALL /GOSUB ... RETURN

Da die aufgerufene Prozedur mit RETURN wieder zurückkehrt, muß man den Begriff "Verzweigung" allerdings etwas relativiert sehen

  • Bedingte Verzweigung
IF (Bedingung) THEN ...  ELSE .... END IF
  • Auswahl / Bedingte Mehrfach-Verzweigung
SELECT CASE  .....   END SELECT
  • Wiederholungs-Schleifen

Wichtige Unterscheidung ist, ob die Schleifenbedingung VOR oder NACH den enthaltenen Anweisungen geprüft wird

DO .. WHILE         Prüfung am Ende des Durchlaufs

WHILE ... WEND      Prüfung vorher

FOR .. NEXT   (Sonderform von WHILE...WEND, meist als Zählschleife)

Siehe auch