ZAS und der Speicher im Grundgerät

von Mario Leubner

Heute ist es nun so weit, das neue ZAS ist fertig - Ralf hatte es ja in der letzten Ausgabe der KC-News bereits angekündigt. Über den Sinn und Zweck wurde bereits einiges gesagt. Das Hauptziel ist einerseits die Vereinfachung für den Anwender und auf der anderen Seite die bessere Transparenz für den Programmierer und natürlich die Nutzung des Grundgeräte-RAM's. Wie Ralf bereits feststellte, so bin auch ich der Auffassung, daß nur dann davon Gebrauch gemacht wird, wenn eine andere Lösung nicht möglich ist. Denn diese speziellen Programme laufen dann wirklich nur noch auf dem KC85/4.

1. Das Prinzip der Speicherverwaltung

Stellt Euch mal vor, Ihr wollt mehrere Programme unter CAOS in den Speicher laden und abwechselnd abarbeiten. Da stellt sich doch gleich die Frage, welchen Speicher benötigt jedes der Programme? Man wird also die angezeigten Adressen beim Laden der Programme beobachten müssen. Doch es reicht noch nicht aus, daß sich die Programme nicht überschneiden, meist weiß niemand, an welcher Stelle Daten abgelegt werden. Nach Murphy benutzen zwei verschiedene Programme mindestens ein Byte in derart unterschiedlicher Art und Weise, daß ein Wechsel der Programme nicht mehr möglich ist. Das gleiche Problem besteht natürlich in der CP/M-Betriebsart des KC-Systems. Der Speicher im Grundgerät ist nicht ausgelastet und könnte für KC-spezifische Anwenderprogramme sinnvoll genutzt werden. Nun weiß jedoch wiederum kein Programm(ierer), welcher Speicherbereich noch frei ist. Da gab es bisher zwei Möglichkeiten: Entweder der Verzicht auf die Treiber im Grundgerät oder das Risiko, eine andere Anwendung zu stören.

ZAS in der Version 1.3 setzt an diesem Problem an und übernimmt die Verwaltung des freien Speichers. Das sind die Bereiche von 1C00H bis 3AFFH im RAM0 und 4000H bis 7FFFH im RAM4. Dazu werden die beiden Bereiche in Segmente zu je 256 Bytes - sogenannte Pages - aufgeteilt. Die Anwenderprogramme können nun einen freien Bereich zugeteilt bekommen, indem sie ZAS mitteilen, wieviele Pages benötigt werden. Der so zugeteilte Bereich gilt dann solange als ,,belegt``, bis er durch einen Befehl an ZAS wieder freigegeben wird. Nun mag der eine oder andere denken, was soll das ganze - unter CP/M kann doch maximal ein Programm laufen? Richtig, aber bereits die Hardcopy-Funktion des KC kann jedes laufende Programm unterbrechen und eine Routine im Grundgerät aufrufen. Ich denke da sofort an die Programme DRUCK und HPKC von Frank Dachselt. Dazu kommen noch Interruptroutinen, und vielleicht ein Maustreiber? Alle diese kleinen ,,Progrämmchen`` sollen sich miteinander vertragen. Mit ZAS 1.3 kann das Programm im D004 jetzt die bereits belegten Bereiche erkennen und so ein Überschreiben verhindern. Und die vorhandenen Programme, die ZAS 1.3 noch nicht kennen? Die laufen wie bisher, eben nur mit dem Risiko, eine andere Anwendung zu stören und einen Rechnerabsturz zu wagen - eben wie bisher. Einen Vorteil gibt es trotzdem: man kann alle Treiber, die nach dem neuen Prinzip arbeiten, vorher deaktivieren und erhöht dadurch die Funktionssicherheit.

2. ZAS 1.3 aus der Sicht des Anwenders

Der Anwender (und dazu zähle ich mich auch, wenn ich ein Programm starte) bemerkt von ZAS 1.3 zunächst nichts. Alle geladenen Programme/Treiber teilen sich den Speicher im Grundgerät und führen ihre Arbeit wie gewohnt durch. Das einzige was jetzt passieren kann, wäre eine Fehlermeldung der Art ,,Nicht genug RAM verfügbar`` oder ,,Treiber nicht vorhanden``. Dann bleibt zumindest die Möglichkeit, nicht benötigte Treiber zu deaktivieren, geforderte Treiber nachzuladen und den Programmstart erneut zu versuchen. Zur Erinnerung: Bisher war an dieser Stelle der Absturz des Rechners die wahrscheinlich einzige Reaktion!

Über die Möglichkeiten zum Laden der Treiber kann ich an dieser Stelle noch nicht allzuviel sagen. Geplant ist ein universelles Ladeprogramm, mit dem einzelne Treiber oder ganze Treiberpakete in einem Zug geladen werden können. Verschiedene Anwenderprogramme werden ihre eigenen Treiber selbst laden, so daß der Anwender gar nichts davon bemerkt. Das mitgegebene Testprogramm ZASTEST.COM liefert unter anderem einen Überblick über alle aktiven Treiber. Es ist damit auch möglich, Speicher zu reservieren und so eine Art Treiber (allerdings ohne Funktion) zu definieren und einzelne oder alle Treiber zu deaktivieren. ZASTEST liegt als Turbo-PASCAL Quelltext bei und demonstriert die Anwendung der ESC-Funktionen in einer höheren Programmiersprache.

3. ZAS 1.3 aus der Sicht des Programmierers

Hier muß man zunächst noch einmal unterscheiden zwischen der Programmierung der Treiber und der Nutzung von Treiberfunktionen in D004-Programmen. Die Treiber sollten auf alle Fälle so programmiert werden, daß sie universell genutzt werden können. Dazu gehört auch die Beschreibung der Treiberfunktionen und Systemanforderungen.

3.1. Treiberprogrammierung

Das Prinzip der Speicherverwaltung kann nur funktionieren, wenn die Treiber verschieblich sind oder auf verschiedene Adressen gelinkt werden können. Verschiebliche Treiber kann man unter CAOS z.B. durch Nutzung des relativen UP-Aufrufs 0F00FH realisieren. Die andere Möglichkeit ist die Nutzung des PRL-Formates, die der Linker LINK131 bietet. Derartige PRL-Dateien können mit einem Relokationsprogramm nachträglich auf andere Adressen gebunden werden. Eine geeignete Routine liegt als RELOC.Z80 und RELOC.REL vor und kann bei Bedarf in eigene Programme eingebaut werden. Auf alle Fälle wird das geplante Ladeprogramm derartige PRL-Dateien unterstützen.

Alle Treiber beginnen mit einem Header, der für den Zugriff von ZAS und Ladeprogramm einen einheitlichen Aufbau haben muß:

BASE:   JR      VERTEIL       ; Einsprung zur Programmsteuerung
ID: DB ID ; ID-Kennung
VER: DB VERSION ; interne Versionsnummer (BCD-kodiert)
PG: DB PAGES ; Speicherbedarf
USE: DB 0 ; Anzahl der Nutzer des Treibers

SUB: DB SUB_ID ; ID eines benoetigten Treibermoduls
DB SUB_ADR ; Versionsnummer/Adresse (Pagebeginn)
DB 0 ; Ende der Tabelle der noetigen Treiber
ISTRG: DB 'ID-String',0 ; Klartext-Identifizierung

Die Einsprungstelle auf BASE+0 dient ZAS zum Aufruf der Treiberfunktionen. Im Register A wird dabei die Funktionsnummer übergeben, zwei Treiberfunktionen sind fest vorgeschrieben und müssen in jedem Treiber realisiert werden:

A=0 Treiber aktivieren
A=1 Treiber deaktivieren

Bei der Aktivierung wird der USE-Counter um 1 erhöht. Wird der USE-Counter dabei von 0 auf 1 erhöht (erste Aktivierung) initialisiert sich der Treiber. Die Deaktivierung verringert den USE-Counter um 1. Die letzte Deaktivierung, also wenn der USE-Counter zu 0 wird, muß alle vom Treiber getätigten Veränderungen rückgängig machen. Als Merkmal der Deaktivierung löscht der Treiber seine ID im Header. Damit ist der benutzte Speicherbereich wieder freigegeben. Die Treiberfunktionen A=2..15 sind für spätere Erweiterungen reserviert, die Funktionen A=16..255 stehen zur freien Verfügung und können je nach Art des Treibers belegt werden.

Der ID-Code auf BASE+2 dient ZAS zur Erkennung, daß der Treiber aktiv ist. Bei der Speicheranforderung initialisiert ZAS deshalb die Headerpage mit dem ID-Code. Sobald die ID-Nummer im Header (mit Null) überschrieben wird, gilt der Treiber als deaktiviert und folgende Speicheranforderungen nutzen diesen Bereich wieder.

Die Versionsnummer auf BASE+3 dient zur Unterscheidung von Treibern mit gleicher ID, also bei Weiterentwicklungen. Für Treiber mit höheren Versionsnummern muß sichergestellt werden, daß die Funktionen der alten Versionen in vollem Umfang erhalten bleiben. Bei der Mitbenutzung von anderen Treibern erfolgt der Versionstest anhand der Tabelle ab BASE+6.

Auf BASE+4 steht das Page-Byte, also der Speicherbedarf des Treibers. Dieser Wert wird bei der Übertragung des Treibers benötigt und kann später zur Ermittlung der Endadresse des genutzten Bereiches verwendet werden. In Bit 0 bis 5 steht die Anzahl der benötigten Pages minus 1. Es sind also maximal 64 Pages möglich, was dem gesamten RAM4 entspricht. Bit 6 gibt an, welcher RAM-Bereich genutzt werden soll: 0 für RAM0 und 1 für RAM4. Ist Bit 7 gleich 0, dann ist der jeweils andere Bereich auch möglich, bei BIT 7 gleich 1 nicht. Hier legt der Programmierer des Treibers fest, wo sein Treiber lauffähig ist.

Der USE-Counter auf BASE+5 kennzeichnet den Nutzungsgrad des Treibers. USE=0 kennzeichnet einen noch nicht aktivierten Treiber. Bei einem Treiberaufruf mit A=0 zählt der Treiber seinen eigenen USE-Counter hoch. Im Falle der Initialisierung (USE-Counter 0->1) wird dies den mitbenutzten Treibern durch den Aufruf mit A=0 angezeigt. Diese zählen dabei ebenfalls wieder ihren eigenen USE-Counter hoch. Eine Deaktivierung der Treiber kann nur erfolgen, wenn USE=0 oder 1 ist. Wird der USE-Counter bei einem Aufruf mit A=1 zu 0, dann deaktiviert sich der Treiber und zeigt dies den mitgenutzten Treibern wieder durch den Aufruf mit A=1 an. Dabei werden alle mitbenutzten Treiber auch wieder freigegeben. Als Erkennungsmerkmal für eine erfolgreiche Deaktivierung löscht der Treiber seinen ID-Code und der Bereich ist frei für andere Anwendungen.

Auf BASE+6 folgt noch die Tabelle der mitbenutzten Treiber. Diese enthält zwei Byte für jeden benötigten Treiber. Im ersten Byte steht der ID-Code, danach die erforderliche Versionsnummer des Treibers und nach Übertragung zum Grundgerät die PAGE-Adresse. Die Adressen muß das Ladeprogramm im D004 ermitteln und eintragen. Die Tabelle wird mit einer Null abgeschlossen. Werden keine anderen Treiber benötigt, dann ist nur die Null anzugeben.

Als letztes steht im Header noch eine Zeichenkette zur Klartext- Identifizierung. Je nach Anzahl der mitbenutzten Treiber steht diese auf BASE+7, BASE+9 usw. Die Zeichenkette endet mit einer Null.

3.2. Nutzung der Treiber und ESC-Funktionen

Die Speicherverwaltung erweitert ZAS um einige ESC-Funktionen. Ab der kaum verbreiteten Version 1.2 sind zusätzlich die Aufrufe ESC-0 bis ESC-9 möglich. Diese führen zu den äquivalenten ESC-Funktionen des CAOS und sind vorteilhaft verwendbar bei der Umsetzung von BASIC- Programmen von CAOS-BASIC zu HCBASIC.COM. Mit ZAS 1.3 wurden die fünf Funktionen ESC-l bis ESC-p neu eingeführt.

Neu ist auch die Einführung von Identifizierungscodes (kurz: ID), das sind sozusagen die Kennbytes der Treiber. Für die Nutzung der ESC- Funktionen zur Speicherverwaltung ist immer der ID-Code erforderlich. Anhand der ID-Codes kann Speicher beantragt werden, der Treiber aufgerufen oder gelöscht werden. Zum Aufruf von Treiberfunktionen muß das D004-Programm nur die entsprechende ESC-Funktion aufrufen ohne Kenntnis an welcher Stelle im Speicher der Treiber steht.

Alle ESC-Funktionen sind nach folgendem Schema zu programmieren:

MEMANF  EQU     0FFAEH          ; Speicheranforderung/Quittung

LD A,0FFH
LD (MEMANF),A ; Anfangswert eintragen
CALL STRING
DB ESC,... ; ESC-Funktion aufrufen
WAIT: LD A,(MEMANF)
CP 0FFH
JR Z,WAIT ; Quittung von ZAS abwarten
CP 0F0H
JR NC,ERROR ; zur Fehlerbehandlung

Die zu übergebenden Parameter werden alle nach dem ESC ausgegeben. ZAS quittiert die Funktion durch einen Wert in MEMANF, wobei mit 0FxH ein Fehler gemeldet wird. Je nach Funktion ist eine unterschiedliche Anzahl Parameter und Rückgabewerte möglich.

 

Funktion ESC-l

Diese Funktion deaktiviert einen vorhandenen Treiber durch Aufruf der Treiberfunktion A=1 und gibt dessen Speicher frei. Ist der Treiber mit der angegebenen ID nicht vorhanden oder kann der Treiber nicht gelöscht werden, meldet ZAS einen Fehler. Es können nur Treiber gelöscht werden, deren USE-Counter kleiner als 2 sind, d.h. der Treiber wird von keinem anderen Treiber mitbenutzt.

Aufruf: ESC,'l',ID
Ergebnis: 00h - OK
FAh - Treiber kann nicht gelöscht werden
FEh - ID nicht vorhanden

 

Funktion ESC-m

Damit wird Speicher für die Übertragung eines Treibers angefordert. Als Parameter ist der ID-Code und das Page-Byte erforderlich. Diese Werte sind dem Header des zu übertragenden Treibers zu entnehmen. Die Übertragung des Treibers kann mit den bekannten ESC-Funktionen ESC-S, ESC-T oder ESC-Z erfolgen.

Aufruf: ESC,'m',ID,Pages
Ergebnis: xxh - höherwertiger Teil der Anfangsadresse
FCh - ID-Tabelle voll
FDh - nicht genug freier Speicher vorhanden
FEh - ID bereits vorhanden

 

Funktion ESC-n

Damit kann getestet werden, ob ein benötigter Treiber im Grundgerät vorhanden ist. Als Rückgabewert erhält man in MEMANF die Anfangsadresse des Treibers. Werden weitere Informationen zum Treiber benötigt, ist die Headerpage zu lesen. Das kann mit einer der Funktionen ESC-R oder ESC-Y erfolgen.

Aufruf: ESC,'n',ID
Ergebnis: xxh - höherwertiger Teil der Anfangsadresse
FEh - ID nicht vorhanden

 

Funktion ESC-o

Um eine Treiberfunktion aufzurufen wird diese ESC-Funktion benutzt. Anzugeben ist der ID-Code, die Funktionsnummer (Register A), die Anzahl der folgenden Parameter (0 bis 7) und die Parameter selbst. Der Aufruf der Treiberfunktion erfolgt erst, wenn alle Parameter übertragen wurden. Dem Treiber wird dann in HL ein Zeiger auf die Parameterliste übergeben. Der Rückgabewert in MEMANF ist nur gültig, wenn dieser von der Treiberfunktion im Register A bereitgestellt wird. Weitere Registerinhalte können bei Bedarf aus dem Koppel-RAM gelesen werden.

Aufruf: ESC,'o',ID,A,n,...
Ergebnis: xxh - Rückgabewert der Treiberfunktion (00h..EFh)
FBh - Treiber nicht vorhanden
FEh - ID nicht vorhanden
FFBAH = Reg. L FFBBH = Reg. H
FFBCH = Reg. E FFBDH = Reg. D
FFBEH = Reg. C FFBFH = Reg. B

 

Funktion ESC-p

Das ist die einzige Funktion, die ohne ID-Codes auskommt. Es werden damit ALLE Treiber gelöscht und das ganze Treibersystem deaktiviert. Der Sinn der Funktion liegt darin begründet, daß vor einem Wechsel zu CAOS alle Treiber des CP/M-Systems ordnungsgemäß deaktiviert werden. Die Funktion zum Deaktivieren des Treibersystems wird automatisch mit der Funktion ESC-Ö (Exit) ausgeführt, also beim Wechsel zur CAOS- Betriebsart. Die Rückkehr mit QUIT kann die Treiber allerdings nicht wieder aktivieren. Solange alle Treiber korrekt arbeiten und sich löschen lassen, wird kein Fehler gemeldet. Anderenfalls sind USE- Counter so verändert worden, daß kein Treiber mehr löschbar ist und nur ein erneuter Bootvorgang (oder Nachladen von ZAS) kann den Speicher freigeben.

Aufruf: ESC,'p'
Ergebnis: 00h - OK
FAh - Treibersystem fehlerhaft

 

3.3. ID-Nummern und temporäre Bereiche

Gültige ID's liegen im Bereich von 1 bis 255 und sind in mehrere Bereiche unterteilt worden:

Die beiden ID-Nummern 1 und 2 haben einen Sonderstatus und können als temporäre Bereiche benutzt werden. Darunter sind Bereiche zu verstehen, wo D004-Programme während der Laufzeit Daten ablegen. Das könnten Grafikdaten sein, also das Retten von Bildschirmteilen oder ähnliches. Das Programm im D004 beantragt einen Bereich mit der ID- Nummer 1 oder 2 und kann daraufhin diesen Bereich beliebig nutzen. Mit Beendigung des D004-Programmes muß der temp. Bereich genauso wie jeder andere Bereich wieder freigegeben werden. Die Besonderheit der temp. Bereiche liegt darin, daß sie keinen Header besitzen und nicht über ESC-o aufgerufen werden können.

Die ID-Nummern 3 bis 15 sind für Systemtreiber reserviert. Die 3 ist bereits vergeben für den Bildschirmschoner. Außerdem fällt z.B. ein zukünftiger Maustreiber mit in diese Kategorie.

Danach schließt sich der größte Bereich von 16 bis 239 an. Das ist der ,,offizielle`` Bereich. Wer einen Treiber programmiert hat und diesen zur allgemeinen Nutzung zur Verfügung stellen will, erhält eine ID-Nummer aus dem Bereich. Diese wird beim Betriebssystemkoordinator beantragt damit es keine doppelten ID's gibt. Einige ID's sind ebenfalls schon belegt (siehe HLP-Datei), eine Aktualisierung der Liste wird in den KC-News zu finden sein.

Die letzten 16 ID's von 240 bis 255 sind zum Test freigegeben. Damit kann jeder, der sich an der Programmierung von Treibern versuchen will, seine Programme entwickeln und testen. Ist ein Treiber fertig, wird dann einfach eine offizielle ID beantragt. Um Probleme zu vermeiden, sollten Programme mit Test-ID's den eigenen Rechner möglichst nicht verlassen.

4. Anwendungen

Soweit zu den neuen ESC-Funktionen und ZAS 1.3, ausführlich ist alles in den HELP-Dateien zu ZAS nachzulesen. Dort findet man auch eine komplette Übersicht aller Steuercodes und ESC-Funktionen. Bleibt nur zu hoffen, daß die Speicherverwaltung allseits angenommen wird und fleißig Treiber programmiert werden. Die ersten Programme mit Unterstützung von ZAS 1.3 gibt es gleich dazu:

 

DEP.COM (Version 3.05):
Deaktiviert das Treibersystem vor dem Sprung zur CAOS-Betriebsart. DEP testet, ob ZAS 1.3 läuft und arbeitet wie bisher, wenn eine ältere ZAS-Version läuft.

 

ML.COM (Version 2.2):
Neben kleinen internen Änderungen fordert ML.COM jetzt mit ZAS 1.3 den gesamten RAM4 als temporären Speicher an. Dies ist für die Betrachtung komprimierter PI?/HI?-Bilder erforderlich. Liegt ein aktiver Treiber im RAM4, so erscheint eine Fehlermeldung wenn ein komprimiertes Bild betrachtet werden soll. Alle anderen Funktionen sind uneingeschränkt benutzbar.

 

FADEN.COM:
Das ist der erste echte Bildschirmschoner für den KC85/4! Erforderlich ist neben ZAS 1.3 auch CAOS4.3 und damit die zweite fiktive RAM4-Ebene. Dorthin rettet der Bildschirmschoner nämlich den aktuellen Bildinhalt. Zur Bedienung nur soviel: Der Aufruf FADEN // gibt eine Hilfe aus, angegeben werden kann die Zeitkonstante. Ist der Bildschirmschoner aktiv, reagieren die Tasten (+) und (-) sowie (H) und (V). Jede andere Taste oder eine Ausgabeforderung vom D004 beendet den Bildschirmschoner. Der Tastencode wird quittiert, also nicht zum D004 weitergeleitet.