Programmier-Projekte
Lazarus / Free Pascal
von Ronald Daleske

Startseite Impressum Warenzeichen

CP/M-CONSOLE

CP/M-CONSOLE ist ein sehr komplexes Programm. Mit ihm kann die Softwareschnittstellen eines externen CP/M Computers über die serielle Schnittstelle des PCs bedient werden. Die Anforderungen an dieses Programm ergeben sich aus den definierten CP/M Schnittstellen, CONIN, CONOUT, READ, WRITE und zusätzlich BOOT. Nach dem Programmstart werden alle CP/M Dateien aus dem Ordner "CPM_DIR_IN" eigelesen. Daraus wird ein CP/M Image gebildet. Aus diesem Image werden die Daten für die READ und WRITE-Anweisungen gelesen bzw. geeschrieben. Ein zusätzliches Fenster zeigt alle Zeichen an, die über die CONOUT-Schnittstelle des CP/M Computers ausgegeben werden. Über die Tastatur des PCs können Zeichen an CONIN des CP/M Computers eingegeben werden.

Inhaltsverzeichnis

1. Überblick
2. Kopplung CP/M-Computer mit CONSOLE
3. Das CONSOLE-Protokoll
3.1 Beschreibung der einzelnen Protokoll-Anforderungen
4. Module des CONSOLE-Programms
5. Downloads
6. Lizenz
7. Lizenz SYNASER (license Ararat Synapse)

1. Überblick


Das Projekt CONSOLE entstand zusammen mit meinem ersten CP/M Computer CPD2. Die CONSOLE wird aber auch von den nachfolgenden CP/M Computern CPD3 und CPD5 genutzt werden.

SYNASER

Wie bereits das SETERM - System-Terminal nutzt auch die CONSOLE den SYNASER-Treiber für die serielle Schnittstelle von Lukas Gebauer (siehe Project : Ararat Synapse).

CONOUT

Die anfängliche Konsole, für die Bearbeitung der Anfragen von der seriellen Schnittstelle, wurde wesentlich erweitert. Für die Anzeige der CP/M-Console (CONOUT) steht ein alphanumerischer Bildschirm bereit, der auch einige ESC-Sequenzen verarbeiten kann. So kann z.B. der Editor von Turbo Pascal genutzt werden.

CONIN

Die Tastatureingaben des PCs (wenn das CP/M-Fenster aktiv ist) werden an die CP/M Console CONIN weiter geleitet.

SELDSK, SETTRK, SETSEC, SETDMA, READ, WRITE

Es werden aber auch alle Disketten-Operationen des CP/M Betriebssystems (SELDSK, SETTRK, SETSEC, SETDMA, READ, WRITE) bedient. Dadurch kann das CP/M-BIOS sehr einfach gehalten werden, da alle Funktionsaufrufe entweder nur zwischengespeichert werden, oder an die CONSOLE weiter gereicht werden können.

Disketten-Image

Die Aufrufe des CP/M Betriebssystems an das Diskettensystem werden von einem Disketten-Image bedient. Für das Format des Disketten-Image sind derzeit 3 verschiedene Formate (meist von CP/M-Emulatoren) auswählbar. Dieses Disketten-Image wird bei jedem Programmaufruf neu gebildet. Dazu werden alle Dateien, die sich im Verzeichnis "CPM_DIR_IN" in das Image eingelesen. In der unteren Hälfte des CONSOLE-Hauptfensters wird dann die Belegung des Disketten-Images grafisch dargestellt (Rot=Boot-Sektoren (werden aber nicht genutzt), Blau=Directory-Sektoren, Grün=durch Daten belegte Sektoren, Weiss=freie Sektoren).

Nach dem Schliessen des Programms werden alle Dateien aus dem Disketten-Image in das Verzeichnis "CPM_DIR_OUT" geschrieben. Dadurch kann man Dateien, die sich während der CP/M-Sitzung geändert haben (oder die neu angelegt wurden) abspeichern.

PRINT

Die CP/M-Ausgaben an das LIST-Gerät werden in eine Textdatei mit dem Namen "Print.txt" im Unterordner "PRINT" umgeleitet.

Diese Textdatei kann während des laufenden Programms durch Drücken des Buttons aktualisiert werden (damit werden die LIST-Daten aus dem internen Programmspeicher in die Datei geschrieben).

BOOT-Datei (wird bei CPD2 und CPD3 genutzt, nicht bei CPD5)

Im Original CP/M wird das Betriebssystem zum Zeitpunkt des Starts von den Systempartitionen in den Arbeitsspeicher geladen und anschliessend gestartet. Bei meinen Projekten habe ich einen anderen Weg gewählt. Der Bootloader befindet sich im FLASH des CP/M-Computers. Dies ist ein Minimalsystem. Dieser Bootloader fragt bei der CONSOLE die Anzahl der Sektoren des eigentlichen CP/M-Systems ab (das System befindet sich als COM-Datei im Verzeichnis "BOOT"). Dann lädt der Bootloader das neue CP/M-System ab Adresse 100H in den TPA und startet es. Dann beginnt zu zweiten Mal das Hochladen des BIOS und der Sprung zur Kaltstartroutine des BIOS. Dieses zweite Laden des BIOS geht sehr schnell und gibt dem Syystem eine größere Fexibilität, da das BIOS auf dem CONSOLE-System schnell geändert werden kann.


2. Kopplung CP/M-Computer mit CONSOLE


Die grundsätzliche Arbeitsweise des CP/M-Computers mit der CONSOLE ist in der folgenden Übersicht dargestellt.

3. Das CONSOLE-Protokoll


Bevor die einzelnen Protokoll-Definitionen besprochen werden, soll das Grundprinzip kurz erläutert werden.


3.1 Beschreibung der einzelnen Protokoll-Funktionen


3.1.1 Rücksetzen der Hard- und Software

@ <CR> <LF>

Antwort vom PC:

keine

Länge = 3 Byte

Diese Anforderung sollte immer gesendet werden, wenn der Mikrocontroller zurückgesetzt wurde (Drücken des RESET-Tasters). Auf der PC-Seite wird im CONSOLE-Programm mit dieser Anforderung der Puffer für die Daten der seriellen Schnittstelle geleert (vor allem nach einer fehlerhaften Übertragung notwendig).


3.1.2 Abfrage der Anzahl der Sektoren der BOOT-Datei

a <CR> <LF>

Antwort vom PC:

N 0 A <CR> <LF>

Länge = 3 Byte

Länge = 5 Byte

Beispiel: Anfrage der Anzahl der Sektoren, Antwort = 10 Sektoren

Wie schon oben unter "Überblick" erläutert gibt die CONSOLE zusätzlich die Möglichkeit eine BOOT-Datei mit dem CP/M-Betriebssystem nachzuladen. Dazu muss der Loader aber die Anzahl der zu ladenden Sektoren kennen. Diese Anzahl wird mit dieser Funktion abgefragt. Nach dieser Funktion beginnt in der Regel das Laden der BOOT-Sektoren mit "b" (3.1.3 Lesen eines Sektors der BOOT-Datei).


3.1.3 Lesen eines Sektors der BOOT-Datei

b 0 5 0 3 <CR> <LF>

Antwort vom PC:

R 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 <CR> <LF>

Länge = 7 Byte

Länge = 39 Byte

Beispiel: lese Abschnitt 05 vom Sektor 03, Antwort = die 32 konvertierten Daten-Bytes des Sektors

Nachdem durch die Funktion "a" (3.1.2 Abfrage der Anzahl der Sektoren der BOOT-Datei) die Anzahl der Sektoren der BOOT-Datei bekannt ist, können nun die Sektoren der BOOT-Datei einzeln gelesen werden. Dazu wird "b" + "BSEC_LFD_NR" + "BSEC_SECTOR " + <CR> + <LF>.

Um möglichst viele Daten übertragen zu können, werden die Binärdaten nicht im umgewandelten Hexadezimal-Wert übertragen. Sonst würde der zu übertragende Datensatz nur 16 Datenbytes plus "R" plus >CR> und <LF> lang sein.

Würden die binären Daten direkt gesendet werden, würde es irgendwann zu Problemen kommen, da die Gegenstelle (der Mikrocontroller) auf ein <CR> wartet, was bei der Übertragung des Binärwertes 0DH dann bereits im Datenblock der Fall wäre. Also müssen die binären Datenwerte vorher konvertiert werden.

Prinzip der Konvertierung

Alle Daten werden in den Datenraum 128 bis 255 (Bit 7=1) gehoben. Dadurch wird sicher gestellt, dass niemals ein 0DH oder 0AH als Datenwert übertragen wird.

Das 7. Bit wird immer auf 1 gesetzt. Dann folgt der serielle Datenstrom der 8-Bit Daten, der in die restlichen 7 Bit (Bit6...Bit0) eingelagert wird. Damit werden mehr Bytes benötigt. Das Ergebnis von 36 Byte ist aber wesentlich weniger als 64 Byte mit umgewandelten Hexadezimal-Werten.

Im Mikrocontroller müssen diese konvertierten 7-Byte-Werte wieder in 8-Byte-Datenwerte umgewandelt werden.


3.1.4 Abfrage von Datum und Uhrzeit

c <CR> <LF>

Antwort vom PC:

D D D D D S S M M S S <CR> <LF>

Länge = 3 Byte

Länge = 13 Byte

In CP/M 2.2 wird kein Datum verwendet. Aber in CP/M 3.0 wird ein Datum mit Uhrzeit benötigt. Diese Funktion sendet Datum und Uhrzeit im Hexadezimal-Format an den Mikrocontroller.

Beschreibung des Datums- und Uhrzeiformats

Das Format orientiert sich an das Datums- und Uhrzeitformat von CP/M 3.0.


3.1.5 Übergabe eines Zeichen an die LIST-Schnittstelle

l 4 C <CR> <LF>

Antwort vom PC:

keine

Länge = 5 Byte

Beispiel: Drucken von "L"

Unter CP/M wird der Drucker als LIST bezeichnet. Diese Funktion reicht das Zeichen, das an die LIST-Schnittstelle gesendet wurde (BIOS-Funktion 05 = LIST-Ausgabe) im Hexadezimal-Format an die CONSOLE weiter. Unter CP/M war der Drucker ein zeichenorientiertes Gerät. Unter den modernen grafischen Betriebssystemen ist die Druckerausgabe wesentlich komplexer und benötigt immer spezielle Treiber. Daher werden die Zeichen im CONSOLE-Programm einfach in die Datei "PRINT.txt" im Verzeichnis "PRINT" umgeleitet.

Da während der Laufzeit des Programms CONSOLE, die Datei "PRINT.txt" geöffnet ist, muss das Programm geschlossen werden, oder es muss der Button betätigt werden. Dann wird die Datei "PRINT.txt" zwischengespeichert. Weitere Druckausgaben werden an die bestehenden Druckzeichen in dieser Datei angehängt.


3.1.6 Ausgabe eines Zeichen an die CONOUT-Schnittstelle

o 4 1 <CR> <LF>

Antwort vom PC:

keine

Länge = 5 Byte

Beispiel: Anzeige von "A"

Die Consolen-Ausgabe (CONOUT) ist sicher die wichtigste CP/M-Schnittstelle. Hier werden die Zeichen und Texte, die vom CP/M kommen angezeigt. Die Syntax dieser Funktion ist genau so einfach: "o" + das auszugebende Zeichen im Headezimal-Format + <CR> + <LF>.


3.1.7 Lesen eines Sektors (komprimiert)

r 0 4 <CR> <LF>

Antwort vom PC:

R 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 <CR> <LF>

Länge = 5 Byte

Länge = 39 Byte

Beispiel: lese Abschnitt 04 des Sektors, Antwort = die 32 konvertierten Daten-Bytes des Sektors

Wichtiger Hinweis: Vor dem Ausführen dieser Funktion müssen Sector, Track, Drive (STD) mit der Funktion "s" gesetzt werden.

Nach dem Setzen von Sector, Track, Drive (STD) durch die Funktion "s" werden nun die 32 Byte des Sektorabschittes gelesen. Im wesentlichen entspricht das der BIOS-Funktion READ, nur dass hier 4 einzelne Teilabschnitte eines Sektors gelesen und anschliessend zusammengesetzt werden müssen.

Um möglichst viele Daten übertragen zu können, werden die Binärdaten nicht im umgewandelten Hexadezimal-Wert übertragen. Sonst würde der zu übertragende Datensatz 2*32 Byte=64 Byte plus "R" plus >CR> und <LF> lang sein.

Die binären Daten können aber auch nicht direkt gesendet werden, da die Gegenstelle (der Mikrocontroller) auf ein <CR> wartet, was bei der Übertragung des Binärwertes 0DH ja der Fall wäre. Also müssen die Binärwerte vorher konvertiert werden.

Prinzip der Konvertierung

Alle Daten werden in den Datenraum 128 bis 255 (Bit 7=1) gehoben. Dadurch wird sicher gestellt, dass niemals ein 0DH oder 0AH als Datenwert übertragen wird.

Das 7. Bit wird immer auf 1 gesetzt. Dann folgt der serielle Datenstrom der 8-Bit Daten, der in die restlichen 7 Bit (Bit6...Bit0) eingelagert wird. Damit werden mehr Bytes benötigt. Das Ergebnis von 36 Byte ist aber wesentlich weniger als 64 Byte mit umgewandelten Hexadezimal-Werten.

Im Mikrocontroller müssen diese konvertierten 7-Byte-Werte wieder in 8-Byte-Datenwerte umgewandelt werden.


3.1.8 Einstellen von Sektor, Spur und Laufwerk (Sector, Track, Drive (STD))

s 3 A 0 0 2 7 0 1 <CR> <LF>

Antwort vom PC:

keine

Länge = 3 Byte

Beispiel: setze Sektor (VAR_SECTOR) mit 3AH, Spur (VAR_TRACK ist Word) mit 0027H und Laufwerk (VAR_DISKNO) mit 01

Format: s SE TH TL DR <CR> <LF>

Diese Funktion entspricht im wesentlichen folgenden CP/M-BIOS-Funktionen:

Nach dem Einstellen von Sektor, Spur und Laufwerk folgt in der Regel das Lesen mit "r" (3.1.7 Lesen eines Sektors (komprimiert)) oder das Schreiben eines oder mehrerer Sektoren.


3.1.9 Lesen eines Sektors (unkomprimiert)

u 0 6 <CR> <LF>

Antwort vom PC:

R 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 A 0 B 0 C 0 D 0 E 0 F <CR> <LF>

Länge = 5 Byte

Länge = 35 Byte

Beispiel: lese Abschnitt 06 des Sektors, Antwort = die 16 Daten-Bytes des Sektors im Hexadezimal-Format

Wichtiger Hinweis: Vor dem Ausführen dieser Funktion müssen Sector, Track, Drive (STD) mit der Funktion "s" gesetzt werden.

Nach dem Setzen von Sector, Track, Drive (STD) durch die Funktion "s" werden nun die 16 Byte des Sektorabschittes gelesen. Im wesentlichen entspricht das der BIOS-Funktion READ, nur dass hier 8 einzelne Teilabschnitte eines Sektors gelesen und anschliessend zusammengesetzt werden müssen.

Diese Funktion entspricht im Prinzip der Funktion "r", nur dass hier 1 Datenbyte mit 2 Hexadezimalen-Bytes übertragen wird. Mit 32 Byte werden also nur 16 Datenbytes übertragen. Für einen Sektor werden 8 Abschnitte benötigt.

Dafür ist diese Funktion einfacher zu implementieren, denn im Mikrocontroller muss nun nicht aufwendig wieder konvertiert werden. Diese Funktion ist daher besser für Testzwecke und zur Erstimplementierung.


3.1.10 Schreiben eines Sektors (unkomprimiert)

v 0 6 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 A 0 B 0 C 0 D 0 E 0 F <CR> <LF>

Antwort vom PC:

keine

Länge = 37 Byte

Beispiel: schreibe die folgenden 16 Byte im Hexadezimal-Format in den Sektor mit dem Anschnitt 06

Wichtiger Hinweis: Vor dem Ausführen dieser Funktion müssen Sector, Track, Drive (STD) mit der Funktion "s" gesetzt werden.

Nach dem Setzen von Sector, Track, Drive (STD) durch die Funktion "s" werden nun die 16 Byte des Sektorabschittes geschrieben. Im wesentlichen entspricht das der BIOS-Funktion WRITE, nur dass hier 8 einzelne Teilabschnitte eines Sektors geschrieben werden müssen.

Diese Funktion entspricht im Prinzip der Funktion "w", nur dass hier 1 Datenbyte mit 2 Hexadezimalen-Bytes übertragen wird. Mit 32 Byte werden also nur 16 Datenbytes übertragen. Für einen Sektor werden 8 Abschnitte benötigt.

Dafür ist diese Funktion einfacher zu implementieren, denn im Mikrocontroller muss nun nicht aufwendig wieder konvertiert werden. Diese Funktion ist daher besser für Testzwecke und zur Erstimplementierung.


3.1.11 Schreiben eines Sektors (komprimiert)

w 0 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 <CR> <LF>

Antwort vom PC:

keine

Länge = 41 Byte

Beispiel: schreibe die folgenden 36 Byte (nach Konvertierung = 32 Byte) Daten in den Sektor mit dem Anschnitt 03

Wichtiger Hinweis: Vor dem Ausführen dieser Funktion müssen Sector, Track, Drive (STD) mit der Funktion "s" gesetzt werden.

Nach dem Setzen von Sector, Track, Drive (STD) durch die Funktion "s" werden nun die 32 Byte des Sektorabschittes geschrieben. Im wesentlichen entspricht das der BIOS-Funktion WRITE, nur dass hier 4 einzelne Teilabschnitte eines Sektors geschrieben werden müssen.

Diese Funktion entspricht im Prinzip der Funktion "v", nur dass hier 32 Datenbytes konvertiert und übertragen werden. Mit 41 Byte werden also 32 Datenbytes übertragen. Für einen Sektor werden 4 Abschnitte benötigt.

Im Mikrocontroller müssen die übertragenen Daten wieder konvertiert werden. Diese Funktion kann mehr Daten/Zeiteinheit übertragen als die Funktion "v".


3.1.12 Anzeige einer Fehlernummer

x 0 5 <CR> <LF>

Antwort vom PC:

keine

Länge = 5 Byte

Beispiel: Anzeige von ">> Fehler Nr: 05 vom Controller gesendet" im Anzeigebereich des CONSOLE-Programms

Mit dieser Funktion ist es möglich vom Mikrocontroller an die CONSOLE Fehlermeldungen zu senden. Die Ursachen des Fehlers müssen an Hand der Nummer und der Stelle des Auftretens im BC analysiert werden.

Im Quelltext steht dann:

Write_String:='x03';

WriteLn;


3.1.13 Anzeige eines Kommentars

y H a l l o _ W e l t ! ! ! <CR> <LF>

Antwort vom PC:

keine

Länge je nach Kommentar, hier 16 Byte

Beispiel: Anzeige von "*** Hallo_Welt!!!" im Anzeigebereich des CONSOLE-Programms

Diese Funktion ist nicht für den produktiven Betrieb gedacht. Sie soll vielmehr im Testbetrieb zur Anzeige von durchlaufenen Programstellen dienen.

Im Quelltext steht dann:

Write_String:='yHallo_Welt!!!';

WriteLn;


3.1.14 Senden eines Zeichens an CONIN des Mikrocontrollers

keine

Antwort vom PC:

T 4 2 <CR> <LF>

Länge = 5 Byte

Beispiel: Eingabe des Wetes "B" (042H in hexadezimaler Form) von der Tastatur wird an den uC gesendet

Eigentlich ist diese Funktion nicht richtig implementiert, denn es sollte nur etwas übertragen werden, wenn eine Anforderung von Mikrokontroller erfolgt ist (soll später noch geändert werden).


4. Module des CONSOLE-Programms

... folgt in Kürze ...


5. Downloads

Quelltexte: CONSOLE.ZIP


6. Lizenz

Creative Commons Lizenzvertrag
Diese(s) Werk bzw. Inhalt von Ronald Daleske steht unter einer Creative Commons Namensnennung-Nicht-kommerziell 3.0 Deutschland Lizenz.


keine Mängelgewähr

DIESE SOFTWARE WIRD VOM URHEBERRECHTSINHABER "OHNE MÄNGELGEWÄHR" BEREITGESTELLT. ALLE AUSDRÜCKLICHEN ODER STILLSCHWEIGENDEN GEWÄHRLEISTUNGEN, EINSCHLIESSLICH DER STILLSCHWEIGENDEN GEWÄHRLEISTUNG DER MARKTGÄNGIGKEIT UND EIGNUNG FÜR EINEN BESTIMMTEN ZWECK (JEDOCH NICHT DARAUF BESCHRÄNKT), WERDEN AUSGESCHLOSSEN. DER URHEBERRECHTSINHABER IST IN KEINEM FALL UND NACH KEINER HAFTUNGSTHEORIE (SEI ES AUF VERTRAGSBASIS, AUF DER BASIS STRENGER HAFTUNG ODER UNERLAUBTER HANDLUNGEN, EINSCHLIESSLICH FAHRLÄSSIGKEIT) FÜR BELIEBIGE VERURSACHTE DIREKTE, INDIREKTE, ZUFÄLLIGE, BESONDERE, EXEMPLARISCHE SCHÄDEN ODER FOLGESCHÄDEN (EINSCHLIESSLICH, JEDOCH NICHT BESCHRÄNKT AUF BESCHAFFUNG VON ERSATZPRODUKTEN ODER -LEISTUNGEN, NUTZUNGSAUSFALL, DATEN- UND GEWINNVERLUST ODER GESCHÄFTSAUSFALL) HAFTBAR, DIE AUFGRUND DER VERWENDUNG DIESER SOFTWARE ENTSTEHEN KÖNNEN. DIES GILT AUCH, WENN AUF DIE MÖGLICHKEIT SOLCHER SCHÄDEN HINGEWIESEN WURDE.


THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


7. Lizenz SYNASER (license Ararat Synapse)

BDS style license

Die Lizenzbedingungen zum SYNASER-Treiber für die serielle Schnittstelle finden Sie unter license Ararat Synapse




Startseite Impressum Warenzeichen