Unterrichts- und Lernmaterial für Mikrocontroller
Unterrichts- und Lernmaterial fürMikrocontroller

Fundamentum 1

In Fundamentum 1 wird auf den Maschinencode, der sich hinter der Assemblerprogrammierung versteckt, etwas näher eingegangen.

Die Speicher

Die ATmega Prozessoren verfügen über drei verschiedene Speicher.

  • Flash (Programmspeicher) - nicht flüchtig
Abbildung 1 - Programmspeicher des ATmega8515
  • SRAM (static RAM) - flüchtig
Abbildung 2 - Der Datenspeicher des ATmega8515

Das Speicherregister unterteilt sich noch einmal in das I/O memory und register file.

  • EEPROM (electrical erasable programmable read only memory) - nicht flüchtig

Der Programmspeicher enthält Instruktionen von 16-Bit Wortlänge; er ist WORD-adressierbar, besteht also aus zwei Byte. SRAM und EEPROM sind Byte-adressierbar.

Die Register

Der ATmega8515 besitzt unter anderen

  • 32 GPIO Register (8-Bit) : R0 - R31,
  • einen 16-Bit Programmzähler (PC),
  • ein Befehlsregister (instruction register)
  • ein Befehls-Decoder-Register.

Die letzten drei Register sorgen dafür, dass die im Programmspeicher abgelegten Instruktionen korrekt ausgeführt werden.

Betrachten wir als Beispiel die Instruktion

  • LDI hreg_1, high(Ramend)

Im AVR Instruction Manual werden alle Instruktionen der AVR-Controller beschrieben. Die LDI Instruktion ist ein 16-Bit Opcode mit folgendem Format:

Die 16-Bit der Instruktion LDI (load immediately) sind in vier Nibble aufgeteilt.

Nibble 3 ist der sogenannte OP-Code der Instruktion, hier also 0b1110.

Nibble 0 und 2 stellen acht Bit für eine Konstante zur Verfügung. Es lassen sich damit Werte von 0 bis  255 darstellen.

Nibble 1 beschreibt das Zielregister, in das die Konstante geladen werden soll. Mit vier Bits lassen sich maximal 16 Register benennen: R16 - R31. Zur Darstellung der Zahlen 16 bis 31 benötigt man binär eigentlich 5 Bits, die alle im höchsten Bit eine 1 stehen haben. "Schneidet" man diese 1 ab, dann entspricht der Binärzahl 0b0000 das Register R16, 0b0001 das Register R17 usw.

 

Der Befehl

  • LDI hreg_1, high(RAMEND)

lädt in das Register hreg_1 (R16) das higher Byte von Ramend und das ist 02. Der zugehörige  binäre Maschinencode lautet:

  • 1110  0000  0000  0010    oder hexadezimal   $E0 02

Nibble 3 ist der OP-Code für die Instruktion LDI, in Nibble 2 und Nibble 0 steht die Konstante 2 und in Nibble 2 das Zielregister R16 mit der Adresse 0b0000.

 

Der Befehl

  • LDI hreg_1, low(RAMEND)

lädt in das Register hreg_1 das lower Byte von Ramend, das ist 5F. Der zugehörige binäre Maschinencode lautet jetzt:

  • 1110  0101  0000  1111    oder hexadezimal  $E5 0F

Die beiden eben besprochenen Ladebefehle tauchen in einem strukturierten Assemblerprogramm meistens gleich zu Anfang des Programms im Reset-Block auf und initialisieren den sogenannten Stack. Das nachfolgende einfache Programm macht nichts anderes als nur den Stack zu initialisieren.

 

  • Gib das folgende Programm in den Editor ein, speichere es unter dem Namen fundamente1.asm ab und kompiliere es anschließend.

Gleich zu Anfang des Programms wurde die Direktive

  • .LIST

eingebaut. Dadurch wurde im Project-Manager von AVR Studio im Verzeichnis OUTPUT nach dem Kompilierungsvorgang eine Datei fundamente1.lst angelegt. Mit einem Doppelklick öffnen wir sie.

Ganz links befinden sich zwei Spalten. Die schauen wir uns jetzt näher an. Die Spalte ganz links beginnt bei 000000 und gibt die Adresse im Programmspeicher an. Rechts daneben steht der Maschinencode, also das, was der Compiler aus unserem Assemblerprogramm "gemacht" hat. Der Maschinencode ist für jede Instruktion einzeln ausgewiesen.

  • Der Befehl LDI hreg_1, high(Ramend) wird als Maschinencode zu $E0 02.
  • Der Befehl LDI hreg_1, low(Ramend) wird als Maschinencode zu $E5 0F.

Es sind genau die Ergebnisse, die wir oben gerade besprochen haben.

Auf die gleiche Weise lassen sich die beiden anderen Maschinenbefehle aus dem Assemblerprogramm herleiten. Dazu muss nur der OP-Code der Instruktion OUT (AVR Instruction Manual) und die Adresse des Stackpointer-Registers nachgeschlagen werden.

 

Die OUT Instruktion ist ein 16-Bit Opcode mit folgendem Format:

Nibble 3 ist der sogenannte OP-Code der Instruktion OUT.

Nibble 0 und 2 stellen sieben Bit für eine Zieladresse im I/O Registerraum. Es lassen sich damit Werte von 0 bis  63 eingeben. Das Highbyte des Stackpointers (SPH) hat die Adresse $3E oder 0b0011 1110, das Lowbyte $3D oder 0b0011 1101. Das höchste Bit in Nibble 2 ist vom Hersteller vorgegeben eine 1 und das niedrigste Bit ist das höchste Bit (Bit 5) für das in der Instruktion angesprochene Arbeitsregister R16 (0b10000).

Nibble 1 beschreibt die restlichen vier Bits des angesprochenen Arbeitsregisters, aus dem Daten an die Zieladresse übertragen werden.

Der Befehl

  • OUT SPH, hreg_1

wird als binärer Maschinencode zu:

  • 1011  1111  0000  1110    oder hexadezimal   $EF 0E

Der Befehl

  • OUT  SPL, hreg_1

wird als binärer Maschinencode zu:

  • 1011  1111  0000 1101   oder hexadezimal  $EF 0D.

Im Programmlisting finden wir genau diese Eintragungen.

Auf die gleiche Weise lässt sich für die abschließende RJMP-Instruktion dem Instruction Manual entnehmen:

In den Nibbeln 0 - 2 steht die Anzahl der Zeilen, die innerhalb des Programmes zurück- oder vorgesprungen werden soll. In diesem Fall ist es ein Rücksprung um eine Programmzeile, also -1 oder 0b1111 1111 1111 oder $FFF. Zusammen mit dem OP-Code ergibt sich als Maschinencode: $CF FF.

Der Maschinencode ist im Programmspeicher abgelegt und kann mit Hilfe des Debuggers im AVR-Studio sichtbar gemacht werden.

Der Maschinencode ist in little-endian-order im Programmspeicher ab Position $0000 abgelegt. Er setzt sich aus fünf Instruktionen zusammen: zwei LDI-, zwei OUT-Instruktionen und einer RJMP-Instruktion.

Die Map-Datei

Im Verzeichnis Output wird nach dem Compilieren eines Programms eine Tabelle *.map angelegt, in der alle benutzten Symbole mit den ihnen zugeordneten Werten zu finden sind. Für das vorliegende Beispielprogramm finden sich am Ende der Liste folgende Eintragungen:

Kommentar schreiben

Kommentare

  • olaf (Sonntag, 10. Dezember 2017 08:35)

    wow...die mit Abstand beste Site, die ich bisher zu diesem Thema gesehen habe :-))
    Vielen Dank dafür. Hilft super beim Erklären!!

  • David Eisenblätter (Sonntag, 11. Februar 2018 13:38)

    Sehr schön erklärt, und zufällig heute, wo ich nochmal nach einer detailierten Gedankenstütze diesbezüglich gesucht habe!

    Vielen vielen Dank!

    David.

Bitte geben Sie den Code ein
* Pflichtfelder
Druckversion Druckversion | Sitemap
© Reinhard Rahner - Gettorf