★ APPLICATIONS ★ PROGRAMMATION ★ Vertrackte Warte-Takte ★ |
Relokalisator (Computer Technik) | Applications Programmation |
Einfacher Relokalisator für Schneider, Spectrum und andere Z80-Systeme Es ist schon ein Kreuz: Solange man nur ein Maschinencode-Utility im Speicher hat, gehl alles gut, aber wehe, wenn es mehr werden! Wer zuerst kommt, mahlt zuerst, und alle anderen Routinen, die man danach einladen will, spielen ‘Die Reise nach ROM': Wenn ihr vorgesehener Adreß-Bereich bereits durch andere Programme auch nur teilweise belegt ist, muß man auf sie verzichten. Solchen Ärger kann man sich ersparen, wenn man seine Maschinencode-Programme relokalisierbar (verschiebbar) macht. Dann kann man sie immer da hinlegen, wo Platz ist, unabhängig von der Position, an der sie einmal geschrieben wurden. Das Problem beim Verschieben sind die absoluten Adressen, sei es von Variablen oder von Unterprogrammen, die auf eine Adresse Bezug nehmen. Bei relativen Adressen wird dagegen die Entfernung zur Position des adressierenden Befehls angegeben (JR± Offset). Wird ein Mcode-Programm an einer anderen Stelle eingeladen als an die, für die es geschrieben wurde, stimmen die absoluten Adressen nicht mehr; nur noch die relativen, denn Abstände innerhalb des Programmes ändern sich beim Verschieben ja nicht. Benutzt man aber in einem verschiebbaren Programm absolute Adressen, so muß man diese vor dem ersten Aufruf an die tatsächliche Programm-Position anpassen. Dazu braucht man ein Verschiebe-Programm und eine Tabelle, in der alle Stellen eingetragen sind, an denen absolute Adressen Vorkommen. Schieben Listing 1 zeigt einen solchen Relokalisator, wie er für alle Z80-Systeme verwendbar ist. Er wird bei der Programmentwicklung vor das eigentliche Programm ‘gehängt' und mit diesem zusammen abgespeichert. Nachher lädt man das Programm an einer beliebigen Stelle ein und ruft den Relokalisator auf, der dann alle absoluten Adressen anpaßt.
Dieser muß zuerst einmal feststellen, wo das Programm überhaupt liegt (Zeilen 15—20). Dazu ruft er einfach irgendeine Stelle im RAM oder ROM auf, die garantiert immer ein ‘RET' enthält. Beim Schneider CPC wäre das zum Beispiel Adresse 15 (OFh) oder beim ZX-Spectrum Adresse 82 (52h). Bei Unterprogramm-Aufrufen legt der Prozessor die Return-Adresse, das ist die Adresse des nächsten Befehls, auf den Maschinenstapel. Im Listing ist diese Stelle mit dem Label ‘STELLE' markiert. Mit dem Return aus dem Dummy-Unterprogramm wird dieser Stack-Eintrag aber wieder verbraucht. Man muß daher den Stapelzeiger ‘SP' wieder um zwei Stellen erniedrigen, um mit ‘POP HL' die Rücksprungadresse ein zweites Mal vom Stack holen zu können. Sollte aber ausgerechnet vor dem zweiten ‘DEC SP' ein Interrupt dazwischenfunken, wäre die Rücksprungadresse zerstört. Deswegen wird für die Dauer dieser Operation der Interrupt abgestellt. Als nächstes bestimmt das Programm den Abstand zur ursprünglichen Adreßlage (Zeilen 24—27). Dazu zieht man den Original-Wert von ‘STELLE' von dessen tatsächlicher Position ab und erhält hiermit die Entfernung, um die das Programm verschoben wurde. Dieser Wert kann, je nach Ver-schiebe-Richtung, positiv oder negativ sein. Er wird für den Rest des Programmes im Register DE gespeichert. Um nun zu einer absoluten Adresse den neuen Wert zu berechnen, muß man zu deren alten Wert immer diesen Offset addieren. Die erste absolute Adresse, die angepaßt werden muß, ist die Adresse der Tabelle selbst, damit der Relokalisator sie überhaupt findet. Das geschieht in den Zeilen 31 und 32. Die tatsächliche Adresse ist nun im HL-Register, und das dient im weiteren Verlauf des Programmes als Zeiger auf die Tabellen-Einträge. In Zeile 39 beginnt nun die Schleife über alle Einträge: Zuerst wird eine Adresse aus der Tabelle geholt und HL gleich weitergestellt. Diese Adresse ist nun die Original-Adresse einer Stelle, an der die absolute Adressierung verwendet wurde. Als Endmarke der Tabelle ist der Eintrag 0000h vorgesehen, was die Routine in den Zeilen 46—48 testet. In diesem Fall verzweigt sie in irgendeine weitere Initialisierungs-Routine. Gibt es keine, kann man hier ein RET Z einsetzen. Benutzt man hierfür aber einen absoluten Sprung (JP Z.xxxx), muß man natürlich auch diesen relokalisieren. Andernfalls geht es weiter: In den Zeilen 52 bis 54 bestimmt das Verschiebeprogramm, wo die Stelle, an der die absolute Adressierung verwendet wurde, jetzt tatsächlich liegt. Hierfür kopiert sie den Offset aus dem DE-Register ins IX-Register und addiert den Original-Wert dazu. Nun zeigt IX auf die absolute Adresse. Aus einem Grund, der nachher noch erläutert wird, nicht direkt, sondern auf eine Stelle davor. Jetzt endlich erfolgt die Adreßänderung (Zeilen 58—64). Zuerst werden die niederwertigen Bytes von Offset und Original-Adresse addiert und wieder abgespeichert und dann die höherwertigen, diesmal aber mit ‘ADC', um einen eventuellen Übertrag zu berücksichtigen. In Zeile 66 springt das Programm wieder an den Schleifenanfang, um die nächste Adresse anzupassen. Mit Aufruf dieses Relokalisators wird das Programm also an seine tatsächliche Lage angepaßt. Er darf allerdings nur einmal aufgerufen werden, da der Offset sonst ein zweites Mal zu den Adressen addiert würde. Schließlich kann man den Platz, den der Relokalisator samt Tabelle einnimmt, nachher wieder für andere Programme benutzen, er wird hier ja nicht mehr benötigt. Entwickeln Schreibt man ein neues Programm, assembliert man es zunächst immer ganz normal für eine beliebige, feste Startadresse (Origin). Dort wird es dann ausgetestet, bis es läuft. Steht das Programm, ‘linkt' man den Relokalisator davor. Dann muß man die Tabelle eingeben. Das ist der langweiligste Teil des Ganzen und ist doch mit der größten Sorgfalt durchzuführen. Zunächst durchsucht man das ganze Programm systematisch nach allen Stellen, an denen eine absolute Adresse vorkommt: Das sind zum Beispiel folgende Befehle: CALL xxxxEinige Befehle sind zweideutig, sie können eine absolute Adresse benutzen: |
|
|