summaryrefslogtreecommitdiff
path: root/doc/porting-z80
diff options
context:
space:
mode:
authorLars-Dominik Braun <lars@6xq.net>2019-02-04 13:09:03 +0100
committerLars-Dominik Braun <lars@6xq.net>2019-02-04 13:09:03 +0100
commit04e68443040c7abad84d66477e98f93bed701760 (patch)
tree2b6202afae659e773bf6916157d23e83edfa44e3 /doc/porting-z80
downloadeumel-src-04e68443040c7abad84d66477e98f93bed701760.tar.gz
eumel-src-04e68443040c7abad84d66477e98f93bed701760.tar.bz2
eumel-src-04e68443040c7abad84d66477e98f93bed701760.zip
Initial import
Diffstat (limited to 'doc/porting-z80')
-rw-r--r--doc/porting-z80/8/doc/Port.Z802484
-rw-r--r--doc/porting-z80/8/source-disk1
2 files changed, 2485 insertions, 0 deletions
diff --git a/doc/porting-z80/8/doc/Port.Z80 b/doc/porting-z80/8/doc/Port.Z80
new file mode 100644
index 0000000..ed3c80a
--- /dev/null
+++ b/doc/porting-z80/8/doc/Port.Z80
@@ -0,0 +1,2484 @@
+#type ("trium8")##limit (12.0)#
+#pagelength(19.5)#
+#start(1.5,1.5)#
+#type("triumb36")#
+#free(4.0)#
+ EUMEL
+ Portierungshandbuch
+ Z 80
+#type("triumb18")#
+#free(1.5)#
+ Version 8 #page(1)#
+#type ("trium8")##limit (12.0)#
+#block#
+#pagelength(19.5)#
+#head#
+#center#- % -
+
+
+#end#
+#type("triumb14")#Inhalt#a#
+
+Teil 1: Einführung #topage("ein")#
+#free(0.3)#
+ Zweck dieses Handbuchs #topage("zweck")#
+ Referenzliteratur #topage("reflit")#
+ Minimale Hardwarevoraussetzungen #topage("hardw")#
+ Systemdurchsatz #topage("durchsatz")#
+ Softwarekomponenten des EUMEL-Systems #topage("kompo")#
+ Anlieferung des Z80-EUMEL-Systems #topage("anlief")#
+
+Teil 2: Allgemeine Strukturen #topage("allgem")#
+#free(0.3)#
+ Hintergrund #topage("hg")#
+ Archiv #topage("arch")#
+ Hauptspeicher #topage("speicher")#
+
+Teil 3: SHard-Interface Spezifikation #topage("shardifc")#
+#free(0.3)#
+ 0. Vorbemerkungen #topage("vor")#
+ Zur Notation #topage("not")#
+ Link-Leisten #topage("leist")#
+ Allgemeine Link-Bedingungen #topage("link")#
+ Interrupts #topage("intr")#
+ 1. System laden #topage("laden")#
+ 2. Systemstart und -ende #topage("start")#
+ 3. Speicherverwaltung #topage("spver")#
+ Hauptspeicher #topage("haupt")#
+ Schattenspeicher #topage("schatt")#
+ Blocktransfer im Speicher #topage("ldir")#
+ Speicherfehler #topage("memerr")#
+ 4. Zeitgeber #topage("zeit")#
+ 5. Kanäle #topage("channel")#
+ 5.1 Stream-IO #topage("stream")#
+ Terminals #topage("term")#
+ Drucker, Plotter #topage("druck")#
+ Exoten #topage("exot")#
+ 5.2 Block-IO #topage("block")#
+ Block-IO bei Hintergrund und Archiv #topage("bhgarch")#
+ 5.3 IO-Steuerung #topage("iocontrol")#
+ Einstellung serieller Schnittstellen #topage("v24")#
+ Flußkontrolle #topage("fluss")#
+ Kalender #topage("kalender")#
+ 6. SHard-Interface Version #topage("shdver")#
+ 7. ID-Konstanten #topage("ID")#
+ 8. Zusätzliche Leistungen #topage("shdelan")#
+ 9. Spezialroutinen #topage("ke")#
+
+Teil 4: Tips zur Portierung #topage("tips")#
+ 0-Version des SHards #topage("0ver")#
+ Effizienzprobleme #topage("eff")#
+ Typische Fehler #topage("fehler")#
+
+Anhang A: EUMEL-Debugger "Info" #topage("info")#
+#free(0.3)#
+ Aufruf des Infos #topage("aufrinf")#
+ Info-Format #topage("forminf")#
+ Info-Kommandos #topage("cmdinf")#
+ Einige Systemadressen #topage("sysaddr")#
+ Leitblock #topage("pcb")#
+#page#
+#cc("Teil 1: ","Einführung")#
+#goalpage("ein")#
+
+
+#b("Zweck dieses Handbuchs")#
+#goalpage("zweck")#
+
+Dieses Portierungshandbuch wendet sich an diejenigen, die das EUMEL-System auf einem
+neuen Rechnertyp implementieren wollen. Es ist Teil einer Serie von Portierungshandbüchern
+für verschiedene Prozessortypen. Dieses bezieht sich auf Rechner mit Z80-Prozessoren.
+
+Zum Betrieb eines EUMEL-Systems wird dieses Handbuch nicht benötigt!
+
+
+
+#b("Referenzliteratur")#
+#goalpage("reflit")#
+
+
+ "EUMEL Benutzerhandbuch"
+
+ "EUMEL Systemhandbuch"
+
+ "EUMEL Quellcode der insertieren ELAN-Pakete"
+
+ "Z80-Assembly Language Programming Manual"
+ Zilog, 1977
+
+
+
+#b("Minimale Hardwarevoraussetzungen")#
+#goalpage("hardw")#
+
+Um das EUMEL-System effizient einsetzen zu können, sollte die Hardware mindestens
+folgenden Kriterien genügen:
+
+ #ib#CPU#ie# Die Z80-CPU sollte mit mindestens 2.5 MHz arbeiten. Falls
+ die Buszugriffe durch einen CRTC o.ä. verlangsamt werden,
+ sollte die echte Z80-Leistung durchschnittlich mindestens
+ einem ungebremsten 2.5 MHz System entsprechen.
+ Seltene Verlangsamungen (z.B. nur bei I/O-Operationen)
+ spielen bei diesen Überlegungen keine Rolle.
+
+ RAM Das System sollte über mindestens 64 K Byte #ib#Hauptspeicher#ie#
+ verfügen, besser sind 128 K als Anfangsausrüstung.
+
+ #ib#Hintergrund#ie# Als Hintergrundmedium sind #ib#Floppy#ie#, #ib#Harddisk#ie# und RAM bzw.
+ ROM denkbar.
+
+ Kapazität: > 300 K, besser > 400 K (Single-User)
+ > 750 K, besser > 1000 K (Multi-User)
+
+ Zugriff: < 500 ms (Single-User)
+ < 200 ms (Multi-User) *)
+#foot#
+#f#*) Hier ist die durchschnittliche Zugriffszeit auf einen 512 Byte großen Block gemeint. Für Platten und Floppies kann man
+sie als Summe der Positionierzeit über die halbe Platte und der Zeit einer halben Umdrehung berechnen.#a#
+#end#
+
+ #ib#Archiv#ie# Als Archivgerät wird meistens eine Floppy eingesetzt. Aber
+ auch Band oder Kassettenrecorder sind denkbar. Die An­
+ forderungen an Kapazität und Geschwindigkeit sind anwen­
+ dungsspezifisch.
+
+ #ib#Bildschirm#ie# Angestrebt werden sollte ein Bildschirm mit 24 Zeilen mit je
+ 80 Zeichen (oder größer). Kleinere Bildschirme sind anschließ­
+ bar, aber mit 40 Zeichen pro Zeile läßt sich nicht mehr kom­
+ fortabel arbeiten.
+ Rollup und freie Cursorpositionierung sind notwendige Vor­
+ aussetzungen, invers-video ist erwünscht, aber nicht not­
+ wendig. Weiterhin werden 'Löschen bis Zeilenende' und
+ 'Löschen bis Schirmende' benötigt. Lokale Editierfunktionen
+ sind überflüssig.
+
+ #ib#Tastatur#ie# An Steuertasten sollten mindestens ESC und die vier Cursor­
+ tasten vorhanden sein. Dabei ist es günstig, wenn die Cursor­
+ tasten ergonomisch als Block bzw. Kreuz angeordnet sind.
+ EUMEL benötigt weitere Steuertasten für HOP, RUBIN,
+ RUBOUT und MARK. Dafür können beliebige Tasten der
+ Tastatur gewählt werden.
+
+
+
+#b("Systemdurchsatz")#
+#goalpage("durchsatz")#
+
+Da das EUMEL-System auf dem Prinzip des Demand Paging aufbaut, hängt der System­
+durchsatz von
+
+ - CPU Leistung
+ - Speichergröße (RAM)
+ - Geschwindigkeit beim Hintergrundzugriff (Floppy, Harddisk)
+
+ab. Mit zunehmender Benutzerzahl steigen in der Regel die Anforderungen an das Paging
+(Hintergrund-Zugriff) schneller als an die CPU. In diesem Bereich kann man die System­
+leistung dann durch mehr Speicher und/oder eine schnellere Platte in größerem Umfang
+steigern. Dabei läßt sich eine langsame Platte teilweise durch mehr RAM und umgekehrt
+wenig RAM durch eine schnelle Platte ausgleichen.
+
+
+
+#b("Softwarekomponenten des EUMEL-Systems")#
+#goalpage("kompo")#
+
+Das EUMEL-System besteht aus mehreren Schichten:
+
+
+
+ EUMEL  2: Standardpakete, Editor, ...
+
+ EUMEL  1: ELAN Compiler
+
+ EUMEL  0: Basismaschine
+
+ EUMEL -1: SHard
+
+ H a r d w a r e
+
+
+Dieses #ib#Schichtenmodell#ie# ist nach oben offen und kann deshalb um beliebig viele (höhere)
+Schichten erweitert werden.
+
+EUMEL > 0 Die Standardsoftware der Schichten > 0 ist in der Sprache ELAN geschrie­
+ ben (siehe "EUMEL Quellcode"). Dementsprechend sind alle Schichten ober­
+ halb der EUMEL-0-Maschine prozessor- und rechnerunabhängig, d.h.
+ Anpassungen an einen neuen Rechnertyp sind nicht erforderlich.
+
+#ib#EUMEL 0#ie# Die sogenannte "EUMEL-0-Maschine" enthält alle Basisoperationen und
+ hängt davon ab, welchen Prozessortyp der Rechner als CPU verwendet. Sie
+ existiert für verschiedene Prozessortypen. Hier wird nur auf den Typ Z80
+ Bezug genommen. Bei der Portierung auf einen Z80-Rechner wird die
+ Z80-EUMEL-0-Maschine ohne Anpassungen (!) übernommen.
+
+EUMEL -1 Diese Schicht stellt das Interface zwischen der EUMEL-0-Maschine und der
+ eigentlichen Hardware (vom Prozessor abgesehen) dar. Insbesondere umfaßt
+ sie alle Routinen zur Ansteuerung peripherer Geräte (Gerätetreiber).
+ Diese Schicht wird "SHard" genannt ("S"oftware-"Hard"ware Interface).
+
+Der SHard ist der einzige Teil des Systems, der bei der Portierung auf einen Z80-Rech­
+ner angepaßt bzw. neu geschrieben werden muß. Deshalb besteht der größte Teil dieses
+Handbuchs aus der Spezifikation des Z80-SHards.
+
+
+
+#b("Anlieferung des Z80-EUMEL-Systems")#
+#goalpage("anlief")#
+
+Der Implementierer erhält die EUMEL-Software auf Disketten. Dabei stehen folgende Stan­
+dardformate zur Wahl:
+
+ 8", 1D, 77 Spuren, 16 Sektoren (\#0...\#15) � 512 Byte
+
+ 8", 2D, 77 Spuren, 16 Sektoren (\#0...\#15) � 512 Byte
+
+ 5", 2D, 40 Spuren, 9 Sektoren (\#1...\#9) � 512 Byte *)
+#foot#
+#f#*) 48 tpi#a#
+#end#
+
+
+Die Diskettenlieferung enthält
+
+ - Single-User Hintergrund
+ - Multi-User Hintergrund
+ - Standardarchive
+ - Archive mit weiterer Anwendersoftware
+
+Dabei enthält der Hintergrund auch die EUMEL-0-Software (oft auch als "Urlader" be­
+zeichnet).
+
+#on("i")#Bitte gehen Sie vorsichtig mit diesen Mutterdisketten um. Verwenden Sie sie nur als Quelle
+beim Kopieren. Sie sollten nur auf Kopien davon arbeiten!#off("i")#
+#page#
+#cc("Teil 2: ","Allgemeine Strukturen")#
+#goalpage("allgem")#
+
+
+#b("Hintergrund")#
+#goalpage("hg")#
+
+Der Hintergrund ist in 512 Bytes große Blöcke unterteilt. Sie werden durch Blocknummern (0,
+1, 2, ...) adressiert. Die physische Ablage der Blöcke auf dem Hintergrundmedium bleibt dem
+SHard überlassen. Er kann sie z.B. linear oder versetzt anordnen. Man sollte darauf achten,
+daß Positionierungen auf logisch "nahe" Blöcke möglichst schnell gehen sollten. Deshalb ist
+in der Regel zylinderorientierte Anordnung der oberflächenorientierten vorzuziehen.
+
+Falls auf dem Hintergrundgerät spezielle Blöcke z.B. für Boot und SHard freigehalten werden
+sollen, muß das bei der Abbildung der Hintergrundblocknummern auf die Sektoren der Floppy
+bzw. der Harddisk berücksichtigt werden.
+
+Aufbau des Hintergrundes:
+
+ Block 0 Systemetikett
+
+ Block 10...10+k-1 EUMEL-0-Software (Urlader)
+
+ Block 1...9, 10+k ... Paging-Bereich
+
+
+Aufbau des #ib#Systemetikett#ie#s (#ib#Block 0#ie#):
+
+ Byte Wert/Aufgabe
+
+ 0...5 "EUMEL-"; Kennzeichen für EUMEL-Hintergrund.
+ 6...11 Versionsnummer in druckbaren Zeichen. Sie stellt sicher, daß Urlader und
+ Hintergrund kompatibel sind.
+ 12 FFh ; zur Zeit ohne Bedeutung
+ 13 enthält Wert 0 , wenn System im Shutupzustand ist.
+ 14..15 Systemlaufzähler (14=low, 15=high). Wird bei jedem Systemstart um 1
+ erhöht.
+ 16..35 Reserviert; zur Zeit ohne Bedeutung
+ 36..37 Aus historischen Gründen für interne Zwecke belegt.
+ 38 .. 69 Hier kann eine Installationsnummer geführt werden.
+ 70 .. 79 Info-Paßwort
+ 80 =0 Normalzustand
+ =1 Kompresslauf erforderlich (System frisch von Archiv geladen)
+ 81...255 Reserviert.
+ 256..511 Kann von SHard beliebig verwendet werden.
+
+
+
+#b("Archiv")#
+#goalpage("arch")#
+
+Wie der Hintergrund sind die Archive in 512 Bytes große Blöcke unterteilt. Bisher gibt es
+folgende #dx("Standardformate")#:
+
+
+ 8", 1D, 77 Spuren, 16 Sektoren (\#0...\#15) � 512 Byte
+ 8", 2D, 77 Spuren, 16 Sektoren (\#0...\#15) � 512 Byte
+
+ Block Seite Spur Sektor
+
+ 0 0 0 0
+ 16 0 1 0
+ 77*16 1 0 0
+
+ n n DIV (77*16) n MOD (77*16) DIV 16 n MOD 16
+
+
+ 5", 2D, 40 Spuren, 9 Sektoren (\#1...\#9) � 512 Byte
+
+ Block Seite Spur Sektor
+
+ 0 0 0 1
+ 9 0 1 1
+ 40*9 1 0 1
+
+ n n DIV (40*9) n MOD (40*9) DIV 9 n MOD 9 + 1
+
+
+ 5", 2D, 80 Spuren, 9 Sektoren (\#1...\#9) � 512 Byte
+
+ Block Seite Spur Sektor
+
+ 0 0 0 1
+ 9 0 1 1
+ 80*9 1 0 1
+
+ n n DIV (80*9) n MOD (80*9) DIV 9 n MOD 9 + 1
+
+
+ 5", HD, 80 Spuren, 15 Sektoren (\#1...\#15) � 512 Byte
+
+ Block Seite Spur Sektor
+
+ 0 0 0 1
+ 15 0 1 1
+ 80*15 1 0 1
+
+ n n DIV (80*15) n MOD (80*15) DIV 15 n MOD 15 + 1
+
+
+Selbstverständlich können auch andere #ib#Archivformate#ie# implementiert werden, falls das aus
+Hardwaregründen notwendig ist oder sich dadurch wesentliche Verbesserungen (z.B. in der
+Kapazität) ergeben.
+
+Wenn irgend möglich sollte aber mindestens eines der oben aufgeführten Standardformate
+unterstützt werden - evtl. als zusätzliches Format -, um den Austausch zwischen verschie­
+denen Rechnertypen zu vereinfachen.
+
+#on("i")#Hinweis: Um den Datenaustausch zwischen verschiedenen Rechnertypen zu vereinfachen,
+ sollten möglichst alle der hardwaremäßig möglichen Standardformate (mindestens
+ lesend) unterstützt werden. Dabei sollte SHard sich automatisch auf das Format
+ der jeweils eingelegten Floppy einstellen:#off("i")#
+
+
+ Laufwerkstyp Diskettentyp(en)
+
+ 8" 1D 8" 1D
+ 8" 2D 8" 2D, 1D
+
+ 5" 2D-40 5" 2D-40
+ 5" 2D-80 5" 2D-80, 2D-40 *)
+ 5" HD-80 5" HD-80, 2D-80, 2D-40 *)
+#foot#
+#f#*) Bei der Behandlung von 40-Spur-Disketten auf 80-Spur-Laufwerken gelten meistens folgende Regeln:
+ a) Lesen funktioniert sicher.
+ b) Schreiben ist unsicher, funktioniert aber häufig.
+ c) Formatieren funktioniert fast nie.
+#a#
+#end#
+
+
+
+#b("Hauptspeicher")#
+#goalpage("speicher")#
+
+Die 64 K des direkt vom Z80 adressierbaren #ib#Speicher#ie#s sind folgendermaßen aufgeteilt:
+
+ FFFFh #corner1("-5.0")#
+ Platz für SHard
+ yyyyh #box3("T","3","75.0")#
+ #corner1("-5.0")#
+ Pagingbereich
+
+ xxxxh #box3("T","3","75.0")#
+ #corner1("-5.0")#
+ EUMEL 0
+
+ 1400h #box3("T","3","75.0")#
+ #corner1("-5.0")#
+ Platz für SHard
+ 0000h #box3("T","3","75.0")#
+
+Möglichst große Teile des SHards (am besten alle) sollten im unteren Adreßbereich (bis
+13FFh) liegen, damit dem Paging viel Speicher zur Verfügung steht.
+
+Der nicht direkt (aber durch Banking oder DMA) erreichbare Teil des #ib#RAM#ie#s wird Schatten­
+speicher (siehe S.#topage("schatt")#) genannt.
+
+
+Hinweis: Falls ein Teil des Hauptspeicher-Adreßraums fest (d.h. auch nach dem Boot­
+ loading nicht ausblendbar) durch ROM belegt ist, muß dieses in einem der beiden
+ SHard-Bereichen liegen.
+
+#page#
+#cc("Teil 3: SHard ","Interface Spezifikation")#
+#goalpage("shardifc")#
+
+
+#bb("0. ","Vorbemerkungen")#
+#goalpage("vor")#
+
+
+#b("Zur Notation")#
+#goalpage("not")#
+
+Im folgenden wird zwischen #dx("0-Routinen")#, die dem SHard vom EUMEL-0-System zur
+Verfügung gestellt werden, und #dx("SHard-Routinen")# unterschieden, die der SHard implementie­
+ren muß. Damit dieser Unterschied bei der Spezifikation deutlich wird, werden 0-Routinen
+folgendermaßen aufgeführt:
+
+ name (0-Routine)
+
+Zusätzlich werden 0-Routinen grundsätzlich klein und SHard-Routinen groß geschrieben.
+
+Z80-Befehle werden wie in "Z80-Assembly Language Programming Manual" (Zilog, 1977)
+notiert:
+
+ ld a,27
+ add a,l
+
+Hexadezimale Zahlen werden durch ein nachgestelltes 'h' gekennzeichnet:
+
+ 12h = 18
+ 1Fh = 31
+ FFFFh = 65535
+
+
+#b("Link-Leisten")#
+#goalpage("leist")#
+
+Die Verbindung zwischen SHard und Urlader (EUMEL-0) erfolgt über zwei Tabellen. In der
+"0-Leiste" stellt EUMEL-0 dem SHard verschiedene 0-Routinen zur Verfügung. Diese
+Leiste beginnt an der Adresse 1400h:
+
+ 1400h defm 'EUMEL '
+ 1410h defw eumel0blocks
+ 1412h defw hgversion
+ 1414h defw 1 ; Kennzeichen für Z80-Urlader
+ 1416h defw urladerversion
+ 1418h defw 0 ; reserviert
+ 141ah defw ; kleinste unterstützte SHardversion
+ 141ch defw ; größte ...
+ 141eh jp systemstart
+ jp inputinterrupt
+ jp timerinterrupt
+ jp warte
+ jp grab
+ jp free
+ jp shutup
+ jp info
+
+Diese Leiste wird vom Urlader nach dem Systemstart überschrieben. Der SHard muß daher,
+bevor er nach systemstart springt, die für ihn relevanten Teile (mindestens die Sprungbefehle)
+in einen eigenen Bereich kopieren:
+
+ #ib#eusystemstart#ie#: jp 0
+ #ib#euinputinterrupt#ie#: jp 0
+ #ib#eutimerinterrupt#ie#: jp 0
+ #ib#euwarte#ie#: jp 0
+ #ib#eugrab#ie#: jp 0
+ #ib#eufree#ie#: jp 0
+ #ib#eushutup#ie#: jp 0
+ #ib#euinfo#ie# jp 0
+
+So kann SHard die entsprechenden 0-Routinen vermittels der obigen Vereinbarungen aufru­
+fen:
+
+ jp eusystemstart
+ ...
+ call euwarte
+
+Für die Gegenrichtung muß SHard der 0-Maschine die "SHard-Leiste" zur Verfügung
+stellen, deren Adresse beim Sprung nach 'systemstart' in HL stehen muß. Die 0-Maschine
+kopiert diese Leiste. SHard darf daher anschliessend den Bereich anderweitig (z.B.
+EA-Puffer) verwenden:
+
+
+ #ib#SHDID#ie#: defm 'SHARD ' ; 16 Byte
+ #ib#SHDVER#ie#: defw 8
+ #ib#MODE#ie#: defw
+ #ib#ID4#ie#: defw
+ #ib#ID5#ie#: defw
+ #ib#ID6#ie#: defw
+ #ib#ID7#ie#: defw
+ defw
+ defw
+ #ib#OUTPUT#ie#: jp shout
+ #ib#BLOCKIN#ie#: jp shbin
+ #ib#BLOCKOUT#ie#: jp shbout
+ #ib#IOCONTROL#ie#: jp shiocnt
+ #ib#SYSEND#ie#: jp shend
+ #ib#SCHINF#ie#: jp shsinf
+ #ib#SCHACC#ie#: jp shsacc
+ defw
+ #ib#LIMIT#ie#: defw
+
+
+#b("Allgemeine Link-Bedingungen")#
+#goalpage("link")#
+
+In der Regel sind sowohl 0-Routinen als auch SHard-Routinen durch 'call' aufzurufen:
+
+ call <routine>
+
+Ausnahmen von dieser Regel sind im folgenden stets besonders vermerkt.
+
+Generelle Link-Bedingung (für SHard- und 0-Routinen) ist:
+
+ Alle Register - bis auf die jeweils spezifizierten Ausgangsparameter und das F-Regi­
+ ster *) - bleiben unverändert.
+#foot#
+#f#*) Flags sind i.a. nach dem Aufruf einer Routine undefiniert. Ausnahmen sind natürlich die Flags, die als Ausgangs­
+parameter in manchen Fällen definiert sind.#a#
+#end#
+
+Jede SHard-Routine muß also alle Register (bis auf F), die sie verändert und die keine
+Ausgangsparameter sind, retten und wiederherstellen. Im Gegenzug braucht SHard beim
+Aufruf von 0-Routinen selbst keine Register zu retten.
+
+
+#b("Interrupts")#
+#goalpage("intr")#
+
+Zwei externe Ereignisse (Zeitgeber und Eingabe, siehe S.#topage("zeit")# und S.#topage("inp")#) werden von
+EUMEL-0 behandelt. Die entsprechenden Interrupts muß SHard per 'call' an 0-Routinen
+weiterleiten. Außerhalb des Moduls SHard wird der 'reti'-Befehl nicht verwendet, damit der
+SHard die Kontrolle über die Interruptlevel behält. Die Register (bis auf die Eingangsparame­
+ter) werden von den aufzurufenden 0-Routinen selbst gesichert. Die normale Interrupt-
+Sequenz im SHard sieht dann folgendermaßen aus:
+
+ intadr: push af
+ ld a,<parameter>
+ call <routine>
+ pop af
+ reti
+
+Achtung: SHard muß die Interrupt-Routinen im 'disable-int'-Modus anspringen. Dies ist
+ normalerweise schon durch die Hardware gegeben.
+
+Die 0-Routinen geben von sich aus den 'ei'-Befehl. Dies erfolgt im allgemeinen sehr
+frühzeitig (innerhalb der ersten 30 Befehle), um einen interruptgetriebenen Floppytreiber
+zulassen zu können.
+
+
+
+
+#bb("1. System ","laden")#
+#goalpage("laden")#
+
+SHard muß die EUMEL-0-Software vor dem eigentlichen Start laden. EUMEL-0 befindet
+sich normalerweise auf dem Hintergrund. Es müssen von Block 10 an eumel-0-blocks
+(siehe 0-Leiste) Blöcke in den Speicher von der Adresse 1400h an aufsteigend geladen
+werden.
+
+ Achtung: Zu diesem Zeitpunkt kann SHard die oben aufgeführten 0-Routinen natür­
+ lich noch nicht benutzen. Insbesondere dürfen die Laderoutinen nicht 'warte'
+ aufrufen. Das wird hier besonders betont, weil der Hintergrundzugriff beim
+ eigentlichen Systemlauf in der Regel 'warte' verwenden wird.
+
+ Hinweis: Der erste Block der EUMEL-0-Software (Block 10) enthält in den ersten
+ fünf Bytes den Text "EUMEL", um eine Identifikation durch den SHard-
+ Lader zu ermöglichen.
+
+Es wird empfohlen, nach folgendem Verfahren zu laden:
+
+ IF archivgeraet enthaelt diskette AND eumel 0 auf archiv
+ THEN lade eumel 0 vom archiv
+ ELIF eumel 0 auf hintergrund
+ THEN lade eumel 0 vom hintergrund
+ ELSE laden unmoeglich
+ FI .
+
+So kann man auch bei einem frisch formatierten Hintergrundmedium einen neuen Hinter­
+grund (mit EUMEL-0-Urlader) einspielen, indem man ein Hintergrundarchiv vor dem
+Systemstart in das Archivgerät legt. Dann wird EUMEL-0 von dort geladen, so daß man den
+Hintergrund dann wie im Systemhandbuch beschrieben vom Archiv auf das Hintergrund­
+medium kopieren kann.*)
+#foot#
+#f#*) Kopiervorgänge (Archiv -> Hintergrund) werden vom EUMEL-0-Urlader erledigt, so daß SHard keine derartigen
+Routinen enthalten muß.#a#
+#end#
+
+
+
+#bb("2. System","start und -ende")#
+#goalpage("start")#
+
+SHard muß alle für den Rechner notwendigen (Hardware-) Initialisierungen durchführen und
+erst danach die EUMEL-0-Maschine starten ('systemstart').
+
+ #dx("systemstart")# (0-Routine)
+
+ Eingang: HL = Adresse der SHard-Leiste
+ Interrupts disabled
+
+ Aufruf: jp systemstart
+
+ Zweck: Die EUMEL-0-Maschine wird gestartet. Alle notwendigen
+ Hardwareinitialisierungen (Interrupt Modus des Z80 und Ini­
+ tialisierungen der Peripheriebausteine) müssen vorher schon
+ geschehen sein.
+
+ Hinweis: Der Stackpointer braucht nicht definiert zu sein, da beim
+ Ansprung DI-Zustand herrschen sollte und somit keine
+ Interrupts auftreten können. EUMEL-0 lädt beim Start das
+ SP-Register und läßt Interrupts zu (EI). Falls jedoch in dieser
+ Zeit ein "Non Maskable Interrupt" auftreten kann, muß SHard
+ SP "vorläufig" laden.
+
+ MODE: Über das MODE-Wort in der SHard-Leiste können Op­
+ tionen gesetzt werden:
+
+ Bit 0 = 0 EUMEL-0 ist auf dem Hintergrund abge­
+ speichert. Der entsprechende Bereich bleibt
+ geschützt. (Standard)
+
+ Bit 0 = 1 EUMEL-0 befindet sich nicht auf dem Hin­
+ tergrund. Der entsprechende Bereich steht
+ zur freien Verfügung für andere EUMEL-
+ Daten.
+ (Da die EUMEL-0-Software nur beim
+ Systemstart geladen wird (read only!), kann
+ es bei Geräten mit kleinem Hintergrund
+ interessant sein, diese Blöcke auf dem
+ Hintergrund anderweitig zu nutzen. Das
+ Systemladen kann dann z.B. mit Hilfe einer
+ speziellen Urladediskette vom Archivgerät
+ aus erfolgen.)
+
+ Bit 8 = 0 Beim Systemstart wird der Speicher über­
+ prüft. (Standard)
+
+ Bit 8 = 1 Der Speichertest beim Systemstart unter­
+ bleibt. Man sollte nur bei Rechnern, die
+ beim Einschalten schon eigene Speicher­
+ tests durchführen, auf den Speichertest des
+ EUMEL verzichten.
+
+ Bit 9 = 0 Beim Systemstart wird die Vortest-Tapete
+ ausgegeben und man kann durch Eingabe
+ eines Zeichens die Vortestmenüs aktivieren
+ (s. Systemhandbuch). (Standard)
+
+ Bit 9 = 1 Die Vortest-tapete wird unterdrückt. Es gibt
+ auch keine Möglichkeit, die Vortestfunk­
+ tionen aufzurufen. Der Speichertest unter­
+ bleibt ebenfalls.
+
+
+ #dx("SYSEND")#
+
+ Parameter: -
+
+ Zweck: Hiermit wird SHard das Ende eines Systemlaufs mitgeteilt.
+ Somit können evtl. notwendige Abschlußbehandlungen durch­
+ geführt werden. SHard kann mit 'ret' zu EUMEL-0 zurück­
+ kehren, muß aber nicht. Diese Routine kann z.B. dazu benutzt
+ werden, die Hardware auszuschalten oder in ein umgebendes
+ System zurückzukehren (EUMEL als Subsystem). In den
+ meisten Fällen wird die Routine leer implementiert werden,
+ d.h. nur aus 'ret' bestehen.
+
+
+#bb("3. ","Speicherverwaltung")#
+#goalpage("spver")#
+
+
+#b("Hauptspeicher")#
+#goalpage("haupt")#
+
+Der Hauptspeicher (#ib#RAM#ie#) umfaßt die direkt adressierbaren 64 K des Z80. Da die Anfangs­
+adresse des für EUMEL-0 und Paging verfügbaren Bereichs fest ist (1400h), muß SHard nur
+über die Obergrenze des verfügbaren Bereichs informieren.
+
+ #dx("LIMIT")#
+
+ Über das LIMIT-Wort in der SHard-Leiste kann sich SHard
+ noch Bereiche vor dem Speicherende (z.B. für CP/M BIOS)
+ freihalten. Auf jeden Fall muß CFFFh <= LIMIT gewährleistet
+ sein, d.h. der Bereich bis CFFFh gehört zum Pagingbereich.
+ Im Normalfall wird FFFFh geliefert werden.
+
+
+
+#b("Schattenspeicher")#
+#goalpage("schatt")#
+
+Das EUMEL-System ist in der Lage, trotz der durch die 16-Bit Adressen gegebenen Ein­
+schränkung auf 64 kB, weiteren Speicher anzuschließen. Dieser wird Schattenspeicher
+genannt.
+
+Der Schattenspeicher (#ib#RAM#ie#) sollte so angeschlossen sein, daß über ein nicht zu großes #ib##on("italic")#
+Fenster#ie##off("italic")# des normalen Adressraumes ( < 4 kB) auf diesen zugegriffen werden kann. Welcher
+Bereich des Schattenspeichers dabei gemeint ist, wird durch die SHard-Routine SCHACC
+mitgeteilt (s.u.). Diese Art des Zugriffs wird Fenstermodus genannt. Das Restsystem nutzt das
+Fenster echt (d.h. ohne den Inhalt in andere Bereiche des normalen Adressraumes zu trans­
+portieren).
+
+Ist ein so kleines Fenster in der Hardware nicht vorgesehen (z.B. 48 kB Bänke bzw. nur
+DMA-Zugriff), so kann auch solcher Schattenspeicher benutzt werden (Transportmodus).
+Wichtig ist dabei, daß EUMEL-0 die oben erwähnten echten Fensterzugriffe unterläßt.
+(Simulation im Transportmodus wäre erheblich zu teuer.) Daher muß EUMEL-0 wissen, in
+welchem Modus der Schattenspeicher ansprechbar ist (SCHINF).
+
+Hinweis: Wenn möglich sollte der Fenstermodus implementiert werden, da er im Multi-
+ User-Betrieb (ab ca. 3 Teilnehmern) deutliche Effizienzvorteile bietet.
+
+
+Das Schattenspeicherinterface gibt es in 2 Modi:
+
+ - Fenstermodus (Bit 2**15 von BC gesetzt bei SCHINF)
+ - Transportmodus (Bit 2**14 von BC gesetzt bei SCHINF)
+
+
+#d("Fenstermodus")#
+
+ #dx("SCHINF")# (im Fenstermodus)
+
+ Ausgang: BC 2**15 + Schattenspeichergröße (in K)
+
+ Zweck: EUMEL-0 kann so die Größe des Schattenspeichers und den
+ gewünschten Modus (hier: Fenstermodus) erfragen. Falls kein
+ Schattenspeicher vorhanden ist, muß 0 als Größe geliefert
+ werden. Das Resultat von SCHINF darf sich innerhalb eines
+ Systemlaufs nicht ändern.
+
+
+ #dx("SCHACC")# (im Fenstermodus)
+
+ Eingang: HL Nummer der 1/2K-Seite, die in das Fenster zu schal­
+ ten ist.
+ Ausgang: HL Anfangsadresse (im Normaladreßraum) des aktuellen
+ Fensters
+
+ Zweck: Dient zum Zugriff auf den Schattenspeicher über das Fen­
+ ster. Man beachte, daß mehrere Fenster möglich sind, aber
+ alle im Adreßbereich des SHards liegen müssen! Die Num­
+ mern der 1/2K-Seiten des Schattenspeichers liegen immer
+ im Bereich von 0 bis 2n-1, wobei n die von SCHINF geliefer­
+ te Größe des Schattenspeichers ist. Daraus folgt, daß
+ SCHACC nicht aufgerufen wird, falls kein Schattenspeicher
+ vorhanden ist.
+
+#d("Transportmodus")#
+
+ #dx("SCHINF")# (im Transportmodus)
+
+ Ausgang: BC 2**14 + Schattenspeichergröße (in K)
+
+ Zweck: EUMEL-0 kann so die Größe des Schattenspeichers und den
+ gewünschten Modus (hier: Transportmodus) erfragen. Falls
+ kein Schattenspeicher vorhanden ist, muß 0 als Größe gelie­
+ fert werden. Das Resultat von SCHINF darf sich innerhalb
+ eines Systemlaufs nicht ändern.
+
+
+ #dx("SCHACC")# (im Transportmodus)
+
+ Eingang: A = 1 Transport in den Schattenspeicher
+ A = 2 Transport aus dem Schattenspeicher
+ DE Nummer der 1/2K Seite im Schattenspeicher
+ HL Adresse im normalen Hauptspeicherbereich
+
+ Zweck: Es werden jeweils 512 Bytes aus dem Normal- in den
+ Schattenspeicher (A=1) bzw. aus dem Schattenspeicher in
+ den normalen Hauptspeicher (A=2) kopiert.
+ Die Nummern der 1/2K-Seiten des Schattenspeichers liegen
+ immer im Bereich von 0 bis 2n-1, wobei n die von SCHINF
+ gelieferte Größe des Schattenspeichers ist. Daraus folgt, daß
+ SCHACC nicht aufgerufen wird, falls kein Schattenspeicher
+ vorhanden ist.
+
+ Eingang: A = 3
+ E Index (immer geradzahlig: 0,2,4,...254)
+ Ausgang: BC Bereichslänge DIV 3
+ HL Bereichsadresse
+
+ Zweck: Für den angegebenen Index ist die Adresse eines Haupt­
+ speicherbereichs und 1/3 der Länge dieses Bereichs zu­
+ rückzumelden (Anzahl Einträge � 3 Bytes) Es sind also 128
+ solcher Bereiche zur Verfügung zu stellen. Bei n K Schat­
+ tenspeicher sollte jeder Bereich größer als 6*n/128 Bytes sein.
+ Alle Bereiche müssen gleich groß sein.
+
+ Beispiel: Bei bis zu 256 K sollten 16-Byte-Bereiche
+ benutzt werden:
+
+ shacc3: ld l,e
+ ld h,0
+ add hl,hl
+ add hl,hl
+ add hl,hl
+ ld bc,schtab
+ add hl,bc ; <e> DIV 2 * 16 + schtab
+ ld bc,5 ; 16 DIV 3
+ ret
+
+ schtab: defs 128*16
+
+
+
+
+#b("Blocktransfer im Speicher")#
+#goalpage("ldir")#
+
+
+
+#b("Speicherfehler")#
+#goalpage("memerr")#
+
+Falls die Hardware Speicherfehler aufgrund von Paritybits, ECC oder ähnlichem feststellen
+und an SHard melden kann, sollte das zur Erhöhung der Systemsicherheit genutzt werden.
+
+Wenn SHard (z.B. über Interrupt) einen Speicherfehler mitgeteilt bekommt, sollte er wenn
+möglich eine entsprechende Meldung ausgeben und das System brutal anhalten:
+
+ rien#ub# #ue#ne#ub# #ue#vas#ub# #ue#plus: jr rien#ub# #ue#ne#ub# #ue#vas#ub# #ue#plus
+
+
+Wenn Speicherfehler mit Sicherheit bemerkt werden, verhindert diese Reaktion, daß die
+Fehler auf dem Hintergrund festgeschrieben werden und evtl. später zu Systemfehlern führen.
+
+Der Anwender kann dann durch Hardware-Reset auf den letzten Fixpunkt des EUMEL-
+Systems zurücksetzen. So verliert er zwar evtl. die letzten Minuten seiner Arbeit, behält aber
+auf alle Fälle ein konsistentes System.
+
+
+
+
+#bb("4. ","Zeitgeber")#
+#goalpage("zeit")#
+
+SHard muß einen Zeitgeberinterrupt erzeugen, der ca. 10 bis 100 mal pro Sekunde auftritt.
+Dabei ist die 0-Routine 'timerinterrupt' aufzurufen. Ohne diesen Interrupt wird die Uhr nicht
+geführt, und die Zeitscheibenlogik für das Timesharing fällt aus.
+
+ #dx("timerinterrupt")# (0-Routine)
+
+ Eingang: A seit letztem Zeitgeberinterrupt vergangene Zeit (in ms)
+
+ Zweck: Wird von EUMEL-0 für interne Uhren und für das Schedu­
+ ling (Zeitscheibenlogik) verwendet. Es werden keine hohen
+ Genauigkeitsanforderungen an die Zeitangaben bei #on("i")#einzel­
+ nen#off("i")# Interrupts gestellt. Um EUMEL-0 eine genaue Real­
+ zeituhr zu ermöglichen, sollte die so erzeugte Zeitangabe #on("i")#im
+ Mittel#off("i")# aber möglichst genau sein, d.h. die Summe der inner­
+ halb einer Minute so übergebenen Werte sollte zwischen
+ 59995 und 60005 liegen.
+
+
+
+#bb("5. ","Kanäle")#
+#goalpage("channel")#
+
+Einiges zum Kanalkonzept:
+
+Das System kennt die Kanäle 0..32.
+
+ Kanal 0 ist der Systemhintergrund.
+ Die Kanäle 1..15 sind für Stream-IO (Terminals, Drucker, ...) vorgesehen.
+ Kanal 31 ist der Standard-Archivkanal.
+ Kanal 32 ist der Parameterkanal.
+
+Die Kanäle 2.. 30 können installationsabhängig verfügbar sein oder auch nicht. Deren Funk­
+tion ist dann Absprachesache zwischen Installation und SHard.
+
+Kanäle können über Block-IO (BLOCKOUT, BLOCKIN) oder Stream-IO (OUTPUT,..) ange­
+sprochen werden. Das System erfährt über IOCONTROL, welche Betriebsart des Kanals
+sinnvoll ist.
+
+#on("i")##on("b")#Achtung: Alle Kanaloperationen müssen grundsätzlich für alle Kanäle (0...32) aufgerufen
+ werden können. Dabei können Operationen auf nicht vorhandenen Kanälen und
+ unsinnige Operationen (z.B. Stream-IO auf Kanal 0) leer implementiert wer­
+ den.#off("b")# (Dafür werden im folgenden bei jeder SHard-Routine Vorschläge gemacht.)#off("i")#
+
+
+
+#bb("5.1 ","Stream-IO")#
+#goalpage("stream")#
+
+Über Stream-IO wickelt das System die übliche zeichenorientierte Ein-/Ausgabe auf Termi­
+nals, Druckern, Plottern usw. ab. Stream-IO wird nur für die Kanäle 1...15 gemacht.
+
+ #dx("inputinterrupt")# (0-Routine)#goalpage("inp")#
+
+ Eingang: A Kanalnummer (1...15)
+ B eingegebenes Zeichen
+ C Fehlerbits:
+ Bit 0 = 1 Mindestens ein Zeichen ging
+ verloren.
+ Bit 1 = 1 Es wurde der BREAK-Zustand
+ (bei V24) erkannt.
+ Bit 2 = 1 Das Zeichen ist u.U. falsch
+ (Paritätsfehler).
+
+ Ausgang: A Anzahl Zeichen, die noch übernommen werden kön­
+ nen.
+
+ Zweck: SHard muß EUMEL-0 durch Aufruf dieser Routine mitteilen,
+ daß eine Eingabe vorliegt.
+
+ Hinweise: EUMEL-0 puffert die Zeichen. Siehe auch IOCONTROL:
+ "weiter".
+
+ Bei Kanalnummern <1 oder >15 wird der Aufruf von
+ EUMEL-0 ignoriert.
+
+ Falls die Hardware keine Inputinterrupts zur Verfügung stellt,
+ sollte ein Timer benutzt werden, um alle möglichen Input­
+ quellen regelmäßig abzufragen. Dabei muß man allerdings den
+ goldenen Mittelweg zwischen zu häufiger (Systemdurchsatz
+ sinkt) und zu seltener Abfrage (Zeichen gehen verloren)
+ suchen. Man sollte dabei nicht nur an die menschliche Tipp­
+ geschwindigkeit sondern auch an die höchste Baudrate
+ denken, die man für Rechnerkopplungen noch unterstützen
+ will. *)
+#foot#
+#f#*) Eine weitere Möglichkeit, auf manchen Kanälen ohne Interrupts auszukommen, wird bei der IOCONTROL-Funktion
+"weiter" beschrieben (siehe S.#topage("weiter")#).#a#
+#end#
+
+ Falls SHard Flußkontrolle für den Kanal ausüben soll, muß er
+ die Rückmeldung in A auswerten. Dabei ist mit einem geeig­
+ neten Schwellwert zu arbeiten, da in der Regel die sendende
+ Gegenstelle einer Sendeunterbrechung nicht sofort Folge
+ leistet.
+
+ Achtung: #on("i")#Keinesfalls darf 'inputinterrupt' rekursiv aufgerufen werden.
+ Normalerweise wird das automatisch verhindert, wenn man
+ den zugehörigen Hardwareinterrupt erst nach der 0-Routine
+ wieder freigibt. Falls das nicht möglich ist und unter bestimm­
+ ten Umständen das nächste Zeichen abgeholt werden muß,
+ bevor die 0-Routine beendet ist, muß SHard einen eigenen
+ Puffer implementieren:#off("i")#
+
+ hardwareinterrupt:
+ IF input interrupt aktiv
+ THEN trage zeichen in shard puffer ein ;
+ gib hardware interrupt frei
+ ELSE input interrupt aktiv := true ;
+ gib hardware interrupt frei ;
+ input interrupt ;
+ disable interrupt ;
+ WHILE shard puffer enthaelt noch zeichen REP
+ nimm zeichen aus shard puffer ;
+ enable interrupt ;
+ input interrupt ;
+ disable interrupt
+ PER ;
+ input interrupt := false ;
+ enable interrupt
+ FI .
+
+
+ #d("OUTPUT")#
+
+ Eingang: A Kanalnummer (1...15)
+ BC Anzahl auszugebender Zeichen
+ HL Adresse der Zeichenkette
+ Ausgang: BC Anzahl der übernommenen Zeichen
+ C-Flag gesetzt <=> alle Zeichen übernommen
+
+ Zweck: Ausgabe einer Zeichenkette. Diese ist (möglichst ganz) zwi­
+ schenzupuffern, denn die Ausführung von OUTPUT sollte kein
+ Warten auf IO enthalten. Der Ausgabepuffer muß mindestens
+ 50, besser 100 Zeichen fassen können. Durch eine Inter­
+ ruptlogik oder etwas Äquivalentes ist sicherzustellen, daß
+ dieser Puffer parallel zur normalen Verarbeitung ausgegeben
+ wird. Wenn die auszugebende Zeichenkette nicht vollstän­
+ dig in den Puffer paßt, sollten trotzdem so viele Zeichen wie
+ möglich übernommen werden. Im weiteren Verlauf ruft
+ EUMEL-0 dann wieder OUTPUT mit dem Rest der Zei­
+ chenkette auf.
+
+ Hinweis: OUTPUT kann mit BC=0 aufgerufen werden. Auch diese
+ leere Operation muß mit gesetztem C-Flag quittiert wer­
+ den.
+
+ Achtung: #on("i")#Keinesfalls darf innerhalb von OUTPUT die 0-Routine 'warte'
+ aufgerufen werden.#off("i")#
+
+ Vorschlag: Falls der Kanal nicht existiert bzw. OUTPUT darauf unsinnig
+ ist, sollte vorgegaukelt werden, alle Zeichen seien ausge­
+ geben (BC unverändert und C-Flag gesetzt).
+
+
+
+#b("Terminals")#
+#goalpage("term")#
+
+"Normale" #ib#Terminal#ie(1,", normales")#s können ohne weitere Unterstützung des SHards angeschlossen wer­
+den. Die zur Anpassung an den EUMEL-Zeichensatz *) notwendigen #ib#Umcodierungen#ie# werden
+von den höheren Ebenen aus eingestellt. Da diese Umsetztabellen vom SHard unabhängig
+sind, stehen automatisch alle so angepaßten Terminaltypen allen EUMEL-Anwendern zur
+Verfügung!
+#foot#
+#f#*) Siehe "EUMEL Benutzerhandbuch"#a#
+#end#
+
+Für den Anschluß eines #on("b")##on("i")#integrierten #ib#Terminal#ie(1,", integriertes")#s#off("i")##off("b")#, in dessen Bildwiederholspeicher direkt gear­
+beitet wird, kann man häufig den Terminaltyp 'psi' verwenden (siehe auch "Exoten").
+
+Näheres zu Terminaltypen und -anschlüssen findet man im "EUMEL Systemhandbuch"
+unter den Stichwörtern #on("i")#Konfiguration#off("i")# und #on("i")#Konfigurierung#off("i")#.
+
+
+
+#bb("Drucker, ","Plotter")#
+#goalpage("druck")#
+
+#ib#Drucker#ie# und Plotter werden vom EUMEL-System wie Terminals angesehen. Da in der Regel
+der Rechner aber schneller Zeichen senden als der Drucker drucken kann, müssen solche
+Geräte in der Regel mit Flußkontrolle angeschlossen werden (siehe S.#topage("fluss")#).
+
+Wenn Drucker oder Plotter über eine Parallelschnittstelle angeschlossen werden, kann man
+auf diesem Kanal möglicherweise auf einen Ausgabepuffer verzichten. Voraussetzung ist
+dabei, daß
+
+ a) der Drucker einen eigenen Puffer hat und
+ b) der Puffer "schnell" gefüllt werden kann (< 0.1 ms/Zeichen).
+
+Dann kann man auf den bei der SHard-Routine OUTPUT geforderten Puffer verzichten und
+die Zeichenkette direkt über die Parallelschnittstelle an den Drucker übergeben. Wenn der
+Drucker 'Puffer voll' signalisiert, sollte die Zeichenübernahme bei OUTPUT abgebrochen
+werden. *) #on("i")#Auf keinen Fall darf CPU-intensiv auf Freiwerden des Puffers gewartet werden!#off("i")#
+#foot#
+#f#*) siehe auch IOCONTROL "frout", S.#topage("frout")##a#
+#end#
+
+
+
+#b("Exoten")#
+#goalpage("exot")#
+
+Exotische #ib#Terminal#ie(1," exotisches")#s (im Sinne dieser Beschreibung) sind solche, für die eine Umsetztabelle
+im System (siehe Konfiguratorbeschreibung) nicht ausreicht bzw. nicht nötig ist (Beispiele:
+Terminals, in deren Bildwiederholspeicher direkt gearbeitet wird; Terminals, die soweit
+programmierbar sind, daß sie den EUMEL-Zeichencode können).
+
+Für solche Terminals muß in der Konfiguration der Terminaltyp '#ib#psi#ie#' eingestellt werden. Dieser
+wirkt ohne Umcodierungen, d.h. die EUMEL-Codes (siehe Benutzerhandbuch) werden direkt
+dem SHard zugestellt (wie bei 'transparent'), jedoch mit folgenden Besonderheiten:
+
+Eingabeseitig werden zusätzlich folgende Codezuordnungen getroffen:
+
+ Code Funktion
+
+ 7 SV (Aktivierung: 'gib supervisor kommando:')
+ 17 STOP (Ausgabe auf diesen Kanal wird gestoppt)
+ 23 WEITER (Ausgabe läuft wieder weiter)
+ 4 INFO (System geht in Debugger, falls Debugoption)
+
+
+
+#bb("5.2 ","Block-IO")#
+#goalpage("block")#
+
+Über Block-IO wickelt das System die Zugriffe zum Pagingmedium und zum Archiv ab.
+Ferner ist daran gedacht, auch auf V.24-Schnittstellen Block-IO z.B. für Rechnerkopplung
+zuzulassen. Die Kanalnummer in Reg. A unterscheidet diese Fälle. Außer beim Paging (A=0)
+wird ein Block-IO durch die ELAN-Prozeduren 'blockin' und blockout' induziert.
+
+Bei Block-IO wird immer ein 512 Byte großer Hauptspeicherbereich mit übergeben. Dieser
+kann (im Gegensatz zu OUTPUT) direkt benutzt werden, d.h. es muß keine Umpufferung
+erfolgen.
+
+Dieser Hauptspeicherbereich darf nur bei BLOCKIN verändert werden.
+
+SHard darf (anders als bei OUTPUT) erst dann zur Aufrufstelle zurückgeben, wenn die
+verlangte Operation abgeschlossen ist. Treten während der Operation Wartezeiten auf, so muß
+SHard die 0-Routine 'warte' aufrufen, damit das System andere Prozesse weiterlaufen
+lassen kann.
+
+EUMEL-0 definiert bestimmte Funktionen für Hintergrund (Kanal 0) und Archiv (Kanal 31).
+Operationen auf anderen Kanälen kann SHard nach Belieben implementieren und deren
+Leistung seinen Installationen über ELAN-Pakete zur Verfügung stellen. Das System vergibt
+auch in Zukunft für den #ib##on("italic")#Funktionscode#ie##off("italic")# in Register BC nur positive Werte (Bit 7 von B = 0).
+Der SHard kann selbst negative Codes einführen.
+
+
+ #d("BLOCKIN")#
+
+ Eingang: A Kanalnummer (0...32)
+ BC Funktionscode 1
+ DE Funktionscode 2
+ HL Adresse des Hauptspeicherbereichs
+ Ausgang: A undefiniert (darf also verändert werden)
+ BC Rückmeldecode
+ HL darf verändert werden
+
+ Der Inhalt des Hauptspeicherbereichs (<HL>... <HL>
+ +511) darf verändert sein.
+
+ Zweck: "Einlesen" von Blöcken. Die genaue Wirkung hängt vom
+ Funktionscode und dem Kanal ab.
+
+ Vorschlag: Falls der Kanal nicht existiert bzw. BLOCKIN darauf unsinnig
+ ist, sollte die Rückmeldung -1 in BC geliefert werden.
+
+
+ #d("BLOCKOUT")#
+
+ Eingang: A Kanalnummer (0...32)
+ BC Funktionscode 1
+ DE Funktionscode 2
+ HL Adresse des Hauptspeicherbereichs
+ Ausgang: A undefiniert (darf also verändert werden)
+ BC Rückmeldecode
+ HL darf verändert werden
+
+ Der Inhalt des Hauptspeicherbereichs darf #on("i")#nicht#off("i")# verändert
+ werden!
+
+ Zweck: "Ausgeben" von Blöcken. Die genaue Wirkung hängt vom
+ Funktionscode und dem Kanal ab.
+
+ Vorschlag: Falls der Kanal nicht existiert bzw. BLOCKOUT darauf un­
+ sinnig ist, sollte die Rückmeldung -1 in BC geliefert wer­
+ den.
+
+
+ #dx("warte")# (0-Routine)
+
+ Ausgang: Alle Register undefiniert!
+
+ Zweck: Diese Routine ist bei 'blockin' oder 'blockout' dann aufzu­
+ rufen, wenn SHard im Augenblick nichts zu tun hat. Durch
+ den Aufruf von 'warte' erhalten andere Systemteile die
+ Möglichkeit, weiterzuarbeiten. Ein 'warte' kann bis zu ca. 1/4
+ Sekunde Zeit aufnehmen. 'warte' darf nicht in Interrupt­
+ routinen und Stream-IO verwendet werden! 'warte' zerstört
+ alle Register! SHard muß davon ausgehen, daß 'warte' sei­
+ nerseits andere SHard-Komponenten aufruft.
+
+
+Die Verwendung der 0-Routine 'warte' soll hier an einigen Beispielen verdeutlicht werden:
+
+
+ blockout auf platte :
+ WHILE platte noch nicht frei REP
+ warte
+ ENDREP ;
+ uebertrage schreibbefehl an controller ;
+ uebertrage daten an controller .
+
+ blockin von platte :
+ WHILE platte noch nicht frei REP
+ warte
+ ENDREP ;
+ uebertrage lesebefehl an controller ;
+ WHILE daten noch nicht gelesen REP
+ warte
+ ENDREP ;
+ hole daten vom controller .
+
+
+ blockout auf floppy :
+ seekbefehl an controller ;
+ WHILE seek noch nicht fertig REP
+ warte
+ ENDREP ;
+ setze dma auf schreiben block zur floppy ;
+ schreibbefehl an controller ;
+ WHILE schreiben noch nicht fertig REP
+ warte
+ ENDREP .
+
+ blockin von floppy :
+ seekbefehl an controller ;
+ WHILE seek noch nicht fertig REP
+ warte
+ ENDREP ;
+ setze dma auf lesen block von floppy ;
+ lesebefehl an controller ;
+ WHILE lesen noch nicht fertig REP
+ warte
+ ENDREP .
+
+
+
+#b("Block-IO bei Hintergrund und Archiv")#
+#goalpage("bhgarch")#
+
+#ib#Hintergrund#ie# (Kanal 0) und #ib#Archiv#ie# (Kanal 31) unterscheiden sich in den Link-Bedingungen nur
+in der Kanalnummer. Die Aufrufe von BLOCKIN und BLOCKOUT werden mit folgenden
+Eingangsparametern versorgt:
+
+ #on("b")#BLOCKIN#off("b")# A 0 bzw. 31
+ B 0
+ C Blocknummer DIV 65536
+ DE Blocknummer MOD 65536
+ HL Hauptspeicheradresse
+
+ Der angegebene 512-Byte-Block ist in den Hauptspeicher
+ ab <HL> einzulesen.
+
+ #on("b")#BLOCKOUT#off("b")# A 0 bzw. 31
+ B 0
+ C Blocknummer DIV 65536
+ DE Blocknummer MOD 65536
+ HL Hauptspeicheradresse
+
+ Der Hauptspeicherbereich (<HL>...<HL>+511) ist auf den
+ angegebenen Block zu schreiben.
+
+Als Rückmeldungen sind zu liefern:#goalpage("errcod")#
+
+ 0 Operation korrekt ausgeführt.
+ 1 Manuell behebbarer Fehler (z.B. Laufwerktür offen)
+ 2 Permanenter Fehler (z.B. Daten nicht lesbar)
+ 3 Versorgungsfehler (zu hohe Blocknummer)
+
+Zusätzlich zu der Rückmeldung muß bei BC <> 0 in HL die Adresse eines Fehlerstrings
+(Längenbyte + Fehlertext) geliefert werden. *)
+#foot#
+#f#*) Diese Zusatzrückmeldung ist nur für die BLOCKIN/OUT Aufrufe auf Kanal 0/31 von Bedeutung. Sie wird nur von
+EUMEL-0 beim Paging und im Hardwaretest ausgewertet.#a#
+#end#
+
+#dx("Fehlerwiederholungen")#: Das EUMEL-System führt von sich aus Fehlerwiederho­
+ lungen beim Hintergrund- und beim Archivzugriff
+ durch. SHard sollte deshalb im Fehlerfall die Opera­
+ tion nicht selbst wiederholen, sondern einen Lese/
+ Schreibfehler zurückmelden. So werden dem
+ EUMEL-System auch Soft-Errors gemeldet. In
+ manchen Fällen soll vor einem erneuten Lese- oder
+ Schreibversuch der Arm auf Spur 0 positioniert
+ werden o.ä. Um das zu erreichen, sollte SHard diese
+ "Reparaturaktion" direkt im Anschluß an den fehler­
+ haften Versuch durchführen.
+
+#dx("Kontrollesen")#: Falls Kontrollesen (nach jedem Schreibzugriff) notwendig ist,
+ muß das allerdings vom SHard durchgeführt werden.
+ In der Regel reicht es dazu, den geschriebenen
+ Block "ohne Datentransport" zu lesen, so daß nur
+ CRC überprüft wird.
+
+Will SHard weitere Archivlaufwerke zur Verfügung stellen, so kann er dafür Kanalnummern
+(30,29..) vergeben. Auf ELAN-Ebene kann die archivierende Task durch 'continue (x)' das
+Laufwerk 'x' ansteuern.
+
+Hinweis: Das System versucht Hintergrund und Archiv parallel zu betreiben, d.h. wenn
+ SHard bei der Hintergrundbehandlung das UP 'warte' aufruft, kann 'warte' seiner­
+ seits die Archivbehandlung des SHards aufrufen. Wenn beides z.B. denselben
+ Floppykontroller benutzt, muß SHard sicherstellen, daß das gut geht (z.B. durch
+ Semaphoren).
+
+
+
+
+#bb("5.3 ","IO-Steuerung")#
+#goalpage("iocontrol")#
+
+Die IO-Steuerung erlaubt Steuerung und Zustandsabfragen der Kanäle. IO-Steuerung wird
+(außer bei Kanal 0) auch durch 'control' in ELAN induziert.
+
+Der Funktionscode in BC unterliegt denselben Konventionen wie bei Block-IO, d.h. das
+System verwendet nur positive Codes. Der SHard-Schreiber kann auch negative Codes für
+Sonderzwecke vorsehen.
+
+
+ #d("IOCONTROL")#
+
+ Eingang: A Kanalnummer (0...32)
+ BC Funktionscode 1
+ DE Funktionscode 2
+ HL Funktionscode 3
+ Ausgang: BC Rückmeldung
+ A darf verändert werden, in einigen Fällen zusätzliche
+ Rückmeldung
+ C-Flag (in einigen Fällen zusätzliche Meldung)
+
+ Zweck: abhängig von 'Funktionscode 1' (s.u.)
+
+Das System verlangt folgende Informations- und Steuerleistungen über IOCONTROL:
+
+ #d("IOCONTROL ""typ""")#
+
+ Eingang: A Kanalnummer (0...31)
+ BC 1
+ Ausgang: BC Kanaltyp
+
+ Zweck: Informiert EUMEL-0, welche IO für den angegebenen Kanal
+ sinnvoll ist. Die Rückmeldung in BC wird bitweise interpre­
+ tiert:
+
+ Bit 0 gesetzt <=> 'inputinterrupt' kann kommen.
+ Bit 1 gesetzt <=> OUTPUT ist sinnvoll.
+ Bit 2 gesetzt <=> BLOCKIN ist sinnvoll.
+ Bit 3 gesetzt <=> BLOCKOUT ist sinnvol.
+ Bit 4 gesetzt <=> IOCONTROL "format" ist sinn­
+ voll.
+
+ Hinweis: #on("i")#Trotz dieser Informationsmöglichkeit wird nicht garantiert, daß
+ nur sinnvolle Operationen für den Kanal aufgerufen werden.#off("i")#
+
+
+ #dx("IOCONTROL ""frout""")##goalpage("frout")#
+
+ Eingang: A Kanalnummer (1...15)
+ BC 2
+ Ausgang: BC Anzahl Zeichen, die nächster OUTPUT übernimmt
+ C-Flag gesetzt <=> Puffer leer
+
+ Zweck: Liefert Information über die Belegung des Puffers. Diese
+ Information wird von EUMEL-0 zum Scheduling benutzt.
+
+ Achtung: #on("i")#Wenn EUMEL-0 längere Zeit kein OUTPUT gemacht hat,
+ muß irgendwann BC > 49 gemeldet werden.#off("i")#
+
+ Hinweis: Unter Berücksichtigung des oben Gesagten darf "gelogen"
+ werden. Man kann z.B. immer 50 in BC zurückmelden, muß
+ dann aber schlechtere Nutzung der CPU bei Multi-User-
+ Systemen in Kauf nehmen.
+
+ Falls auf dem angegebenen Kanal ein Drucker mit eigenem
+ Puffer über Parallelschnittstelle angeschlossen ist (siehe
+ S.#topage("druck")#) und man auf einen SHard-internen Puffer verzichtet hat,
+ sollte bei 'Druckerpuffer voll' 0 in BC und 'NC' zurückge­
+ meldet werden. Wenn aber Zeichen übernommen werden
+ können, sollte 50 in BC und 'C-Flag gesetzt' gemeldet
+ werden.
+
+ Vorschlag: Falls der Kanal nicht existiert oder nicht für Stream-IO zur
+ Verfügung steht, sollten 200 in BC und C-Flag gesetzt
+ zurückgemeldet werden.
+
+
+
+
+ #dx("IOCONTROL ""weiter""")##goalpage("weiter")#
+
+ Eingang: A Kanalnummer (1...15)
+ BC 4
+ Ausgang: -
+
+ Zweck: Das System ruft "weiter" für den in A angegebenen Kanal
+ auf, wenn es wieder Eingabezeichen puffern kann.
+
+ Hinweis: "weiter" wird von EUMEL-0 auch immer dann aufgerufen,
+ wenn ein Prozeß auf dem angegebenen Kanal auf Eingabe
+ wartet und keine Zeichen mehr gepuffert sind. Wenn der
+ betroffene Kanal von sich aus keine Interrupts erzeugt, kann
+ SHard dies benutzen, um durch Aufruf von 'inputinterrupt' ein
+ Eingabezeichen zuzustellen.
+ #on("i")#Diese Betriebsart sollte nicht für normale Terminalkanäle
+ eingesetzt werden. Denn dann wird die SV-Taste nur an
+ EUMEL-0 zugestellt, wenn ein Prozeß auf diesem Kanal auf
+ Eingabe wartet. Somit sind in dieser Betriebsart CPU-inten­
+ sive Endlosschleifen nicht normal abbrechbar!#off("i")#
+
+
+ #d("IOCONTROL ""size""")#
+
+ Eingang: AL Kanalnummer (0...31)
+ CX 5
+ DX Schlüssel
+ Ausgang: CX Anzahl Blöcke MOD 65536
+ AL Anzahl Blöcke DIV 65536
+
+ Zweck: EUMEL-0 ruft 'size' auf, um die Anzahl Blöcke zu erfahren,
+ die ein Block-IO-Kanal verkraften kann (Größe von Hin­
+ tergrund und Archiven). Bei Archivlaufwerken, die mehrere
+ Formate bearbeiten können, dient dieser Aufruf auch zum
+ Einstellen des Formats für die folgenden blockin/blockout-
+ Operationen anhand des Schlüssels.
+
+ Schlüssel: 0 Wenn möglich 'erkennend', sonst 'standard'. Im ersten
+ Fall erkennt SHard das Format der eingelegten Disket­
+ te und stellt dieses ein.
+
+ Die weiteren Schlüssel sind stets definierend. Dabei gibt es
+ die EUMEL-Standardformate:
+
+ 1 5" 2D-40, Sektor 1..9, 512 Bytes
+ 2 5" 2D-80, Sektor 1..9, 512 Bytes
+ 3 5" HD-80, Sektor 1..15, 512 Bytes
+ 10 8" 1D-77, Sektor 0..15, 512 Bytes
+ 11 8" 2D-77, Sektor 0..15, 512 Bytes
+
+ Zusätzlich kann man sämtliche Spezialformate angeben:
+
+ 8192 * laufwerkstyp 1: 8"
+ 2: 5"
+ 3: 3"
+
+ + 4096 * seiten 0: einseitig
+ 1: doppelseitig
+
+ + 1024 * dichte 0: single
+ 1: double
+ 2: high
+
+ + 256 * spuren 0: 35
+ 1: 40
+ 2: 77
+ 3: 80
+
+ + 64 * sektorbytes 0: 128
+ 1: 256
+ 2: 512
+
+ + 32 * erster sektor 0: \#0
+ 1: \#1
+
+ + sektoren pro spur 0 ... 31
+
+ So bezeichnet '8762' das Format 8" 1S-77 Sektor 1..26 a
+ 128 Bytes.
+
+ Anmerkung: SHard sollte alle physisch möglichen EUMEL-Standard­
+ formate unterstützen. Von den Spezialformaten sollten die für
+ den Datenaustausch wichtigen Formate berücksichtigt werden.
+ Die EUMEL-Standardformate (1,2,3,10,11) sollten auch über
+ die entsprechenden analytischen Codes erreicht werden. (Z.B.
+ bezeichnen 1 und 21929 dasselbe Format.) Die Numerierung
+ der Blöcke ist in jedem Fall seitenorientiert, d.h. entsprechend
+ den Standardformaten (siehe S.#topage("arch")#).
+
+ Hinweis: Bei Archiven wird 'size' aufgerufen, nachdem der Archivträ­
+ ger eingelegt wurde. D.h. SHard hat die Gelegenheit, die
+ Größe anhand des eingelegten Archivträgers zu bestimmen
+ (z.B. ob single- oder doublesided).
+
+ Vorschlag: Diese Funktion sollte auf nicht vorhandenen und den
+ Stream-IO-Kanälen 0 liefern. Sie muß aber mindestens auf
+ Kanal 0 (Hintergrund) und Kanal 31 (Archiv) "echte" Werte
+ liefern.
+
+ Achtung: #on("i")#Ausnahmsweise darf bei dieser IOCONTROL-Funktion die
+ 0-Routine 'warte' aufgerufen werden.#off("i")#
+
+
+ #d("IOCONTROL ""format""")#
+
+ Eingang: A Kanalnummer (0...31)
+ BC 7
+ Ausgang: BC Fehlercode wie bei Archiv-BLOCKOUT (siehe S.#topage("errcod")#)
+
+ Zweck: Dient zum Formatieren eines Mediums. Diese Funktion kann
+ für jeden Kanal leer implementiert sein ('ret'). Sie sollte aber
+ "formatierend" (z.B. auf Kanal 31) arbeiten, falls auf diesem
+ Kanal die "typ"-Abfrage "Formatieren sinnvoll" liefert. Falls
+ (bei Diskettenlaufwerken) mehrere Formate möglich sind,
+ bestimmt der Schlüssel das gewünschte Format.
+
+ Schlüssel: wie bei IOCONTROL "size"
+
+ Hinweis: Falls für das Formatieren ein großer Speicherbereich benö­
+ tigt wird, sollte das Formatieren von Disketten besser in
+ einem Boot-Dialog vor dem Start von EUMEL-0 angebo­
+ ten werden. Denn sonst müßte der Pagingbereich unnötig
+ eingeschränkt werden.
+ Man kann das Formatieren einer Spur CPU-intensiv im­
+ plementieren (d.h. ohne DMA im DI-Modus), wenn man in
+ Kauf nimmt, daß alle anderen Tasks des EUMEL-Systems in
+ dieser Zeit "stehen". Dann sollte man aber nach jeder Spur
+ mehrmals die 0-Routine 'warte' aufrufen.
+
+ Achtung: #on("i")#Ausnahmsweise darf bei dieser IOCONTROL-Funktion die
+ 0-Routine 'warte' aufgerufen werden.#off("i")#
+
+
+
+#b("Konfigurierung serieller Schnittstellen")#
+#goalpage("v24")#
+
+Bei Kanälen, die hardwaremäßig auf #ib#serielle Schnittstellen#ie# (#ib#V.24#ie#) zurückgeführt werden, sind
+in der Regel die Größen
+
+ - #ib#Baudrate#ie# (..., 2400, 4800, 9600, ...)
+ - #ib#Zeichenlänge#ie# (7 Bits, 8 Bits)
+ - #ib#Parität#ie# (keine, gerade, ungerade)
+
+einstellbar. Dafür muß SHard die IOCONTROL-Funktionen "baud" und "bits" zur Verfü­
+gung stellen. Diese werden in zwei Modi benutzt:
+
+ a) #on("b")#einstellend#off("b")#
+ Läuft der aufrufende EUMEL-Prozeß auf dem privilegierten Steuerkanal (A = 32),
+ wird der als Parameter mit übergebene #on("i")#adressierte Kanal#off("i")# auf die geforderten Werte
+ eingestellt, sofern das möglich ist.
+
+ b) #on("b")#abfragend#off("b")#
+ Läuft der aufrufende EUMEL-Prozeß nicht auf Kanal 32 (A <> 32), wird lediglich
+ abgefragt, ob der #on("i")#adressierte Kanal#off("i")# auf die übergebenen Werte eingestellt werden
+ könnte.
+
+Aufgrund des zweiten Modus können die höheren EUMEL-Ebenen dem Anwender bei der
+Konfigurierung mitteilen, welche Werte sich auf dem jeweiligen Kanal einstellen lassen. Das
+nutzt z.B. das Standard-Konfigurationsprogramm aus.
+
+Hinweis: Bei einigen Kanälen (z.B. bei einem integrierten Terminal oder einer Parallel­
+ schnittstelle) sind Baudrateneinstellungen sinnlos. Bei anderen können sie nur
+ hardwaremäßig vorgenommen werden (Jumper, Dip Switches). In allen diesen
+ Fällen muß SHard bei allen Einstellungen 'unmöglich' melden. (Standardmäßig
+ wird der Anwender bei der Einstellung seiner Konfiguration dann auch nicht
+ danach gefragt.)
+
+
+ #d("IOCONTROL ""baud""")#
+
+ Eingang: A eigener Kanal (1...15 / 32)
+ BC 8
+ DE adressierter Kanal
+ HL Schlüssel
+ Ausgang: BC Rückmeldung (0 = ok, 1 = nicht möglich)
+
+ Zweck: Wird diese Routine auf dem Steuerkanal (A=32) aufgerufen,
+ wird die angegebene Baudrate für den durch Register DE
+ adressierten Kanal eingestellt, falls das möglich ist.
+ Wird diese Routine auf einem anderen Kanal als 32 aufge­
+ rufen, informiert sie den Aufrufer lediglich, ob eine derartige
+ Einstellung des adressierten Kanals möglich wäre.
+
+ Schlüssel: 1 50 Baud
+ 2 75 Baud
+ 3 110 Baud
+ 4 134.5 Baud
+ 5 150 Baud
+ 6 300 Baud
+ 7 600 Baud
+ 8 1200 Baud
+ 9 1800 Baud
+ 10 2400 Baud
+ 11 3600 Baud
+ 12 4800 Baud
+ 13 7200 Baud
+ 14 9600 Baud
+ 15 19200 Baud
+ 16 38400 Baud
+
+ Anmerkung: In der Regel werden nicht alle Baudraten vom SHard un­
+ terstützt werden. Bei V.24 Schnittstellen sollten aber min­
+ destens 2400, 4800 und 9600 Baud zur Verfügung stehen,
+ besser auch 300, 600, 1200 und 19200 Baud.
+
+ Hinweis: Falls SHard-spezifisch weitere Baudraten implementiert
+ werden sollen, darf SHard hierfür negative Schlüsselwerte
+ (Register HL) vergeben.
+
+
+ #d("IOCONTROL ""bits""")#
+
+ Eingang: A eigener Kanal (1...15 / 32)
+ BC 9
+ DE adressierter Kanal
+ HL Schlüssel
+ Ausgang: BC Rückmeldung (0 = ok, 1 = nicht möglich)
+
+ Zweck: Wird diese Routine auf dem Steuerkanal (A=32) aufgerufen,
+ wird die angegebene Zeichenlänge (Bits pro Zeichen) und
+ Parität für den durch Register DE adressierten Kanal einge­
+ stellt, falls das möglich ist.
+ Wird diese Routine auf einem anderen Kanal als 32 aufge­
+ rufen, informiert sie den Aufrufer lediglich, ob eine derartige
+ Einstellung des adressierten Kanals möglich wäre.
+
+
+ Schlüssel: stop * 32 + par * 8 + (bit - 1)
+
+ stop: 0 1 Stopbit
+ 1 1.5 Stopbits
+ 2 2 Stopbits
+
+ par: 0 keine Parität
+ 1 ungerade Parität
+ 2 gerade Parität
+
+ bit: 1...8 Bits pro Zeichen
+
+
+ Anmerkung: In der Regel werden nicht alle Kombinationen vom SHard
+ unterstützt werden. Bei V.24 Schnittstellen sollten aber
+ möglichst 1 Stopbit, 7 und 8 Bits pro Zeichen und alle drei
+ Paritätseinstellungen zur Verfügung stehen.
+
+ Hinweis: Falls SHard-spezifisch weitere Einstellungen implementiert
+ werden sollen, darf SHard hierfür negative Schlüsselwerte
+ (Register HL) vergeben.
+
+
+
+
+#b("Flußkontrolle")#
+#goalpage("fluss")#
+
+Die stromorientierten Kanäle (1...15) werden nicht nur zum Anschluß schneller Geräte (wie
+Terminals) verwendet, sondern auch, um langsame Geräte (wie Drucker) anzuschließen, die
+die Daten u.U. nicht so schnell übernehmen können, wie sie der Rechner schickt. Dabei ist
+auf eine geeignete Flußkontrolle zu achten (nicht schneller senden, als der Andere emp­
+fangen kann). Dieses Problem stellt sich auch bei einer Rechner-Rechner-Kopplung. Hier
+ist in der Regel sogar zweiseitige Flußkontrolle notwendig.
+
+Als Flußkontrolle ist die #ib#REQUEST TO SEND/CLEAR TO SEND#ie# Logik der V.24-Schnitt­
+stelle oder das #ib#XON/XOFF#ie#-Protokoll zu verwenden. Das letztere kann auch bei Parallel­
+schnittstellen eingesetzt werden.
+
+Zur eingabeseitigen Flußkontrollsteuerung kann SHard die Rückmeldung der 0-Routine
+'inputinterrupt' (siehe S.#topage("inp")#) und die IOCONTROL-Funktion "weiter" (siehe S.#topage("weiter")#) verwen­
+den:
+
+Unterschreitet die Rückmeldung einen von SHard zu bestimmenden Schwellwert, muß SHard
+auf der V.24-Schnittstelle das Signal 'REQUEST TO SEND' wegnehmen bzw. XOFF senden.
+Dadurch wird bei den meisten Fremdrechnern ein weiteres Senden unterbrochen, sofern (im
+ersten Fall) das Signal 'REQUEST TO SEND' dort mit dem V.24-Eingang 'CLEAR TO
+SEND' verbunden ist. Wird von EUMEL-0 "weiter" aufgerufen, so kann auf dem enspre­
+chenden Kanal wieder empfangen werden (RTS setzen bzw. XON senden).
+
+Für die ausgabeseitige Flußkontrolle muß rechnerseitig ebenfalls das Signal 'CLEAR TO
+SEND' bzw. der Empfang von XOFF/XON berücksichtigt werden. Wenn an der Schnittstelle
+das 'CLEAR TO SEND' weggenommen wird, darf SHard keinen weiteren Output auf dieser
+Schnittstelle machen, bis 'CLEAR TO SEND' wieder anliegt. Entsprechend muß der Empfang
+von XOFF die Ausagbe anhalten und XON sie wieder starten.
+
+Bemerkung: Die meisten Systeme enthalten die CTS-Funktion schon in ihrer Hardware,
+ so daß im SHard dafür keine Vorkehrungen getroffen werden müssen.
+
+
+Zur Einstellung der gewünschten Flußkontrolle eines Kanals dient die IOCONTROL-Funk­
+tion "flow". Ähnlich wie "baud" und "bits" wirkt auch "flow" nur auf Kanal 32 #on("i")#einstellend#off("i")#
+und auf allen anderen Kanälen lediglich #on("i")#abfragend#off("i")#.
+
+
+ #d("IOCONTROL ""flow""")#
+
+ Eingang: A eigener Kanal (1...15 / 32)
+ BC 6
+ DE adressierter Kanal
+ HL Modus
+ Ausgang: BC Rückmeldung (0 = ok, 1 = nicht möglich)
+
+ Zweck: Wird diese Routine auf dem Steuerkanal (A=32) aufgeru­
+ fen, muß sie den gewünschten Flußkontrollmodus für den
+ adressierten Kanal einstellen.
+ Dabei sind folgende Modi festgelegt:
+
+ HL= 0 Keine Flußkontrolle
+ HL= 1 XON/XOFF (in beide Richtungen)
+ HL= 2 RTS/CTS (in beide Richtungen)
+ HL= 5 XON/XOFF (nur ausgabeseitig)
+ HL= 6 RTS/CTS (nur ausgabeseitig)
+ HL= 9 XON/XOFF (nur eingabesetig)
+ HL=10 RTS/CTS (nur eingabeseitig)
+
+ Wenn keine Flußkontrolle gewünscht wird (HL=0), muß SHard
+ "weiter" ignorieren; bei HL=1 oder HL=9 muß bei "stop"
+ XOFF und bei "weiter", sofern zuletzt XOFF geschickt wurde,
+ XON geschickt werden; bei HL=2 oder HL=10 muß bei
+ "stop" das Signal RTS auf low und bei "weiter" wieder auf
+ high gesetzt werden. Mit "stop" ist hierbei das Unterschreiten
+ des Schwellwertes bei der Rückmeldung von "inputinterrupt"
+ gemeint.
+ Bei HL=1 oder HL=5 müssen empfangene XON/XOFF-Zei­
+ chen, bei HL=2 oder HL=6 das Signal CTS beachtet wer­
+ den.
+
+ Wird diese Routine auf einem anderen Kanal als 32 aufge­
+ rufen, informiert sie den Aufrufer lediglich, ob der geforderte
+ Flußkontrollmodus auf dem adressierten Kanal einstellbar
+ wäre.
+
+ Hinweis: Falls SHard-spezifisch weitere Flußkontrollmodi implemen­
+ tiert werden sollen, darf SHard hierfür negative Moduswerte
+ (Register HL) vergeben.
+
+ "weiter" wird von EUMEL-0 sehr oft aufgerufen. Es ist daher
+ nicht sinnvoll, jedesmal XON zu senden, da dies die Gegen­
+ stelle damit überfluten würde. SHard muß sich merken, ob der
+ Kanal im XOFF-Zustand ist und nur dann bei "weiter" ein
+ XON senden.
+
+#b("Kalender")#
+#goalpage("kalender")#
+
+Die Datums- und Uhrzeitabfrage ist bei Rechnern mit eingebauter Uhr unnötig. EUMEL holt
+sich Datum und Uhrzeit dann von SHard.
+
+ #d("IOCONTROL ""calendar""")#
+
+ Eingang: CX 10
+ DX (1=Minute, 2=Stunde, 3=Tag, 4=Monat, 5=Jahr)
+ gewünscht
+ Ausgang: CX Rückmeldung
+
+ Zweck: Erfragen von Datum und Uhrzeit. Falls keine Uhr vorhanden
+ ist, muß bei jedem Aufruf -1 zurückgemeldet werden, bei
+ eingebauter Uhr jeweils das Gewünschte (Minute: 0..59,
+ Stunde: 0..23, Tag: 1..7, Monat: 1..12, Jahr: 0..99). Die Rück­
+ meldung muß als BCD-Zahl erfolgen.
+
+ Hinweis: Die Uhr darf zwischen zwei Aufrufen umspringen. Die daraus
+ resultierende Probleme werden auf höheren Ebenen abgehan­
+ delt.
+
+
+
+
+#bb("6. SHard-","Interface Version")#
+#goalpage("shdver")#
+
+Die #ib#Versionsnummer#ie# der Interface-Spezifikation, auf der SHard aufbaut, muß als 1-Byte-
+Konstante #ib#SHDVER#ie# in der SHard-Leiste stehen. Für das hier beschriebene Interface muß sie
+den Wert 8 haben.
+
+So sind spätere Erweiterungen des SHard-Interfaces möglich, ohne daß alle SHard-
+Moduln geändert werden müssen.
+
+
+
+#bb("7. ","ID-Konstanten")#
+#goalpage("ID")#
+
+SHard muß direkt hinter SHDVER vier 2-Byte-Konstanten ablegen. Diese können von den
+höheren Ebenen durch die ELAN-Prozedur
+
+ INT PROC #ib#id#ie# (INT CONST no)
+
+abgefragt werden. Dabei werden id(0) bis id(3) von EUMEL-0 geliefert, während SHard in der
+Leiste die Werte für id(4) bis id(7) zur Verfügung stellen muß:
+
+ ID4 #ib#Lizenznummer#ie# des SHards *)
+#foot#
+#f#*) Dieser Wert muß mit der Nummer des Lizenzvertrags zwischen Implementierer und GMD übereinstimmen!#a#
+#end#
+
+ ID5 #ib#Installationsnummer#ie# des EUMEL-Anwenders **)
+#foot#
+#f#**) Diese Nummer vergibt der Lizenznehmer an die von ihm belieferten Anwender.#a#
+#end#
+
+ ID6 zur freien Verfügung
+
+ ID7 zur freien Verfügung
+
+
+
+
+#bb("8. ","Zusätzliche Leistungen")#
+#goalpage("shdelan")#
+
+Will der SHard-Implementierer zusätzliche Leistungen anbieten, die mit den Standardopera­
+tionen nicht möglich sind, kann er weitere Codes für BLOCKIN, BLOCKOUT und
+IOCONTROL zur Verfügung stellen. Um Überdeckungen mit Codes zu vermeiden, die von
+EUMEL-0 intern verwendet oder erst später eingeführt werden, darf SHard für zusätzliche
+Leistungen nur negative Werte als 'Funktionscode 1' verwenden.
+
+
+Zum Ansprechen der neuen Leistungen stehen die ELAN-Prozeduren #on("i")#'#ib#blockout#ie#', '#ib#blockin#ie#'#off("i")#
+und #on("i")#'#ib#control#ie#'#off("i")# zur Verfügung.
+
+Ferner steht dem SHard ein Parameterkanal (32) zur Verfügung. Funktionen, die (im Multi-
+User) nicht jeder Task zur Verfügung stehen dürfen, müssen über diesen Kanal 32 abge­
+wickelt werden und dürfen nur dort wirken.
+
+
+ PROC blockout (ROW 256 INT CONST para, (* --> HL *)
+ INT CONST funktion1, (* --> BC *)
+ funktion2, (* --> DE *)
+ INT VAR antwort) (* <-- BC *)
+
+ PROC blockin (ROW 256 INT VAR para, (* --> HL *)
+ INT CONST funktion1, (* --> BC *)
+ funktion2, (* --> DE *)
+ INT VAR antwort) (* <-- BC *)
+
+ PROC control (INT CONST funktion1, (* --> BC *)
+ funktion2, (* --> DE *)
+ funktion3, (* --> HL *)
+ INT VAR antwort) (* <-- BC *)
+
+Hinweis: Der SHard darf für 'funktion 1' (BC) zusätzlich zu den hier beschriebenen Stan­
+ dardcodes nur negative Codes vereinbaren.
+
+
+Beispiel:
+
+ Gibt eine Task, die durch 'continue (x)' an Kanal 'x' hängt, den Befehl
+
+ control (-7,1200,13,antwort),
+
+ so wird IOCONTROL mit (A='x', BC=-7, HL=13, DE=1200) aufgerufen. Verläßt
+ SHard 'control' mit BC = 1, so enthält 'antwort' anschließend eine 1.
+
+
+Hinweis: Um die zusätzlichen Leistungen dem Anwender einfach (und abgesichert) zur
+ Verfügung zu stellen, sollte man sie in ein ELAN-Paket einbetten und dieses
+ ebenfalls an die Anwender ausliefern.
+
+ Beispiel: PACKET zusatz DEFINES fanfare, ... :
+
+ PROC fanfare (INT CONST tonhoehe, dauer) :
+
+ IF dauer < 0
+ THEN errorstop ("negative dauer")
+ ELIF tonhoehe < 16
+ THEN errorstop ("infraschall")
+ ELIF tonhoehe > 20000
+ THEN errorstop ("ultraschall")
+ ELSE control (-37, 20000 DIV tonhoehe, dauer)
+ FI
+
+ ENDPROC fanfare ;
+
+ . . .
+
+
+
+
+#bb("9. ","Spezialroutinen")#
+#goalpage("ke")#
+
+Als Testhilfe und zur Fehlerdiagnose kann SHard in seine Routinen Kontrollereignisse einbau­
+en. Das geschieht durch Aufruf der 0-Routine 'info'. Dieser EUMEL-Debugger wird im
+Anhang A (siehe S.#topage("info")#) beschreiben.
+
+ #dx("info")# (0-Routine)
+
+ Aufruf: call info
+ jr weiter
+ defm ' text'
+ weiter:
+
+ Zweck: Info wird aufgerufen. Dabei wird 'text' zur Identifikation des
+ Kontrollereignisses ausgegeben. #on("i")#Der übergebene Text muß
+ mit einem Blank beginnen!#off("i")#
+
+ Hinweis: Bei Systemen "ohne Info" (nur solche dürfen an Anwender
+ ausgeliefert werden) wird nur der Info-Text ausgegeben und
+ EUMEL-0 angehalten.
+
+ Achtung: Da der Info selbst die hier beschriebenen Stream-IO-Rou­
+ tinen benutzt, darf man ihn von diesen Routinen aus (input­
+ interrupt, OUTPUT, IOCONTROL "frout", IOCONTROL
+ "weiter") nicht aufrufen. Wenn die Ein-/Ausgabe auf Termi­
+ nal 1 interruptgetrieben läuft, dürfen die Interrupts beim
+ Info-Aufruf natürlich nicht gesperrt sein.
+
+
+Falls SHard für bestimmte Aktionen, die selten durchgeführt werden (z.B. Formatieren), viel
+Speicher benötigt, kann er diesen dynamisch anfordern und später wieder freigeben.
+
+ #dx("grab")# (0-Routine)
+
+ Eingang: HL Anfangsadresse des zu reservierenden Bereichs im
+ Datensegment von EUMEL-0, muß auf 512 Byte
+ ausgerichtet sein.
+ BC Länge des zu reservierenden Bereichs in 512-Byte-
+ Kacheln
+ Ausgang: BC Rückmeldecode
+
+ Zweck: Wenn möglich wird der zu verlangte Bereich von EUMEL-0
+ "leergekämpft" und SHard zur Verfügung gestellt.
+ Rückmeldecode: 0 ok, Speicher steht zur Verfügung
+ 1 augenblicklich nicht möglich
+ 3 grundsätzlich nicht möglich
+
+ Achtung: Der Aufruf von 'grab' wird in der Regel 'warte' und Block-IO
+ auf Kanal 0 induzieren.
+
+ Hinweis: Es wird empfohlen, Speicher ab A000h anzufordern, da diese
+ Adresse stets im frei einplanbaren Paging-Bereich liegt.
+
+
+ #dx("free")# (0-Routine)
+
+ Eingang: HL Anfangsadresse des freizugebenden Bereichs im
+ Datensegment von EUMEL-0, muß auf 512 Byte
+ ausgerichtet sein.
+ BC Länge des zu freizugebenden Bereichs in 512-Byte-
+ Kacheln
+
+ Zweck: Der entsprechende Bereich muß vorher mit 'grab' beschafft
+ worden sein. Hiermit wird er wieder EUMEL-0 zur freien
+ Verfügung gestellt.
+
+
+Für spezielle Fehlersituationen steht die 0-Routine 'shutup' zur Verfügung. Damit kann
+SHard z.B. bei Netzausfall ein kontrolliertes Systemende erzwingen. Das ist allerdings nur
+sinnvoll, wenn durch Batteriepufferung oder Ähnliches sichergestellt ist, daß noch genügend
+Zeit bleibt, um alle Seiten auf den Hintergrund zurückzuschreiben.
+
+ #dx("shutup")# (0-Routine)
+
+ Zweck: Erzwingt Rückschreiben aller Seiten und Systemende, d.h.
+ entspricht der ELAN-Prozedur 'shutup'.
+
+ Achtung: Der Aufruf von 'shutup' wird in der Regel 'warte' und Block-
+ IO auf Kanal 0 induzieren.
+#page#
+#cc("Teil 4: ","Tips zur Portierung")#
+#goalpage("tips")#
+
+
+#b("0-Version des SHards")#
+#goalpage("0ver")#
+
+
+Es wird empfohlen, zuerst eine "0-Version" des SHard zu entwickeln, die möglichst einfach
+aufgebaut und nicht auf Effizienz und vollständige Ausnutzung der Betriebsmittel ausge­
+richtet sein sollte. Damit kann man rasch praktische Erfahrung gewinnen, die dann den
+Entwurf und die Implementation des eigentlichen SHard erleichtert. Die 0-Version sollte
+
+ - keinen Schattenspeicher kennen (SCHINF meldet 0),
+
+ - nur die Kanäle 0 (Hintergrund), 1 (Terminal) und 31 (Archiv) behandeln,
+
+ - keine Baudraten-, Zeichenlängen-, Paritäts- und Flußkontrolleinstellungen unter­
+ stützen (immer 'nicht möglich' melden),
+
+ - vorhandene (ROM-) Routinen möglichst nutzen, ohne sich um Unschönes wie
+ "busy wait" beim Floppy- bzw. Plattenzugriff zu grämen.
+
+Mit dieser 0-Version sollte man dann versuchen, EUMEL zu starten. Da der Hintergrund
+beim ersten Mal noch leer ist, muß man das HG-Archiv (Archivfloppy mit EUMEL-0 und
+höheren Ebenen) in das Archivlaufwerk einlegen und von dort laden. Der Vortest sollte sich
+direkt nach dem Start folgendermaßen auf Terminal 1 melden:
+
+ E U M E L - Vortest
+
+ Terminals: 1,
+ RAM-Groesse (gesamt): 64 kB
+ Pufferbereich: ? kB
+ Hintergrund-Speicher: ? kB
+
+ Speichertest: ************
+
+Man sollte während der ****-Ausgabe des Speichertests irgendein Zeichen eingeben. Das
+EUMEL-System muß dann in das ausführliche Start-Menü überwechseln. (Andernfalls
+funktioniert die Eingabe nicht richtig!)
+
+Als nächstes sollte man versuchen, den Hintergrund vom Archiv aus zu laden. (Diese Mög­
+lichkeit wird im Start-Menü angeboten.) Nach dem Ende dieser Operation wird der
+EUMEL-Lauf automatisch beendet. Jetzt kann man das HG-Archiv aus dem Archivlauf­
+werk entfernen und das System neu starten. Dann sollte EUMEL-0 vom Hintergrund geladen
+werden.
+
+Bei Problemen kann der "Info" (siehe S.#topage("info")#) hilfreich sein. Voraussetzung für seine Ver­
+wendung ist aber, daß die Terminal Ein-/Ausgabe schon funktioniert.
+
+Beim Start des EUMEL-Systems kann (wie im Systemhandbuch beschrieben) durch den
+Konfigurationsdialog der Terminaltyp von Kanal 1 eingestellt werden. Falls das verwendete
+Terminal in dieser Liste nicht aufgeführt wird und auch keinem der aufgeführten (in Bezug auf
+die Steuercodes) gleicht, kann man z.B.
+
+ - den neuen Terminaltyp an einem anderen EUMEL-Rechner verfügbar machen
+ (Umsetztabellen definieren) und per Archiv zum neuen Rechner tragen,
+
+ - die notwendigen Umcodierungen per SHard durchführen.
+
+Diese Problematik entsteht bei Rechnern mit integriertem Terminal in der Regel nicht, weil
+Steuerzeichen dort sowieso algorithmisch interpretiert werden müssen. In diesem Fall wird
+man direkt die EUMEL-Codes als Grundlage wählen, so daß keine Umsetzungen erfor­
+derlich sind.
+
+Bei einer provisorischen Anpassung kann man auf Invers-Video ohne weiteres verzichten.
+
+
+Im Gegensatz zu der 0-Version sollte man bei der eigentlichen SHard-Implementierung
+darauf achten, die Möglichkeiten der Hardware effizient zu nutzen. Der Testverlauf entspricht
+dann wieder im wesentlichen dem oben beschriebenen Vorgang.
+
+
+
+#b("Typische Fehler")#
+#goalpage("fehler")#
+
+
+ a) SHard-Routinen zerstören Registerinhalte bzw. sichern sie beim Interrupt nicht
+ vollständig. Hierbei sollte man auch an den zweiten Registersatz des Z80-Pro­
+ zessors und an die Register IX und IY denken.
+
+ b) 'call' bzw. 'ret' verändern den Stackpointer.
+
+ c) Fehler bei der Interruptbehandlung führen zu Blockaden ("hängende Interrupts").
+
+ d) Cursorpositionierung außerhalb des Bildschirms bei einem internen Terminal
+ (Bildwiederholspeicher im Rechner) wird nicht abgefangen. Das führt dann zu
+ wildem Schreiben in den Hauptspeicher.
+
+ e) 'warte' wird unerlaubt aufgerufen. ('warte' darf nur von BLOCKIN, BLOCKOUT,
+ IOCONTROL "size" und IOCONTROL "format" aus aufgerufen werden. Ferner
+ kann man 'warte' noch nicht beim Systemladen aufrufen!)
+
+ f) OUTPUT-Verhaspler oder -Blockaden entstehen durch Fehlsynchronisation
+ zwischen dem Füllen des Ausgabepuffers durch die Routine OUTPUT und der
+ Interruptroutine, die den Puffer leert und ausgibt.
+
+ g) IOCONTROL "frout" meldet in gewissen Situationen nie "mindestens 50 Zei­
+ chen im Puffer frei" und "Puffer leer". Das kann schon im Vortest zu Output-
+ Blockaden führen.
+
+ h) Obwohl "frout" einen Wert größer als x meldet, nimmt "output" nicht alle x
+ Zeichen an.
+
+ i) IOCONTROL "size" meldet falsche Werte.
+
+ j) IOCONTROL verkraftet keine beliebigen (auch unsinnige) Werte.
+
+ k) BLOCKIN bzw. BLOCKOUT geben die Kontrolle an das System zurück, bevor alle
+ Daten übertragen sind. (Sofort nach der Rückgabe geht EUMEL-0 davon aus,
+ daß der Puffer frei ist und anderweitig benutzt werden kann!)
+
+ l) Einem SIO-Baustein wird nach Ausgabe des letzten Zeichens oder nach Ände­
+ rung des externen Status nicht mitgeteilt, daß keine Interrupts mehr erzeugt
+ werden sollen. (SIOs wiederholen Interrupts so lange, bis man es ihnen explizit
+ verbietet!)
+
+ m) Die Stepping-Rate eines Festplattencontrollers wird falsch eingestellt, bezie­
+ hungsweise die Platte wird nicht im 'buffered step mode' betrieben, obwohl sie
+ beschleunigend positionieren kann. Dadurch werden die Zugriffszeiten auf dem
+ Hintergrund unnötig verlangsamt. Man bedenke, daß man so einen Fehler leicht
+ übersieht, weil sich das System nicht fehlerhaft, sondern nur langsamer verhält.
+ Außerdem macht sich die Verlangsamung erst bemerkbar, wenn größere Teile des
+ Hintergrundes benutzt werden.
+
+ n) Bei schnellem Zeichenempfang treten "Dreher" auf. Das deutet meistens auf
+ einen rekursiven Aufruf der 0-Routine 'inputinterrupt' hin. Dabei überholt dann
+ das zweite Zeichen das erste.
+
+ o) Bei schnellem Zeichenempfang, speziell bei gleichzeitiger Ausgabe, gehen Einga­
+ bezeichen verloren oder werden verfälscht. In der Regel ist das auf Timingpro­
+ bleme bei der Interruptbehandlung zurückzuführen. Interrupts gehen verloren bzw.
+ die Zeichen werden nicht schnell genug abgeholt.
+
+
+#b("Effizienzprobleme")#
+#goalpage("eff")#
+
+ a) Bei #on("i")##on("b")#V.24- und Parallelschnittstellen#off("i")##off("b")# ist schlechter Durchsatz in der Regel auf
+ Fehlverhalten von "frout" zurückzuführen. Auch kostet es in Multi-User-Sy­
+ stemen sehr viel, wenn OUTPUT immer nur ein Zeichen übernimmt. (Dann läuft
+ der ganze Apparat der EUMEL-0-Maschine für jedes Zeichen wieder an.)
+
+ Besonders bei der Parallelschnittstelle achte man darauf, daß nicht durch un­
+ glückliches Timing häufig Blockaden auftreten. So kann zu kurzes 'busy wait' auf
+ Freiwerden der Parallelschnittstelle dazu führen, daß jedes zweite Zeichen
+ abgelehnt wird, so daß OUTPUT faktisch zeichenweise arbeitet. Andererseits darf
+ natürlich 'busy wait' auch nicht auf Millisekunden ausgedehnt werden.
+
+
+ b) Wenn #on("i")##on("b")#Floppies ohne DMA#off("i")##off("b")# angeschlossen werden, kann man bei Single-
+ User-Systemen ohne weiteres 'busy wait' einsetzen, um nach dem Seek-
+ Vorgang auf den Block zu warten. Im Multi-User sollte das aber wenn irgend
+ möglich umgangen werden, da eine halbe Umdrehung immerhin ca. 100 ms
+ kostet.
+ Falls nur ein Endeinterrupt nach jeder Floppyoperation zur Verfügung steht, kann
+ folgendes Verfahren günstig sein:
+
+ seek befehl an controller ;
+ warten auf endeinterrupt ;
+ lesebefehl ohne datentransport auf sektor davor ;
+ warten auf endeinterrupt ;
+ lese oder schreib befehl auf adressierten sektor ;
+ cpu intensives warten und datentransport .
+
+ Die Dummyoperation auf den Sektor vor dem adressierten dient dabei nur dazu,
+ ohne CPU-Belastung einen Zeitpunkt zu finden, wo man dem eigentlichen Sektor
+ möglichst nahe ist. Die Zeit, in der die CPU benötigt wird, sinkt damit auf ca. 25
+ ms. Die Implementation dieses Algorithmus' ist aber nicht ganz einfach, da die
+ 0-Routine 'warte' wegen der verlangten kurzen Reaktionszeiten nicht verwendet
+ werden kann. Alle 'warte auf ...' müssen also durch Interrupts realisiert werden:
+
+ setze interrupt auf lesen davor ;
+ stosse seek an ;
+ REP
+ warte
+ UNTIL komplette operation beendet ENDREP .
+
+ lesen davor :
+ setze interrupt auf eigentliche operation ;
+ stosse lesen davor an .
+
+ eigentliche operation :
+ ignoriere fehler beim datentransport ;
+ stosse lesen oder schreiben an ;
+ REP
+ REP UNTIL bereit ENDREP ;
+ uebertrage ein byte
+ UNTIL alles uebertragen ENDREP ;
+ melde komplette operation beendet .
+
+
+ c) Bei der Ansteuerung von #on("i")##on("b")#Harddisks#off("b")##off("i")# sollte man darauf achten, daß die 0-Rou­
+ tine 'warte' nicht öfter als notwendig aufgerufen wird. Sonst wird das Paging zu­
+ gunsten der CPU-intensiven Prozesse zu stark verlangsamt. Z.B. kann man bei
+ vielen Plattencontrollern auf eine eigene Seek-Phase verzichten:
+
+ beginne seek ; beginne seek und lesen ;
+ REP REP
+ warte warte
+ UNTIL fertig PER ; UNTIL fertig PER
+ beginne lesen ;
+ REP
+ warte
+ UNTIL fertig PER
+
+ Hier braucht die linke Fassung immer mindestens ein 'warte' mehr als die rechte.
+ Bei starker CPU Belastung wird sie deshalb bis zu 100 ms länger für das Einle­
+ sen eines Blocks benötigen.
+
+ Eine ähnliche Situation kann auftreten, wenn die Platte in 256-Byte-Sektoren
+ unterteilt ist, so daß zu jedem EUMEL-Block zwei Sektoren gehören. Wenn
+ möglich sollte dann zwischen diesen beiden Sektoren kein 'warte' aufgerufen
+ werden. Andererseits darf natürlich auch nicht längere Zeit CPU-intensiv gewar­
+ tet werden. Evtl. lohnt es sich in solchem Fall, mit der Sektorverschränkung zu
+ experimentieren.
+
+#page#
+#cc("Anhang A: EUMEL-","Debugger ""Info""")#
+#goalpage("info")#
+
+
+Für interne Testzwecke gibt es den "Info". Systeme "mit Info" und "ohne Info" unterschei­
+den sich nur im EUMEL-0-Teil (Urlader). Der SHard-Implementierer erhält zum Test
+Hintergründe "mit Info" und zur Auslieferung solche "ohne Info". Infofähige Systeme dürfen
+nur von den SHard-Implementierern verwendet werden.
+
+ #on("i")##on("b")#Achtung: Infofähige Systeme dürfen auf keinen Fall an Anwender ausgeliefert wer­
+ den, da vermittels Info alle Systemsicherungs- und Datenschutzmaßnah­
+ men unterlaufen werden können.#off("i")##off("b")# *)
+#foot#
+#f#*) Ausnahmen von dieser Regel bedürfen der expliziten Zustimmung der EUMEL-Systemgruppe (GMD bzw. HRZ
+Bielefeld) und des jeweiligen Anwenders. Solche System müssen immer durch spezielle Schlüsselworte abgesichert werden.#a#
+#end#
+
+
+#b("Aufruf des Info")#
+#goalpage("aufrinf")#
+
+Zum Aufruf des Infos gibt es drei Möglichkeiten:
+
+ a) Beim Start des EUMEL-Systems geht man durch Eingabe eines beliebigen Zei­
+ chens während des Vortests in den ausführlichen Start-Dialog. Durch Eingabe von
+ 'I' gelangt man dann in den Info-Modus. #on("i")#(Diese Möglichkeit wird in dem Start­
+ menü nicht aufgeführt.)#off("i")#
+
+ b) Man kann den Info durch die ELAN-Prozedur 'ke' aufrufen. D.h. wenn das System
+ gestartet wurde und sich eine Task am Terminal mit "gib kommando" gemeldet
+ hat, kann man durch 'ke *return*' in den Info-Modus gelangen.
+
+ c) Wenn sich am Terminal keine Task befindet, die auf Eingabe wartet, gelangt man
+ durch die Tastenfolge 'i *info*' (*info* meist = CTL d, zur Tastendefinition siehe
+ "Systemhandbuch, Konfigurierung") in den Info-Modus.
+
+Alle diese Möglichkeiten funktionieren nur bei infofähigen Systemen.
+
+Bei schweren Systemfehlern, die eine Weitermeldung an die höheren Ebenen des EUMEL-
+Systems unmöglich machen, wird soweit möglich ebenfalls der Info aufgerufen. Bei Systemen
+"ohne Info" wird lediglich eine Meldung auf Kanal 1 ausgegeben und das System angehalten.
+
+Bevor das System Infokommandos annimmt, muß mit dem Kommando 'P' ein Paßwort einge­
+geben werden. Lediglich dieses Kommando und das Kommando 'g' werden immer angenom­
+men. Das Paßwort kann mit dem Kommando 'yP' oder mit der ELAN-Prozedur "info
+password" eingestellt werden.
+
+#b("Info-Format")#
+#goalpage("forminf")#
+
+Der Info ist bildschirmorientiert. Beim Aufruf des Infos und nach den meisten Info-Kom­
+mandos werden die drei obersten Zeilen wie folgt aufgebaut: *)
+#foot#
+#f#*) Bildschirmgetreues Verhalten kann der Info allerdings erst nach der Konfigurierung des Kanals zeigen. Vorher (d.h.
+insbesondere beim Aufruf aus dem Vortest heraus) werden Cursorpositionierungen in der Regel nicht korrekt durchgeführt.#a#
+
+#end#
+
+#limit(14.0)#
+XY TEXT
+F A C B E D L H F A C B E D L H IX SP IY PC
+xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
+#limit(12.0)#
+
+wobei
+
+ X den Miniprozeß bezeichnet, der den Übergang in den Info veranlaßt hat (A=Archiv,
+ E=Elan, L=Lader, M=Müllabfuhr),
+
+ Y den Maxiprozeß (Task) bezeichnet, der gerade durch den Elan-Prozessor bear­
+ beitet wird (Y ist code (tasknummer + code ("0"))),
+
+ TEXT den Grund für den Info-Modus anzeigt,
+
+Die zweite und dritte Zeile zeigen die Inhalte der Z80-Register an (beide Registersätze).
+In der untersten Zeile erscheint die Eingabeaufforderung 'info:'.
+
+
+#b("Info-Kommandos")#
+#goalpage("cmdinf")#
+
+Info-Kommandos können in der 'info:'-Zeile mit dem Format
+
+ [<zahl>]<buchstabe>
+
+gegeben werden oder, wenn der Cursor sich im Dump befindet, mit dem Format
+
+ <buchstabe>
+
+wobei dann für <zahl> die der Cursorposition entsprechende Dumpadresse (modulo 2**16)
+gesetzt wird (siehe '*cup*').
+
+<zahl> ist immer in Hexaform einzugeben.
+
+'g' Der Info-Modus wird wieder verlassen. Dies ist allerdings bei harten Fehlern ge­
+ sperrt.
+
+'z' Der Leitblock des angezeigten Maxiprozesses wird dargestellt, falls <zahl> = 0 ist,
+ sonst der Leitblock der Task mit der Nummer <zahl>. (Nur im ELAN-Miniprozeß).
+
+'q' Die Task mit der Nummer <zahl> wird nach dem nächsten 'g'-Kommando in den
+ Info überführt. Dies ist nötig, wenn man sich die Datenräume dieser Task anschauen
+ will ('s').
+
+'s' Dumps werden auf den Datenraum <zahl> eingestellt. Ist <zahl>=FF, so wird der
+ Realspeicher eingestellt. (s:=<zahl>)
+
+'l' Dumps werden auf die Länge <zahl> eingestellt. Desungeachtet kann man einen
+ versehentlich zu langen Dump durch eine beliebige Eingabe abbrechen. Dann wird
+ allerdings '*cup*' gesperrt (siehe unten).
+
+'p' Dumps werden auf die Byteadresse <zahl> eingestellt (p:=<zahl>; wmodus:=
+ FALSE).
+
+'w' Dumps werden auf die Wortadresse <zahl> eingestellt. Die vor jeder Dumpzeile
+ ausgegebene Adresse ist dann auch eine Wortadresse. Ein Wort = 2 Bytes. (p:=2*
+ <zahl>; wmodus:=TRUE)
+
+'k' Block <zahl> laden und per Dump anzeigen. Es erfolgt dabei eine Umstellung auf
+ den Realdatenraum (s=FF).
+
+'P' Paßworteingabe: P<text>*return*
+ Erst nach diesem Kommando sind die übrigen Kommandos ausführbar.
+
+'x' Suchen nach Bytekette:
+
+--> xc text
+--> xh xx xx ...
+--> x
+
+ Es wird nach 'text' bzw. Hexafolge 'xx xx ...' bzw. nach der durch das letzte
+ 'x'-Kommando eingestellten Bytekette gesucht.
+ Das Kommando ist durch *return* abzuschließen.
+ Die Suche beginnt ab Position 'p' und ist auf die Länge <zahl> Seiten (512 Byte-
+ Einheiten) begrenzt (0=unendlich).
+ Eine beliebige Eingabe bricht die Suche vorzeitig ab.
+
+'*return*'
+ Es wird der eingestellte Dump ausgegeben (siehe 's','l','p','w'). Bei wmodus (siehe
+ 'p', 'w') werden Wortadressen ausgegeben.
+
+'o' Wie '*return*', jedoch wird zuvor p := p+l gesetzt (zum Weiterblättern).
+
+'r' Freigabe der anderen Miniprozesse.
+
+ Zunächst werden bei Übergang in den Info alle Miniprozesse gesperrt, um eine
+ Verfälschung der Fehlersituation zu vermeiden. Bei manchen Kommandos an den Info
+ müssen aber andere Miniprozesse u.U. aktiv werden (z.B. beim 'k' der Lader). Wenn
+ dies erforderlich ist, meldet der Info:
+ 'paging erforderlich'. Man kann dann 'r' geben und das letzte Infokommando wieder­
+ holen, oder mit anderen Kommandos fortfahren, falls man den Fehlerzustand noch so
+ beibehalten will.
+
+'y' Zweitfunktion ausführen.
+
+--> 'yP<text>*return*'
+ Neues Paßwort einstellen (max. 9 Zeichen). Dieses bleibt auch nach 'shutup'
+ gültig.
+
+--> 'yt' Block <zahl> von Archiv lesen. Dient zum Test des Archivs.
+ Es wird eine Kachel freigemacht und der Block mit der Nummer <zahl>
+ eingelesen. Der Inhalt wird sofort angezeigt (wie Kommando 'k').
+
+--> 'yb' Breakpoint an die Adresse <zahl> setzen. Es wird ein Aufruf an den Info
+ abgesetzt. Nur im Realspeicher sinnvoll. Dieser Aufruf meldet sich mit
+ TEXT= 'test'. Wird er mit 'g' verlassen, so stellt Info zuvor die alten
+ Z80-Befehle wieder her und führt sie an ihrem originalen Ort aus.
+
+--> 'yc' wie 'yb', jedoch werden die originalen Z80-Befehle an einem anderen Ort
+ (im Info) ausgeführt. Sie dürfen daher z.B. keinen Relativsprung enthalten
+ und keine 'push'/'pop'-Befehle. Dafür bleibt dieser Breakpoint auch nach
+ dem zugehörigen 'g' im Code erhalten. Dieser Breakpoint meldet sich mit
+ TEXT='test 2'. 'yc' darf nicht gegeben werden, wenn der Info im 'test 2'
+ steht (Umhängen verboten).
+
+ #on("i")#Achtung: Die Verwendung von 'yb' und 'yc' ist sehr kritisch durchzuführen.
+ Zu beachten ist, daß der in den Code eingesetzte Sprung (Z80 jp)
+ 3 Byte belegt.#off("i")#
+
+
+--> 'yl' Lernmodus ein (wie beim Editor).
+
+--> 'ye' Ende Lernmodus.
+
+--> 'ya' Ausführen. Die zwischen 'yl' und 'ye' eingegebenen Zeichen werden dem
+ Info so vorgesetzt, als kämen sie von der Tastatur.
+
+ Achtung: Rekursion ('ya' im Lernmodus) wird nicht abgefangen. Das Gelern­
+ te wird nach jedem Kommando, das die ersten drei Zeilen
+ wiederaufbaut (z.B. *return*), in der Zeile vier angezeigt, wobei
+ für Steuerzeichen eine Ersatzdarstellung erscheint (%x mit
+ x=code (code (zeichen) +code ("A")), also z.B. %M für
+ *return*).
+
+--> 'y *return*'
+ Wie *return*, jedoch wird der Dump auch beim Ausführen (ya) ausgege­
+ ben. (Ein gelerntes *return* führt im Ausführmodus nicht zum Dump).
+
+'*cup*' *) (Cursor up). Umschaltung in den Modus zum Ändern in Dumps.
+#foot#
+#f#*) Falls der Kanal noch nicht konfiguriert ist, muß man natürlich eine Taste betätigen, die den EUMEL-Code für Cursor
+Up erzeugt. In der Regel ist das CTL c. Falls das Terminal ohne Konfigurierung keine Cursorpositionierungen durchführt, ist
+dieser Modus nicht sehr gut benutzbar.#a#
+#end#
+ Der Cursor fährt in den Dump und kann mit den Cursortasten dort bewegt
+ werden. Wird eine Hexazahl jetzt eingegeben, so wird diese als Inhalt des
+ Bytes eingetragen, auf dem der Cursor gerade steht. Dies funktioniert auch
+ auf beliebigen Datenräumen. Info beantragt dann bei der Speicherverwal­
+ tung einen Schreibzugriff für die entsprechende Datenraumseite, so daß
+ Änderungen mit der Copy-on-Write-Logik erfolgen, also nur taskspezi­
+ fisch sind (durch 'q' eingestellt). Für diese Task sind die Änderungen al­
+ lerdings dann permanent, da sie auch auf den Hintergrund wirken.
+
+ Hinweis: Dumpt man mit 'k' einen Block und ändert dann darin, so sind
+ diese Änderungen u.U. nur temporär, da der Info kein Rückschrei­
+ ben des Blockes veranlaßt.
+
+ Achtung: Jede Eingabe, die kein Positionierzeichen und kein gültiges
+ Zahlzeichen ist, beendet diesen Modus. Das neue Zeichen wird als
+ Info-Kommando aufgefaßt, wobei <zahl> auf die aktuelle Adres­
+ se gesetzt wird.
+ (Für 'yc' / 'yb' sinnvoll: Man setzt den Cursor auf die Stelle, an
+ der ein Break ausgelöst werden soll und gibt 'yc'/'yb').
+ Somit wird dieser Änderungsmodus üblicherweise durch *return*
+ beendet.
+
+#b("Einige Systemadressen")#
+#goalpage("sysaddr")#
+
+Der Info nützt nur wenig, wenn man nicht weiß, was man sich anschauen soll. Wesentliche
+Angaben über die Systemstruktur enthält das 'Brikett' (interne Systemdokumentation für
+Projekt Mikros der GMD). Da diese etwas allgemeiner gehalten ist, geht sie nicht auf imple­
+mentationsabhängige Konstanten ein. Diese sind hier aufgeführt.
+
+Ab 1500h liegt die 'ktab'. Sie enthält Informationen, welche Blöcke an welcher Stelle des
+Arbeitsspeicher liegen: In der Kachel mit der Adresse 512*i befindet sich der Inhalt des
+Blockes, dessen Nummer in ktab+i, ktab+100h+i steht. Ferner enthält die Tabelle, zu
+welchem Datenraum (drid) und welcher Seite des Datenraums der Inhalt gehört. (Nur rele­
+vant, wenn die Prozeßnummer <> 255 ist).
+
+Steuerbits: 2**0 : Inhalt wird gerade transportiert (zum HG oder Archiv).
+ 2**1 : Inhalt ist identisch mit Inhalt auf HG. Wird beim Schreiben auf die
+ Kachel (per Software) zurückgesetzt.
+ 2**2 : Schreiberlaubnis (siehe Brikett).
+ 2**3 : Inhalt wurde kürzlich benutzt. Solche Kacheln werden 'weniger
+ stark' verdrängt.
+
+
+ ktab frei niederwertige Blocknummer
+
+ +80h frei frei Steuerbits
+
+ +100h frei höherwertige Blocknummer
+
+ +180h frei frei Prozeßnummer
+
+ +200h frei frei drid (prozeßspezifisch)
+
+ +280h frei frei Seitennummer (höherw.)
+
+ +300h frei frei Seitennummer (niederw.)
+
+ ^ ^
+ <-- unbenutzt --> ! +-- Beginn echter Kacheln
+ +-- Beginn der Anforderungen
+
+
+Der 'Beginn echter Kacheln' hängt von der Größe der Z80-Teile ('urlader') ab (i.A.
+30h < i < 40h).
+
+'Beginn der Anforderungen' liegt bei i=1Fh. Es handelt sich um Blocknummern von zu
+ladenden Blöcken. Ist der höherwertige Teil der Blocknummer gleich FDh, so ist dies keine
+Anforderung.
+
+Blocknummern > FF00h stehen für Blöcke mit dem Inhalt 512 FFh's und werden nie auf dem
+Hintergrundmedium gespeichert.
+
+
+
+1E2Bh enthält den DR-Eintrag des drdr (siehe Brikett).
+
+
+'musta': Das System fordert Checkpoints und Müllabfuhren über die Zelle 'musta' an. Diese
+ findet man mit dem Info durch
+
+ xc musta
+
+ (hierfür ist der Text 'musta' vor der Zelle abgesetzt).
+
+ Die Zelle selbst enthält
+
+ FFh : Keine Müllabfuhr oder Checkpoint
+ 01h : Müllabfuhr
+ 02h : Checkpoint
+ 03h : beides
+ 04h : Systemendecheckpoint
+ 0Bh : System auf Archiv schreiben ('save system')
+ F0h : Müllabfuhr und Checkpoint sind geperrt (nur durch Setzen im Info
+ möglich)
+
+ Durch Einsetzen der Werte mit dem Info kann die entsprechende Operation veran­
+ laßt werden. Beim Einsetzen darf der Info nicht im 'r'-Zustand (siehe Eingabe 'r')
+ stehen; zum Ausführen der Operation muß 'r' (man bleibt im Info) oder 'g' (Info
+ verlassen) gegeben werden.
+
+
+1880h-18FFh:
+ enthält die Aktivierungstabelle. Ist (1880h+i)=01h, so ist die Task i aktiv. Hin­
+ weis: 18FFh enthält immer 01h, ohne daß dieser Zelle eine Task zugeordnet ist.
+
+
+#b("Leitblock")#
+#goalpage("pcb")#
+
+Mit dem 'z'-Kommando wird der Leitblock einer Task dargestellt. Es werden Hexapaare,
+gefolgt von einer Bezeichnung, ausgegeben. In der folgenden Beschreibung werden die
+Hexapaare durch a,b,c dargestellt.
+
+ a b c icount Der virtuelle Befehlszähler der Task steht auf (cMOD4)*
+ 10000h+b*100h+a = <ic> im Datenraum 4 dieser Task.
+ Durch die Eingabefolge:
+ 4s<ic>w*return*
+ kann man sich den Code, der ausgeführt werden soll, anse­
+ hen.
+
+ Bit 2**7 von c zeigt den Fehlerzustand an.
+ Bit 2**6 von c zeigt 'disable stop' (siehe Benutzerhandbuch)
+ an.
+ Bit 2**4 zeigt vorzeichenlose Arithmetik an (Compilierung).
+
+ a b lbas Die lokale Basis steht auf 10000h+b*100h+c = <lb> im
+ Datenraum 4 (Wortadresse).
+
+ a b hptop Der Arbeitsheap geht von 30000h (Byteadr.) bis (aMOD16)*
+ 10000h+b*100h+(aDIV16)*10h (Byteadr!).
+
+ a b channel Die Task hängt an Kanal 100h*b+a (Terminalnummer). 0 =
+ kein Terminal angekoppelt.
+
+ a b taskid Die Tasknummer der betrachteten Task ist a. (b ist die
+ Versionsnummer zum Abdichten von 'send'/ 'wait').
+
+Um den Code, auf den der 'icount' zeigt, zu interpretieren, ziehe man das Brikett zu Rate.
+
+
+Hinweis: Wenn der Info einen internen Fehler anzeigt, und auch bei 'ke', ist der durch 'z'
+ angezeigte Leitblock u.U. nicht aktualisiert. Man kann dies durch die Eingaben 'r',
+ 'g' erzwingen. (Der Info stellt wegen 'r' dem Interpreter einen Restart zu, der dann
+ beim 'g' den Leitblock aktualisiert und den Befehl erneut aufsetzt). Tritt dabei der
+ Fehler nicht wieder auf, handelte es sich um einen transienten Fehler (z.B. der
+ Codeblock war noch im Einlesen und ist jetzt voll da). So etwas kann z.B. passie­
+ ren, wenn der SHard den Abschluß einer Leseoperation zu früh meldet.
+
diff --git a/doc/porting-z80/8/source-disk b/doc/porting-z80/8/source-disk
new file mode 100644
index 0000000..ff072f3
--- /dev/null
+++ b/doc/porting-z80/8/source-disk
@@ -0,0 +1 @@
+porting/portdoc-z80-8.img