Unterprogrammtechniken: Unterprogrammanschluß, Parameterübergabe, Globale Programm- und Datenzugriffe

Unterprogrammtechniken

Unterprogramme sind in sich abgeschlossene Befehlsfolgen, die an beliebigen Stellen eines übergeordneten Programms, des Haupt- oder Oberprogramms, wiederholt aufgerufen und ausgeführt werden können. Nach Abarbeitung eines Unterprogramms wird das übergeordnete Programm hinter der Aufrufstelle fortgesetzt. In Bild 3.10 ist der zeitliche Ablauf zweier Unterprogrammaufrufe durch aufeinanderfolgende Nummern illustriert. Beim Aufruf kann ein Unterprogramm mit Rechengrößen versorgt werden, und es kann seinerseits Ergebnisse an das Oberprogramm zurückgeben. Man bezeichnet diese Größen als Parameter und den Vorgang als Parameterübergabe.

Unterprogrammtechniken: Unterprogrammanschluß, Parameterübergabe, Globale Programm- und Datenzugriffe

Die Verwendung von Unterprogrammen bietet folgende Vorteile :

  • Sich oft wiederholende Befehlsfolgen brauchen nur einmal programmiert und nur einmal gespeichert zu werden.
  • Programme lassen sich modular aufbauen; sie werden dadurch übersichtlicher, sind leichter zu testen und besser zu dokumentieren.
  • Ein Unterprogramm kann unabhängig vom Oberprogramm und von anderen Unterprogrammen übersetzt werden. Bei einer Fehlerkorrektur im Unterprogramm braucht dann nur dieses neu übersetzt zu werden.
  • Größere Programme können in Unterprogramme zerlegt und von mehreren Personen gleichzeitig geschrieben werden.
  • Bibliotheken mit Standardunterprogrammen können allen Benutzern eines Mikroprozessorsystems zur Verfügung gestellt werden.

Unterprogrammanschluß

Unterprogrammaufruf. Der Aufruf eines Unterprogramms erfolgt durch den Befehl JSR mit dem Namen des Unterprogramms als Adresse. Diese Adresse steht als Symbol im Namensfeld des ersten auszuführenden Befehls des Unterprogramms. JSR schreibt den aktuellen Befehlszählerinhalt (das ist die Adresse des auf JSR folgenden Befehls) als Rücksprungadresse in den aktuellen Stack (Normal- oder Systemstack) und lädt den Befehlszähler mit der im Adreßteil von JSR stehenden Unterprogrammadresse. Danach obliegt die Programmsteuerung dem Unterprogramm. Der Rücksprung in das Oberprogramm erfolgt mit dem Befehl RTS, der das Unterprogramm abschließt. RTS liest den letzten Stackeintrag – die Rücksprungadresse – und lädt ihn in den Befehlszähler.

Wird der Stack vom Unterprogramm z.B. über die Befehle PUSH und POP auch zur Datenspeicherung benutzt, so ist darauf zu achten, daß der RTS-Befehl genau denjenigen Stackpointer vorfindet, der unmittelbar nach dem Unterprogrammaufruf vorlag; andernfalls erfolgt ein unkontrollierter Sprung. Im allgemeinen werden deshalb die Rücksprungadressen und die Daten getrennt voneinander in einem Programm- und einem Datenstack angelegt.

Statusretten. Wenn das Unterprogramm und das Oberprogramm die Prozessorregister völlig unabhängig voneinander benutzen, so muß beim Unterprogrammaufruf der gesamte Prozessorstatus gerettet und bei der Rückkehr ins Oberprogramm wieder geladen werden. Zum Prozessorstatus gehören neben dem Befehlszählerstand die Inhalte der allgemeinen Prozessorregister und der Inhalt des Statusregisters. Während das Retten und Laden des Befehlszählers automatisch bei der Ausführung der Befehle JSR und R TS erfolgt, muß es für die übrigen Register explizit programmiert werden. Für das Retten und Laden der allgemeinen Register kann der MOVEM-Befehl herangezogen werden; für das Retten und Laden des Statusregisters steht der MOVSR-Befehl zur Verfügung. Bei Programmen im Normalmodus muß anstelle des privilegierten Befehls MOVSR der MOVCC-Befehl verwendet werden, der lediglich die Bedingungsbits transportiert. Dies ist jedoch keine Einschränkung, da im Normalmodus die Statusbits im Statusregister nicht verändert werden. Als Ort für das Speichern der Statusinformationen kann der Normal- bzw. Systemstack verwendet werden, der auch für das Retten der Rücksprungadresse benutzt wird.

Das Retten und das Laden des Prozessorstatus kann sowohl im Oberprogramm als auch im Unterprogramm durchgeführt werden. Welche Möglichkeit gewählt wird, ist eine Frage der Programmorganisation. Erfolgt das Retten im Oberprogramm und ist die Benutzung der Register durch das Unterprogramm nicht bekannt, so müssen alle allgemeinen Prozessorregister berücksichtigt werden. Erfolgt das Retten hingegen im Unterprogramm, so kann man sich auf diejenigen Register beschränken, die vom Unterprogramm benutzt werden. Der Vorgang des Statusrettens wird dadurch beschleunigt.

Beispiel 3.17. Retten und Laden des Prozessorstatus. Beim Aufruf eines Unterprogramms im Normalmodus soll der Prozessorstatus, bestehend aus der Rücksprungadresse, den Bedingungsbits ce und den allgemeinen Registern RO bis R6 auf den Normalstack gerettet werden. – Das Retten der Rücksprungadresse erfolgt durch den Befehl JSR. Die Bedingungsbits und die Registerinhalte RO bis R6 werden vom Unterprogramm mit den Befehlen MOVCC und MOVEM auf den Normalstack geschrieben, wobei R7 als Stackpointerregister verwendet wird. Das Laden des Status mit Abschluß des Unterprogramms erfolgt in umgekehrter Reihenfolge; RTS übergibt über die im Stack gespeicherte Rücksprungadresse die Programmsteuerung wieder an das Oberprogramm. Die korrespondierenden Nummern im Programm und in der Abbildung zeigen die Wirkung der Befehle auf die Belegung des Stacks.

Unterprogrammtechniken: Unterprogrammanschluß, Parameterübergabe, Globale Programm- und Datenzugriffe

Beispiel 3.17.

Parameterübergabe

Für die Übergabe von Parametern an das Unterprogramm bzw. zurück ins Oberprogramm gibt es drei Gesichtspunkte, die die Programmierungstechnik beeinflussen:

  1. Art des Parameters, z.B. Wert, Adresse,
  2. Ort der Parameterübergabe, z.B. allgemeine Prozessorregister, Stack, Datenbereich des Oberprogramms, Programmbereich des Oberprogramms,
  3. Anzahl der Parameter.

Art der Parameter. Bei einem Unterprogrammaufruf mit Wertübergabe (call by value) wird der Wert einer Rechengröße als Parameter in den Datenbereich des Unterprogramms kopiert; dort muß ein Speicherplatz für diesen Wert reserviert sein. Das Unterprogramm hat direkten Zugriff auf den Wert und kann ihn verändern, ohne daß der ursprüngliche Wert im Oberprogramm beeinflußt wird. Bei einem Unterprogrammaufruf mit Adreßübergabe (call by reference) wird die Adresse einer Rechengröße als Parameter in das Unterprogramm transportiert, d.h. der Operand selbst verbleibt im Oberprogramm. Der Zugriff auf den Operanden durch das Unterprogramm erfolgt indirekt über den Adreßparameter. Die Parameterübergabe zurück an das Oberprogramm erfolgt als Wertübergabe entweder direkt, z.B. im Registerspeicher, oder indirekt über einen Adreßparameter.

Die Parameter, mit denen das Unterprogramm als fiktive Größen geschrieben wird, nennt man formale Parameter. Vor der Ausführung des Unterprogramms müssen diese durch die zum Zeitpunkt des Aufrufs bekannten Parameter, die aktuellen Parameter, ersetzt werden.

Ob beim Unterprogrammaufruf die Wertübergabe, die Adreßübergabe oder eine Kombination bei der Möglichkeiten verwendet wird, ist von Fall zu Fall verschieden und hängt unter anderem von folgenden Kriterien ab:

  • Zeitaufwand für die Parameterübergabe,
  •  Speicherplatzbedarf für die Parameter,
  • Adressierungsaufwand für den Zugriff durch das Unterprogramm,
  • Schreibschutz für die Daten des Oberprogramms.

Unterprogrammtechniken: Unterprogrammanschluß, Parameterübergabe, Globale Programm- und Datenzugriffe

Üblicherweise wird die Wertübergabe nur für Einzelwerte benutzt; für die Übergabe von Feldern wird aus Gründen der Zeit- und Speicherplatzersparnis die Adreßübergabe bevorzugt. – Den prinzipiellen Ablauf der Parameterübergabe zeigt Bild 3.11. In der Flußdiagrammdarstellung wird ein Unterprogrammaufruf durch doppelte Seitenlinien im Rechtecksymbol gekennzeichnet.

Parameter, die an das Unterprogramm übergeben werden und deren Werte dort benutzt, aber nicht verändert werden, bezeichnet man als Eingangsparameter. Dementsprechend bezeichnet man Parameter, denen erst im Unterprogramm Werte zugewiesen werden und die auch erst danach benutzt werden können, als Ausgangsparameter. Parameter, deren Werte im Unterprogramm zuerst benutzt und danach verändert werden, bezeichnet man als Übergangsparameter.

Ort der Parameterübergabe. Der Ort der Parameterübergabe muß sowohl dem Ober- als auch dem Unterprogramm zugänglich sein. Werden nur wenige Parameter übergeben, so bietet sich hierfür der Registerspeicher des Prozessors an. Diese Möglichkeit erfordert den geringsten Organisationsaufwand für die Vorbereitung und die Durchführung der Parameterübergabe. Reicht die Anzahl der verfügbaren Register nicht aus, so müssen die Parameter in einem von Ober- und Unterprogramm gemeinsam verwalteten Speicherbereich übergeben werden, was zu einem höheren Organisationsaufwand führt. Hier bieten sich drei Möglichkeiten an.

  1. Man schreibt die Parameter vor dem Unterprogrammaufrufin einen Stackbereich und übergibt dem Unterprogramm den Stackpointer im Registerspeicher; der Parameterzugriff erfolgt über den Stackpointer.
  2. Man faßt die Parameter im Datenbereich des Oberprogramms zu einem Parameterfeld zusammen und übergibt dessen Anfangsadresse dem Unterprogramm ; die Adreßübergabe kann in einem allgemeinen Register oder über den Normal- bzw. Systemstack vorgenommen werden; der Parameterzugriff erfolgt über diese Adresse.
  3. Man faßt die Parameter im Programmbereich des Oberprogramms in einem Parameterfeld zusammen, das unmittelbar hinter dem Unterprogrammsprungbefehl JSR steht; der Parameterzugriff erfolgt über die im Normalbzw. Systemstack gespeicherte Rücksprungadresse des Unterprogramms.

Im folgenden illustrieren wir die verschiedenen Möglichkeiten der Parameterübergabe durch das bereits in Beispiel 3.16 dargestellte Problem, das allerdings wegen der Kürze des Programmtextes nicht als repräsentativ angesehen werden kann. Um das Programm nicht noch mehr zu kürzen, verzichten wir auf die Verwendung des CMPS-Befehls. Welche der Möglichkeiten – einschließlich der Parameterübergabe im Registerspeicher – bevorzugt wird, hängt von der Problemstellung, von der Datenbereichsstruktur und vom persönlichen Stil des Programmierers ab.

Beispiel 3.18. Parameterübergabe im Registerspeicher. Das Durchsuchen eines Pufferbereichs mit 512 ASCII-Zeichen nach einem bestimmten Zeichen soll von einem Unterprogramm durchgeführt werden (vgJ. Beispiel 3.16). Beim Auffinden dieses Zeichens ist dem Oberprogramm die Pufferposition dieses Zeichens zu übermitteln; steht das Zeichen nicht im Puffer, so ist sie auf Null zu setzen. – Die Eingangsparameter werden als Werte (in RO die Pufferlänge N, in R2 das Vergleichszeichen CHAR) und als Adresse (in R3 die um Eins erhöhte höchste Pufferadresse BUFFER + N) an das Unterprogramm übergeben. Zur späteren Übergabe der Pufferpositionen an das Oberprogramm wird beim Unterprogrammaufruf die Adresse INDEX in R1 als Adresse des Ausgangsparameters übergeben.

Unterprogrammtechniken: Unterprogrammanschluß, Parameterübergabe, Globale Programm- und Datenzugriffe

Beispiel 3.18.

Wie bereits erwähnt, erfordert die Parameterübergabe im Registerspeicher den geringsten Organisationsaufwand und ist dementsprechend sehr effizient. Sie setzt jedoch voraus, daß die Anzahl der Eingangsparameter die Anzahl der zur Verfügung stehenden Register nicht übersteigt.

Beispiel 3.19. Parameterübergabe im Stack. Beispiel 3.18 soll so modifiziert werden, daß die Parameter im Normal- bzw. Systemstack übergeben werden. Der Stack soll außerdem den Status der Register RO bis R6 des Oberprogramms aufnehmen. – Das Oberprogramm schreibt die Eingangsparameter mit den Befehlen PUSH und PEA als Werte bzw. Adressen in den Stack, wobei das Register R7 (bzw. R7′) implizit als Stackpointerregister verwendet wird. Zuvor kopiert es jedoch den Inhalt von R7 nach R6. Das Unterprogramm verwendet R6, nachdem es den Registerstatus mit dem MOVEM-Befehl auf den Stack gerettet hat, zur Übernahme der Parameter. Es ist damit von R 7 unabhängig, dessen Inhalt sich sowohl beim Retten der Rücksprungadresse, als auch beim Retten des Registerstatus verändert. Außerdem bleibt dadurch in R7 die aktuelle Stackbelegung dokumentiert, wodurch das Unterprogramm wiedereintrittsfest wird (s. Abschnitt 3.3.4). Mit Abschluß des Unterprogramms wird der Registerstatus des Oberprogramms wieder geladen, womit auch R6 wieder auf den Stand gebracht wird, den es vor der Parameterbereitstellung im Oberprogramm hatte. Das Oberprogramm kopiert den Inhalt von R6 nach R7, wodurch es den Parameterbereich auf dem Stack freigibt. Die korrespondierenden Nummern im Programm und in der Abbildung zeigen die Wirkung der Befehle auf die Belegung des Stacks.

Unterprogrammtechniken: Unterprogrammanschluß, Parameterübergabe, Globale Programm- und Datenzugriffe

Beispiel 3.19.

Die Parameterübergabe im Stack wird bevorzugt bei blockstrukturierten Programmen eingesetzt, in denen die Datenbereiche der Unterprogramme pulsierend nach dem UFO-Prinzip aneinandergefügt und wieder freigegeben werden (dynamische Datenspeicherverwaltung).

Beispiel 3.20. Parameterübergabe im Datenbereich des Oberprogramms. In Abänderung von Beispiel 3.18 sollen die Parameter in einer Parameterliste PLIST im Datenbereich des Oberprogramms zusammengefaßt und deren Anfangsadresse an das Unterprogramm übergeben werden. Der Status der Register RO bis R3 des Oberprogramms soll im Stack gespeichert werden. – Das Oberprogramm schreibt die Parameter in das Feld PLIST und übergibt dem Unterprogramm die Feldanfangsadresse in R6. Das Unterprogramm liest die Parameter in den Registerspeicher, nachdem es zuvor den Registerstatus des Oberprogramms auf den Stack geschrieben hat.

Unterprogrammtechniken: Unterprogrammanschluß, Parameterübergabe, Globale Programm- und Datenzugriffe

Beispiel 3.20.

Bei der Parameterübergabe im Datenbereich des Oberprogramms können mehrere Parameterlisten für ein Unterprogramm existieren, wobei jeweils eine der Listen in Abhängigkeit einer Bedingung an das Unterprogramm übergeben wird.

Beispiel 3.21. Parameterübergabe im Programmbereich des Oberprogramms. Beispiel 3.18 soll so modifiziert werden, daß die Parameter über ein Parameterfeld, das unmittelbar auf den JSR-Befehl folgt, vom Unterprogramm übernommen werden. – Das Parameterfeld im Programmcode des Oberprogramms wird mittels der DCW-Anweisung statisch festgelegt. Für CHAR wird, im Gegensatz zu den anderen Beispielen, nicht der Wert, sondern die Adresse übergeben. Die Wertübernahme erfolgt im Unterprogramm durch den MOVE-Befehl vor der LOOP-Zeile. Für N, dessen Wert konstant ist, wird die bisherige Wertübergabe beibehalten. Der Zugriff des Unterprogramms auf das Parameterfeld erfolgt über die im Stack stehende Rücksprungadresse, die dazu nach R6 geladen wird. Am Schluß des Unterprogramms wird die um acht erhöhte Rücksprungadresse in den Stack zurückgeschrieben, so daß mit R TS der Rücksprung ins Oberprogramm auf den ersten Befehl nach dem Parameterfeld erfolgt.

Unterprogrammtechniken: Unterprogrammanschluß, Parameterübergabe, Globale Programm- und Datenzugriffe

Beispiel 3.21.

Die Parameterübergabe im Programmbereich des Oberprogramms ist aufgrund des statischen Parameterfeldes weniger flexibel als die zuvor beschriebenen Möglichkeiten. Sie zeichnet sich jedoch durch eine übersichtlichere Darstellung, geringeren Speicherplatzbedarf und geringere Ausführungszeiten aus.

Anzahl der Parameter. In den Beispielen 3.18 bis 3.21 wurde davon ausgegangen, daß die Anzahl der Parameter bei jedem Unterprogrammaufruf gleich und beim Schreiben des Unterprogramms bekannt ist. Es gibt jedoch auch Anwendungen, bei denen sich die Parameteranzahl von Aufruf zu Aufruf ändert. In diesen Fällen muß die Parameteranzahl dem Unterprogramm als zusätzlicher Parameter übergeben werden, z.B. über ein allgemeines Register oder als erster Parametereintrag im Stack oder im Parameterfeld.

Globale Programm- und Datenzugriffe

Ober- und Unterprogramme können als eigenständige Programme unabhängig voneinander übersetzt werden. Voraussetzung hierfür ist, daß sie jeweils mit einer AORG- oder RORG-Anweisung beginnen und mit einer END-Anweisung abschließen. Nur die Adreßbezüge innerhalb eines solchen als Modul aufgefaßten Programms können vom Assembler unmittelbar, d.h. ohne Kenntnis der anderen Programmoduln, hergestellt werden. Dies gilt sowohl für Programmsprünge und -verzweigungen als auch für Zugriffe auf Daten, für die innerhalb des Moduls Speicherplatz reserviert ist. Man bezeichnet solche Daten auch als lokale Daten.

Neben den Programm- und Datenzugriffen innerhalb eines Moduls (lokale Zugriffe) gibt es globale Zugriffe zwischen den einzelnen Moduln. Hierzu gehören der Unterprogrammsprung und der Zugriff auf globale Daten, d.h. auf Daten, die in Datenbereichen anderer Moduln gespeichert und mehreren Moduln zugänglich sind. Die entsprechenden Adreßbezüge müssen spätestens während des Ladens der Programmoduln bekannt sein, um sie als absolute oder befehlszählerrelative Adressen in den Programmeode einsetzen zu können.

Um diese Adreßquerbezüge herzustellen, benötigt man die in Abschnitt 3.1.3 beschriebenen Assembleranweisungen DEF und REF. In der DEF-Anweisung werden die in einem Modul definierten Adreßsymbole aufgelistet, die von anderen Moduln verwendet werden. Umgekehrt werden in der REF-Anweisung die im Modul verwendeten Adreßsymbole aufgelistet, die in anderen Moduln definiert sind. Der Assembler wertet diese Information aus und erstellt daraus Zusatzangaben zum Maschinencode eines jeden Moduls. Diese werden vom Binder oder von einem bindenden Lader zur Auflösung der Adreßquerbezüge benutzt.

Umfaßt der Common-Bereich nur wenige Variablen, so können diese auch im Registerbereich bereitgestellt werden. Hierbei entfallt das Erstellen der Adreßquerbezüge während des Bindevorgangs. Der Registerspeicher stellt somit die einfachste Form eines Common-Bereichs dar.

Beispiel 3.22. Common-Datenbereicb im Oberprogramm. Ein Oberprogramm, das verschiedene Unterprogramme als Moduln benutzt, soll mit diesen über einen gemeinsamen Datenbereich (Common-Bereich) kommunizieren. Der Zugriff auf diesen Bereich soll global erfolgen, so daß eine Parameterübergabe an die Moduln entfällt. – Die ProgrammdarsteIlung zeigt das Oberprogramm, das über die globalen Adressen MODi und MOD2 (REF-Anweisung) zwei Unterprogramme aufruft und diesen seinen Datenbereich Ci bis CFELD (DEF-Anweisung) als Common-Bereich zur Verfügung stellt. Das Unterprogramm MODULl mit der Zieladresse MODi (DEF-Anweisung) greift auf die beiden Variablen Cl und C3 des Common-Bereichs zu (REF-Anweisung). Es addiert – um ein einfaches Beispiel zu geben – zum Wert der globalen Variablen C3 den Wert seiner lokalen Variablen X und weist das Resultat der globalen Variablen Ci zu.

Unterprogrammtechniken: Unterprogrammanschluß, Parameterübergabe, Globale Programm- und Datenzugriffe

Beispiel 3.22.

Geschachtelte Unterprogramme

Der Aufruf von Unterprogrammen ist nicht auf ein einziges Oberprogramm als aufrufendes Hauptprogramm beschränkt; ein Unterprogramm kann seinerseits wieder Unterprogramme aufrufen und erhält damit die Funktion eines Oberprogramms. Der Aufrufmechanismus kann sich somit – ausgehend vom Hauptprogramm – über mehrere Unterprogrammstufen erstrecken. Man spricht von einer Schachtelung von Unterprogrammen. Bezüglich des Aufruforts und des Aufrufzeitpunkts werden drei Arten geschachtelter Unterprogramme unterschieden:
1. einfache Unterprogramme,
2. rekursive Unterprogramme und
3. reentrante (wiedereintrittsfeste) Unterprogramme.

Einfache Unterprogramme. Bild 3.12 zeigt das Schema einer Schachtelung einfacher Unterprogramme. Verschiedene Programme rufen sich, ausgehend von einem Hauptprogramm, nacheinander auf, wobei das Statusretten und die Parameterübergabe in der bisher beschriebenen Weise erfolgen. Der für das Retten und spätere Laden des Status benutzte Stack entspricht mit seinem Last-in-firstout-Mechanismus genau der Schachtelungsstruktur der Unterprogrammaufrufe. Die beim Aufruf der Unterprogramme nacheinander in den Stack geschriebene Information (im einfachsten Fall die Rücksprungadressen) wird bei der Rückkehr in die Oberprogramme in umgekehrter Reihenfolge wieder gelesen.

Unterprogrammtechniken: Unterprogrammanschluß, Parameterübergabe, Globale Programm- und Datenzugriffe

3.12. Schachtelung von Unterprogrammen

Rekursive Unterprogramme. Rekursive Unterprogramme sind Unterprogramme, die erneut aufgerufen werden, bevor sie ihre gegenwärtige Verarbeitung abgeschlossen haben. Der erneute Aufruf geschieht entweder direkt, wenn sich das Unterprogramm selbst aufruft, oder indirekt, wenn der Wiederaufruf auf dem Umweg über ein oder mehrere Unterprogramme erfolgt. Dementsprechend spricht man von direkt- und indirekt-rekursiven Unterprogrammen. Gegenüber einfachen Unterprogrammen muß bei rekursiven Unterprogrammen dafür gesorgt werden, daß mit jedem Aufruf ein neuer Datenbereich für das Unterprogramm bereitgestellt wird, damit der zuletzt aktuelle Datenbereich nicht beim erneuten Aufruf überschrieben wird. Die Datenbereichszuordnung muß dementsprechend zur Laufzeit, d.h. dynamisch erfolgen. Hier bietet sich aufgrund der Schachtelungsstruktur der Unterprogrammaufrufe der Stack als Bereich für die Unterprogrammdaten und für die Parameter an. Die gegenwärtigen Unterprogrammdaten können beim Wiederaufruf und bei der Rückkehr als Erweiterung des Prozessorstatus angesehen werden.

Bild 3.13 zeigt das Schema einer rekursiven Unterprogrammschachtelung. Ein Hauptprogramm ruft ein Unterprogramm auf, das sich wiederholt selbst aufruft, und zwar so lange, bis der Selbstaufruf durch eine Programmverzweigung übersprungen wird. Die jeweils gegenwärtigen Daten des Unterprogramms werden vor dem Selbstaufruf gerettet und nach der Rückkehr wieder geladen. Sind die Daten im Stack untergebracht, so bedeutet das Retten und Laden lediglich ein Verändern des Stackpointers. Sind die Daten hingegen in einem festen (statischen) Unterprogrammdatenbereich untergebracht, so müssen sie dazu in den Stack transportiert und von dort wieder geholt werden. Häufig wird der Datenstack unabhängig vom Normal- bzw. Systemstack angelegt, um die Zugriffe auf die Unterprogrammdaten von den Zugriffen auf den eigentlichen Prozessorstatus zu trennen.

Unterprogrammtechniken: Unterprogrammanschluß, Parameterübergabe, Globale Programm- und Datenzugriffe

Bild 3.13. Unterprogrammschachtelung durch Rekursion

Reentrante Unterprogramme. Reentrante (wiedereintrittsfeste) Unterprogramme können von unterschiedlichen Unterbrechungsprogrammen aufgerufen und dementsprechend auch von ihnen unterbrochen werden. Die Zeitpunkte des Aufrufens bzw. des Unterbrechens liegen im Gegensatz zu den rekursiven Unterprogrammen nicht von vornherein fest, da sie von externen Unterbrechungsbedingungen abhängen. Das bedeutet, daß das Retten der Daten eines unterbrochenen Unterprogramms unmittelbar nach dem Wiedereintritt in das Unterprogramm und das Laden der Unterprogrammdaten unmittelbar vor der Rückkehr in den unterbrochenen Unterprogrammablauf erfolgen müssen. Aufgrund der Schachtelungsstruktur der Unterprogrammaufrufe bietet sich wie bei den rekursiven Unterprogrammen der Stack als Speicherort an.

Bild 3.14 zeigt den zweimaligen Aufruf eines reentranten Unterprogramms. Das Auftreten eines Interrupts IRl führt auf ein Interruptprogramm IPl (1), das ein Unterprogramm UP aufruft (2). Während der Ausführung des Unterprogramms (3) im Auftrag von IP1 wird einem Interrupt höherer Priorität IR2 stattgegeben (4). Dessen Interruptprogramm IP2 ruft erneut das Unterprogramm UP auf (6), führt es aus (7,8) und gibt schließlich mit dem RTE-Befehl die Programmsteuerung an die UnterbrechungssteUe im Unterprogramm zurück (11), wonach das Unterprogramm seine Arbeit für das erste Interruptprogramm beendet (12). Das Unterprogramm sorgt jeweils selbst für das Retten und Laden der Unterprogrammdaten des vorangegangenen Unterprogrammlaufs. Auch beim ersten Aufruf werden die Daten gerettet, obwohl es eigentlich nicht erforderlich wäre. Dies wird meist in Kauf genommen, um zusätzliche Programmverzweigungen zu ersparen, die bei jedem der wiederholten Aufrufe zu einer Erhöhung der Laufzeit führen würden.

Unterprogrammtechniken: Unterprogrammanschluß, Parameterübergabe, Globale Programm- und Datenzugriffe

Bild 3.14. Zweimaliger Aufruf eines reentranten Unterprogramms

Like this post? Please share to your friends:
Schreibe einen Kommentar

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: