APPLICATIONSPROGRAMMATION ★ Z80-REGISTERCHECK V1.2 ★

Z80-Registercheck v1.2Applications Programmation
★ Ce texte vous est présenté dans sa version originale ★ 
 ★ This text is presented to you in its original version ★ 
 ★ Este texto se presenta en su versión original ★ 
 ★ Dieser Text wird in seiner Originalfassung präsentiert ★ 

Befehls-erweiterung für RSX

Das Schneider-Basic läßt sich fast beliebig erweitern.

Heimcomputern ist die Sache relativ einfach. Hier gibt es nur einen Befehl für den Aufruf von Unterprogrammen, der normalerweise SYS, SYSTEM oder CALL heißt. Beim Schneider dagegen ist die Sache zumindest auf den ersten Blick etwas verwirrender, denn man verfügt über insgesamt vier Möglichkeiten, um Maschinenprogramme in ein bestehendes (Hochsprachen-)Programm zu integrieren.

So kompliziert, wie sich das anhört. ist die Sache dann aber doch nicht. Zwei Möglichkeiten scheiden für den normalen Benutzer sofort aus: Das Arbeiten mit zugeschalteten RAM- oder ROM-Bereichen und normalerweise auch die Einbindung von Programmen mit Patches.

Parallele ROMs können Programmerweiterungen enthalten

Der Schneider kann mit Hilfe von Softwareroutinen zwischen verschiedenen parallel liegenden Speicherbereichen umschalten und so mit einem Hintergrund-ROM auf-rufen. Dies alles setzt jedoch voraus, daß man überhaupt eine Hardware-Erweiterung besitzt oder sich selbst eine basteln kann. Sonst nützt die beste Erweiterungs-Software nichts.

Wer also keine Erfahrung mit dem Brennen von EPROMs hat, kann diese Eigenschaften nicht nutzen.

Bei den Patches handelt es sich um »Flickstellen« an strategisch wichtigen Punkten des Betriebssystems. Diese Punkte liegen am Ende eines Teilbereiches. zum Beispiel nach dem Teil, der die Berechnung einer Funktion vornimmt. Konnte ein Betriebssystemteil eine Umformung. Berechnung oder Befehlsausführung nicht vornehmen, so gibt er normalerweise eine Fehlermeldung aus. Kurz zuvor ruft er jedoch ein Unterprogramm im RAM auf , das normalerweise nur aus einem RET-Befehl besteht und dort nach dem Start installiert wurde. Dies ist die Stelle für den Patch.

Durch das RET-Kommando wird der Computer angewiesen, in die nächste Stelle oder besser gesagt Adresse, des Basic-Interpreters zurückzukehren, also an die Stelle von der aus der Sprung erfolgte Dort steht dann normalerweise eine Fehlerüberprüfung und der CPC gibt die zugehörige Fehlermeldung aus. Im Normalfall hat diese Konstruktion, natürlich außer ein paar Sprüngen mehr, keinen Sinn. Der Befehlsablauf wird nicht beeinflußt. Da der RETum-Befehl aber im RAM-Speicher liegt, ist er nicht auf ewig festgelegt. Wenn wir also etwas an dieser RAM-Adresse ändern, so besteht die Möglichkeit, in das Betriebssystem — beziehungsweise den Ablauf der Befehlsinterpretation — einzugreifen. Dazu braucht man nur RET durch einen Verweis auf ein neues Maschinenprogramm zu ersetzen und hat dieses so in das Betriebssystem eingeklinkt. Unser Maschinenprogramm könnte beispielsweise prüfen, ob ein neuer Befehl, eine neue Verknüpfung oder, was ja auch möglich ist. eme echte Fehleingabe vorliegt. Ein RET am Ende unseres neuen Maschinenprogramms würde wieder zur Fehlerausgabe ins Betriebssystem zurückleiten. Dies muß jedoch nicht sein. Wir können natürlich auch aus unserem Maschinenprogramm zu jeder anderen Stelle des Betriebssystems springen. Somit ist es natürlich auch möglich, verschiedene Routinen des Interpreters nacheinander aufzurufen und so mit einem völlig neuen Befehl zu konstruieren. Allerdings ist in jedem Fall eine Kenntnis des ROM-Listings. oder zu-mindestens des Ablaufs einiger Betriebssystemroutinen, notwendige Bedingung für das Arbeiten mit den Patches.

Aber auch ohne diese etwas komplizierten Eingriffe haben wir noch zwei weitere Methoden zur Verfügung. von Basic eine Maschinenroutine aufzurufen: den CALL-Befehl und. eme Spezialität des Schneider, die RSX (Resident System eXten-sions). Bei der RSX handelt es sich um eine Erweiterung des Betriebssystems. die nicht, wie bei. den Erweiterungs-ROMs durch Änderung der Hardware zusätzliche Routinen bereitstellt, sondern um Maschinenprogramme, die in das RAM geladen werden, dann aber ähnlich wie Erweiterungs-ROMs wirken. Zunächst jedoch zum Aufruf von Maschinencode-Programmen mit CALL. Im Basic-Programm befindet sich der Befehl CALL mit nachfolgender Angabe der aufzurufenden Speicherstelle. Diese darf irgendwo im variablen Speicher des Computers liegen. Das Maschinenprogramm wird dabei vom Basic-Interpreter als Unterprogramm aufgerufen. Mit dem Maschinensprache-Befehl RET (&C9) kehrt das Programm wieder in die Hochsprache zurück.

Hier sind nun noch ein paar Worte zur Auswahl von Speicherbereichen, der sogenannten Speicherfreischaltung, notwendig. Wer sich mit dem Speicheraufbau des Schneider etwas auskennt, weiß, daß der Computer die unteren (Adresse &0000-&3FFF) und oberen (Adresse &C000-&FFFF) 16 KByte des RAM mit den ROM-Adressen für Betriebssystem und Interpreter überlagert. Beim Aufruf einer Maschinenroutine mit CALL sind beide ROMs ausgeschaltet. Es wird also im ganzen Speicher RAM angesprochen. Deshalb kann unser Maschinenprogramm auch im unteren Teil des Speichers oder theoretisch im Grafikspeicher liegen, wobei der letztgenannte Speicherplatz nicht besonders sinnvoll ist.

Soweit zur Grundstruktur. Kommen wir nun zu den Punkten Daten-und Informationsübergabe Insgesamt kann man mit jedem CALL-Befehl maximal 32 Integerwerte (Ganzzahlen) zwischen -32768 und +32767 übergeben. Das Betriebssystem legt diese dann nacheinander auf einem Stapel, dem Maschinen-Stack, ab und stellt in den Registern A, B und IX die notwendigen Steuerinformationen zur Verfügung.

Will man also ein Ausgabeprogramm schreiben, das selbständig hintereinander eine beliebige Anzahl von Zeichen ab einer bestimmten Speicherstelle an den Drucker ausgibt, so würde dieses Maschinenprogramm zwei Eingabedaten benötigen: Den Anfang des zu druckenden Feldes und dann die Länge beziehungsweise die Anzahl der auszugebenden Zeichen. Wir können diese Informationen im CALL-Befehl, durch Kommas getrennt, an das Unterprogramm weiterleiten. Soll also zum Beispiel die Ausgabe ab Speicherstelle 41000 für 100 Zeichen Länge erfolgen und ware die Ansprungadresse des Programms 40000, so würde der Befehl wie folgt lauten:

»CALL 40000, 41000, 100«


Der Basic-Interpreter würde nun ein Maschinenprogramm an der Speicherstelle 40000 im RAM aufru-fen und gleichzeitig die beiden übermittelten Zahlenwerte Zwischenspeichern, das heißt auf dem Stack ablegen. Um nun auf diese Werte im Maschinenprogramm zurückzugreifen, muß man einiges über die Informationsübermittlung des Interpreters beim Aufruf einer Maschmensprach-Routine wissen. Schauen wir uns also den Inhalt der einzelnen Register beim Einsprung etwas näher an. Als Hüfsprogramm dient das Programm »Z80-Register-check« (Listing 1). Es ist zugleich Hilfsprogramm und Untersuchungsobjekt.

Kurz ein paar Worte zu der Funktion des Programms. »Z80-Register-check« ist ein Basic-Programm mit einer Maschinensprache-Hilfsroutine. mit dem man jederzeit den aktuellen Inhalt des Z80-Registersatzes abfragen kann. Zu Anfang werden die für die Maschinensprache-Routine benötigten Bytes geladen. Dazu muß zuerst ein sicherer Speicherplatz für deren Ablage gefunden werden. Am einfachsten geht das mit dem Kommando MEMORY. Der CPC legt mit einem Zeiger (HIMEM) fest, welcher Teil des RAM dem Benutzer zur Verfügung steht (Benutzerspeicher) beziehungsweise welcher dem Betriebssystem Vorbehalten ist. Unterhalb von HIMEM liegen die Basic-Variablen; darüber belegt die Firmware einige Speicherplätze. Schiebt man nun diesen Zeiger nach unten, so bleibt der Zwischenraum unbenutzt. Hier können dann Maschinencode-Programme sicher abgelegt werden. Dabei ist allerdings zu beachten, daß dieser Zeiger, je nachdem ob die Floppy angeschlossen ist oder nicht, andere Werte annimmt. Doch Vorsicht — jedes Zeichen, für das wir mit SYMBOL AFTER Platz reservieren, kostet v/eitere acht Bytes. Es empfiehlt sich daher, die Speichergrenze auch bei kleinen Maschinenprogrammen etwas weiter nach unten zu schieben und nicht jedes Byte auszureizen. Der Registercheck setzt HIMEM auf 39999 herab, so daß dann ab 40000 für gute 2 KByte Platz ist.

In diesen Bereich des Speichers wird nun die in DATA-Zeilen abgelegte Hilfsroutine gespeichert. Ihre Aufgabe besteht im wesentlichen darin, den Stapelzeiger (Register SP) zu verändern. Normalerweise legt der Prozessor Daten, die kurzfristig gespeichert werden sollen, auf dem Maschinensprache-Stapel ab. Er verläuft von Adresse hex C000 nach unten. Man kann jedoch jederzeit das Register SP. das die aktuelle Höhe des Stapels angibt, verändern und so auf einen anderen Bereich ausweichen. Von dieser Technik machen wir hier Gebrauch. Beim Ansprung der Routine wird der alte Stand des Maschinenstapels in SYS-STACK gespeichert und dann auf den neuen Stapel umgeschaltet. Beim Rücksprung aus der eigentlichen Maschinencode-Routine werden dann alle Register der CPU auf den neuen Stapel (MACHSTACK) abgelegt, bevor die Rückschaltung erfolgt. Dieses Verfahren ist etwas kompliziert, was sich aber leider nicht vermeiden läßt. Der Prozessor benutzt den Maschinen-Stapel nämlich ziemlich häufig. Würden wir die Register also ohne die Umschaltung ablegen, so würden sie sofort wieder durch neue Daten überschrieben. Bei der Ausführung des nächsten Basic-Befehls wären sie bereits zerstört. So aber kann man die Registerinhalte nacheinander mit Hilfe von PEEK aus dem neuen Stapel auslesen. Der Rest ist reine Formsache Die Werte der einzelnen Rcgi ster müssen formatiert zusammengefügt und dann ausgegeben werden (Zeile 410 bis 470). Jetzt brauchen wir zum Ttest nur noch ein beliebiges Maschinenprogramm, welches wir mit der Abfrageroutine in Zeile 260 bis 300 einiesen können.

Wir nehmen dazu das einfachste Programm, den RET-Befehl. Dieses Programm ist ein Byte lang und soll ab Adresse 41000 abgelegt werden. Nachdem Sie das Programm eingetippt und gespeichert haben, geben Sie also 1,41000. &C9 (den Code für RET) und wieder 41000 ein. Der CPC zeigt Ihnen dann im oberen WINDOW den Inhalt der einzelnen Register. Was bedeuten die Inhalte nun?

A, B und IX stehen in direktem Zusammenhang mit der Anzahl der

übermittelten Daten. In A befindet sich ihre Anzahl. B gibt die Differenz zum Maximalwert 32 hex oder 20 hex an. Zum Aufruf des Maschinenprogramms haben wir einen einfachen CALL-Befehl ohne weitere Parameter benutzt (Zeile 390). A enthält daher 0; B die 20 hex. IX enthält BFFE. Nun fügen wir ein paar Parameter an den CALL-Befehl an. Als Beispiel wollen wir einmal an ein fiktives Maschinenprogramm den Wert 100 übermitteln. Der CALL-Befehl am Ende von Zeile 390 wird dadurch zu »CALL 40060, 100«. A ist jetzt 1. B hat sich auch um 1 vermindert und enthält nun hex 1F. Als Kennzeichen, daß Daten übergeben wurden, ist zudem das Zero-Flag rückgesetzt. IX ist um 2 nach unten gewandert. Dieses Register zeigt immer auf den zuletzt angegebenen Parameter. Zwei Bytes höher liegt dann der zweitletzte Parameter und so weiter. Die Speicherung der übermittelten Zahlenwerte erfolgt dabei immer als 16-Bit-Wert im Format Lo-Hi. Dabei werden die untersten acht Bit zuunterst gespeichert.

Den Bits auf der Spur

Darüber stehen dann die höherwertigen Bits. Konkret: 100 läßt sich binär mit »PRINT BIN$(100,16)« als »0000000001100100« darstellen. Die höherwertigen Bits sind alle 0. In BFFD steht daher eine 0. Adresse BFFC dagegen enthält die nieder-wertigen Bits, die den Wert 100 repräsentieren. Mit diesem Wissen ausgestattet, können wir nun jede beliebige Anzahl von Werten problemlos bearbeiten. Wir brauchen nur noch die einzelnen Daten ins Register der CPU zu laden und haben sie dann sofort zur Verfügung. Eine sehr schöne Programmierhilfe ergibt sich dabei mit den indizierten Ladebefehlen. »LD register, (IX + d)« lädt den Inhalt der durch (IX + d) adressierten Speicherstelle in das angegebene Register. Somit können wir mit »LD B,(IX + 0); LD C,(IX +1); LD D, (IX + 2)« und so weiter nacheinander alle Register füllen. Experimentieren Sie doch einmal mit verschiedenen Zusatzangaben im CALL-Befehl und schauen Sie sich dann das Resultat im Registersatz an.

Welche Funktion haben aber nun die noch nicht besprochenen Register des Prozessors? Eine sehr interessante Information liefert uns das Registerpaar HL. Es enthält die absolute Position im Basic-Programm, von der aus das Maschinenprogramm angesprungen wurde und an die es zurückkehren soll. In un-serm Fall wäre das das erste Byte nach dem CALL-Befehl. Sie werden daher feststellen, daß Sie, wenn Sie neue Parameter an das CALL-Kommando anhängen, auch für den Wert von HL höhere Angaben erhalten. Soll unser Maschinenprogramm zum Beispiel auf verschiedene Aufrufe von unterschiedlichen Basic-Zeilen aus auch anders reagieren, so brauchen wir in das Maschinenprogramm nur einen Vergleich einzubauen, der überprüft, woher der Aufruf kam. und dann die entsprechende Aktion einleitet.

Ganzzahlige Absolutwerte sind zwar eine interessante Art, Daten zu übertragen, aber normalerweise hat man es mit Variablen zu tun. Es stellt sich die Frage, wie wir Variablen an ein Maschinencode-Programm übergeben können. Das Schlagwort hierzu lautet: Variablenpointer. Wahrscheinlich sind Sie mit dieser sehr nützlichen Funktion des CPC noch kaum in Berührung gekommen. Man erreicht sie über den Klammeraffen »@«. Definieren Sie zum Beispiel »a$ = "abcd'i und geben dann »PRINT @a$« ein. so erhalten Sie einen Zahlenwert — die absolute Position der Variablen im Speicher. Bei normaler Eingabe des Programms »Registercheck«, das heißt ohne unnötige Leerstellen, müßten Sie hier den Wert 1852 erhalten. An dieser Stelle befindet sich bei Strings die Länge des Strings mit nachstehender Positionsangabe, bei Integers das niedere Byte und bei Fließkommazahlen das erste Mantissenbyte. Definieren wir a$ auf »willi« (Länge 5) und lassen uns dann @a$ ausgeben, so erhalten wir zunächst den Wert 5 für die Länge. In den nächsten beiden Bytes findet sich dann die absolute Position im Speicher, an der der String abgelegt ist, und zwar die des ersten Bytes. Die Position ist dabei wieder als 16-Bit-Wert in der Form Lo-Hi gespeichert. Wir können diese Angabe jederzeit mit »PEEK (@a$ + 1)+ 256 * PEEK (@a$ + 2) ausrechnen. Sie erhalten als Ergebnis dieser Operation eine Zahl direkt an der Obergrenze des Speichers. Wenn Sie sich diese und die nachfolgenden Speicherstellen mit »PRINT CHR$ (PEEK(< Speicherstelle >))« ausgeben lassen, erhalten Sie unseren »willi«.

Bei Integervariablen, also ganzen Zahlen zwischen -32768 und + 32767, weist der Variablenpointer direkt auf die Zahl. Wir können eine Integervariable, wie j% daher mit »PRINT PEEK (@j%) + PEEK(@j% +1)« jederzeit umrechnen. Diese Algorithmen, die wir jetzt benutzt haben, um Positionen in das Dezimalsystem umzurechnen, können wir natürlich auch zur Basis für die Entwicklung von Maschinencode-Routinen machen. Wenn wir statt der festen Werte, die wir weiter oben benutzt haben, auf Angaben mit Hilfe des Variablenpointers zurückgreifen, können wir nun auch Werte, die in Basic-Variablen gespeichert sind, bearbeiten. Dazu übergeben wir einfach den Variablenpointer an die Maschinenroutine, die dann die Bearbeitung fortsetzt. Aber auch der umgekehrte Weg ist mit dieser Methode machbar. Wir können nämlich mit »@« den Platz einer Variablen an das Maschinenprogramm weiterleiten, die eine Information an das Basic-Programm zurückgeben soll. Wenn die Maschinenroutine auf das Speicherformat der verschiedenen Variablen Rücksicht nimmt, ist es kein Problem, diese Variable dann in Basic wieder zu lesen.

Ein Beispiel, bei dem beide Wege auftauchen, bildet eine umgekehrt laufende INSTR-Routine Hier muß das Maschinencode-Programm drei Angaben erhalten, um korrekt ablaufen zu können. Als erstes benötigt es natürlich den String, der untersucht werden soll, zum Beispiel a$. Die zweite Angabe bildet das zu suchende Zeichen, beispielsweise CHR$(32) , also ein Leerzeichen. Abschließend müssen wir dem Computer natürlich noch mitteilen, wohin das Ergebnis gespeichert werden soll. Wir nehmen hier einmal an, es würde eine Integervariable existieren (j%). die die Zielkoordinaten aufnehmen soll. Unsere negative INSTR-Routine soll wieder ab 40000 liegen. Der zugehörige CALL-Befehl müßte dann lauten: »CALL 40000 ,@a$, 32, @j%«.

Die erste Aufgabe des Maschinenprogramms ist es dann, mit Hilfe der ersten Angabe die Länge des Strings und seine Position einzulesen. Das gesuchte Zeichen folgt im zweiten Schritt. Danach müßte der String Zeichen für Zeichen durchsucht werden, bis die Länge auf 0 zusammengeschrumpft ist, oder das fragliche Symbol gefunden wurde Dann wäre der dritte Parameter einzulesen, wonach die Position der Zielvariablen bekannt ist. Abspeichern und Rücksprung bilden den Schluß. Versuchen Sie doch einmal dieses kleine Programm zu schreiben. Mit den Informationen zur Ablage der Variablen und zum Ablauf des CALL-Befehls und einigen Kenntnissen in der Maschinensprache müßten Sie jetzt dazu in der Lage sein. In der nächsten Ausgabe werden wir die Lösung vorstellen und uns damit beschäftigen, wie wir Maschinenprogramme mit größerem Komfort ansprechen können.

Carsten Straush/lg , Happy Computer

★ PUBLISHER: Happy Computer
★ YEAR: 1985
★ CONFIG: 64K + AMSDOS
★ LANGUAGE:
★ LiCENCE: LISTING
★ COLLECTION: HAPPY COMPUTER 1985
★ AUTHOR: Carsten Straush
 

★ AMSTRAD CPC ★ DOWNLOAD ★

Type-in/Listing:
» Z80-Registercheck  v1.2    (Happy  Computer)    LISTING    GERMANDATE: 2017-01-23
DL: 210
TYPE: PDF
SiZE: 87Ko
NOTE: Uploaded by hERMOL ; 1 page/PDFlib v1.6

★ AMSTRAD CPC ★ A voir aussi sur CPCrulez , les sujets suivants pourront vous intéresser...

Lien(s):
» Applications » RSX Text-Basic (CPC Magazin)
» Applications » ExBasic
» Applications » Asso (CPC Magazin)
» Applications » Amstrad Forth (Computing with the Amstrad)
» Applications » 8080 Fig Forth
» Applications » PDQ Pascal
Je participe au site:
» Pour ce titre nous ne disposons de fichier executable sur CPC (Dump, Saisie du listing) , alors si vous avez ça dans vos cartons ou vous désirez usé vos petit doigts boudinés sur votre clavier faites le nous savoir.
» Vous avez des infos personnel ?
» Vous avez remarqué une erreur dans ce texte ?
» Aidez-nous à améliorer cette page : en nous contactant via le forum ou par email.

CPCrulez[Content Management System] v8.7-desktop/c
Page créée en 603 millisecondes et consultée 2635 fois

L'Amstrad CPC est une machine 8 bits à base d'un Z80 à 4MHz. Le premier de la gamme fut le CPC 464 en 1984, équipé d'un lecteur de cassettes intégré il se plaçait en concurrent  du Commodore C64 beaucoup plus compliqué à utiliser et plus cher. Ce fut un réel succès et sorti cette même années le CPC 664 équipé d'un lecteur de disquettes trois pouces intégré. Sa vie fut de courte durée puisqu'en 1985 il fut remplacé par le CPC 6128 qui était plus compact, plus soigné et surtout qui avait 128Ko de RAM au lieu de 64Ko.