Basic und MaschinencodeZ80-RelocalisitorDer Schneider CPC unterstuetzt sehr weitreichend den Wunsch, Zusatz-Routinen nach Bedarf zu einem Hauptprogramm dazuladen zu können. Dabei ist es prinzipiell nicht vermeidbar, dass der (noch) freie Speicher dynamisch an die verschiedenen Erweiterungs-Programme verteilt wird. 'Das heißt, ein Programmpaket mit System-Erweiterungen kann nicht damit rechnen, an eine bestimmte, feste Adresse eingeladen zu werden!' Ideal wäre deshalb ein Maschinencode-Programm, das vollkommen ortsunabhängig geschrieben wurde. Das ist bei der Die ICs im Überblick: Die CPU Z80 Vorausgesetzt, die Lade-Adresse ist zwar zunächst einmal unbekannt, die Lage des Programmes ändert sich nach der Initialisierung aber nicht mehr (wie das in Datentypen: StringsStrings der Fall sein kann), so genügt es, bei der Initialisierung des Programmpaketes alle Adressierungsarten der Z80: Absolutabsoluten Adressen an die tatsächliche Position des Programms anzupassen. Adressierungen Adressierungsarten der Z80: Relativrelativ zum Programmzeiger (JR und DJNZ) müssen dagegen nicht angepasst werden. Entfernungen innerhalb eines Programmes ändern sich ja nicht, wenn es an einer anderen Adresse eingeladen wird. FunktionsweiseDieser einfache Z80-Relocalisator benötigt für seine Arbeit eine Tabelle, in der man alle Stellen eintragen muss, an denen eine Adressierungsarten der Z80: Absolutabsolute Adresse verwendet wurde. 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 Relocalisator auf, der dann alle Adressierungsarten der Z80: Absolutabsoluten Adressen anpasst. Zunächst einmal muss er feststellen, wo im Speicher das Programm überhaupt liegt. Dazu wartet er einfach auf den nächsten Alle noch folgenden Anschlüsse fallen unter die Rubrik STEUER- oder auch CONTROLBUS:: INT - InterruptInterrupt (Alle noch folgenden Anschlüsse fallen unter die Rubrik STEUER- oder auch CONTROLBUS:: HaltHALT), der als Die CPU Z80: Unterprogramm-AufrufeUnterprogramm-Aufruf die Return-Adresse auf den Maschinenstapel PUSHt. Das ist die mit dem Label 'STELLE' markierte Stelle. Mit dem Return vom Alle noch folgenden Anschlüsse fallen unter die Rubrik STEUER- oder auch CONTROLBUS:: INT - InterruptInterrupt wird dieser Stack-Eintrag aber wieder verbraucht. Deshalb wird der Stapelzeiger wieder um zwei Stellen erniedrigen (DEC SP), um mit 'POP HL' die Rücksprungsadresse ein zweites Mal vom Stack holen zu können. Sollte aber ausgerechnet zwischen den beiden 'DEC_SP" erneut ein Alle noch folgenden Anschlüsse fallen unter die Rubrik STEUER- oder auch CONTROLBUS:: INT - InterruptInterrupt dazwischenfunken, wäre ein Datentypen: Bytes Danach wird aus der tatsächlichen Lage von 'STELLE' (im HL-Register) und der nominalen Lage (im DE-Register) die Verschiebeweite errechnet. Dieser Wert kann, je nach Verschiebe-Richtung, positiv oder negativ sein und wird für den Rest der Relozierung im Doppelregister BC gespeichert. Nun kann zu jeder Adressierungsarten der Z80: Absolutabsoluten Nominal-Adresse deren augenblicklicher Wert berechnet werden, indem einfach der Offset aus dem BC-Register addiert wird. Die erste Adressierungsarten der Z80: Absolutabsolute Adresse, die angepasst werden muss, ist die Adresse der Tabelle selbst, damit der Relocalisator sie überhaupt findet. In der Programmschleife ab RELOOP werden dann alle Adressierungsarten der Z80: Absolutabsoluten Adressen im eigentlichen Programm angepasst. Bei jedem Schleifen-Durchgang ist zunächst einmal im BC-Register der Offset und im HL-Register der Zeiger in die Tabelle enthalten. In der Tabelle stehen dabei die 'unverschobenen, Adressierungsarten der Z80: Absolutabsoluten Adressen der Stellen, an denen eine Adressierungsarten der Z80: Absolutabsolute Adresse steht, die verschoben werden muss.' Das muss man sich klar machen, um zu verstehen, was nun in jedem Schleifendurchgang gemacht werden muss. Aus einem Grund, der nachher noch erklärt wird, werden in die Tabelle dabei nicht die Adresse der Adresse selbst, sondern die Adresse der Stelle davor eingetragen. Zunächst wird eine Adresse aus der Tabelle in das DE-Register gelesen und der Tabellenzeiger HL um zwei Datentypen: Bytes Dann wird erst einmal auf das Tabellen-Ende getestet, wofür der Eintrag &0000 vorgesehen ist. Danach werden das HL- und DE-Register vertauscht, weil nur im HL-Register gerechnet werden kann. Zunächst wird zur Nominal-Adresse aus der Tabelle der Offset BC addiert, wodurch man die tatsächliche Adresse der zu verschiebenden Adresse erhält. Danach kann die Adresse endlich selbst angepasst werden, was über zwei Byte-Additionen im Akku geschieht. Zum Schluss wird der Tabellen-Zeiger, der die ganze Zeit im DE-Register unverändert blieb, wieder nach HL zurückgetauscht. Auch der Offset im BC-Register wurde nicht angetastet, so dass man jetzt wieder zum Schleifenkopf springen kann. Programm-EntwicklungZunächst wird ein neues Programm ganz normal für eine feste Startadresse geschrieben und dort ausgetestet, bis es fehlerfrei läuft. Danach muss man den Relocalisator VOR den Programmtext hängen. (Nur dann kann man nach der Initialisierung den Relocater und seine Tabelle 'vergessen' und den Platz wieder für andere Aufgaben benutzen.) Wie das im Einzelnen geschieht, ist von Assembler zu Assembler unterschiedlich. Bei einigen kann man mehrere Source-Dateien 'linken' (logisch verbinden, so dass sie zusammen einen 'Gesamt-Quellcode' bilden). Im Zweifelsfall muss man (evtl. mit Hilfe eines Textverarbeitungsprogrammes) aus der Textdatei mit dem Programm und der mit dem Relocater eine einzige machen. Zum Schluss muss man auch noch die Tabelle eingeben. Das ist der langweiligste Teil des Ganzen. Trotzdem muss man hier äußerst sorgfältig vorgehen. Dafür durchsucht man das ganze Programm systematisch nach allen Stellen, an denen eine Adressierungsarten der Z80: Absolutabsolute Adresse vorkommt. Das sind zum Beispiel folgende Befehle: Maschinencode über HIMEM: CALLCALL adresse
JP adresse
LD HL,(adresse)
LD (adresse),DE
Einige Befehle KÖNNEN eine Adressierungsarten der Z80: Absolutabsolute Adresse enthalten, was im Einzelfall aus dem Programm-Zusammenhang hervorgehen muss: LD HL,adresse DEFW adresse Jede gefundene, Adressierungsarten der Z80: Absolutabsolute Adresse wird dann darauf untersucht, ob eine Stelle innerhalb des Programms adressiert wird: • Liegt die Adresse außerhalb des Programmes, und kann sie sich überhaupt nicht ändern, wenn das Programm verschoben wird, dann darf sie natürlich auch nicht reloziert werden. Hierbei handelt es sich in der Regel um Systemvariablen und Grundlagen: UnterprogrammeUnterprogramme des Betriebssystems, die normalerweise über die entsprechenden Vektoren der Firmware-Jumpblocks angesprungen werden sollten. • Liegt die Adresse aber im Programm, so muss diese Stelle in die Tabelle eingetragen werden. Markieren von absoluten AdressenDazu markiert man die Stelle, an der die Adresse steht (nicht die adressierte Stelle!), mit einem Label, und trägt dieses Label in die Tabelle ein. Da es sich in den meisten Fällen um einen 3-Byte-Befehl handelt, bei dem der Adresse ein Befehlsbyte vorangeht, ist es sinnvoll, nicht die Stelle direkt zu markieren, sondern die Adresse des Datentypen: Bytes Bei 4-Byte-Befehlen und bei Adressen in Data-Bereichen (mittels DEFW) geht das nicht, hier muss man 'die Stelle davor' mit der Assembler-Pseudo-Operation 'EQU' markieren. Um den Die Firmware des Schneider CPC: ÜberblickÜberblick zu behalten, sollte man für die Relocator-Label eine einheitliche Nomenklatur verwenden, um sie sofort von den 'normalen' Label unterscheiden zu können. Die in diesem Beispiel verwendete Version mit fortlaufenden Nummern ist dabei empfehlenswert, weil dann auch kein Label in der Tabelle vergessen wird. Außerdem sollte man sich nicht verlocken lassen, ein 'normales' Label mitzubenutzen, weil es schon an der richtigen Stelle steht. In diesem Fall lieber eine Stelle im Programm mit zwei Label versehen, dem 'normalen' und dem für den Relocalisator. Sonst geht die Übersicht schnell verloren! Hat man dann alle Stellen markiert und in die Tabelle eingetragen, geht es ans letzte Austesten: Lauft das Programm nicht, wenn man es an anderen Stellen einlaedt, kann es daran liegen, dass man eine Stelle vergessen, oder auch zuviel markiert hat. Oder man hat einmal daneben 'gelabelt', und z.LOW KERNEL JUMPBLOCK: 000B: LOW KL LOW PCHL Markieren absoluter Adressen für den Relocalisator2-Datentypen: Bytes
3-Byte-Befehle: X2: LD HL,(adresse) X3: LD (adresse),HL X4: LD BC,adresse X5: LD (adresse),Operationen: BD5B / 349A / 349A: FLO SUBA X6: Maschinencode über HIMEM: CALLCALL adresse X7: JP adresse 4-Byte-Befehle: X8: EQU $+1 LD BC,(adresse) X9: EQU $+1 LD (adresse),DE X10: EQU $+1 LD IX,adresse X11: EQU $+1 LD (adresse),IY Achtung: Es gibt auch einen 4-Byte-Befehl: LD HL,(adresse). Praktisch alle Assembler generieren hierfür aber den entsprechenden 3-Byte-Befehl. Mit diesem Relocater können fast alle Z80-Programme relocalisiert werden. Ausgenommen sind nur solche Konstruktionen, bei denen eine Adresse aus zwei Datentypen: Bytes ; ****************************************** ; Relocater und RSX-Binder für RSX-Routinen (c) G.Woigk Erklärung zu den Anschlüssen: Vcc und Vss |