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

Der Stack (Stapel)

Der Stack, organisiert nach dem

  • last-in first-out (LIFO-Prinzip),

gehört zu den grundlegenden Datenstrukturen der Informatik; er ist bei AVR-Prozessoren im SRAM eingebettet. Das LIFO-Prinzip bedeutet, dass das zuletzt auf dem Stapel abgelegte Byte auch zuerst wieder heruntergenommen wird.

Dieses Speicherprinzip ist von grundlegender Bedeutung für das Interrupt-System und den Mechanismus von Prozeduraufrufen bei Mikrocontrollern.

AVR-Mega-Prozessoren enthalten ein Stapelzeiger Register (SPH:SPL), einige wenige Stapel-Instruktionen und einen Stackpointer (SP).

------------------------------------------------------

Wofür wird der Stack benötigt?

  1. vorübergehende Speicherung von Registerwerten (siehe Übung 1)
  2. speichern einer Rücksprungadresse bei Prozedur-/ Unterprogrammaufrufen (siehe Übung 2)
  3. speichern lokaler Variablen und als Speicherbereich für Parameter bei Funktionsaufrufen
  4. bei Aufruf eines Interrupt-Handlers

Der SP zeigt nach seiner Initialisierung auf das Ende des SRAM-Bereichs und enthält die Adresse, an der das nächste Byte durch eine Push-Operation platziert werden soll.

  • Stack-Anweisungen dekrementieren den SP, wenn Daten auf  dem Stack abgelegt werden (PUSH-Instruktion), sodass er „nach unten wächst“.
  • Sie inkrementieren den SP, wenn Daten vom Stack entnommen werden (PULL-Instruktion).

-----------------------------------------------------

Was gilt es zu beachten?

Bevor der Stack genutzt werden kann, muss er initialisiert werden (nur bei den XMEGA-Typen ist die Initialisierung automatisiert). Dies erfolgt in einer bestimmten Routine zu Anfang eines Programms. Dabei wird das Ende des Stapels auf das letzte Byte im SRAM gesetzt:

  • SPH:SPL <- high(RAMEND):low(RAMEND).

Sobald Inhalte auf dem Stack abgelegt werden (PUSH-Instruktion), dekrementiert der SP; er zeigt also nie auf die aktuell abgelegten Daten, sondern immer auf die Adresse, an der das nächste Byte via PUSH-Instruktion abgelegt wird.

 

-----------------------------------------------------

Die Stack-Instruktionen PUSH und POP

Die beiden Instruktionen für den Stack sind

  • PUSH Rr
  • POP Rd

PUSH Rr speichert den Inhalt von Rr an der Adresse, die im SP angegeben ist und dekrementiert anschließend den SP.

  • Over- oder Underflow werden dabei nicht überprüft; das liegt in der Hand des Programmierers.

 

 

 

 

 

 

 

 

Abb. 0a

  • Speichert den Inhalt des Registers Rr auf dem STACK in die Speicherstelle, auf die der Stackpointer zeigt.
  • Anschließend wird der Stackpointer um 1 dekrementiert.
Abb. 0b - 16-Bit OP-Code der Instruktion PUSH

POP Rd inkrementiert zuerst den SP und lädt anschließend das Byte von der Adresse, die im SP steht in das Register Rd.

  • Es wird nicht überprüft, ob der Stack leer ist.

 

 

 

 

 

 

 

Abb. 0c

  • Inhalt der Speicherstelle, auf die der Stackpointer zeigt, wird in das Register Rd geladen.
  • Der Stapelzeiger wird vor Ausführung der POP-Instruktion um 1 inkrementiert.
Abb. 0d - OP-Code der Instruktion POP

Übung 1 - Vorübergehende Speicherung von Registerwerten (Sim)

Übung 1 - Vorübergehende Speicherung von Registerwerten
Aufgabe
  • Gib das Programm stack_1.asm in den Editor des AVR Studio ein und speichere es ab.
  • Bevor das Programm compiliert und im Simulator gestartet wird, überlege dir vorher, was in jeder Programmzeile passiert.
  • Starte anschließend den Debugger/Simulator.
  • Vorausgesetzt sei, dass ALLE Register belegt sind und ein weiteres freies Register für die Ansteuerung von PORTB benötigt wird.
  • Da kein freies Register mehr vorhanden ist, wird ein beliebiges belegtes Register ausgewählt (im Beispiel ist es R16), sein Inhalt auf dem Stack gesichert (PUSH R16), mit einem neuen Wert anschließend belegt (LDI R16, 0xAA) und die Ansteuerung von PORTB durchgeführt (LDI PORTB, R16); anschließend wird der alte Registerinhalt vom Stack zurückgeholt (POP R16).
  • Beschreibe für jede Programmzeile, was im Stack (SPH:SPL) steht und auf welche Stelle im SRAM der SP jeweils zeigt. Überprüfe im Debugger/Simulator deine Ergebnisse.
Material
  • AVR Studio
  • AVR Simulator (optional)

Programm stack_01.asm

In der Simulation lassen sich die Zwischenstände zu jedem Instruktionsaufruf darstellen und die Registerinhalte überprüfen. Das Programm wird NICHT in den Mikrocontroller gebrannt.

 

 

 

 

 

Abb. 1a

Im Stackpointer befinden sich nach Abarbeiten der Programmzeilen 18 - 21 die Bytewerte

  • SPL <- 5F, SPH <- 04

Es ist das obere Ende des SRAM in einem ATmega8.

 

 

 

Abb. 1b

Der Inhalt von R16 wird mit PUSH auf dem Stack abgelegt (Programmzeilen 25, 26).

  • 0x045F <- 0xF1

Der Stackpointer zeigt jetzt auf die Adresse 0x045E.

Nachdem R16 auf dem Stack abgelegt wurde, kann R16 neu beschrieben werden (Programmzeilen 27, 28).

Abb. 1c - R16 wird mit 0xAA neu beschrieben und sein Inhalt an PORTB weitergeleitet.

 

 

 

Abb. 1d

Mit dem POP Befehl wird der auf dem Stack gesicherte Inhalt von R16 zurückgeschrieben und der SP befindet sich wieder an der Adresse 0x045F.

  • R16 enthält wieder das Byte 0xF1

In der folgenden Übung 2 wird genauer untersucht was im Stack passiert, wenn ein Unterprogramm aufgerufen wird. Die beiden neuen Instruktionen sind:

RCALL k

 

 

 

 

Abb. 2a

  • Relativer Aufruf einer Adresse innerhalb von PC - 2K + 1 und PC + 2K (Wörter).
  • Die Rückkehradresse k wird auf dem Stack gespeichert.
  • Bei AVR-Mikrocontrollern mit einem Programmspeicher von nicht mehr als 4 K-Worten (8 KB) kann dieser Befehl den gesamten Speicher von jeder Adressstelle aus adressieren.
Abb,. 2b - OP-Code der Instruktion RCALL k

und RET

 

 

 

 

 

 

 

 

Abb. 2c

  • Rückkehr aus einem Unterprogramm.
  • Die Rücksprungadresse wird aus der STACK-Adresse, auf die der Stackpointer zeigt, in den Programmzähler (PC) geladen.
  • Der Stapelzeiger wird um 2 inkrementiert (16-Bit) bzw. 3 inkrementiert (24-Bit).
Abb. 2d - OP-Code der Instruktion RET

Übung 2 - Rücksprungadressen bei UProgrammaufrufen (Sim)

Übung 2 - Rücksprungadressen bei UProgrammaufrufen (Sim)
Aufgabe
  • Gib das Programm stack_2.asm in den Editor des AVR Studio ein und speichere es ab.
  • Bevor das Programm compiliert und im Simulator/Debugger gestartet wird, überlege dir vorher, was in jeder Programmzeile passiert.
  • Starte anschließend den Debugger/Simulator.
  • Beschreibe ab Programmzeile 0018, was im Stack (SPH:SPL) steht und auf welche Stelle der SP jeweils zeigt und welchen Wert der Programmzähler (PC) annimmt. Überprüfe im Debugger/Simulator deine Ergebnisse.
Material
  • AVR Studio
  • AVR Simulator (optional)

Programm stack_02.asm

 

 

 

 

 

 

 

Abb. 2a

Die Initialisierung des Stack erfolgt durch die Programmzeilen 0014 - 0017

Die beiden UProgramme uprog1 und uprog2 starten ab Programmzeile 0020.

Assembler-Listing von Programm stack_02.asm

 

 

Abb. 2b

Das Assembler-Listing zeigt den im Flash abgelegten OP-Code der Instruktionen in Spalte 3 und in Spalte 2 die Position des PC. Er startet bei Adresse 000000 in Line 14.

  • Nach dem Start des Programms im Simulator steht der Cursor an der Adresse 000000 oder in Programmzeile 0014 (siehe Abb. 2b).
  • Nach vier Programmschritten, der PC steht auf 0b00000100, dem nächsten Programmschritt, ist der Stack initialisiert. Bei einem ATmega8 ist die Adresse im SPH:SPL: 0x45F.
  • Der PC ruft den nächsten Befehl auf; mit RCALL wird in das Unterprogramm uprog1 verzweigt. Es befindet sich an der Adresse: 000006: PC + 2 <- PC. Der Programmcounter wird um 2 erhöht und im Stack wird die Adresse PC - 1 -> 0b0000 0101 abgelegt; genauer 3 Bytes bzw. 22 Bit bei einem ATmega8 Controller.  Das ist die Stelle im Programm, an der es nach Abschluss des Unterprogramms weiter geht (siehe Abb. 3a).

 

 

 

 

Abb. 3a

Auf dem Stack wird Einsprungadresse 0x05 abgelegt; Das Programm macht an dieser Stelle nach einem RET Befehl weiter.

  • Im Unterprogramm uprog1 wird ein zweites Unterprogramm uprog2 aufgerufen. PC steht auf 000006. Uprog2 hat die Adresse 000008 (Line 22) (siehe Abb. 2b): PC+ 2 <- PC. PC wird um 2 auf neu 0b00001000 erhöht. Auf dem Stack wird die Adresse 0b00000111 abgelegt. Mit der dort stehenden Instruktion geht es nach Abschluss des Unterprogramms uprog2 weiter.

 

 

 

 

Abb,. 3b

Auf dem Stack wird Einsprungadresse 0x07 abgelegt; Das Programm macht an dieser Stelle nach einem RET Befehl im Unterprogramm uprog2 weiter.

Druckversion | Sitemap
© Reinhard Rahner - Gettorf