★ CODING ★ ROM ★ Alle Wege führen ins ROM ★![]() |
| Alle Wege führen ins ROM (CPC Amstrad International) |
Einsteigen ohne Probleme Nichts geht im CPC ohne das Betriebssystem. Diese 16 KByte umfassende Sammlung von Unterprogrammen in Maschinensprache hat insbesondere die Aufgabe, den Kontakt zu den Peripheriegeräten herzustellen, also zum Bildschirm, zum Drucker, zur Tastatur, zum Soundchip und so weiter. Dem Programmierer bleibt es dadurch erspart, sich spezielle Hardware-Kenntnisse anzueignen. Will er ein Zeichen an den Drucker ausgeben, so ruft er einfach die entsprechende Betriebssystem-Routine auf, ohne sich Gedanken um irgendwelche Portadressen zu machen. Auch der BASIC-Interpreter benutzt das Betriebssystem als Arbeitsgrundlage. Bei einem DRAW-Kommando ist es zwar die Aufgabe des CPC-BASICs, dieses Kommando richtig zu interpretieren und die nachfolgenden Parameter zu lesen. Diese werden dann jedoch einer Betriebssystem-Routine übergeben, die für die Ausführung zuständig ist. Im CPC herrscht also eine genau definierte Arbeitsteilung. I can hear you callin'... Von BASIC aus kann man die Betriebs-system-Routinen per CALL- Befehl aufrufen. Probieren Sie z.B. einmal CALL &BB18. Danach herrscht zunächst Sendepause, der Cursor bleibt verschwunden. Wenn Sie eine beliebige Taste drücken, erscheint er jedoch wieder: Das war nämlich eine Routine, die auf einen beliebigen Tastendruck wartet. Dieser CALL ersetzt also die übliche BASIC-Konstruktion WHILE INKEY$ = "" : WENDOder angenommen, Sie haben etwas zu wüst mit den Farben herumgespielt und sind schließlich bei blauer Schrift auf blauem Hintergrund gelandet. Was nun? Probieren Sie einfach mal im Blindflug CALL &BC02, wodurch die INK-Farben wieder auf die Startwerte zurückgesetzt werden. Und hier ein Special für CPC 464-Besitzer: Mit CALL &BC6E können Sie den Kassettenmotor ein- und mit CALL &BC71 wieder ausschalten, wenn die PLAY-Taste gedrückt ist.Nützlich ist weiterhin CALL &BB81, um während eines laufenden Programms den Cursor erscheinen zu lassen. Die Abfrage der Cursortasten und die Steuerung mit LOCATE müssen Sie jedoch selbst programmieren, da sich das BASIC während einer Pro-grammausführung nicht im Eingabemodus befindet. Mit CALL &BB84 wird der Cursor wieder ausgeschaltet. Wenn Sie sich noch an die in Heft 2/88 erläuterte Speicheraufteilung des CPC erinnern, sollten Sie allerdings bei den Adressen stutzig werden, die wir hier benutzen. Das Betriebssystem befindet sich im unteren ROM, also im Adreß-bereich von &0000 bis &3FFF. Unsere CALL-Adressen liegen jedoch ganz woanders, nämlich zwischen &BB00 und &BDFF im RAM des CPC. Immer auf dem Sprung In der Tat haben wir mit unseren CALLs nicht das Betriebssystem direkt aufgerufen, sondern sogenannte 'Sprungvektoren'. Diese können Sie sich als eine Ansammlung spezieller GOTO-Befehle vorstellen, die dann den eigentlichen Sprung ins Betriebssystem ausführen. Dieser Umweg ist aus zwei wichtigen Gründen notwendig. Erstens ist zum Zeitpunkt des Aufrufs das untere ROM noch durch das im gleichen Adreßbereich liegende RAM verdeckt und muß erst aktiviert werden, was durch eine sehr raffinierte Programmierung dieser Sprung befehle erreicht wird. Zweitens mußten die Entwickler des CPC eventuelle Änderungen im Betriebssystem berücksichtigen. Angenommen, es wird ein neuer Programmteil eingebaut (wie etwa die FILL-Routine beim 664/6128), so verschieben sich alle nachfolgenden Einsprungadressen. Programme, die direkt das ROM aufrufen, würden dann hoffnungslos baden gehen, da keine Adresse mehr stimmt! Mit den Sprungvektoren ist das jedoch kein Problem. Ihre Lage bleibt in allen CPC-Versio-nen unverändert, nur das Sprungziel dieser 'Spezial-GOTOs' ist unterschiedlich. Auf diese Weise läßt sich übrigens auch das Diskettenlaufwerk nachträglich in den CPC 464 integrieren: Alle Sprungvektoren für den Kassettenbetrieb werden auf das Floppy-ROM umgebogen. Dadurch kann man testen, in welcher Konfiguration der Rechner betrieben wird: IF PEEK(&BC77)=223 THEN PRINT “Disk” ELSE PRINT “Cassette"Wer nun allerdings glaubt, daß sich über die Betriebssystem-Einsprünge noch zahlreiche bislang unbekannte Möglichkeiten aus dem Rechner hervorzaubern lassen, wird eine Enttäuschung erleben. Das Locomotive-BA-SIC nutzt das Betriebssystem nämlich sehr gut aus, die meisten Funktionen stehen bereits als BASIC-Befehle zur Verfügung. Weiterhin erfordern die meisten CALLs noch zusätzlich die Übergabe von Zahlenwerten (Parameter) , was in BASIC nicht ohne weiteres realisierbar ist.Interne Register... Um zu verstehen, wie diese Parameterübergabe vor sich geht, müssen wir uns etwas mit dem Innenleben des Z 80 beschäftigen. Neben den 64 KByte RAM des CPC verfügt der Prozessor nämlich noch über ein paar interne Speicherstellen, die seinen Arbeitsplatz darstellen. Ein typischer Arbeitszyklus sieht mb allgemeinen so aus:
Das A-Register (auch Akku oder Akkumulator genannt) ist 8 Bit breit und nimmt bevorzugt Werte auf, mit denen irgendwelche Rechenoperationen durchgeführt werden sollen. Im F-Re-gister (Flagregister) stehen dagegen keine Zahlenwerte. Hier hat jedes einzelne Bit eine besondere Bedeutung und signalisiert, was bei der vorhergehenden Operation passiert ist. Ein bestimmtes Bit ist z.B. immer dann gesetzt, wenn das Ergebnis einer Operation gleich Null ist (Zero-Flag), ein anderes, wenn sich beim Rechnen ein Übertrag ergeben hat (Carry-Flag). In Maschinensprache kann man die 'Flaggensignale' abfragen und im Programmablauf entsprechend reagieren. Die 8-Bit-Register B,C,D,E,H und L finden als allgemeine Datenregister Verwendung, können jedoch bei bestimmten Maschinen befehlen auch spezielle Aufgaben übernehmen. So dient das B-Register z.B. als Zähler bei Programmschleifen, ähnlich wie die Laufvariable beim FOR...NEXT in BASIC. Falls man auf Maschinenebene mit Zahlen arbeitet, die den 8-Bit-Bereich überschreiten, so kann man diese Register paarweise zu den Doppelregistern BC, DE und HL zusammenfassen. Insbesondere das HL-Regi-ster steht dann als eine Art 16-Bit-Akkumulator für Rechenoperationen zur Verfügung, wobei das höherwertige Byte ('Highbyte') in H und das niederwertige Byte ('Lowbyte') in L steht — deshalb ist es auch mit diesen beiden Buchstaben bezeichnet worden. Die Register SP (StackPointer), IX und IY (Indexregister) sind 16 Bit breit und enthalten bevorzugt irgendwelche Speicheradressen. Ihre Bedeutung wird in den kommenden Folgen noch genau erklärt werden. Wie Sie aus diesen Angaben entnehmen können, ist der Z 80 also schon ein halber 16-Bit-Prozessor. Ganz hat er diesen Rang allerdings nicht verdient, da der Datentransfer zwischen den Registern und dem Speicher immer nur in 8-Bit-Portionen stattfindet. Das Problem bei den Betriebssystem-CALLs ist nun, daß die zu übergebenden Werte in bestimmten internen Registern erwartet werden, und diese lassen sich von BASIC aus nicht ohne weiteres erreichen. Damit Sie trotzdem etwas Erfahrung mit diesen Betriebssystem-Aufrufen und den Prozessor-Registern sammeln können, möchten wir Ihnen in dieser Folge mit Listing 1 ein kleines Werkzeug zur Verfügung stellen. Es besteht aus zwei Unterprogrammen, die in eigene Programme integriert werden können und das Laden der Register direkt von BASIC aus erlauben. Natürlich geht das nicht ohne etwas Maschinencode. Das Unterprogramm ab Zeile 20000 stellt deshalb einen typischen BASIC-Lader dar, der den Code ab Adresse &A000 im Speicher ablegt. Die Festlegung der Startadresse in Zeile 20040 kann bei Bedarf geändert werden, da das Maschinenprogramm relokatibel ist, sich also frei im Speicher verschieben läßt. Das Unterprogramm ab Zeile 10000 dient dazu, ein beliebiges Maschinenprogramm aufzurufen (also auch eine Betriebssystem-Routine) und vorher die Prozessorregister mit bestimmten Werten zu versorgen. Dabei wird eine sehr spezielle Möglichkeit des CPC-BASICs benutzt, mit der man die Adresse einer Variablen im Speicher ermitteln kann. Das geschieht, indem man dem Variablennamen das Zeichen voranstellt. Probieren Sie einfach mal folgendes: var% = 0: PRINT @var%Der Variablen var wird hier der Wert Null zugewiesen, damit sie überhaupt erst einmal im Speicher existiert. Wendet man diese sogenannte 'Variablen-pointer-Funktion' auf eine noch nicht definierte Variable an, so erhält man nur die Fehlermeldung 'lmproper Argument'. Mitunter ist es sehr von Vorteil, die Adresse einer Variablen im Speicher zu kennen, da man dann direkt mit PEEK oder POKE auf sie zugreifen kann, wie das folgende Beispiel demonstriert:var%=0: POKE @var%,77: PRINT var%Das Prozent-Zeichen hinter der Variablen sorgt dafür, daß der CPC sie als Ganzzahl-Variable (Integer) behandelt, da die Struktur einer Fließkommavariablen ziemlich kompliziert und für unsere Zwecke ungeeignet ist. Integer-Variablen sind dagegen sehr einfach aufgebaut. Sie belegen zwei Byte (also 16 Bit) im Speicher, und zwar zuerst dasLowbyte (der niederwertige Teil) und dann das Highbyte an der darauffolgenden Speicheradresse. Um den Variableninhalt komplett auszulesen, müßte man also z.B. so vorgehen: var%=456:Der Inhalt des Highbytes ist wegen der internen Zahlendarstellung also 256-mal so viel wert wie das Lowbyte. Natürlich ist es viel einfacher, sich eine Variable direkt mit PRINT ausgeben zu lassen. Diese Beispiele sollen auch nur das Prinzip demonstrieren. Will man sich Low- und Highbyte jedoch separat anschauen oder sogar die Variable von einem Maschinenprogramm aus verwenden, so ist der Weg über die Variablenadresse außerordentlich praktisch. Nun zurück zu dem Unterprogramm ab Zeile 10000: Vor dem Aufruf müssen Sie einige Integer-Variablen mit den Werten belegen, die in die Prozessor-Register übertragen werden sollen. Die Variablennamen wurden in Analogie zu den Registerbezeichnungen gewählt: a% entspricht dem A-Register, flags% spricht für sich selbst, bc%, de% und hl% sind die bereits erwähnten Registerpaare und ix % bzw. iy % die beiden Indexregister. |
| ![]() |
|