Unterprogramme
Aufbau eines Unterprogramms
Ein Unterprogramm beginnt mit einem Label und endet mit ret
(=return).
Beispiel:
zeit:
; Code
ret
Aufruf eines Unterprogramms
Für den Aufruf eines Unterprogramms existieren zwei Befehle
Nahezu jeder Assembler erlaubt die Verwendung von
call
, welches er je nach Bedarf in ein
acall
oder
lcall adr16
umsetzt.
Bei einem call
-Befehl springt der Mikrocontroller in das Unterprogramm, arbeitet es ab und kehrt mit ret
direkt hinter
den call
-Befehl zurück.
Ein jmp
-Befehl würde zwar ausreichen um in das Unterprogramm zu springen, allerdings könnte man nicht mehr zum Aufrufer zurückkehren,
da dessen Adresse nicht gespeichert wäre.
Da ein Unterprogramm von mehreren beliebigen Stelle im Code aufgerufen werden kann, muss sich der Mikrocontroller
die Rücksprungadresse merken. Da ein Unterprogramm wiederum Unterprogramme aufrufen kann reicht ein einziger Speicherplatz für diese Rücksprungadresse
nicht aus. Aus diesem Grund wird für die Sicherung der Rücksprungadressen der Stack verwendet.
Der Stack
Ein Stack (im deutchen Kellerspeicher) ist ein Speicher in welchen man Werte speichern kann und diese beim Auslesen in umgekehrter Reihenfolge
bekommt. Er verhält sich also wie ein Tellerstapel, das zuletzt abgelegte Teller wird als erstes wieder herausgenommen.
Einen Wert auf den Stack legen nennt man pushen, einen Wert vom Stack nehmen heißt popen. Der Assembler hat hierfür die Befehle push dadr
und pop dadr
.
Bei einem Unterprogrammaufruf wird die aktuelle Adresse des Programm Counters (PC) auf den Stack gepushed, zuerst das niederwertige und dann das
höherwertige Byte des PC. Bei einem ret
werden die zwei obersten Werte vom Stack genommen (gepoped) und in den PC geschrieben.
Durch diese Änderung des PC kehrt das Programm wieder zum Aufrufer zurück.
Da der Stack eine variable Größe hat merkt sich der Mikrocontroller in dem Stackpointer (SP) an Adresse 081h im SFR die Adresse des letzten Werts
des Stacks. Der Stackinhalt (die gespeicherten Werte) werden im RAM abgelegt. Zu Beginn hat der SP den Wert 7. Beim Ablegen auf den Stack wird
zuerst der SP erhöht und an der Speicherzelle im RAM, auf welche SP verweist, der Wert gespeichert.
Beim herunternehmen eines Wertes wird genau umgekehrt vorgegangen: Zuerst wird der Wert vom Stack ausgelesen (Adresse aus dem SP)
und dann der SP um eins vermindert.
Werte sichern
Ein Unterprogramm soll nur die Werte der Speicherzellen verändern die es muss. Berechnet ein Unterprogramm etwas und legt das Ergebnis an
Port 1 ab, so sollte sich außer P1 nichts verändern. Ist ein Unterprogramm nur dazu da um eine gewisse Zeit zu warten, so soll es keine
Speicherzelle verändern.
Bei dem Beispiel eines Unterprogramms, welches wartet verändern die Zeitschleifen darin z.B. die Register R0 bis R2. Damit dennoch die Werte
der Register vor und nach dem Aufruf des Unterprogramms gleich sind müssen sie gesichert werden. Für dieses Sichern und Wiederherstellen wird
der Stack verwendet.
Werte sichern geschieht mit
push dadr
, das Wiederherstellen am Ende des Unterprogramms mit
pop dadr
. Hierbei ist darauf
zu achten, dass man die Werte in umgekehrter Reihenfolge wiederherstellt in welcher man sie gesichert hat.
Beispiel: Sichern von Werten auf dem Stack
zeit:
push R3
push R2
push R1
;Zeitschleife
pop R1
pop R2
pop R3
ret