TURBO Pascal 3.0 Projekte



1. Problematik der Hintergrundverarbeitung von Tastatureingaben (CP/M)

Bekanntlich ist CP/M ein System, bei dem dem Programmierer keine Möglichkeit der Interruptprogrammierung zur Verfügung steht. Es sei denn, man paßt sich speziell an die Hardware seiner Maschine an, wobei allerdings das Betriebssystem umgangen wird. Dies hat den Nachteil, daß unter dieser Voraussetzung entwickelte Programme eben nur an einer einzigen Maschine lauffähig sind, was dem eigentlichen Sinn von CP/M entgegen spricht.

Eine Möglichkeit bietet sich dem Assemblerprogrammierer, der an geeigneter Stelle eine Abfrage der Tastatur einbauen kann, z.B. immer dann, wenn rechenintensive Operationen durchgeführt werden. Ein anschauliches Beispiel für eine solche Anwendung bietet der Editor VDO25, der aus dem Public Domain Bereich erhältlich ist.

Jedoch auch dem TURBO PASCAL Programmierer bietet sich eine Möglichkeit, den Zustand der Tastatur abzufragen und anstehende Zeichen zu sammeln, bis diese bei einer Eingabe benötigt werden. Eine Möglichkeit ist, eine Prozedur zu schreiben, die dann zum geeigneten Zeitpunkt aufgerufen wird, ähnlich der erwähnten Methode der Assemblerprogrammierung. Schöner wäre es jedoch, wenn der Aufruf einer solchen Prozedur automatisch erfolgt. Mit einem kleinen Trick läßt sich eine bestimmte Eigenschaft von TURBO PASCAL (hier wird Bezug genommen auf die Version 3.0) für diese Zwecke ausnutzen.

Dem Handbuch ist zu entnehmen, daß mit dem Compilerbefehl {$U+} eine Abfrage der Tastatur erfolgt speziell für das Kontrollzeichen Ctrl-C, was als Unterbrechung interpretiert wird.

Was verbirgt sich nun hinter dieser Option bezogen auf die Ausführung des Prozessors Z80 (oder 8080)?
Der Compiler fügt schlicht hinter jede Anweisung den Operationscode RST 38H (Z80 Mnemonic) bzw. RST 7 (8080 Mnemonic) - Hex Code FF. Diese Anweisung wirkt exakt wie ein Unterprogrammaufruf (CALL), d.h. der Program Counter wird auf dem Stack abgelegt und - in diesem Falle - ein Aufruf der Adresse Hex 0038 ausgeführt. In dieser Adresse steht i.a. ein Sprung auf eine Adresse, wo die eigentliche Routine ausgeführt wird. Auf den ersten Blick sieht diese Aktion etwas umständlich aus, der Vorteil gegenüber einem direkten CALL liegt in der Kürze der Anweisung. Ein CALL benötigt drei Bytes, die RST Anweisung jedoch nur ein Byte.
(Die RST Möglichkeit war übrigens bei den älteren Prozessoren 8080 die gängige Art, Interrupts zu bearbeiten).
Und hier gibt es nun Schwierigkeiten mit dem JOYCE, weil bei dieser Maschine die Interrupts über die RST 7 Anweisung ausgeführt werden, also ein Konflikt besteht zwischen JOYCE Interrupts und TURBO PASCAL Option {$U+}.
In der Tat wird jeder JOYCE Benutzer, der diese Option zur gezielten Programmunterbrechung bereits eingesetzt hat, böse Überraschungen erlebt haben, am JOYCE funktioniert diese Option nämlich nicht (Wobei sich diese Aussage allerdings auf TURBO Versionen bezieht, die etwa Anfang bis Mitte 1986 angeschafft wurden. Ob dieser Misstand mittlerweile abgebaut ist, kann ich nicht sagen).
Glücklicerweise zeigt sich der Vertreiber von TURBO PASCAL, die Firma HEIMSOETH Software auf Fragen sehr zuvorkommend. Es sei deshalb hier die nötige Änderung der Datei TURBO.COM angegeben, die den ursprünglichen RST 7 auf RST 6 (Hex F7) ändert. Dadurch funktioniert die Compiler Option {$U+} einwandfrei.

2. TURBO PASCAL 3.0 Patch

Benötigt werden dazu die Dateien TURBO.COM und SID.COM auf möglichst gleicher Diskette. Dann müssen folgende Kommandos eingetippt werden:
    A>SID TURBO.COM          ( Aufruf des Debuggers             )
    CP/M 3 SID - Version 3.0 ( Bereitmeldung von SID            )
    NEXT MSZE  PC  END
    7980 7980 0100 D2FF      ( Statistikausgabe von SID         )
    #F372,F372,30            ( Umsetzen RST 7 auf RST 6         )
    #F378,F378,31            (          dto.                    )
    #F595,F595,F7            ( OpCode ändern                    )
    #WTURBOP.COM             ( Neue Datei TURBOP.COM erzeugen   )
    00F1h record(s) written  ( SID Fertigmeldung                )
    #^C                      ( STOP Taste am JOYCE              )
    A>TURBOP                 ( Aufruf des geänderten Compilers  )

3. Die TURBO PASCAL Routinen

Vorgestellt wird hier nun eine Reihe von Prozeduren und Funktionen, die als Include Datei vorliegen, um die Compiler Option {$U+} zum Sammeln von Zeichen auszunutzen.

Vorab sei auf folgende Nachteile hingewiesen:

  1. Die Option {$U+} erhöht die Ausführungszeit von Programmen
  2. Ein Sammeln von Zeichen ist nur sinnvoll bei der Verarbeitung von Strings. Das Verarbeiten von Zeichen ist möglich, ebenso von Zahlen. Im letzten Fall muß allerdings eine Wandlung in die entsprechende Zahlentype (Integer, Real) vorgenommen werden.
Die hier vorgestellten Programmteile sollen deshalb auch nur als Grundlage dienen.

Damit die Prozeduren funktionieren, wird eine Typen Deklaration LINE benötigt, die ein String mit einer vom Programmierer vorgegebenen Länge darstellt, also z.B.:

          TYPE LINE : STRING [80];
um einen Puffer zum Sammeln von maximal 80 Zeichen bereitzustellen. Die Include Datei erzeugt intern vier globale Variable, die dann natürlich nicht mehr vom Hauptprogramm deklariert werden dürfen. Diese sind:
  BUFFER : LINE; Dies ist der interne Puffer für das Sammeln der Zeichen
  BUFMAX : INTEGER; Dies ist eine Variable, die die maximale Anzahl der zu sammelnden Zeichen angibt
  UOPT : BOOLEAN; Diese Boolsche Variable zeigt an, ob eine Programmunterbrechung bei Ctrl-C vorgenommen werden soll oder nicht
  DETECT : BOOLEAN; Dies ist eine interne Boolsche Variable

Die Prozeduren und Funktionen:

AHEAD;

Diese, komplett in Assembler geschriebene Prozedur wird immer dann aufgerufen, wenn vom Compiler die RST 6 Funktion ausgeführt wird. Falls ein Ctrl-C eingegeben wurde, so erfolgt dann ein Programmabbruch, wenn vorher die Variable UOPT entsprechend gesetzt wurde. Zu beachten ist, daß zur Installation die Prozedur INI_AHEAD aufgerufen werden muß.

INI_AHEAD(BUFF:INTEGER;OPT:BOOLEAN);

Diese Prozedur installiert die besprochene Prozedur AHEAD. Sie
  setzt die Puffergrösse auf den Wert BUFF
  initialisiert den BUFFER
  trägt die Prozedur AHEAD an die RST 6 Adresse ein
und setzt die BREAK Option auf den Wert OPT. Ist OPT TRUE, so erfolgt ein Programmabbruch, wenn Ctrl-C gefunden wurde.
(Dies wirkt wie die Originaloption {$U+})

GET_AHEAD(VAR XIN:LINE):BOOLEAN;

Diese Funktion, von der ein Teil in Assembler geschrieben ist, verarbeitet gesammelte Zeichen. Hierbei ist XIN ein Puffer, in den die vorhandenen Zeichen kopiert werden. Neben dem zurückgegebenen Boolschen Wert der Funktion wird auch noch die interne Boolsche Variable DETECT gesetzt. Es ergeben sich folgende Funktionen in Abhängigkeit der Boolschen Variablen:
Variable: DETECT GET_AHEAD Funktion
Fall 1 FALSE FALSE Kein Zeichen gesammelt
Fall 2 FALSE TRUE Es wurden Zeichen gesammelt und komplett in den Puffer XIN übernommen. Der alte Puffer ist leer.
Fall 3 TRUE TRUE Es wurden Zeichen gesammelt und ein RETURN wurde gefunden. Der neue Puffer ist bis zum RETURN gefüllt und im alten Puffer sind noch Zeichen vorhanden.
Das letzte Ergebnis erlaubt das Bearbeiten mehrerer Zeilen.

READ_LINE(TEXT:LINE):LINE;

Diese Funktion erlaubt das Einlesen einer Zeile aus dem Puffer. Als Ergebnis wird eine Zeile zurückgegeben. Bezogen auf die oben aufgeführten Fälle ergibt sich:
Fall 1 Der String TEXT wird auf dem Bildschirm ausgegeben und eine komplette Zeile von der Tastatur eingelesen.
Fall 2 Der String TEXT sowie die bereits gesammelten Zeichen werden auf dem Bildschirm ausgegeben und die Zeile von der Tastatur aufgefüllt.
Fall 3 Der Inhalt des Puffers wird zurückgegeben. Eine Ausgabe des Strings TEXT erfolgt nicht.

4. Abschliessende Hinweise

  1. Unter keinen Umständen sollte die Option {$U+} innerhalb der Include Datei eingeschaltet werden. Dies kann zu Systemabstürzen führen.
  2. Jedoch sollte die Option {$U+} nach der Include Datei eingeschaltet werden, damit der Mechanismus wirksam wird.
  3. Bei zeitkritischen Routinen kann der Mechanismus am Anfang einer Prozedur oder Funktion mit {$U-} abgeschaltet werden. Sie sollte aber am Ende mit {$U+} reaktiviert werden. Unter Umständen kann dabei aber ein Zeichen verlorengehen.
  4. Im Fall 2, d.h. bei teilweise gefülltem Puffer ist ein Löschen der bereits eingegebenen Zeichen nicht mit der vorliegenden Funktion READ_LINE möglich.



Abgedruckt in Klubzeitung Nr. 54 - Nov. 1998.    Autor: Werner Cirsovius