|
Unterprogramme (Subroutines)
Unterprogramme sind Programmteile (=Befehlsfolgen), die mit einem Namen
versehen sind und unter diesem Namen aufgerufen werden. UP können inden Programmen, die diese verwenden, oder außerhalb derselbendefiniert sein UP-Bibliotheken. Sie sollen möglichst universell programmiert (und damit für wechselndeDatenwerte) sein Parameter müssenübergeben werden (Eingabe- und Ausgabeparameter).Subroutines müssen am beliebiger Stelle des Hauptprogramms aufgerufenwerden können (und damit auch an mehreren Stellen), sie sollten daherden Inhalt derjenigen Register sichern (z. B. auf dem Stack), dieinnerhalb des UP verändert werden. Typische Anwendungen der UP-Technik sind: - Verwendung gleicher Programmteile an mehreren Programmstellen
- Rückgriff auf Programmbibliotheken
- Übersichtlicher Aufbau von Programmen (modular + strukturiert) Programmerstellung durch mehrere Programmierer möglich
Programme mit UP dauern etwas länger als ohne (meist überwiegen jedochdie Vorteile der UP). Anmerkungen zur Dokumentation: - Dokumentation ist wichtig für problemlose und fehlerfreie Verwendung vonUP (besonders von fremden UP)
- Die innere Struktur der UP muß für deren Anwendung nicht unbedingtbekannt sein
- Folgende Informationen sind notwendig:
- Zweck (Beschreibung der Aufgabe) des UP
- Beschreibung der Ein- und Ausgabeparameter
- Angabe der veränderten Register und Speicherplätze
- Anwendungs-(Aufruf-) Beispiel
- Dokumentation soll bereits im Programmlisting durch entsprechende Kommentare
vorgenommen werden
Aufgaben des aufrufenden Programms:
- Initialisierung des/der Stackpointer (Hauptprogramm)
- Bereitstellen der Eingabeparameter an vereinbarter Stelle
- eventuell Platzreservierung für Ausgabeparameter
- Aufruf des UP
- falls erforderlich, Wegspeichern der Ausgabeparameter
Unterprogramm-Sprungbefehle
sind spezielle Sprungbefehle, die vor dem Sprung die Rücksprungadresse auf dem
Stack sichern. Beim Rücksprung wird diese Adresse automatisch geladen.
Sprung in das UP: JSR, BSR
Unterscheidung in der Adressierungsart. Wirkung:
- Speichern des PC auf dem Stack (da der Sprungbefehl bereis geholt und dekodiert
wurde, zeigt der PC auf den nächsten Befehl (= Rücksprungadresse)). Zuerst
Speicherung des PC-LSB, dann PC-MSB.
- Laden des PC mit der Startadresse des UP
Rücksprung aus dem UP: RTS
Letzter Befehl des UP, Wirkung:
- Laden der Rücksprungadresse vom Stack in den PC
Achtung: Vor dem Rücksprung muß der Stackpointer i. a. auf die gleiche Adresse
zeigen, wie nach dem Ansprung des UP Sorgfalt
bei Stackoperationen notwendig! Beim UP-Sprung (und Rücksprung) wird nur
der PC-Inhalt geändert, der Inhalt aller anderen Register bleibt erhalten.
Register können zur Parameterübergabe
verwendet werden
Im UP verwendete Register müssen gegebenenfalls
gesichert werden
Vorteil der Speicherung der Rücksprungadresse auf dem Stack:
- Aufruf weiterer UP durch ein UP möglich
verschachtelte UP
- Rückkehradresse immer am Stack-Ende
- Schachtelungstiefe nur durch Stackgröße begrenzt
Parameter-Übergabe
Eingabeparameter: Werte UP
Ausgabeparameter: Werte UP
Möglichkeiten der Parameterübergabe:
- Direkte Übergabe in Registern
Elegante Methode, jedoch durch Registerzahl begrenzt
- Über festen Speicherbereich
inflexibel (manchmal bei BS-Aufrufen)
- Über variablen Speicherbereich (Parameterblock)
Anfangsadresse des Parameterblocks wird in einem Register übergeben
indirekte Parameterübergabe
- Über den Stack
Ablage im aufrufenden Programm mittels PSHx.
Da die Parameter vor dem UP-Sprung abgelegt wurden (und somit der PC-Stand
der letzte Wert auf dem Stack ist), sind sie mit PULx nicht ohne weiteres erreichbar
(außer Rücksprungadresse wird zwischengespeichert). Der Zugriff ist
daher komplizierter. Vom HP kann vor UP-Aufruf Stackplatz für Ausgabeparameter
freigehalten werden (Nach Rückkehr Bereinigung des Stack nötig).
Beispiel: Verzögerungsroutine
Es soll eine Verzögerung von 1 ms erreicht werden. Das Prinzip der Routine
ist recht einfach: Ein Akkumulator wird mit einem Anfangswert besetzt und dann
in einer Schleife solange dekrementiert, bis sein Wert Null geworden ist.
ORG PROG Programm soll bei Adresse PROG beginnen
MAIN BSR VERZ Aufruf Unterprogramm
STOP BRA STOP Endlosschleife, stoppt Programm
("Wiederbeleben" des Computers mit Reset)
* Verzögerungs-Unterprogramm
* Verzögerungszeit: 1 ms
* Keine Parameter
*
VERZ LDAA #221 Anfangswert (Konstante) laden (siehe unten)
VZ NOP No Operation (Zeitverzoegerung)
NOP No Operation (Zeitverzoegerung)
DECA A runterzählen bis 0
BNE solange A != 0, weiterer Durchlauf
RTS Verzögerung erreicht (A = 0)
END
Berechnung der Verzögerungszeit: Aus der Befehlstabelle kann man die Anzahl
der Taktzyklen für jeden Befehl entnehmen. Wenn man nun noch die Taktfrequenz
weiß, kann man die Ablaufzeit eines Programms ausrechnen. Wir müssen
vier Zeiten wissen:
tl Ausführungszeit LDAA 2 Taktzyklen
td -"- DECA + 2 NOP 6 -"-
tb -"- BNE 3 -"-
tr -"- RTS 5 -"-
Bei unserem Praktikumsrecher dauert ein Taktzyklus 0,5 Mikrosekunden. Die Gesamtzeit tg ergibt
sich zu:
tg = 0,5 * n * (td + tb) + tl + tr
= 0,5 * n * (6 + 3 ) + 2 + 5
= 0,5 * n * 9 + 7
Da tg = 1 ms = 1000 Mikrosekunden sein soll, berechnet sich n zu
n = (1000 - 7) / 4,5
= 993 / 4,5
= 220,66
n = 221
Im gezeigten Beispiel "Verzögerungsroutine" ist die maximale Verzögerungszeit
durch die Wortbreite des Akku A (8 Bit 0..255) auf
etwas mehr als 1 ms begrenzt.
Für größere Verzögerungen:
- Verlängerung von ts durch zusätzliche Befehle (NOP, BRN)
- Verwendung eines 16-Bit-Registers (z. B. D, X, Y)
- Schachtelung von Schleifen
- Durch Parameter erhält man UP mit variabler Verzögerungszeit
Beispiel: Gegeben ist folgende Verzögerungsroutine mit 16-Bit-Register:
* Verzögerungs-Unterprogramm
* Verzögerungszeit: 500 ms
* Keine Parameter
*
VERZ LDX #ANF Anfangswert (Konstante) laden
VZ NOP No Operation (Zeitverzoegerung)
NOP No Operation (Zeitverzoegerung)
DEX X runterzählen bis 0
BNE solange X != 0, weiterer Durchlauf
RTS Verzögerung erreicht (X = 0)
Frage: Welchen Wert muß ANF haben, um eine Verzögerung von
500 ms zu erreichen?
|
|
|