summaryrefslogtreecommitdiff
path: root/doc
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
downloadeumel-src-04e68443040c7abad84d66477e98f93bed701760.tar.gz
eumel-src-04e68443040c7abad84d66477e98f93bed701760.tar.bz2
eumel-src-04e68443040c7abad84d66477e98f93bed701760.zip
Initial import
Diffstat (limited to 'doc')
-rw-r--r--doc/porting-8086/8/doc/Port.80862483
-rw-r--r--doc/porting-8086/8/source-disk1
-rw-r--r--doc/porting-mc68k/1985.11.26/doc/Port.680002173
-rw-r--r--doc/porting-mc68k/1985.11.26/source-disk1
-rw-r--r--doc/porting-z80/8/doc/Port.Z802484
-rw-r--r--doc/porting-z80/8/source-disk1
-rw-r--r--doc/programmer-manual/1.8.7/doc/programmierhandbuch.1650
-rw-r--r--doc/programmer-manual/1.8.7/doc/programmierhandbuch.2a1845
-rw-r--r--doc/programmer-manual/1.8.7/doc/programmierhandbuch.2b1395
-rw-r--r--doc/programmer-manual/1.8.7/doc/programmierhandbuch.3728
-rw-r--r--doc/programmer-manual/1.8.7/doc/programmierhandbuch.41692
-rw-r--r--doc/programmer-manual/1.8.7/doc/programmierhandbuch.51329
-rw-r--r--doc/programmer-manual/1.8.7/doc/programmierhandbuch.5b1481
-rw-r--r--doc/programmer-manual/1.8.7/doc/programmierhandbuch.61441
-rw-r--r--doc/programmer-manual/1.8.7/doc/programmierhandbuch.index449
-rw-r--r--doc/programmer-manual/1.8.7/doc/programmierhandbuch.inhalt249
-rw-r--r--doc/programmer-manual/1.8.7/doc/programmierhandbuch.titel52
-rw-r--r--doc/programmer-manual/1.8.7/source-disk1
-rw-r--r--doc/system-manual/1.8.7/doc/systemhandbuch.11685
-rw-r--r--doc/system-manual/1.8.7/doc/systemhandbuch.21351
-rw-r--r--doc/system-manual/1.8.7/doc/systemhandbuch.31366
-rw-r--r--doc/system-manual/1.8.7/doc/systemhandbuch.41185
-rw-r--r--doc/system-manual/1.8.7/source-disk1
-rw-r--r--doc/user-manual/1.7.3-pd/doc/pd.Handbuch.Teil1924
-rw-r--r--doc/user-manual/1.7.3-pd/doc/pd.Handbuch.Teil10771
-rw-r--r--doc/user-manual/1.7.3-pd/doc/pd.Handbuch.Teil111072
-rw-r--r--doc/user-manual/1.7.3-pd/doc/pd.Handbuch.Teil12234
-rw-r--r--doc/user-manual/1.7.3-pd/doc/pd.Handbuch.Teil2628
-rw-r--r--doc/user-manual/1.7.3-pd/doc/pd.Handbuch.Teil32097
-rw-r--r--doc/user-manual/1.7.3-pd/doc/pd.Handbuch.Teil42306
-rw-r--r--doc/user-manual/1.7.3-pd/doc/pd.Handbuch.Teil5667
-rw-r--r--doc/user-manual/1.7.3-pd/doc/pd.Handbuch.Teil6a1590
-rw-r--r--doc/user-manual/1.7.3-pd/doc/pd.Handbuch.Teil6b1425
-rw-r--r--doc/user-manual/1.7.3-pd/doc/pd.Handbuch.Teil72469
-rw-r--r--doc/user-manual/1.7.3-pd/doc/pd.Handbuch.Teil81345
-rw-r--r--doc/user-manual/1.7.3-pd/doc/pd.Handbuch.Teil9936
-rw-r--r--doc/user-manual/1.7.3-pd/doc/source-disk1
-rw-r--r--doc/user-manual/1.8.7/doc/benutzerhandbuch.1580
-rw-r--r--doc/user-manual/1.8.7/doc/benutzerhandbuch.2443
-rw-r--r--doc/user-manual/1.8.7/doc/benutzerhandbuch.32019
-rw-r--r--doc/user-manual/1.8.7/doc/benutzerhandbuch.42242
-rw-r--r--doc/user-manual/1.8.7/doc/benutzerhandbuch.5a1446
-rw-r--r--doc/user-manual/1.8.7/doc/benutzerhandbuch.5b1632
-rw-r--r--doc/user-manual/1.8.7/doc/benutzerhandbuch.5c711
-rw-r--r--doc/user-manual/1.8.7/doc/benutzerhandbuch.5d211
-rw-r--r--doc/user-manual/1.8.7/doc/benutzerhandbuch.5e223
-rw-r--r--doc/user-manual/1.8.7/doc/benutzerhandbuch.6474
-rw-r--r--doc/user-manual/1.8.7/doc/benutzerhandbuch.anhang484
-rw-r--r--doc/user-manual/1.8.7/doc/source-disk1
49 files changed, 50974 insertions, 0 deletions
diff --git a/doc/porting-8086/8/doc/Port.8086 b/doc/porting-8086/8/doc/Port.8086
new file mode 100644
index 0000000..a709a2a
--- /dev/null
+++ b/doc/porting-8086/8/doc/Port.8086
@@ -0,0 +1,2483 @@
+#type ("trium6")##limit (12.)#
+#limit (30.0)#
+#type ("trium8")##limit (12.0)#
+#start(1.5,1.5)#
+#type("triumb36")#
+#free(4.0)#
+ EUMEL
+ Portierungshand­
+ buch
+ 8086 / 8088
+#type("triumb18")#
+#free(1.5)#
+ Version 8
+#page(1)#
+#type ("trium8")##limit (12.0)#
+#block#
+#pagelength(19.5)#
+#head#
+#center#- % -
+
+
+#end#
+#type("triumb12")#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 8086/8088-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")#
+ 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")#
+ Block-IO zur MS-DOS-Partition #topage("bmsdosp")#
+ 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 8086/ 8088-Prozes­
+soren.
+
+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"
+
+ "iAPX 86,88-Users Manual"
+ intel, 1981
+
+
+
+#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 8086-CPU sollte mit mindestens 2.5 MHz (8088: 4.0 MHz)
+ arbeiten. Falls die Buszugriffe durch einen CRTC o.ä. ver­
+ langsamt werden, sollte die echte 8086/ 8088-Leistung
+ durchschnittlich mindestens einem ungebremsten 2.5 MHz (4.0
+ MHz) System entsprechen.
+ Seltene Verlangsamungen (z.B. nur bei I/O-Operationen)
+ spielen bei diesen Überlegungen keine Rolle.
+
+ RAM Das System sollte über mindestens 80 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 Anfor­
+ derungen 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 komfortabel
+ 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 Cur­
+ sortasten vorhanden sein. Dabei ist es günstig, wenn die
+ Cursortasten 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 8086/
+ 8088 Bezug genommen. Bei der Portierung auf einen 8086/8088-Rechner
+ wird die 8086/8088-EUMEL-0-Maschine ohne Anpassungen (!) übernom­
+ men.
+
+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 8086/8088-
+Rechner angepaßt bzw. neu geschrieben werden muß. Deshalb besteht der größte Teil dieses
+Handbuchs aus der Spezifikation des 8086/8088-SHards.
+
+
+
+#b("Anlieferung des 8086/8088-EUMEL-Systems")#
+#goalpage("anlief")#
+
+Der Implementierer erhält die EUMEL-Software auf Disketten. Dabei stehen folgende
+Standardformate zur Wahl:
+
+ 8", 1D, 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...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 vereinfa­
+ chen, sollten möglichst alle der hardwaremäßig möglichen Standardformate (min­
+ destens 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")#
+
+Der #ib#Speicher#ie# wird EUMEL-0 vom SHard in maximal vier Speicherbereichen (M0...M3)
+zugewiesen. M0 muß immer vorhanden sein, M1, M2 und M3 nur in speziellen Betriebsarten:
+
+ #dx("M0")# #on("b")#allgemeines #ib#RAM#ie(1,", allgemeines")##off("b")#
+ Dieser Bereich muß immer vorhanden sein. Bei den meisten Rechnern liegt der
+ Urlader nicht in einem ROM, sondern wird von SHard in das RAM geladen. Das
+ geschieht dann an den Anfang von M0. Der Rest wird für Tabellen und als Pa­
+ gingbereich benutzt. M0 umfaßt deshalb meistens allen verfügbaren Speicher, bis
+ auf den Platz für SHard, Boot-ROM und Bildwiederholspeicher.
+
+ #dx("M1")# #on("b")#Urlader-#ib#ROM#ie(1,", Urlader")##off("b")#
+ Gibt es nur bei Rechnern, die den Urlader in einem ROM haben. (M0 wird dann
+ nur für Tabellen und als Pagingspeicher eingesetzt.)
+
+ #dx("M2")# #on("b")#Hintergrund-#ib#ROM#ie(1,", Hintergrund")##off("b")#
+ Gibt es nur bei Rechnern, die nicht Floppy oder Festplatte sondern ROM und
+ RAM als Hintergrundspeicher verwenden.
+
+ #dx("M3")# #on("b")#Hintergrund-#ib#RAM#ie(1,", Hintergrund")##off("b")#
+ Gibt es nur bei Rechnern, die nicht Floppy oder Festplatte sondern ROM und
+ RAM oder RAM allein als Hintergrundspeicherverwenden.
+
+Damit sind drei verschiedene Betriebsarten des EUMEL-Systems möglich:
+
+ #dx("Normalbetrieb")#: M0 (> 80 K)
+ Hintergrundgerät (Festplatte oder Floppy)
+ Archivgerät (Floppy)
+
+ Im Normalbetrieb befindet sich der Hintergrund auf einer Festplatte oder Floppy.
+ RAM wird für den Urlader und zum Paging eingesetzt. Alle mittleren und grö­
+ ßeren Systeme verwenden den Normalbetrieb.
+
+
+ #dx("Minibetrieb")#: M0 (> 80 K)
+ M3 (mindestens 300 K)
+ Archivgerät (Floppy)
+
+ Im Minibetrieb wird RAM als Hintergrundspeicher eingesetzt. Dieser wird beim
+ Einschalten über das Archivgerät geladen und beim Abschalten ('shutup') wieder
+ zurückgeschrieben.
+
+
+ #dx("ROM-Betrieb")#: M0 (> 24 K)
+ M1 (> 45 K)
+ M2 (> 170 K)
+ M3 (> 60 K)
+ Archivgerät (Kassettenrecorder oder Floppy)
+
+ Im ROM-Betrieb stehen Urlader und Standardteil des Hintergrundes im ROM.
+ Der übrige Hintergrund befindet sich im RAM.
+
+#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 implemen­
+tieren 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.
+
+8086/8088-Befehle werden wie in "iAPX 86,88 Users Manual" (intel, 1981) notiert:
+
+ mov al,27
+ add ab,bl
+
+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 M0:0 (im Normal- oder Minimodus) bzw. M1:0 (im ROM-
+Modus):
+
+ Adresse
+
+ 00h eumel0id db 'EUMEL '
+ db 10 dup (?)
+ 10h eumel0blocks dw
+ 12h hgver dw
+ 14h cputype dw 3 ; für 8086 oder kompatible CPU
+ 16h urver dw
+ 18h dw
+ 1Ah shdvermin dw
+ 1Ch shdvermax dw
+ 1E dw
+ 20h systemstart dd
+ 24h inputinterrupt dd
+ 28h timerinterrupt dd
+ 2Ch warte dd
+ 30h grab dd
+ 34h free dd
+ 38h shutup dd
+ 3Ch info dd
+
+Hinweis: Die Segmentteile der 'dd'-Addressen in dieser Link-Leiste sind natürlich unde­
+ finiert. Deshalb muß SHard diese auf M0 bzw. M1 setzen. Dazu ist es mindestens
+ beim ROM-Urlader erforderlich, die 0-Leiste in einen von SHard verwalteten
+ RAM-Bereich zu kopieren.
+
+
+Für die Gegenrichtung muß SHard der 0-Maschine die "SHard-Leiste" zur Verfügung stel­
+len:
+
+ Adresse
+
+ 00h SHDID db 'SHARD '
+ db 10 dup (?)
+ 10h SHDVER dw 8
+ 12h MODE dw
+ 14h ID4 dw
+ 16h ID5 dw
+ 18h ID6 dw
+ 1Ah ID7 dw
+ db 4 dup (?)
+ 20h OUTPUT dd
+ 24h BLOCKIN dd
+ 28h BLOCKOUT dd
+ 2Ch IOCONTROL dd
+ 30h SYSEND dd
+ db 12 dup (?)
+ 40h M0START dw
+ 42h M0SIZE dw
+ 44h M1START dw
+ 46h M1SIZE dw
+ 48h M2START dw
+ 4Ah M2SIZE dw
+ 4Ch M3START dw
+ 4Eh M3SIZE dw
+
+
+Dabei ist als 'MxSTART' eine Paragraphenadresse (d.h. Adresse DIV 16) und entsprechend
+als 'MxSIZE' die Länge des Bereichs als Bytelänge DIV 16 anzugeben.
+
+
+
+
+#b("Allgemeine Link-Bedingungen")#
+#goalpage("link")#
+
+In der Regel sind sowohl 0-Routinen als auch SHard-Routinen durch 'call' aufzurufen:
+
+ call dword ptr <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-Re­
+ gister *) - bleiben unverändert.
+#foot#
+#f#
+*) Flags sind i.a. nach dem Aufruf einer Routine undefiniert. Ausnahmen sind natürlich die Flags, die als Ausgangspara­
+meter 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.
+Das schließt auch die Segmentregister mit ein. Um SHard-eigene Daten über DS zu adres­
+sieren, muß SHard also DS sichern, neu laden und zum Schluß wiederherstellen. Entspre­
+chendes gilt für ES. SS darf nicht verändert werden.
+
+
+#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.
+Die Register (bis auf AX und F) werden von den aufzurufenden 0-Routinen selbst gesi­
+chert. Auch die Segmentregister DS und ES werden von EUMEL-0 geladen. (CS wird
+automatisch durch den "far call" gesetzt, SS darf sowieso nicht verändert werden.) Die
+normale Interrupt-Sequenz im SHard sieht dann folgendermaßen aus:
+
+ intadr: push ax
+ mov al,<parameter>
+ call dword ptr <routine>
+ ; interrupt level freigeben
+ pop ax
+ iret
+
+
+
+#bb("1. System ","laden")#
+#goalpage("laden")#
+
+SHard muß die EUMEL-0-Software vor dem eigentlichen Start an den Anfang der Spei­
+cherregion M0 laden. EUMEL-0 befindet sich normalerweise auf dem Hintergrund von Block
+10 ab. Der erste Block (10) enthält am Anfang die 0-Leiste. Dort steht an der Stelle 10h die
+Größe 'eumel0blocks'. Sie gibt an, wieviel Blöcke konsekutiv geladen werden müssen. Hat
+sie beispielsweise den Wert 80, müssen die Blöcke 10 bis 89 geladen werden.
+
+ Achtung: Zu diesem Zeitpunkt kann SHard die oben aufgeführten 0-Routinen na­
+ türlich 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 Hintergrundme­
+dium 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: DS:BX Adresse der SHard-Leiste
+ Interrupts disabled
+
+ Aufruf: jmp dword ptr systemstart
+
+ Zweck: Die EUMEL-0-Maschine wird gestartet. Alle notwendigen
+ Hardwareinitialisierungen (z.B. der Peripheriebausteine)
+ müssen vorher schon geschehen sein.
+
+ Hinweis: Der Stackpointer und die Segmentregister brauchen nicht
+ definiert zu sein, da beim Ansprung alle Interrupts maskiert
+ sein sollten und somit keine Interrupts auftreten können.
+ EUMEL-0 lädt beim Start CS, SS, SP, DS, ES und läßt In­
+ terrupts zu (STI). Falls jedoch in dieser Zeit ein "Non Maskable
+ Interrupt" auftreten kann, muß SHard SS und SP "vorläufig"
+ laden.
+
+ MODE: Über das MODE-Wort in der SHard-Leiste können Optionen
+ 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 inter­
+ essant sein, diese Blöcke auf dem Hinter­
+ grund anderweitig zu nutzen. Das Systemla­
+ den kann dann z.B. mit Hilfe einer speziellen
+ Urladediskette vom Archivgerät aus erfolgen.)
+
+ Bit 8 = 0 Beim Systemstart wird der Speicher überprüft.
+ (Standard)
+
+ Bit 8 = 1 Der Speichertest beim Systemstart unterbleibt.
+ Man sollte nur bei Rechnern, die beim Ein­
+ schalten schon eigene Speichertests durch­
+ fü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 Vortestfunktionen
+ aufzurufen. Der Speichertest unterbleibt
+ ebenfalls.
+
+
+
+ #d("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 mei­
+ sten 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 umfaßt die Teile des 8086/8088-Speichers, die EUMEL-0 verwalten
+darf, nämlich die Bereiche M0, M1, M2 und M3 (siehe S.#topage("speicher")#). M1, M2 und M3 sind dabei nur
+bei speziellen Betriebsarten nötig. Jeder der vier Bereiche wird in der SHard-Leiste durch
+die Anfagsadresse MxSTART und seine Länge MxSIZE beschrieben:
+
+ MxSTART Anfang des Bereichs als Paragraphenadresse (Byteadresse DIV
+ 16)
+ MxSIZE Größe des Bereichs in Paragraphen (Bytegröße DIV 16)
+
+Nicht vorhandenen Bereiche werden durch MxSIZE = MxSTART = 0 gekennzeichnet.
+
+
+
+
+
+#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 ne vas plus: jmp rien ne vas 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üh­
+ren.
+
+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: AL 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 in­
+ nerhalb 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,..)
+angesprochen 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 Ter­
+minals, Druckern, Plottern usw. ab. Stream-IO wird nur für die Kanäle 1...15 gemacht.
+
+ #dx("inputinterrupt")# (0-Routine)#goalpage("inp")#
+
+ Eingang: AL Kanalnummer (1...15)
+ CH eingegebenes Zeichen
+ CL Fehlerbits:
+ Bit 0 = 1 Mindestens ein Zeichen konnte auf
+ diesem Kanal nicht empfangen
+ werden (z.B. weil Interrupts gesperrt
+ waren).
+ Bit 1 = 1 Es wurde ein BREAK erkannt (bei
+ V24). Dieses Ereignis kann nicht
+ durch ein Sonderzeichen gemeldet
+ werden, da bei einer 8-bit-Über­
+ tragung schon alle Zeichen vergeben
+ sind. Daher wird BREAK hier aufge­
+ nommen, obwohl es im eigentlichen
+ Sinne kein Fehler sein muß.
+ Bit 2 = 1 Das übergebene Zeichen ist verfälscht
+ (z.B. Parität falsch).
+
+ Ausgang: AL Zahl der noch freien Bytes im Eingabepuffer von
+ EUMEL-0. Die Angabe gilt für den Puffer dieses
+ Kanals nach Eintrag des übergebenen Zeichens.
+
+ Zweck: SHard muß EUMEL-0 durch Aufruf dieser Routine mitteilen,
+ daß eine Eingabe vorliegt.
+
+ Hinweise: EUMEL-0 puffert die Zeichen. Falls 0 geliefert wird, ist der
+ Puffer voll und EUMEL-0 ignoriert weitere Eingaben, bis
+ wieder Platz im Puffer vorhanden ist. (siehe IOCONTROL
+ "weiter", S.#topage("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) such­
+ en. Man sollte dabei nicht nur an die menschliche Tippge­
+ schwindigkeit sondern auch an die höchste Baudrate denken,
+ die man für Rechnerkopplungen noch unterstützen will. *)
+
+ Falls SHard Flußkontrolle für den Kanal
+ ausüben soll, muß er die Rückmeldung in AL
+ auswerten. Dabei ist mit einem geeigneten
+ Schwellwert zu arbeiten, da in der Regel die
+ sendende Gegenstelle einer Sendeunterbrechung
+ nicht sofort Folge leistet.
+
+#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#
+
+ 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 enthält noch
+ zeichen REP
+ nimm zeichen aus shard puffer ;
+ enable interrupt ;
+ input interrupt ;
+ disable interrupt
+ PER ;
+ input interrupt := false ;
+ enable interrupt
+ FI .
+
+
+
+ #d("OUTPUT")#
+
+ Eingang: AL Kanalnummer (1...15)
+ CX Anzahl auszugebender Zeichen
+ DS:BX Adresse der Zeichenkette
+ Ausgang: CX 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 Interrupt­
+ logik oder etwas Äquivalentes ist sicherzustellen, daß dieser
+ Puffer parallel zur normalen Verarbeitung ausgegeben wird.
+ Wenn die auszugebende Zeichenkette nicht vollständig 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 Zeichenkette auf.
+
+ Hinweis: OUTPUT kann mit CX=0 aufgerufen werden. Auch diese leere
+ Operation muß mit gesetztem C-Flag quittiert werden.
+
+ 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 ausgege­
+ ben (CX 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, Teil 3: Editor, 5. Zeichencode"#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 pro­
+grammierbar 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 1.7
+Seite 106) 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 Rechnerkopp­
+lung zuzulassen. Die Kanalnummer in Reg. AL unterscheidet diese Fälle. Außer beim Paging
+(AL=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 ver­
+langte 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 Parameter in Register CX nur positive Werte (Bit 7 von CH = 0).
+Der SHard kann selbst negative Codes einführen.
+
+
+ #d("BLOCKIN")#
+
+ Eingang: AL Kanalnummer (0...32)
+ CX Parameter 1
+ DX Parameter 2
+ DS:BX Adresse des Hauptspeicherbereichs
+ Ausgang: AL undefiniert (darf also verändert werden)
+ CX Rückmeldecode
+ DS:BX darf verändert werden
+
+ Der Inhalt des Hauptspeicherbereichs (<DS:BX>... <DS:
+ BX> +511) darf verändert sein.
+
+ Zweck: "Einlesen" von Blöcken. Die genaue Wirkung hängt vom
+ Parameter und dem Kanal ab.
+
+ Vorschlag: Falls der Kanal nicht existiert bzw. BLOCKIN darauf unsinnig
+ ist, sollte die Rückmeldung -1 in CX geliefert werden.
+
+
+ #d("BLOCKOUT")#
+
+ Eingang: AL Kanalnummer (0...32)
+ CX Parameter 1
+ DX Parameter 2
+ DS:BX Adresse des Hauptspeicherbereichs
+ Ausgang: AL undefiniert (darf also verändert werden)
+ CX Rückmeldecode
+ DS:BX 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
+ Parameter und dem Kanal ab.
+
+ Vorschlag: Falls der Kanal nicht existiert bzw. BLOCKOUT darauf un­
+ sinnig ist, sollte die Rückmeldung -1 in CX 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,
+ weiter zu arbeiten. Ein 'warte' kann bis zu ca. 1/4 Sekunde
+ Zeit aufnehmen. 'warte' darf nicht in Interruptroutinen und
+ Stream-IO verwendet werden! 'warte' zerstört alle Register,
+ bis auf die Segmentregister CS und SS! SHard muß davon
+ ausgehen, daß 'warte' seinerseits andere SHard-Kompo­
+ nenten aufruft.
+
+
+Die Verwendung der 0-Routine 'warte' soll hier an einigen Beispielen verdeutlicht wer­
+den:
+
+
+ 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")# AL 0 bzw. 31
+ CH 0
+ CL Blocknummer DIV 65536
+ DX Blocknummer MOD 65536
+ DS:BX Hauptspeicheradresse
+
+ Der angegebene 512-Byte-Block ist in den Hauptspeicher
+ ab <DS:BX> einzulesen.
+
+ #on("b")#BLOCKOUT#off("b")# AL 0 bzw. 31
+ CH 0
+ CL Blocknummer DIV 65536
+ DX Blocknummer MOD 65536
+ DS:BX Hauptspeicheradresse
+
+ Der Hauptspeicherbereich (<DS:BX>... <DS:BX>+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 CX <> 0 in DS:BX 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 Fehlerwiederholungen
+ beim Hintergrund- und beim Archivzugriff durch. SHard sollte
+ deshalb im Fehlerfall die Operation 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
+ fehlerhaften 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 Datentrans­
+ port" 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' sei­
+ nerseits die Archivbehandlung des SHards aufrufen. Wenn beides z.B. denselben
+ Floppykontroller benutzt, muß SHard sicherstellen, daß das gut geht (z.B. durch
+ Semaphoren).
+
+
+Sollen auch #on("b")#Disketten nach #ib#DIN 66 239#ie##off("b")# auf dem Archivkanal gelesen und geschrieben
+werden können, müssen auf Kanal 31 zusätzlich Blöcke mit 'deleted data mark' gelesen und
+geschrieben werden können. Dafür kann BLOCKIN (beim Lesen einer Diskette) als weitere
+Rückmeldung liefern:
+
+ 4 'Deleted data mark' gelesen.
+
+Ausgabeseitig wird ein entsprechendes BLOCKOUT benötigt:
+
+ #on("b")#BLOCKOUT#off("b")# AL 31
+ CH 40h
+ CL Blocknummer DIV 65536
+ DX Blocknummer MOD 65536
+ DS:BX Hauptspeicheradresse
+
+ Der Hauptspeicherbereich (<DS:BX>... <DS:BX>+511) ist
+ mit der Kennung 'deleted data mark' auf den angegebenen
+ Block zu schreiben.
+
+Anmerkung: Diese Funktion muß nur implementiert werden, wenn Disketten nach DIN 66 239
+ beschrieben können werden sollen.
+
+
+
+#b("Block-IO zur MS-DOS-Partition")#
+#goalpage("bmsdosp")#
+
+Auf EUMEL-Rechnern, die mit einer Festplatte ausgerüstet sind, kann man einen Teil der
+Platte als MS-DOS-Partition und einen anderen als EUMEL-Partition reservieren. Für den
+Datenaustausch auf Dateiebene existiert EUMEL-Software, die über den Kanal 29 auf die
+MS-DOS-Partition zugreift. Falls SHard dieses unterstützen will, muß er entsprechende
+BLOCKIN/OUT-Operationen zur Verfügung stellen. Diese entsprechen den Operationen auf
+Kanal 0:
+
+ #on("b")#BLOCKIN#off("b")# AL 29
+ CH 0
+ CL Blocknummer DIV 65536
+ DX Blocknummer MOD 65536
+ DS:BX Hauptspeicheradresse
+
+ Der angegebene 512-Byte-Block ist in den Hauptspeicher
+ ab <DS:BX> einzulesen. Hier bezieht sich die Blocknummer
+ auf die MS-DOS-Partition. Dabei muß Block 0 derjenige
+ sein, der den Urladesektor der MS-DOS-Partition enthält.
+ (Hier steht der Bios-Parameterblock.) Die weiteren Blöcke
+ werden genauso wie in der von MS-DOS verwendeten
+ Numerierung relativ zu diesem Urladesektor adressiert.
+
+ #on("b")#BLOCKOUT#off("b")# AL 29
+ CH 0
+ CL Blocknummer DIV 65536
+ DX Blocknummer MOD 65536
+ DS:BX Hauptspeicheradresse
+
+ Der Hauptspeicherbereich (<DS:BX>... <DS:BX>+511) ist
+ auf den angegebenen Block zu schreiben. Für die Blocknu­
+ merierung gilt das oben beschreibenen.
+
+Als Rückmeldungen sind zu liefern:
+
+ 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)
+
+ Wichtig: Wird ein Block angesprochen, der nicht zur MS-DOS-Parti­
+ tion gehört, so muß 'Versorgungsfehler' (3) gemeldet werden.
+
+
+Anmerkung: Diese Funktionen müssen nur implementiert werden, wenn Datenaustausch
+ mit MS-DOS-Partitionen auf Plattenmaschinen unterstützt werden soll.
+
+
+#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 CX 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: AL Kanalnummer (0...32)
+ CX Funktionscode 1
+ DX Funktionscode 2
+ BX Funktionscode 3
+ Ausgang: CX Rückmeldung
+ AL 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: AL Kanalnummer (0...31)
+ CX 1
+ Ausgang: CX Kanaltyp
+
+ Zweck: Informiert EUMEL-0, welche IO für den angegebenen Kanal
+ sinnvoll ist. Die Rückmeldung in CX 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")#
+
+
+ #d("IOCONTROL ""frout""")#
+ #goalpage("frout")#
+
+ Eingang: AL Kanalnummer (1...15)
+ CX 2
+ Ausgang: CX 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 CX > 49 gemeldet werden.#off("i")#
+
+ Hinweis: Unter Berücksichtigung des oben Gesagten darf "gelogen"
+ werden. Man kann z.B. immer 50 in CX 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 CX und 'NC' zurückge­
+ meldet werden. Wenn aber Zeichen übernommen werden
+ können, sollte 50 in CX und 'C-Flag gesetzt' gemeldet wer­
+ den.
+
+ Vorschlag: Falls der Kanal nicht existiert oder nicht für Stream-IO zur
+ Verfügung steht, sollten 200 in CX und C-Flag gesetzt zu­
+ rückgemeldet werden.
+
+
+ #d("IOCONTROL ""weiter""")#
+ #goalpage("weiter")#
+
+ Eingang: AL Kanalnummer (1...15)
+ CX 4
+ Ausgang: -
+
+ Zweck: Das System ruft "weiter" für den in AL angegebenen Kanal
+ auf, wenn es wieder Eingabezeichen puffern kann. (siehe
+ auch: Flußkontrolle S.#topage("fluss")#)
+
+ 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 be­
+ troffene 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 Diskette
+ 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: AL Kanalnummer (0...31)
+ CX 7
+ DX Schlüssel
+ Ausgang: CX Fehlercode wie bei Archiv-BLOCKOUT (siehe S.#topage("errcod")#)
+
+ Zweck: Dient zum Formatieren einen 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"
+
+ 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 (AL = 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 (AL <> 32), wird le­
+ diglich 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: AL eigener Kanal (1...15 / 32)
+ CX 8
+ DX adressierter Kanal
+ BX Schlüssel
+ Ausgang: CX Rückmeldung (0 = ok, 1 = nicht möglich)
+
+ Zweck: Wird diese Routine auf dem Steuerkanal (AL=32) aufgeru­
+ fen, wird die angegebene Baudrate für den durch Register DX
+ 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 unter­
+ stützt werden. Bei V.24 Schnittstellen sollten aber minde­
+ stens 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 BX) vergeben.
+
+
+ #d("IOCONTROL ""bits""")#
+
+ Eingang: AL eigener Kanal (1...15 / 32)
+ CX 9
+ DX adressierter Kanal
+ BX Schlüssel
+ Ausgang: CX Rückmeldung (0 = ok, 1 = nicht möglich)
+
+ Zweck: Wird diese Routine auf dem Steuerkanal (AL=32) aufgeru­
+ fen, wird die angegebene Zeichenlänge (Bits pro Zeichen) und
+ Parität für den durch Register DX 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ög­
+ lichst 1 Stopbit, 7 und 8 Bits pro Zeichen und alle drei Pari­
+ tätseinstellungen zur Verfügung stehen.
+
+ Hinweis: Falls SHard-spezifisch weitere Einstellungen implementiert
+ werden sollen, darf SHard hierfür negative Schlüsselwerte
+ (Register BX) 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")#), die "stop" signalisieren kann, und die IOCONTROL-Funktion
+"weiter" (siehe S.#topage("weiter")#)verwenden:
+
+Allerspätestens bei der 'inputinterrupt'-Rückmeldung AL=0 muß SHard
+auf der V.24-Schnittstelle das Signal 'REQUEST TO SEND' wegnehmen bzw. XON senden
+(oder
+weiter einlaufenden Input selbst zwischenpuffern). Dadurch wird bei den meisten Fremd­
+rechnern 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 ensprechenden Kanal wieder empfangen
+werden (RTS setzen bzw. XON senden). In der Regel wird SHard schon reagieren müssen,
+bevor der EUMEL-Puffer gänzlich gefüllt ist, da die Sendehardware nicht schnell genug
+reagieren kann bzw. da noch sich noch Zeichen in Hardwarepuffern befinden können.
+
+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: AL eigener Kanal (1...15 / 32)
+ CX 6
+ DX adressierter Kanal
+ BX Modus
+ Ausgang: CX Rückmeldung (0 = ok, 1 = nicht möglich)
+
+ Zweck: Wird diese Routine auf dem Steuerkanal (AL=32) aufgeru­
+ fen, muß sie den gewünschten Flußkontrollmodus für den
+ adressierten Kanal einstellen.
+ Dabei sind folgende Modi festgelegt:
+
+ BX= 0 Keine Flußkontrolle
+ BX= 1 XON/XOFF (in beide Richtungen)
+ BX= 2 RTS/CTS (in beide Richtungen)
+ BX= 5 XON/XOFF (nur ausgabeseitig)
+ BX= 6 RTS/CTS (nur ausgabeseitig)
+ BX= 9 XON/XOFF (nur eingabesetig)
+ BX=10 RTS/CTS (nur eingabeseitig)
+
+ SHard wird hierdurch informiert, wie er auf "Puffer voll" und
+ "weiter" reagieren soll. Wenn keine Flußkontrolle gewünscht
+ wird (BX=0), muß SHard "stop" und "weiter" ignorieren; bei
+ BX=1 oder BX=9 muß bei "stop" XOFF und bei "weiter" XON
+ geschickt werden; bei BX=2 oder BX=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 BX=1 oder BX=5 müssen empfangene XON/XOFF-Zei­
+ chen, bei BX=2 oder BX=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 BX) vergeben.
+
+ "weiter" wird von EUMEL-0 sehr oft aufgerufen. Es
+ ist daher nicht sinnvoll, jedesmal XON zu senden, da dies die Gegenstelle
+ 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ückmeldung muß als BCD-Zahl erfolgen.
+
+ Hinweis: Die Uhr darf zwischen zwei Aufrufen umspringen. Die daraus
+ resultierende Probleme werden auf höheren Ebenen abge­
+ handelt.
+
+
+
+
+#bb("6. SHard-","Interface Version")#
+#goalpage("shdver")#
+
+Die #ib#Versionsnummer#ie# der Interface-Spezifikation, auf der SHard aufbaut, muß als 2-By­
+te-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-Mo­
+duln 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 Standardope­
+rationen 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ätzli­
+che 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 Mul­
+ti-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, (* --> DS:BX *)
+ INT CONST funktion1, (* --> CX *)
+ funktion2, (* --> DX *)
+ INT VAR antwort) (* <-- CX *)
+
+ PROC blockin (ROW 256 INT VAR para, (* --> DS:BX *)
+ INT CONST funktion1, (* --> CX *)
+ funktion2, (* --> DX *)
+ INT VAR antwort) (* <-- CX *)
+
+ PROC control (INT CONST funktion1, (* --> CX *)
+ funktion2, (* --> DX *)
+ funktion3, (* --> BX *)
+ INT VAR antwort) (* <-- CX *)
+
+Hinweis: Der SHard darf für 'funktion 1' (CX) 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 (AL='x', CX=-7, BX=13, DX=1200) aufgerufen. Verläßt
+ SHard 'control' mit CX = 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 ein­
+bauen. 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 dword ptr info
+ jr weiter
+ db ' text'
+ weiter:
+
+ Zweck: Info wird aufgerufen. Dabei wird 'text' zur Identifikation des
+ Kontrollereignisses ausgegeben. Der übergebene Text darf
+ nicht mit 0h beginnen.
+
+ 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-Routi­
+ nen benutzt, darf man ihn von diesen Routinen aus (inputin­
+ terrupt, OUTPUT, IOCONTROL "frout", IOCONTROL "weiter")
+ nicht aufrufen. Wenn die Ein-/Ausgabe auf Terminal 1 inter­
+ ruptgetrieben 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: BX Anfangsadresse des zu reservierenden Bereichs im
+ Datensegment von EUMEL-0, muß auf 512 Byte
+ ausgerichtet sein.
+ CX Länge des zu reservierenden Bereichs in 512-Byte-
+ Kacheln
+ Ausgang: CX 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 grundsätzlich nicht möglich
+ 2 augenblicklich 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 3800h anzufordern, da diese
+ Adresse stets im frei einplanbaren Paging-Bereich liegt.
+
+
+ #dx("free")# (0-Routine)
+
+ Eingang: BX Anfangsadresse des freizugebenden Bereichs im Da­
+ tensegment von EUMEL-0, muß auf 512 Byte ausge­
+ richtet sein.
+ CX Länge des zu freizugebenden Bereichs als 'Bytes DIV
+ 512'
+
+ 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, abschließend wird 'sysend'
+ aufgerufen.
+#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 soll­
+te
+
+ - nur die Kanäle 0 (Hintergrund), 1 (Terminal) und 31 (Archiv) behandeln,
+
+ - keine Baudraten-, Zeichenlängen-, Paritäts- und Flußkontrolleinstellungen un­
+ terstü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 Hintergrund-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): ? 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 gela­
+den 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 die Segmentregister 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 Zeichen
+ im Puffer frei" und "Puffer leer". Das kann schon im Vortest zu Output-Blok­
+ kaden führen.
+
+ h) Obwohl "frout" einen Wert größer als x meldet, nimmt "output" nicht alle x Zei­
+ chen 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) Fälschlicherweise wird davon ausgegangen, daß DS oder ES konstant bleiben.
+
+ m) Die Stepping-Rate eines Festplattencontrollers wird falsch eingestellt, bezie­
+ hungsweise die Platte wird nicht im 'buffered step mode' betrieben, obwohl
+ 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 Ein­
+ gabezeichen verloren oder werden verfälscht. In der Regel ist das auf Timing­
+ probleme 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-
+ Systemen 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 ung­
+ lückliches Timing häufig Blockaden auftreten. So kann zu kurzes 'busy wait' auf
+ Freiwerden der Parallelschnittstelle dazu führen, daß jedes zweite Zeichen abge­
+ lehnt 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 um­
+ gangen 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 ver­
+ wendet 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 .
+
+ Hinweis: Solche Systeme sind über V.24 nicht netzfähig, da sie Eingabezeichen
+ verlieren werden.
+
+
+ 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
+ zugunsten 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 Einlesen
+ 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 werden,
+ da vermittels Info alle Systemsicherungs- und Datenschutzmaßnahmen un­
+ terlaufen werden können.#off("i")##off("b")# *)
+#foot#
+#f#
+*) Ausnahmen von dieser Regel bedürfen der expliziten Zustimmung der EUMEL-Systemgruppe (GMD bzw. HRZ Bie­
+lefeld) 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 Startmenü
+ 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
+eingegeben werden. Lediglich dieses Kommando und das Kommando 'g' werden immer
+angenommen. Das Paßwort kann mit dem Kommando 'yP' 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)#
+XYY TEXT
+F AL AH CL CH DL DH BL BH SI DI SP BP PC DS ES
+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),
+
+ YY den Maxiprozeß (Task) bezeichnet, der gerade durch den Elan-Prozessor bear­
+ beitet wird (YY ist die hexadezimale Tasknummer),
+
+ TEXT den Grund für den Info-Modus anzeigt,
+
+Die zweite und dritte Zeile zeigen die Inhalte der 8086/8088-Register an. 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. (s:=<zahl>)
+ Auch der Realspeicher kann hiermit in verschiedenen Modi eingestellt werden:
+ FF absolute Adressierung
+ 0 CS-relativ
+ 1 DS-relativ
+ 2 ES-relativ
+ 3 SS-relativ
+
+'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=1).
+
+'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 Ver­
+ fä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 wie­
+ derholen, 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 wird bei 'shutup' (erst
+ dann!) in Block 0 eingetragen.
+
+--> '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 INT3 (für Aufruf von
+ Info) abgesetzt. Info verwaltet gleichzeitig bis zu 10 gesetzte Breakpoints. Die
+ Breakpointnummer kann man aus der nach jedem Setzen (und Löschen)
+ angezeigten Breakpoint-Tabelle entnehmen. Breakpoints sind nur im Real­
+ speicher sinnvoll. Ein Aufruf meldet sich mit TEXT= 'break z--xxxx:yyyy' (z
+ = Breakpointnummer, xxxx = CS, yyyy = PC beim Aufruf des Breakpoints).
+ Wird Info mit 'g' verlassen, so stellt er zuvor die alten 8086/8088-Befehle
+ wieder her und führt sie an ihrem originalen Ort aus. Direkt danach wird der
+ Breakpoint wieder hergestellt.
+
+--> 'yc' Löscht den Breakpoint an der Adresse <zahl> und stellt die ursprüngli­
+ chen Befehle wieder her. In der Breakpoint-Tabelle muß ein Breakpoint an
+ dieser Adresse vermerkt sein.
+
+--> 'yw' Zu anderen Miniprozeß wechseln. Nur sinnvoll, wenn ein anderer Mini unter
+ 'vor info' aufgeführt ist.
+
+--> '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 Ge­
+ lernte 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 *re­
+ turn*).
+
+--> 'y *return*'
+ Wie *return*, jedoch wird der Dump auch beim Ausführen (ya) ausgegeben.
+ (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 aller­
+ dings 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 Zahl­
+ zeichen ist, beendet diesen Modus. Das neue Zeichen wird als
+ Info-Kommando aufgefaßt, wobei <zahl> auf die aktuelle
+ Adresse 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 1s100h 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 8086/8088-Teile ('urlader') ab (i.A.
+30h < i < 40h).
+
+'Beginn der Anforderungen' liegt bei i=2. Es handelt sich um Blocknummern von zu laden­
+den Blöcken. Ist der höherwertige Teil der Blocknummer gleich FDh, so ist dies keine Anfor­
+derung.
+
+Blocknummern > FF00h stehen für Blöcke mit dem Inhalt 512 FFh's und werden nie auf
+dem Hintergrundmedium gespeichert.
+
+
+
+1sA00h 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 ver­
+ anlaß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.
+
+
+1s480h-4FFh:
+ enthält die Aktivierungstabelle. Ist (480h+i)=01h, so ist die Task i aktiv. Hin­
+ weis: 4FFh 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, ansehen.
+
+ 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 Ver­
+ sionsnummer 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-8086/8/source-disk b/doc/porting-8086/8/source-disk
new file mode 100644
index 0000000..8aeb5a2
--- /dev/null
+++ b/doc/porting-8086/8/source-disk
@@ -0,0 +1 @@
+porting/portdoc-x86-8.img
diff --git a/doc/porting-mc68k/1985.11.26/doc/Port.68000 b/doc/porting-mc68k/1985.11.26/doc/Port.68000
new file mode 100644
index 0000000..0ca6840
--- /dev/null
+++ b/doc/porting-mc68k/1985.11.26/doc/Port.68000
@@ -0,0 +1,2173 @@
+#type ("trium8")##limit (12.0)#
+#start(2.0,1.5)#
+#type("triumb36")#
+#free(4.0)#
+ EUMEL
+ Portierungs­
+ handbuch
+ MC68000
+#type("triumb18")#
+#free(1.5)#
+ Stand 26.11.85
+#page(1)#
+#type ("trium8")##limit (12.0)#
+#block#
+#pagelength(18.4)#
+#head#
+#center#- % -
+
+
+#end#
+#type("triumb12")#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 MC68000-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")#
+ 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 I/O-Steuerung #topage("iocontrol")#
+ Konfigurierung 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")#
+#free(0.3)#
+ Nullversion des SHards #topage("0ver")#
+ Typische Fehler #topage("fehler")#
+ Effizienzprobleme #topage("eff")#
+
+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")#
+
+Anhang B: Einige EUMEL-Begriffe #topage("glossar")#
+#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 Portierungs­
+handbüchern für verschiedene Prozessortypen. Dieses bezieht sich auf Rechner mit
+MC68000-Prozessoren.
+
+Zum Betrieb eines EUMEL-Systems wird dieses Handbuch nicht benötigt!
+
+
+
+#b("Referenzliteratur")##goalpage("reflit")#
+
+
+ "EUMEL Benutzerhandbuch"
+
+ "EUMEL Systemhandbuch"
+
+ "EUMEL Quellcode der insertierten ELAN-Pakete"
+
+ "MC68000 16-bit microprocessor - Users Manual"
+ Motorola, 1982
+
+ "68000 Assembler Reference"
+ XENIX Group, Microsoft Corp., 1982
+
+ "Anhang zu '68000 Assembler Reference'"
+ TA Nürnberg, 1984
+
+
+Siehe auch die Vorbemerkungen zur Notation in Teil 3 (S. #topage("not")#), sowie die Begriffserklä­
+rungen im Anhang B (S. #topage("glossar")#).
+
+
+#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 MC68000-CPU sollte mit mindestens 8.0 MHz arbeiten. Falls die
+ Buszugriffe durch einen CRTC o.ä. verlangsamt werden, sollte die
+ echte MC68000-Leistung durchschnittlich mindestens einem unge­
+ bremsten 8.0 MHz System entsprechen.
+ Seltene Verlangsamungen (z.B. nur bei I/O-Operationen) spielen bei
+ diesen Überlegungen keine Rolle.
+
+ RAM Das System sollte über mindestens 256 KByte #ib#Hauptspeicher#ie# verfü­
+ gen.
+
+ #ib#Hintergrund#ie# Als Hintergrundmedium sind #ib#Diskette#ie#, #ib#Platte#ie# und RAM bzw. ROM
+ denkbar.
+
+ Kapazität:
+ > 300 K, besser > 400 K (Single-User)
+ > 750 K, besser > 1000 K (Multi-User)
+
+ Zugriff: *)
+#foot#
+#f#*) Hier ist die durchschnittliche Zugriffszeit auf einen 512 Byte großen Block gemeint. Für Platten und Disketten kann
+man sie als Summe der Positionierzeit über die halbe Anzahl der Spuren und der Zeit einer halben Umdrehung be­
+rechnen.
+#a#
+#end#
+ < 500 ms (Single-User)
+ < 200 ms (Multi-User)
+
+ #ib#Archiv#ie# Als Archiv wird meistens eine Diskette eingesetzt. Aber auch Band
+ oder Kassette sind denkbar. Die Anforderungen an Kapazität und
+ Geschwindigkeit sind anwendungsspezifisch.
+
+ #ib#Bildschirm#ie# Angestrebt werden sollte ein Bildschirm mit 24 Zeilen zu je 80 Zeichen
+ (oder größer). Kleinere Bildschirme sind anschließbar, aber mit 40 Zei­
+ chen pro Zeile läßt sich nicht mehr komfortabel arbeiten.
+ Rollup und freie Cursorpositionierung sind notwendige Voraussetzun­
+ gen, invers-video ist erwünscht, aber nicht notwendig. Weiterhin
+ werden die Funktionen 'Löschen bis Zeilenende' und 'Löschen bis
+ Schirmende' benötigt.
+
+ #ib#Tastatur#ie# An Steuertasten sollten mindestens ESC und die vier Cursortasten
+ vorhanden sein. Dabei ist es günstig, wenn die Cursortasten ergono­
+ misch als Block bzw. Kreuz angeordnet sind. EUMEL benötigt weitere
+ Steuertasten für HOP, RUBIN, RUBOUT und MARK. Dafür können
+ beliebige, anderweitig nicht benötigte 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 (Diskette, Platte)
+
+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: Systemkern (EUMEL-0-Maschine, EUMEL-0)
+
+ 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 ge­
+ schrieben (siehe "EUMEL Quellcode"). Dementsprechend sind alle Schich­
+ ten oberhalb der EUMEL-0-Maschine prozessor- und rechnerunabhän­
+ gig, d.h. Anpassungen an einen neuen Rechnertyp sind nicht erforderlich.
+
+EUMEL   0 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
+ MC68000 Bezug genommen. Bei der Portierung auf einen MC68000-
+ Rechner wird die MC68000-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 MC68000-
+Rechner angepaßt bzw. neu geschrieben werden muß. Deshalb besteht der größte Teil
+dieses Handbuchs aus der Spezifikation des MC68000-SHards.
+
+
+
+#b("Anlieferung des MC68000-EUMEL-Systems")##goalpage("anlief")#
+
+Der Implementierer erhält die EUMEL-Software auf Disketten. Dabei stehen folgende
+Standardformate zur Wahl:
+
+ Diskette 200 (8"), 1D, 77 Spuren, 16 Sektoren (\#0...\#15) zu 512 Byte
+
+ Diskette 130 (5.25"), 2D, 40 Spuren, 9 Sektoren (\#1...\#9) zu 512 Byte *)
+#foot#
+#f#*) 48 tpi
+#a#
+#end#
+
+
+Die Diskettenlieferung **) enthält
+#foot#
+#f#**) Zu Inhalt und Zweck der angelieferten Disketten siehe EUMEL Systemhandbuch, Teil 1: System einrichten.
+#a#
+#end#
+
+ - Single-User Hintergrund
+ - Multi-User Hintergrund
+ - Standardarchive
+ - ggfs. Archive mit weiterer Anwendersoftware (installationsspezifisch)
+
+Dabei enthält der Hintergrund auch die EUMEL-0-Maschine (oft auch als "Urlader"
+bezeichnet).
+
+#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 Hintergrundmedium spezielle Blöcke z.B. für Bootstrap und SHard freige­
+halten werden sollen, muß das bei der Abbildung der Hintergrundblocknummern auf die
+Sektoren der Diskette bzw. der Platte berücksichtigt werden.
+
+Aufbau des Hintergrundes:
+
+ Block 0 Systemetikett
+
+ Block 10...10+k-1 EUMEL-0-Maschine (z.Zt. ist k=200; dieser Wert ist nur
+ für EUMEL-0 von Bedeutung)
+
+ 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ß System-
+ kern und Hintergrund kompatibel sind.
+ 12 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 #d("Standardformate")#:
+#foot#
+#f#*) Der genaue Aufbau der Archivblöcke ist weder für den SHard-Implementierer, noch für den Benutzer von Be­
+deutung. SHard hantiert nur mit Blöcken aufgrund von Blocknummern, unabhängig vom Inhalt der Blöcke. Der Benut­
+zer "sieht" nur Datenräume bzw. Dateien, unabhängig von ihrem Format auf dem Archiv.
+#a#
+#end#
+
+
+ Diskette 200 (8"), 1D, 77 Spuren, 16 Sektoren (\#0...\#15) zu 512 Byte
+ Diskette 200 (8"), 2D, 77 Spuren, 16 Sektoren (\#0...\#15) zu 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
+
+
+ Diskette 130 (5.25"), 2D, 40 Spuren, 9 Sektoren (\#1...\#9) zu 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
+
+
+ Diskette 130 (5.25"), 2D, 80 Spuren, 9 Sektoren (\#1...\#9) zu 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
+
+
+ Diskette 130 (5.25"), HD, 80 Spuren, 15 Sektoren (\#1...\#15) zu 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 ver­
+schiedenen Rechnertypen zu vereinfachen.
+
+#on("i")#Hinweis: Um den Datenaustausch zwischen verschiedenen Rechnertypen zu vereinfa­
+ chen, sollten möglichst alle hardwaremäßig möglichen Standardformate (min­
+ destens lesend) unterstützt werden. Dabei sollte SHard sich automatisch auf
+ das Format der jeweils eingelegten Diskette 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")#
+
+Der #ib#Speicher#ie# wird EUMEL-0 vom SHard in maximal vier Speicherbereichen (M0...M3)
+zugewiesen. Die Anfangsadresse eines solchen Bereiches muß ein Vielfaches von 512B
+sein. M0 muß immer vorhanden sein, M1, M2 und M3 nur in speziellen Betriebsarten:
+
+ #d("M0")# #on("b")#allgemeines #ib#RAM#ie(1,", allgemeines")##off("b")#
+ Dieser Bereich muß immer vorhanden sein. Bei den meisten Rechnern liegt der
+ Systemkern nicht in einem ROM, sondern wird von SHard in das RAM geladen.
+ Das geschieht dann an den Anfang von M0. Der Rest wird für Tabellen und als
+ Pagingbereich benutzt. M0 umfaßt deshalb meistens allen verfügbaren Spei­
+ cher, bis auf den Platz für SHard, Boot-ROM und Bildwiederholspeicher. **)
+#foot#
+#f#**) Der im Tabellenspeicher liegende 'ktab' ist für die Verwaltung von max. 2048 Kacheln (=1MB) ausgelegt. Der
+Speicherbedarf des Systemkerns liegt bei 80KB, für Tabellen werden 40KB benötigt. Dies sollte man bei der Angabe
+von M0SIZE berücksichtigen.
+#a#
+#end#
+
+ #d("M1")# #on("b")#Systemkern-#ib#ROM#ie(1,", Systemkern")##off("b")#
+ Gibt es nur bei Rechnern, die den Systemkern in einem ROM haben. (M0 wird
+ dann nur für Tabellen und als Pagingspeicher eingesetzt.)
+
+ #d("M2")# #on("b")#Hintergrund-#ib#ROM#ie(1,",Hintergrund")##off("b")#
+ Gibt es nur bei Rechnern, die nicht Diskette oder Platte sondern ROM und
+ RAM als Hintergrundspeicher verwenden.
+
+ #d("M3")# #on("b")#Hintergrund-#ib#RAM#ie(1,",Hintergrund")##off("b")#
+ Gibt es nur bei Rechnern, die nicht Diskette oder Platte sondern ROM und
+ RAM oder RAM allein als Hintergrundspeicher verwenden.
+
+Damit sind drei verschiedene Betriebsarten des EUMEL-Systems möglich:
+
+ #d("Normalbetrieb")#: M0 (> 256 KB)
+ Hintergrundgerät (Platte oder Diskette)
+ Archivgerät (Diskette)
+
+ Im Normalbetrieb befindet sich der Hintergrund auf einer Platte oder Diskette
+ RAM wird für den Systemkern und zum Paging eingesetzt. Alle mittleren und
+ größeren Systeme verwenden den Normalbetrieb.
+
+
+ #d("Minibetrieb")#: M0 (> 256 KB)
+ M3 (mindestens 300 KB)
+ Archivgerät (Diskette)
+
+ Im Minibetrieb wird RAM als Hintergrundspeicher eingesetzt. Dieser wird beim
+ Einschalten über das Archivgerät geladen und beim Abschalten ('shutup')
+ wieder zurückgeschrieben.
+
+
+ #d("ROM-Betrieb")#: M0 (>40 KB)
+ M1 (>60 KB)
+ M2 (>170 KB)
+ M3 (>60 KB)
+ Archivgerät (Kassettenrecorder oder Diskettenlaufwerk)
+
+ Im ROM-Betrieb stehen Systemkern und Standardteil des Hintergrundes im
+ ROM. Der übrige Hintergrund befindet sich im RAM. *)
+#foot#
+#f#*) Für ROM-Betrieb benötigt man eine Spezialversion des Systemkerns.
+#a#
+#end#
+
+#page#
+#cc("Teil 3: SHard ","Interface Spezifikation")##goalpage("shardifc")#
+
+
+#bb("0. ","Vorbemerkungen")##goalpage("vor")#
+
+
+#b("Zur Notation")##goalpage("not")#
+
+Im folgenden wird zwischen #d("0-Routinen")#, die dem SHard vom EUMEL-0-System zur
+Verfügung gestellt werden, und
+#d("SHard-Routinen")# unterschieden, die der SHard implementieren muß. Damit dieser Unter­
+schied 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ß geschrie­
+ben.
+
+MC68000-Befehle werden wie im "Anhang zu '68000 Assembler Reference'", (TA, 1984)
+notiert:
+
+ moveq \#27,d0
+ addw d3,d1
+
+
+Hexadezimale Zahlen werden durch ein vorangestelltes '/' gekennzeichnet:
+
+ /12 = 18
+ /1f = 31
+ /ffff = 65535
+
+
+Achtung: Die Übergabe von Integer-Parametern zwischen SHard und EUMEL-0 erfolgt
+ grundsätzlich in den niederwertigen 16 Bits des jeweils angegebenen Daten­
+ registers.
+
+#b("Link-Leisten")##goalpage("leist")#
+
+Die Verbindung zwischen SHard und 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 M0 (im Normal- oder Minimodus) bzw. M1 (im ROM-
+Modus):
+
+ Adresse Assemblerbefehl
+
+ M0 + 0 eumel0id: .ascii "EUMEL jj-mm-tt  " !Kennung mit Datum
+ +16 eumel0blocks: .word ... !Anzahl EUMEL0-Bloecke auf HG
+ +18 hgver: .word 173 !HG-Versionsnummer
+ +20 cputype: .word 4 !MC68000 oder kompat. CPU
+ +22 eumel0ver: .word mmmtt !EUMEL0-Version (mmm=1 --> Jan.84)
+ +24 shdvermin: .word 8 !Minimum bzw. Maximum fuer die
+ +26 shdvermax: .word 8 ! SHard-Versionsnummer
+ +28 systemstart: jmp ... !Ab hier stehen Sprungbefehle zu
+ +34 inputinterrupt: jmp ... ! den entsprechenden 0-Routinen
+ +40 timerinterrupt: jmp ...
+ +46 warte: jmp ...
+ +52 shutup: jmp ...
+ +58 info: jmp ...
+
+
+Für die Gegenrichtung muß SHard der 0-Maschine die "SHard-Leiste" zur Verfügung
+stellen:
+
+ Adresse Assemblerbefehl
+
+SHDID+ 0 SHDID: .ascii "SHARD jj-mm-tt  " !Kennung mit Datum
+ +16 SHDVER: .word 8 !Versionsnummer d. SHard-Schnittstelle
+ +18 MODE: .word !Modusbits:
+ BITEUDEL = 0 ! EUMEL-0-Bloecke auf HG freigeben
+ BITNORMAL = 1 ! Normalbetrieb
+ BITMINI = 2 ! Minibetrieb
+ BITROM = 3 ! ROM-Betrieb
+ +20 ID4: .word !ID-Konstanten (s.S. #topage("ID")#)
+ +22 ID5: .word ! dito
+ +24 ID6: .word ! dito
+ +26 ID7: .word ! dito
+ +28 OUTCHAR: jmp !Ab hier stehen Sprungbefehle in die
+ +34 OUTPUT: jmp ! entsprechenden SHard-Routinen
+ +40 BLOCKIN: jmp
+ +46 BLOCKOUT: jmp
+ +52 IOCONTROL: jmp
+ +58 SYSEND: jmp
+ +64 SYSABORT: jmp
+ +70 M0START: .long !Startadr bzw.
+ +74 M0SIZE: .long ! Länge (in Bytes) des Bereiches M0
+ +78 M1START: .long ! dito f. M1
+ +82 M1SIZE: .long
+ +86 M2START: .long ! dito f. M2
+ +90 M2SIZE: .long
+ +94 M3START: .long ! dito f. M3
+ +98 M3SIZE: .long
+
+
+
+#b("Allgemeine Link-Bedingungen")##goalpage("link")#
+
+In der Regel sind sowohl 0-Routinen als auch SHard-Routinen durch 'jbsr' aufzurufen:
+
+ jbsr <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 die 'condi­
+ tion code'-Flags im Status Register *) - bleiben unverändert.
+#foot#
+#f#*) Condition-Code-Flags sind i.a. nach dem Aufruf einer Routine undefiniert. Ausnahmen sind natürlich die Flags,
+die als Ausgangsparameter in manchen Fällen definiert sind.
+#a#
+#end#
+
+Jede SHard-Routine muß also alle Register, die sie verändert und die keine Ausgangs­
+parameter 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 'jbsr' an 0-Routinen
+weiterleiten.
+Die Register (bis auf die Parameterregister) werden von den aufzurufenden 0-Routinen
+selbst gesichert. Die normale Interrupt-Sequenz im SHard sieht dann folgendermaßen
+aus:
+
+ intadr:  movl d0,(sp)-
+ movw <parameter>,d0
+ jbsr <routine>
+ andw \#/fcff,sr ! interrupt level freigeben
+ movl (sp)+,d0
+ rti
+
+Achtung: SHard muß die Interrupt-Routinen im 'disable-int'-Modus anspringen, d.h. im
+ Status Register muß der korrekte Interrupt-Level gesetzt sein. (MC68000 setzt
+ beim Interrupt schon automatisch die Interrupt-Level-Flags.)
+
+
+
+
+
+#bb("1. System ","laden")##goalpage("laden")#
+
+SHard muß die EUMEL-0-Software vor dem eigentlichen Start an den Anfang des Spei­
+cherbereiches M0 laden. EUMEL-0 befindet sich auf dem Hintergrund von Block 10 ab.
+Der erste Block von EUMEL-0 enthält am Anfang die 0-Leiste. Dort steht an der
+Byteadresse 16 die Größe 'eumel0blocks'. Sie gibt an, wieviel Blöcke konsekutiv geladen
+werden müssen. Hat sie beispielsweise den Wert 80, müssen die Blöcke 10 bis 89 gela­
+den 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 von EUMEL-0 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) einspielen, indem man ein Hintergrundarchiv vor dem Systemstart
+in das Archivgerät legt. Dann wird EUMEL-0 von dort geladen, so daß man den Hinter­
+grund dann wie im Systemhandbuch beschrieben vom Archiv auf das Hintergrundmedium
+kopieren kann.*)
+#foot#
+#f#*) Kopiervorgänge (Archiv -> Hintergrund) werden von EUMEL-0 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').
+
+ #d("systemstart")# (0-Routine)
+
+ Eingang: a0 = Adresse der SHard-Leiste
+
+ Aufruf: jmp systemstart
+
+ Zweck: Die EUMEL-0-Maschine wird gestartet. Alle notwendigen Hard­
+ wareinitialisierungen (z.B. der Peripheriebausteine) müssen vorher
+ schon geschehen sein.
+
+ Hinweis: SHard muß den Stackpointer (a7) "vorläufig" definieren (etwa 100
+ Langworte reichen dafür aus), da beim Sprung in EUMEL-0 Inter­
+ rupts auftreten können.
+
+
+
+ #d("SYSEND")#
+
+ Parameter: -
+
+ Zweck: Hiermit wird SHard das Ende eines Systemlaufs mitgeteilt. Somit
+ können evtl. notwendige Abschlußbehandlungen durchgeführt
+ werden. SHard kann mit 'rts' zu EUMEL-0 zurückkehren, muß
+ aber nicht. Diese Routine kann z.B. dazu benutzt werden, die
+ Hardware auszuschalten oder in ein umgebendes System zurück­
+ zukehren (EUMEL als Subsystem). In den meisten Fällen wird die
+ Routine leer implementiert werden, d.h. nur aus 'rts' bestehen.
+
+
+
+
+#bb("3. ","Speicherverwaltung")##goalpage("spver")#
+
+
+#b("Hauptspeicher")##goalpage("haupt")#
+
+Der Hauptspeicher umfaßt die Teile des MC68000-Speichers, die EUMEL-0 verwalten
+darf.
+
+
+
+#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 wer­
+den.
+
+Wenn SHard (z.B. über Interrupt) einen Speicherfehler mitgeteilt bekommt, sollte er, wenn
+möglich, eine entsprechende Meldung ausgeben und das System anhalten:
+
+ basta: jra basta
+
+
+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.
+
+ #d("timerinterrupt")# (0-Routine)
+
+ Eingang: d0 = seit letztem Zeitgeberinterrupt vergangene Zeit (in ms)
+
+ Zweck: Wird von EUMEL-0 für interne Uhren und für das Scheduling
+ (Zeitscheibenlogik) verwendet. Es werden keine hohen Genauig­
+ keitsanforderungen an die Zeitangaben bei #on("i")#einzelnen#off("i")# Interrupts
+ gestellt. Um EUMEL-0 eine genaue Realzeituhr zu ermöglichen,
+ sollte die so erzeugte Zeitangabe #on("i")#im Mittel#off("i")# aber möglichst genau
+ sein, d.h. die Summe der innerhalb 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.
+ 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
+Funktion ist dann Absprachesache zwischen Installation und SHard.
+
+Kanäle können über Block-IO (BLOCKOUT, BLOCKIN) oder Stream-IO (OUTPUT,..)
+angesprochen 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 werden.#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 Ter­
+minals, Druckern, Plottern usw. ab. Stream-IO wird nur für die Kanäle 1...15 gemacht.
+
+ #d("inputinterrupt")# (0-Routine)#goalpage("inp")#
+
+ Aufruf: movl kanalnummer,(sp)- !1...15
+ movl zeichen,(sp)- !rechtsbündig
+ jbsr inputinterrupt
+ lea 8(sp),sp !restore stackpointer
+
+ Zweck: SHard muß EUMEL-0 durch Aufruf dieser Routine mitteilen, daß
+ eine Eingabe vorliegt.
+
+ Hinweise: EUMEL-0 puffert die Zeichen. EUMEL-0 signalisiert den Zustand
+ "Puffer voll" durch IOCONTROL "stop" und ignoriert weitere
+ Eingaben, bis wieder Platz im Puffer vorhanden ist. (siehe
+ IOCONTROL "stop" und "weiter", S.#topage("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 Inputquellen regel­
+ mäßig abzufragen. Dabei muß man allerdings den goldenen Mittel­
+ weg zwischen zu häufiger (Systemdurchsatz sinkt) und zu seltener
+ Abfrage (Zeichen gehen verloren) suchen. Man sollte dabei nicht
+ nur an die menschliche Tippgeschwindigkeit 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-Funk­
+tion "weiter" beschrieben (siehe S.#topage("weiter")#).
+#a#
+#end#
+
+Achtung: #on("i")#Keinesfalls darf 'inputinterrupt' rekursiv aufgerufen werden. Nor­
+ malerweise 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 bestimmten Umstän­
+ den das nächste Zeichen abgeholt werden muß, bevor die
+ 0-Routine beendet ist, muß SHard einen eigenen Puffer imple­
+ mentieren:#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: d0 = Kanalnummer (1...15)
+ d2 = Anzahl auszugebender Zeichen
+ a0 = Adresse der Zeichenkette
+ Ausgang: d2 = Anzahl der übernommenen Zeichen
+
+ Zweck: Ausgabe einer Zeichenkette. Diese ist (möglichst ganz) zwischen­
+ zupuffern, denn die Ausführung von OUTPUT sollte kein Warten
+ auf IO enthalten. Der Ausgabepuffer muß mindestens 50 Zeichen
+ fassen können. Durch eine Interruptlogik oder etwas Äquivalentes
+ ist sicherzustellen, daß dieser Puffer parallel zur normalen Verar­
+ beitung ausgegeben wird. Wenn die auszugebende Zeichenkette
+ nicht vollständig 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 Zeichenkette
+ auf.
+
+
+ Achtung: #on("i")#Keinesfalls darf innerhalb von OUTPUT die 0-Routine 'warte' auf­
+ gerufen werden.#off("i")#
+
+ Vorschlag: Falls der Kanal nicht existiert bzw. OUTPUT darauf unsinnig ist,
+ sollte vorgegaukelt werden, alle Zeichen seien ausgegeben (d2
+ unverändert).
+
+
+
+ #d("OUTCHAR")#
+
+ Eingang: d0 = Kanalnummer (1...15)
+ d1 = auszugebendes Zeichen
+
+ Zweck: Ausgabe eines Zeichens.
+
+ Hinweis: Ob das Zeichen übernommen wird, kann vorher durch einen Aufruf
+ IOCONTROL "frout" erfragt werden, s. S. #topage("frout")#.
+
+
+
+#b("Terminals")##goalpage("term")#
+
+"Normale" #ib#Terminal#ie(1,", normales")#s können ohne weitere Unterstützung des SHards angeschlossen
+werden. 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, Teil 3: Editor, 5. Zeichencode"
+#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
+gearbeitet 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 je 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 abgebro­
+chen 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 Umsetz­
+tabelle 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 1.7
+Seite 106) 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 Hintergrund und zum Archiv ab.
+Ferner ist daran gedacht, auch auf V.24-Schnittstellen Block-IO z.B. für Rechnerkopp­
+lung zuzulassen. Die Kanalnummer in Reg. d0 unterscheidet diese Fälle. Außer beim
+Paging (d0=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 Um­
+pufferung 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 weiter­
+laufen 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("i")#Funktionscode#ie##off("i")# in Register d1 nur positive Werte (Bit 15
+von d1 = 0). Der SHard kann selbst negative Codes einführen.
+
+
+ #d("BLOCKIN")#
+
+ Eingang: d0 = Kanalnummer (0...32)
+ d1 = Funktionscode 1
+ d2 = Funktionscode 2
+ a0 = Adresse des Hauptspeicherbereichs
+ Ausgang: d0 = undefiniert (darf also verändert werden)
+ d1 = Rückmeldecode
+ a0 = darf verändert werden
+
+ Der Inhalt des Hauptspeicherbereichs (<a0>... <a0>+511) darf
+ verändert sein.
+
+ Zweck: "Einlesen" von Blöcken. Die genaue Wirkung hängt vom Funk­
+ tionscode und dem Kanal ab.
+
+ Vorschlag: Falls der Kanal nicht existiert bzw. BLOCKIN darauf unsinnig ist,
+ sollte die Rückmeldung -1 in d1 geliefert werden.
+
+
+ #d("BLOCKOUT")#
+
+ Eingang: d0 = Kanalnummer (0...32)
+ d1 = Funktionscode 1
+ d2 = Funktionscode 2
+ a0 = Adresse des Hauptspeicherbereichs
+ Ausgang: d0 = undefiniert (darf also verändert werden)
+ d1 = Rückmeldecode
+ a0 = 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 Funk­
+ tionscode und dem Kanal ab.
+
+ Vorschlag: Falls der Kanal nicht existiert bzw. BLOCKOUT darauf unsinnig ist,
+ sollte die Rückmeldung -1 in d1 geliefert werden.
+
+
+ #d("warte")# (0-Routine)
+
+ Ausgang: Alle Register undefiniert!
+
+ Zweck: Diese Routine ist bei 'blockin' oder 'blockout' dann aufzurufen,
+ wenn SHard im Augenblick nichts zu tun hat. Durch den Aufruf von
+ 'warte' erhalten andere Systemteile die Möglichkeit, weiter zu ar­
+ beiten. Ein 'warte' kann bis zu ca. 1/4 Sekunde Zeit aufnehmen.
+ 'warte' darf nicht in Interruptroutinen und Stream-IO verwendet
+ werden! 'warte' zerstört alle Register! SHard muß davon ausgehen,
+ daß 'warte' seinerseits andere SHard-Komponenten aufruft.
+
+
+Die Verwendung der 0-Routine 'warte' soll hier an einigen Beispielen verdeutlicht wer­
+den:
+
+
+ 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")# d0 = 0 bzw. 31
+ d1 = 0
+ d2 = Blocknummer
+ a0 = Hauptspeicheradresse
+
+ Der angegebene 512-Byte-Block ist in den Hauptspeicher ab
+ <a0> einzulesen.
+
+ #on("b")#BLOCKOUT#off("b")# d0 = 0 bzw. 31
+ d1 = 0
+ d2 = Blocknummer
+ a0 = Hauptspeicheradresse
+
+ Der Hauptspeicherbereich (<a0>... <a0>+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)
+
+
+#d("Fehlerwiederholung")#: Das EUMEL-System führt von sich aus Fehlerwiederholungen beim
+ Hintergrund- und beim Archivzugriff durch. SHard sollte deshalb
+ im Fehlerfall die Operation nicht selbst wiederholen, sondern einen
+ Lese/ Schreibfehler zurückmelden. So werden dem EUMEL-Sy­
+ stem 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 fehlerhaften Versuch
+ durchführen.
+
+#d("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,
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+System verwendet nur positive Codes. Der SHard-Schreiber kann auch negative Codes
+für Sonderzwecke vorsehen.
+
+
+ #d("IOCONTROL")#
+
+ Eingang: d0 = Kanalnummer (0...32)
+ d1 = Funktionscode 1
+ d2 = Funktionscode 2
+ d3 = Funktionscode 3
+ Ausgang: d1 = Rückmeldung
+
+ Zweck: abhängig von 'Funktionscode 1' (s.u.)
+
+Das System verlangt folgende Informations- und Steuerleistungen über IOCONTROL:
+
+
+ #d("IOCONTROL ""typ""")#
+
+ Eingang: d0 = Kanalnummer (0...31)
+ d1 = 1
+ Ausgang: d1 = Kanaltyp
+
+ Zweck: Informiert EUMEL-0, welche IO für den angegebenen Kanal
+ sinnvoll ist. Die Rückmeldung in d1 wird bitweise interpretiert:
+
+ Bit 0 gesetzt  <=> 'inputinterrupt' kann kommen.
+ Bit 1 gesetzt  <=> OUTPUT ist sinnvoll.
+ Bit 2 gesetzt  <=> BLOCKIN ist sinnvoll.
+ Bit 3 gesetzt  <=> BLOCKOUT ist sinnvoll.
+ Bit 4 gesetzt  <=> IOCONTROL "format" ist sinnvoll.
+
+ Hinweis: #on("i")#Trotz dieser Informationsmöglichkeit wird nicht garantiert, daß nur
+ sinnvolle Operationen für den Kanal aufgerufen werden.#off("i")#
+
+
+ #d("IOCONTROL ""frout""")##goalpage("frout")#
+
+ Eingang: d0 = Kanalnummer (1...15)
+ d1 = 2
+ Ausgang: d1 = Anzahl Zeichen, die nächster OUTPUT übernimmt, bzw.
+ Anzahl der OUTCHAR-Aufrufe, deren Zeichen übernommen
+ wird.
+
+ Zweck: Liefert Information über die Belegung des Puffers. Diese Informa­
+ tion wird von EUMEL-0 zum Scheduling benutzt.
+
+ Achtung: #on("i")#Wenn EUMEL-0 längere Zeit kein OUTPUT gemacht hat, muß
+ irgendwann d1 > 49 gemeldet werden.#off("i")#
+
+ Hinweis: Unter Berücksichtigung des oben Gesagten darf "gelogen" werden.
+ Man kann z.B. immer 50 in d1 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 'Druk­
+ kerpuffer voll' 0 in d1 zurückgemeldet werden. Wenn aber Zeichen
+ übernommen werden können, sollte 50 in d1 gemeldet werden
+
+ Vorschlag: Falls der Kanal nicht existiert oder nicht für Stream-IO zur Verfü­
+ gung steht, sollten 200 in d1 zurückgemeldet werden.
+
+
+ #d("IOCONTROL ""weiter""")##goalpage("weiter")#
+
+ Eingang: d0 = Kanalnummer (1...15)
+ d1 = 4
+ Ausgang: -
+
+ Zweck: Das System ruft "weiter" für den in d0 angegebenen Kanal auf,
+ wenn es wieder Eingabezeichen puffern kann. (siehe auch: Fluß­
+ kontrolle S.#topage("fluss")#)
+
+ 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 diesen Aufruf dazu
+ benutzen, den Kanal auf mögliche Eingabe abzufragen und ggfs.
+ das Eingabezeichen durch Aufruf von 'inputinterrupt' EUMEL-0
+ zuzustellen.
+ #on("i")#Diese Betriebsart sollte nicht für normale Terminalkanäle eingesetzt
+ werden, weil sie die SV-Taste nur dann an EUMEL-0 zustellt,
+ wenn ein Prozeß auf diesem Kanal auf Eingabe wartet. Dadurch
+ wären aber CPU-intensive Endlosschleifen nicht normal abbrech­
+ bar! #off("i")#
+
+
+ #d("IOCONTROL ""size""")#
+
+ Eingang: d0 = Kanalnummer (0...31)
+ d1 = 5
+ d2 = Schlüssel
+ Ausgang: d1 = Anzahl Blöcke
+
+ Zweck: EUMEL-0 ruft 'size' auf, um die Anzahl Blöcke zu erfahren, die
+ ein Block-IO-Kanal verkraften kann (Größe von Hintergrund und
+ Archiven). Bei Archivlaufwerken, die meherere Formate bearbeiten
+ können, dient dieser Aufruf auch zum Einstellen des Formats für
+ die folgenden blockin/blockout-Operationen anhand des Schlüs­
+ sels.
+
+ Schlüssel: 0 Wenn möglich 'erkennend', sonst 'standard'. Im ersten Fall
+ erkennt SHard das Format der eingelegten Diskette und stellt
+ dieses ein.
+
+ Die weiteren Schlüssel sind stets definierend:
+
+ 1 5.25" 2D-40, Sektor 1..9, 512 Bytes
+ 2 5.25" 2D-80, Sektor 1..9, 512 Bytes
+ 3 5.25" HD-80, Sektor 1..15, 512 Bytes
+ 4 5.25" 1D-80, Sektor 1..9, 512 Bytes
+ 10 8" 1D-77, Sektor 0..15, 512 Bytes
+ 11 8" 2D-77, Sektor 0..15, 512 Bytes
+ 12 8" 1S-77, Sektor 1..26, 128 Bytes
+ 13 8" 1D-77, Sektor 1..26, 256 Bytes
+ 14 8" 2D-77, Sektor 1..16, 256 Bytes
+
+ Hinweis: Bei Archiven wird 'size' aufgerufen, nachdem der Archivträger ein­
+ gelegt 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 (Hinter­
+ grund) 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: d0 = Kanalnummer (0...31)
+ d1 = 7
+ d2 = Schlüssel
+ Ausgang: d1 = 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 ('rts'). Sie sollte aber "forma­
+ tierend" (z.B. auf Kanal 31) arbeiten, falls auf diesem Kanal die
+ "typ"-Abfrage "Formatieren sinnvoll" liefert. Falls (bei Disketten­
+ laufwerken) mehrere Formate möglich sind, bestimmt der Schlüssel
+ das gewünschte Format.
+
+ Schlüssel: 0 Standardformat dieses Rechners
+ 1 5.25" 2D-40, Sektor 1..9, 512 Bytes
+ 2 5.25" 2D-80, Sektor 1..9, 512 Bytes
+ 3 5.25" HD-80, Sektor 1..15, 512 Bytes
+ 4 5.25" 1D-80, Sektor 1..9, 512 Bytes
+ 10 8" 1D-77, Sektor 0..15, 512 Bytes
+ 11 8" 2D-77, Sektor 0..15, 512 Bytes
+ 12 8" 1S-77, Sektor 1..26, 128 Bytes
+ 13 8" 1D-77, Sektor 1..26, 256 Bytes
+ 14 8" 2D-77, Sektor 1..16, 256 Bytes
+
+ 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 angeboten werden. Denn sonst
+ müßte der Pagingbereich unnötig eingeschränkt werden.
+ Man kann das Formatieren #on("i")#einer Spur#off("i")# CPU-intensiv implementie­
+ ren (d.h. ohne DMA im Interrupts-Disabled-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 (d0 = 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 (d0 <> 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: d0 = eigener Kanal (1...15 / 32)
+ d1 = 8
+ d2 = 0
+ d3 = Schlüssel * 256 + adressierter Kanal
+ Ausgang: d1 = Rückmeldung (0 = ok, 1 = nicht möglich)
+
+ Zweck: Wird diese Routine auf dem Steuerkanal (d0=32) aufgerufen, wird
+ die angegebene Baudrate für den durch Register d3(0..7) adres­
+ sierten Kanal eingestellt, falls das möglich ist. Wird diese Routine
+ auf einem anderen Kanal als 32 aufgerufen, 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 unterstützt
+ werden. Bei V.24 Schnittstellen sollten aber mindestens 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 in d3(8..15) ver­
+ geben.
+
+
+ #d("IOCONTROL ""bits""")#
+
+ Eingang: d0 = eigener Kanal (1...15 / 32)
+ d1 = 9
+ d2 = 0
+ d3 = Schlüssel * 256 + adressierter Kanal
+ Ausgang: d1 = Rückmeldung (0 = ok, 1 = nicht möglich)
+
+ Zweck: Wird diese Routine auf dem Steuerkanal (d0=32) aufgerufen, wird
+ die angegebene Zeichenlänge (Bits pro Zeichen) und Parität für
+ den durch Register d3(0..7) adressierten Kanal eingestellt, falls das
+ möglich ist.
+ Wird diese Routine auf einem anderen Kanal als 32 aufgerufen,
+ 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 unter­
+ stützt werden. Bei V.24 Schnittstellen sollten aber möglichst 1
+ Stopbit, 7 und 8 Bits pro Zeichen und alle drei Paritätseinstellun­
+ gen zur Verfügung stehen.
+
+ Hinweis: Falls SHard-spezifisch weitere Einstellungen implementiert werden
+ sollen, darf SHard hierfür negative Schlüsselwerte in d3(8..15) ver­
+ geben.
+
+
+
+#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
+empfangen 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 IOCONTROL-Funktionen
+"stop" und "weiter" (siehe S.#topage("weiter")#) verwenden:
+
+Nach "stop" muß SHard weiter einlaufenden Input selbst zwischenpuffern oder auf der
+V.24-Schnittstelle das Signal 'REQUEST TO SEND' wegnehmen bzw. XON 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 ent­
+sprechenden 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 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 Ausgabe anhalten und XON sie wieder starten.
+
+Bemerkung: Die meisten Systeme enthalten diese CTS-Funktion schon in ihrer Hard­
+ ware, so daß im SHard dafür keine Vorkehrungen getroffen werden müs­
+ sen.
+
+
+Zur Einstellung der gewünschten Flußkontrolle eines Kanals dient die IOCONTROL-
+Funktion "flow". Ähnlich wie "baud" und "bits" wirkt auch "flow" nur auf Kanal 32 #on("i")#ein­
+stellend#off("i")# und auf allen anderen Kanälen lediglich #on("i")#abfragend#off("i")#.
+
+
+ #d("IOCONTROL ""flow""")#
+
+ Eingang: d0 = eigener Kanal (1...15 / 32)
+ d1 = 6
+ d2 = 0
+ d3 = Modus * 256 + adressierter Kanal
+ Ausgang: d1 = Rückmeldung (0 = ok, 1 = nicht möglich)
+
+ Zweck: Wird diese Routine auf dem Steuerkanal (d0=32) aufgerufen, muß
+ sie den gewünschten Flußkontrollmodus für den adressierten Kanal
+ einstellen.
+ Dabei sind folgende Modi festgelegt:
+
+ Modus = 0 Keine Flußkontrolle
+ Modus = 1 XON/XOFF (in beiden Richtungen)
+ Modus = 2 RTS/CTS (in beiden Richtungen)
+ Modus = 5 XON/XOFF (nur ausgabeseitig)
+ Modus = 6 RTS/CTS (nur ausgabeseitig)
+ Modus = 9 XON/XOFF (nur eingabeseitig)
+ Modus = 10 RTS/CTS (nur eingabeseitig)
+
+ SHard wird hierdurch informiert, wie er auf "stop" und "weiter"
+ reagieren soll. Wenn keine Flußkontrolle gewünscht wird
+ (Modus=0), muß SHard "stop" und "weiter" ignorieren; bei
+ Modus=1 oder Modus=9 muß bei "stop" XOFF und bei "weiter"
+ XON geschickt werden; bei Modus=2 oder Modus=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 Modus=1 oder Modus=5 müssen empfangene XON/XOFF­
+ -Zeichen, bei Modus=2 oder Modus=6 das Signal CTS beachtet
+ werden.
+
+ Wird diese Routine auf einem anderen Kanal als 32 aufgerufen,
+ informiert sie den Aufrufer lediglich, ob der geforderte Flußkontroll­
+ modus auf dem adressierten Kanal einstellbar wäre.
+
+ Hinweis: Falls SHard-spezifisch weitere Flußkontrollmodi implementiert
+ werden sollen, darf SHard hierfür negative Moduswerte in d3(8..15)
+ vergeben.
+
+ "weiter" wird von EUMEL-0 sehr oft aufgerufen. Es
+ ist daher nicht sinnvoll, jedesmal XON zu senden, da dies die Gegenstelle
+ 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: d1 = 10
+ d2 = gewünschte Einheit (1=Minute, 2=Stunde, 3=Tag,
+ 4=Monat, 5=Jahr)
+ Ausgang: d1 = 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..31, Monat: 1..12, Jahr: 0..99).
+
+ Hinweis: Die Uhr darf zwischen zwei Aufrufen umspringen. Die daraus re­
+ sultierenden Probleme werden auf höheren Ebenen abgehandelt.
+
+
+
+#bb("6. SHard-","Interface Version")##goalpage("shdver")#
+
+Die #ib#Versionsnummer#ie# der Interface-Spezifikation, auf der SHard aufbaut, muß als
+2-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ß in der Leiste vier 2-Byte-Konstanten ablegen. Diese können von den höhe­
+ren 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 Standardope­
+rationen 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
+abgewickelt werden und dürfen nur dort wirken.
+
+
+ PROC blockout (ROW 256 INT CONST para, (* --> a0 *)
+ INT CONST funktion1, (* --> d1 *)
+ funktion2, (* --> d2 *)
+ INT VAR antwort) (* <-- d1 *)
+
+ PROC blockin (ROW 256 INT VAR para, (* --> a0 *)
+ INT CONST funktion1, (* --> d1 *)
+ funktion2, (* --> d2 *)
+ INT VAR antwort) (* <-- d1 *)
+
+ PROC control (INT CONST funktion1, (* --> d1 *)
+ funktion2, (* --> d2 *)
+ funktion3, (* --> d3 *)
+ INT VAR antwort) (* <-- d1 *)
+
+Hinweis: Der SHard darf für 'funktion 1' (d1) zusätzlich zu den hier beschriebenen
+ Standardcodes 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 (d0='x', d1=-7, d2=1200, d3=13) aufgerufen.
+ Verläßt SHard 'control' mit d1 = 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 ein­
+bauen. Das geschieht durch Aufruf der 0-Routine 'info'. Dieser EUMEL-Debugger wird
+im Anhang A (siehe S.#topage("info")#) beschreiben.
+
+
+ #d("info")# (0-Routine)
+
+ Aufruf: movl \#infomsg,(sp)-
+ jbsr info
+ lea 4(sp),sp ! restore stackpointer
+ .
+ .
+ infomsg: .asciz "text"
+
+ Zweck: Info wird aufgerufen. Dabei wird 'text' zur Identifikation des Kon­
+ trollereignisses ausgegeben. #on("i")#Hinter dem übergebenen Text muß
+ ein Byte /00 stehen (durch '.asciz' sichergestellt)!#off("i")#
+
+ Hinweis: Bei Systemen "ohne Info" (nur solche dürfen an Anwender aus­
+ geliefert werden) wird nur der Info-Text ausgegeben und
+ EUMEL-0 angehalten.
+
+ Achtung: Da der Info selbst die hier beschriebenen Stream-IO-Routinen
+ benutzt, darf man ihn von diesen Routinen aus (inputinterrupt,
+ OUTPUT, OUTCHAR, IOCONTROL "frout", IOCONTROL "stop",
+ IOCONTROL "weiter") nicht aufrufen. Wenn die Ein-/Ausgabe auf
+ Terminal 1 interruptgetrieben läuft, dürfen die Interrupts beim Info­
+ -Aufruf natürlich nicht gesperrt sein.
+
+#page#
+#cc("Teil 4: ","Tips zur Portierung")##goalpage("tips")#
+
+
+#b("Nullversion des SHards")##goalpage("0ver")#
+
+
+Es wird empfohlen, zuerst eine "Nullversion" des SHard zu entwickeln, die möglichst
+einfach aufgebaut und nicht auf Effizienz und vollständige Ausnutzung der Betriebsmittel
+ausgerichtet sein sollte. Damit kann man rasch praktische Erfahrung gewinnen, die dann
+den Entwurf und die Implementation des eigentlichen SHard erleichtert. Die Nullversion
+sollte
+
+ - nur die Kanäle 0 (Hintergrund), 1 (Terminal) und 31 (Archiv) behandeln,
+
+ - keine Baudraten-, Zeichenlängen-, Paritäts- und Flußkontrolleinstellungen un­
+ terstützen (immer 'nicht möglich' melden),
+
+ - vorhandene (ROM-) Routinen möglichst nutzen, ohne sich um Unschönes wie
+ "busy wait" beim Disketten- bzw. Plattenzugriff zu grämen.
+
+Mit dieser Nullversion sollte man dann versuchen, EUMEL zu starten. Da der Hintergrund
+ keitsanforderungen an die Zeitangaben bei #on("i")#einzelnen#off("i")# Interrupts
+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): ... 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. (Andern­
+falls funktioniert die Eingabe nicht richtig!)
+
+Als nächstes sollte man versuchen, den Hintergrund vom Archiv aus zu laden. (Diese
+Möglichkeit 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
+Verwendung 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 verzich­
+ten.
+
+
+Im Gegensatz zu der Nullversion sollte man bei der eigentlichen SHard-Implementierung
+darauf achten, die Möglichkeiten der Hardware effizient zu nutzen. Der Testverlauf ent­
+spricht 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.
+
+ b) 'jbsr' bzw. 'rts' verändern den Stackpointer.
+
+ c) Fehler bei der Interruptbehandlung führen zu Blockaden ("hängende Inter­
+ rupts").
+
+ 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 Zeichen
+ im Puffer frei" und "Puffer leer". Das kann schon im Vortest zu Output-Blok­
+ kaden 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) Die Stepping-Rate eines Plattencontrollers wird falsch eingestellt, beziehungs­
+ weise die Platte wird nicht im 'buffered step mode' betrieben, obwohl sie be­
+ schleunigend 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.
+
+ m) 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.
+
+ n) Bei schnellem Zeichenempfang, speziell bei gleichzeitiger Ausgabe, gehen
+ Eingabezeichen verloren oder werden verfälscht. In der Regel ist das auf
+ Timingprobleme 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-
+ Systemen 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 abge­
+ lehnt wird, so daß OUTPUT faktisch zeichenweise arbeitet. Andererseits darf na­
+ türlich 'busy wait' auch nicht auf Millisekunden ausgedehnt werden.
+
+
+ b) Wenn #on("i")##on("b")#Disketten 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 Diskettenoperation 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 reali­
+ siert 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")#Platten#off("b")##off("i")# sollte man darauf achten, daß die 0-Routi­
+ ne 'warte' nicht öfter als notwendig aufgerufen wird. Sonst wird das Paging
+ zugunsten 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
+ Einlesen 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 ge­
+ wartet 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" unter­
+scheiden sich nur im EUMEL-0-Teil (Systemkern). 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 werden,
+ da vermittels Info alle Systemsicherungs- und Datenschutzmaßnahmen un­
+ terlaufen 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
+ Startmenü 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.
+
+
+
+#b("Info-Format")##goalpage("forminf")#
+
+Der Info ist bildschirmorientiert. Beim Aufruf des Infos und nach den meisten Info-Kom­
+mandos werden die zwei 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 durchge­
+führt.
+#a#
+#end#
+
+Mini: nnnn text eeee
+Maxi: xxxx
+
+
+wobei
+
+ #on("b")#nnnn#off("b")# den Miniprozeß bezeichnet, der den Übergang in den Info veranlaßt hat: INTER
+ (Interpreter), LADER, MUELL (Müllabfuhr) oder ARCHIV,
+
+ #on("b")#xxxx#off("b")# den Maxiprozeß (Task) bezeichnet, der gerade durch den Elan-Prozessor
+ bearbeitet wird (xxxx ist code (tasknummer + code ("0"))),
+
+ #on("b")#text#off("b")# den Grund für den Info-Modus anzeigt und
+
+ #on("b")#eeee#off("b")# eine interne, nur den EUMEL-0-Entwickler interessierende Fehlernummer
+ ist.
+
+In der untersten Zeile erscheint (hinter der Angabe des evtl. angezeigten Datenraumes, der
+Adresse und der Länge) 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. (Nur im Miniprozeß
+ INTER.)
+
+'s' Dumps werden auf den Datenraum <zahl> eingestellt (s:=<zahl>). Auch der
+ Realspeicher kann hiermit in verschiedenen Modi eingestellt werden:
+
+ 1s Programmspeicher (absolute Adressen)
+ ffs Tabellenspeicher (relativ zum Tabellenanfang)
+
+'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).
+
+'x' Suchen nach Bytekette:
+
+--> xctext
+--> xhxx 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).
+
+
+'*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 eingetra­
+ gen, auf dem der Cursor gerade steht. Dies funktioniert auch auf beliebigen Da­
+ tenräumen. Info beantragt dann bei der Speicherverwaltung einen Schreibzugriff für
+ die entsprechende Datenraumseite, so daß Änderungen mit der Copy-on-
+ Write-Logik erfolgen, also nur taskspezifisch sind. Für diese Task sind die Ände­
+ rungen allerdings 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ückschreiben 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-Komman­
+ do aufgefaßt, wobei <zahl> auf die aktuelle Adresse gesetzt wird.
+ Somit wird dieser Änderungsmodus üblicherweise durch *return* been­
+ det.
+
+
+
+#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
+implementationsabhängige Konstanten ein. Diese sind hier aufgeführt.
+
+Der Tabellenspeicher der EUMEL-0-Maschine wird relativ zu M0START angelegt. Im Info
+kann der Tabellenspeicher durch die Datenraumangabe ffs adressiert werden, z.B. wird
+durch das Kommando ffs1000p der Anfang der 'ktab' gezeigt.
+
+Ab /1000 liegt die 'ktab'. Sie enthält Informationen, welche Blöcke an welcher Stelle des
+Arbeitsspeichers liegen: In der Kachel mit der Adresse /a000+/200*i befindet sich der
+Inhalt des Blockes, dessen Nummer in <ktab+2*i> steht. Ferner enthält die Tabelle, zu
+welchem Datenraum (drid) und welcher Seite des Datenraums der Inhalt gehört. (Nur
+relevant, wenn die Prozeßnummer <> /ff ist).
+
+ ktab:
+
+ /1000 Blocknummern (je 2 Bytes)
+ /2000 Prozeßnummern (je 1 Byte)
+ /2800 drid's (prozeßspezifisch, je 1 Byte)
+ /3000 Seitennummern (je 2 Bytes)
+ /4000 Steuerbits (je 1 Byte):
+
+ 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.
+
+
+
+/5d50 enthält den 'Laderpool'. Es handelt sich um Blocknummern von zu ladenden
+ Blöcken. Ist der höherwertige Teil der Blocknummer gleich /fd, so ist dies keine
+ Anforderung.
+
+ Blocknummern > /ff00 stehen für Blöcke mit dem Inhalt 512mal /ff und werden
+ nie auf dem Hintergrundmedium gespeichert.
+
+
+
+/0 enthält den DR-Eintrag des drdr (siehe Brikett).
+
+
+
+
+/5c00.../5cff:
+ enthält die Aktivierungstabelle. Ist (/5c00+i)=/01, so ist die Task i aktiv. Hin­
+ weis: /5cff enthält immer /01, ohne daß dieser Zelle eine Task zugeordnet ist.
+
+
+
+#b("Leitblock")##goalpage("pcb")#
+
+Mit dem 'z'-Kommando wird der Leitblock einer Task dargestellt. Die einzelnen Einträge,
+die voneinander durch je 2 Blanks getrennt sind, haben die Form
+ Bezeichnung=Wert
+wobei Wert in hexadezimaler Form angegeben ist. In der folgenden Beschreibung steht x,
+y und z für irgendeine Hexadezimalziffer.
+
+ ic=0xxxxx Der virtuelle Befehlszähler der Task zeigt auf /xxxxx im Datenraum 4
+ dieser Task. Durch die Eingabefolge:
+ 4s<xxxxx>w*return*
+ kann man sich den Code, der ausgeführt werden soll, ansehen.
+
+ flags=xxyy Bit /80 von yy zeigt den Fehlerzustand an.
+ Bit /40 von yy zeigt 'disable stop' (siehe Benutzerhandbuch) an.
+ Bit /10 von yy zeigt vorzeichenlose Arithmetik an (Compilierung).
+
+ lbas=xxxx Die lokale Basis steht auf /1xxxx im Datenraum 4 (Wortadresse).
+
+ pbas=xx Die Paketbasis steht auf /xx00 im Datenraum 4 (Wortadresse).
+
+ hptop=xyz3 Der Arbeitsheap geht von /30000 (Byteadresse!) bis /3xyz0 (Byte­
+ adresse!).
+
+ chan=xx Die Task hängt an Kanal /xx (Terminalnummer).
+ 0 <==> kein Terminal angekoppelt.
+
+ task=xxyy,zzzz Die Tasknummer der betrachteten Task ist /yy. /xx ist die Stations­
+ nummer im EUMEL-Netz, /zzzz ist die Versionsnummer zum
+ Abdichten von 'send'/ 'wait'.
+
+Um den Code, auf den der 'ic' zeigt, zu interpretieren, ziehe man das Brikett zu Rate.
+#page#
+#cc("Anhang B: Einige ","EUMEL-Begriffe")##goalpage("glossar")#
+
+
+#on("bold")#Archiv:#off("bold")#
+
+ Medium (z.B. Diskette, Band, Kassette) zur Speicherung von Datenräumen (Pro­
+ grammen, Daten und Dateien) einer oder mehrerer Tasks außerhalb eines
+ EUMEL-Systems zum Zwecke der Aufbewahrung oder des Datenaustauschs.
+
+ Auch ein ganzer EUMEL-Hintergrund kann (durch 'save system') auf Archiv (z.B. auf
+ eine oder mehrere Disketten) geschrieben werden. Ein solches "Hintergrundarchiv"
+ kann dann zur Erzeugung eines EUMEL-Hintergrundes (im Vortest) dienen.
+
+
+#on("bold")#Archivsystem:#off("bold")#
+
+ Programmsystem zur Übertragung von Datenräumen zwischen Archiv und Hinter­
+ grund.
+
+
+#on("bold")#EUMEL-0 (EUMEL-0-Maschine, Systemkern):#off("bold")#
+
+ Softwareschicht, aufbauend auf die hardwareabhängige Schicht SHard. EUMEL-0 ist
+ nur vom Prozessor, nicht aber von der jeweiligen Rechnerkonfiguration abhängig. Die
+ durch EUMEL-0 definierte Schnittstelle zu höheren (in ELAN implementierten)
+ Schichten ist auf allen EUMEL-Systemen identisch. EUMEL-0 wird auf dem
+ EUMEL-Hintergrundarchiv angeliefert.
+
+
+#on("bold")#Hintergrund (EUMEL-Hintergrund, HG):#off("bold")#
+
+ 1. Medium (z.B. Platte, Diskette, RAM) zur Speicherung von Datenräumen (Pro­
+ grammen, Daten und Dateien) aller Tasks eines EUMEL-Systems;
+ 2. Die Gesamtheit der auf diesem Medium gespeicherten Information.
+
+ Die Bezeichnung "Hintergrund" ist im Zusammenhang mit dem Konzept des im
+ EUMEL realisierten Virtuellen Speichers zu sehen. Der Datentransfer zwischen Hin­
+ tergrund und Arbeitsspeicher (RAM) erfolgt ohne Zutun oder Wissen des EUMEL-
+ Benutzers bzw. der Task, der die Daten gehören.
+
diff --git a/doc/porting-mc68k/1985.11.26/source-disk b/doc/porting-mc68k/1985.11.26/source-disk
new file mode 100644
index 0000000..bf86ccf
--- /dev/null
+++ b/doc/porting-mc68k/1985.11.26/source-disk
@@ -0,0 +1 @@
+porting/portdoc-m68k_eumel-netz-1985-11-26.img
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
diff --git a/doc/programmer-manual/1.8.7/doc/programmierhandbuch.1 b/doc/programmer-manual/1.8.7/doc/programmierhandbuch.1
new file mode 100644
index 0000000..24f2b03
--- /dev/null
+++ b/doc/programmer-manual/1.8.7/doc/programmierhandbuch.1
@@ -0,0 +1,650 @@
+#headandbottom("1","EUMEL-Benutzerhandbuch","TEIL 1 : Einleitung","1")#
+#pagenr("%",1)##setcount(1)##block##pageblock#
+#headeven#
+#center#EUMEL-Benutzerhandbuch
+#center#____________________________________________________________
+
+#end#
+#headodd#
+#center#TEIL 1 : Einleitung
+#center#____________________________________________________________
+
+#end#
+#bottomeven#
+#center#____________________________________________________________
+1 - % #right#GMD
+#end#
+#bottomodd#
+#center#____________________________________________________________
+GMD #rigth#1 - %
+#end#
+
+TEIL 1 : Einleitung
+
+
+1.1 Allgemeines über EUMEL
+
+Dieses Buch bietet eine Übersicht über die Standardprozeduren des Betriebssystem
+EUMEL. Es bietet damit sowohl Hilfestellung für die Benutzung der standardmäßig
+vorhandenen Kommandos als auch für die Programmierung, also die Erweiterung
+dieses Kommandovorrats. Es ist jedoch kein Lehrbuch der Programmierung!
+
+In den ersten drei Kapiteln dieses Programmierhandbuches werden einige Grund­
+begriffe des Systems, die grundlegende Programmiersprache (ELAN) und der
+EUMEL-Editor erläutert.
+
+Das vierte Kapitel bietet eine Übersicht über diejenigen Prozeduren und Operatoren,
+die eher der 'Job-Control-Language' zugerechnet werden können, also häufig im
+Kommandodialog benutzt werden.
+
+Im fünften Teil sind diejenigen Operationen beschrieben, die meistenteils für die
+Programmierung benutzt werden. (Compiler, Operationen auf den elementaren Daten­
+typen, Dateien, Ein- und Ausgabe usw.).
+
+Diese Trennung ist jedoch recht willkürlich, es ist ja gerade eine der wichtigen Eigen­
+schaften dieses Betriebssystems, daß es keine Trennung zwischen der Kommando­
+sprache des Betriebssystems und Programmmiersprache für das System gibt. Jedes
+Systemkommando ist Aufruf einer ELAN Prozedur, jede neue Prozedur stellt eine
+Erweiterung des Kommandovorrats des Systems dar.
+
+Aus Gründen der Übersichtlichkeit der Zusammenstellung ist dieses Buch nicht frei
+von Vorwärtsverweisen!
+
+#page#
+
+1.2 Struktur des Betriebssystems EUMEL
+
+Grundlegend für das Verständnis des Betriebssystems EUMEL ist der Begriff der
+#on("b")#Task#off("b")#. Eine Task kann als theoretisch unendliche Wiederholung eines Systempro­
+gramms der Form:
+
+ 'nimm Kommando entgegen'
+ 'verarbeite Kommando'
+
+aufgefaßt werden. Einige Tasks existieren bereits als Grundstock des Systems,
+weitere werden von Benutzern des Systems erschaffen und dienen als persönliche
+Arbeitsumgebung für den 'Eigentümer'. Eine Task kann als benutzereigener, unab­
+hängiger Computer im Computer betrachtet werden, denn sie kann Kommandos
+entgegennehmen und ausführen und Daten verwalten und aufbewahren.
+
+Eine Task kann neu erzeugt werden, an einen Bildschirm gekoppelt werden und
+beendet werden.
+
+Das Tasksystem ist in einer baumartigen Struktur angeordnet. Außer der Wurzel 'UR'
+hat jede Task einen Vorgänger ('Vater-Task') und möglicherweise Nachfolger
+('Sohn-Tasks').
+
+#on("u")##ib#Task-Organisation#ie##off("u")#
+
+
+ SUPERVISOR
+ -
+ SYSUR
+ ARCHIVE
+ configurator
+ OPERATOR
+ shutup
+
+ UR
+ PUBLIC
+ Benutzertask1
+ Benutzertask2
+ Benutzertask3
+ .....
+
+
+
+Jeder Benutzer arbeitet innerhalb eines EUMEL-Systems, indem er eine Task an
+sein Terminal koppelt und dort Programme aufruft.
+
+Dateien sind grundsätzlich Eigentum einer Task. Es ist grundlegend für das Verständ­
+nis des Betriebssystems EUMEL, die Beziehung zwischen Tasks und Dateien zu
+erkennen.
+
+Eine Task ist ein Prozeß, der gegebenenfalls Dateien besitzt. Dateien können nur in
+einer Task existieren. Um eine Datei einer anderen Task zur Verfügung zu stellen,
+wird eine Kopie der Datei an die andere Task geschickt, die sendende Task ist da­
+nach Eigentümer des 'Originals', die empfangende Task Eigentümer der 'Kopie'.
+
+Soll eine Hierarchie von Dateien aufgebaut werden, so ist sie über eine Hierarchie
+von Tasks zu realisieren, da in einer Task alle Dateien gleichberechtigt sind.
+
+Bis zu dieser Stelle war stets von Dateien die Rede. Dateien sind jedoch ein Spezial­
+fall der grundlegenderen Struktur des Datenraumes.
+
+Ein #ib#Datenraum#ie# ist ein allgemeiner Datenbehälter. Ein Datenraum kann beliebige
+Daten aufnehmen und erlaubt direkten Zugriff auf diese Daten. Die Struktur der Daten
+im Datenraum unterscheidet sich nicht von der Struktur der Programmdaten. Der
+'innere Datentyp' eines Datenraums wird vom Programmierer festgelegt.
+
+Vorgeprägt vom System gibt es Textdateien, jeder andere Datentyp muß vom Pro­
+grammierer geprägt werden, um so Dateien erzeugen zu können, die Objekte eben
+dieses neuen Typs enthalten.
+#page#
+
+
+1.3 Eigenschaften des Betriebssystems
+
+Der erste Entwurf des Mikroprozessor-Betriebssystems EUMEL (#on("b")#E#off("b")#xtendable multi
+#on("b")#U#off("b")#ser #on("b")#M#off("b")#icroprozessor #on("b")#EL#off("b")#AN system) entstand 1979 mit dem Anspruch, auf Mikrocom­
+putern den Anwendern Hilfsmittel und Unterstützungen zu bieten, wie sie sonst nur
+auf Großrechnern zur Verfügung gestellt werden.
+
+Aspekte, die EUMEL von anderen Betriebssystemen für Mikrocomputer unterscheiden,
+sind:
+
+- Hardwareunabhängigkeit
+- Multitaskingkonzept
+- Multiuserbetrieb
+- Erweiterbarkeit
+- virtuelle Speicherverwaltung
+- Datensicherheit
+
+
+
+#on("u")##on("b")#Das EUMEL-Schichtenmodell#off("b")##off("u")#
+
+Die Hardwareunabhängigkeit des Betriebssystems EUMEL begründet sich in seinem
+Aufbau aus Schichten (sogenannten virtuellen Maschinen), die einen klar definierten
+Leistungsumfang haben.
+
+#center#beliebige Anwendungen
+#center#Textverarbeitung, Datenbanken etc.
+
+#center#Systemdienste: Monitor, Dateiverwaltung, Editor
+#center#Task-System
+#center#Standardpakete (BOOL, INT, REAL, TEXT)
+#center#ELAN-Compiler
+
+#center#EUMEL0
+#center#(virtueller Prozessor mit eigenem Befehlssatz)
+
+#center#SHard (Gerätetreiber)
+
+#center#Hardware
+
+
+Jede Schicht erwartet und erhält von ihren Nachbarn wohldefinierte Eingaben und gibt
+wohldefinierte Ausgaben weiter. Änderungen in einer Schicht müssen also in den
+angrenzenden Schichten beachtet werden, aber nicht in allen Teilen des Systems.
+
+Um EUMEL auf Rechner mit einem neuen Prozessortyp zu portieren, wird zunächst
+eine auf die Eigenheiten des Prozessors abgestimmte EUMEL0-Maschine entworfen
+und eine Hardwareanpassung (#ib#SHard#ie# : Software/Hardware-Interface) für einen
+Rechner mit diesem Prozessor hergestellt. Alle höheren Schichten des Systems
+bleiben unberührt. Weitere mit diesem Prozessortyp ausgestattete Rechner können mit
+EUMEL betrieben werden, indem ein SHard für dieses Rechnermodell geschrieben
+wird.
+
+Aus Benutzersicht ist wichtig, daß dadurch jegliche Software, die auf irgendeinem
+Rechner unter EUMEL verfügbar ist, auf jedem anderen Rechner, für den eine
+EUMEL Portierung existiert, lauffähig ist und gleiches Verhalten zeigt. Eine Vernet­
+zung beliebiger Rechner, auf die EUMEL portiert ist, ist problemlos möglich.
+
+Desweiteren ist für den Benutzer des Systems von Bedeutung, daß er von der hard­
+warenahen Schicht entfernt ist. Weder die Programmiersprache noch irgendwelche
+speziellen Systemfunktionen gewähren direkten Zugriff auf den Speicher oder Regi­
+sterinhalte. Diese Tatsache hat weitreichende Folgen in Hinsicht auf Datenschutz und
+Systemsicherheit.
+
+
+
+
+Multi-Tasking-/Multi-User-Betrieb
+Wie einleitend dargestellt, besteht ein EUMEL-System aus diversen Tasks. Durch
+eine Aufteilung der Prozessorzeit in Zeitscheiben ist eine (quasi) parallele Bedienung
+mehrerer Tasks möglich.
+
+Die multi-user-Fähigkeit des Betriebssystems wird durch den Anschluß mehrerer
+Bildschirmarbeitsplätze (Terminals) an V.24 Schnittstellen des Rechners erreicht.
+Dabei wird jeder Schnittstelle eine sogenannte Kanalnummer zugeordnet. Jeder
+Benutzer kann seine Task dann an einen Kanal (=Terminal) koppeln und an diesem
+Terminal gleichzeitig mit anderen Benutzern arbeiten.
+
+
+
+
+Prozeßkommunikation und Netzwerkfähigkeit
+Grundlage der Kommunikation ist die 'Manager-Eigenschaft' von Tasks. Eine Task
+ist 'Manager', wenn sie Aufträge anderer Tasks annehmen und ausführen kann.
+Insbesondere kann ein Manager veranlaßt werden, eine an ihn geschickte Datei anzu­
+nehmen, bzw. eine ihm gehörende Datei an die fordernde Task zu schicken.
+
+Derartige Kommunikationslinien verlaufen normalerweise in der Baumstruktur des
+Systems: z.B. ist die Task 'PUBLIC' (vergl. Seite 2) grundsätzlich Manager-Task.
+Eine unterhalb von PUBLIC liegende Task kann eine Datei an PUBLIC senden, bzw.
+von PUBLIC holen.
+
+Es ist auch möglich, eine Task für den Zugriff beliebiger anderer Tasks zu öffnen und
+somit beliebige Kommunikationspfade aufzubauen. Prinzipiell ist damit auch schon der
+Aufbau eines Netzwerkes beschrieben, denn sendende und empfangende Tasks
+können sich auf verschiedenen Rechnern befinden.
+
+Durch selbst erstellte Programme kann der Eigentümer einer 'Manager-Task' die
+Reaktion dieser Task auf einen Auftrag von außen bestimmen. Beispielsweise kann
+ein Manager derart programmiert werden, daß er nur Dateien empfängt und ausdruckt,
+aber niemals Dateien verschickt (Spool-Task).
+
+
+
+Erweiterbarkeit
+Die Programmiersprache ELAN ist im EUMEL-System gleichzeitig Programmier-
+und System-Kommandosprache (JCL), denn jedes Kommando ist Aufruf einer
+ELAN-Prozedur und jede vom Benutzer geschriebene ELAN-Prozedur erweitert
+den Kommandovorrat des Systems.
+
+Da alle EUMEL-Werkzeuge (einschließlich Editor) selbst ELAN-Programme sind,
+kann das System vom Benutzer selbst durch Hinzufügen eigener ELAN-Programme
+oder Programmpakete beliebig erweitert werden. Dabei können die bereits implemen­
+tierten Systemteile (z.B. die Fenstertechnik des Editors) genutzt werden.
+
+Ein Benutzer muß, um alle Möglichkeiten vom EUMEL zu nutzen, nur eine Sprache
+lernen und nicht - wie bei anderen Betriebssystemen - zwei unterschiedliche, eine
+Kommando- und eine Programmiersprache.
+
+ELAN selbst ist eine PASCAL-ähnliche Programmiersprache, die mit Hilfe der
+schrittweisen Verfeinerung (Refinement-Konzept) die Top-Down-Programmierung
+unterstützt. Das Paketkonzept, das der Modularisierung dient, und die freie Wahl von
+Bezeichnernamen sind Voraussetzung für übersichtliche und effiziente Programmie­
+rung.
+
+
+
+
+Virtuelle Speicherverwaltung
+Im EUMEL-System wird der Hauptspeicherplatz nach dem #on("b")#Demand-Paging-Prinzip#off("b")#
+verwaltet. Daten und Programme werden dazu in Seiten von 512 Byte aufgeteilt. Nur
+diejenigen Seiten, die wirklich benötigt werden, werden vom Hintergrundspeicher
+(Platte) in den Hauptspeicher geholt. Damit ist für den Benutzer bezüglich seiner
+Programm- bzw. Dateigrößen nicht mehr der Hauptspeicher, sondern die Hinter­
+grundkapazität von Bedeutung. Die Durchsatzgeschwindigkeit (Performance) ist
+abhängig von der Größe des RAM-Speichers und der Zugriffsgeschwindigkeit des
+Hintergrundmediums. Das Demand-Paging-Verfahren ist Grundlage für den
+Multi-User-Betrieb, wobei der Hauptspeicherplatz möglichst effizient zu nutzen und
+kein Benutzer zu benachteiligen ist.
+
+Beim Duplizieren eines Datenraumes wird im EUMEL-System lediglich eine logische,
+keine physische Kopie erzeugt. Zwei Seiten (zweier Datenräume) heißen dann gekop­
+pelt (geshared), wenn beide Seiten physisch demselben Block zugeordnet sind. Erst
+bei einem Schreibzugriff werden die Seiten entkoppelt (entshared) und tatsächlich
+physisch kopiert. Daher der Name "#on("b")#copy-on-write#off("b")#".
+
+Dieses Prinzip wird natürlich auch systemintern angewandt. Beispielsweise erbt eine
+Sohn-Task den Kommandovorrat der Vater-Task, indem der Standard-Datenraum,
+der die vorübersetzten ELAN-Prozeduren enthält, in der beschriebenen Weise kopiert
+wird. Prozeduren, die später hinzugefügt werden, werden natürlich nicht vererbt, da
+die Standard-Datenräume dann entkoppelt werden.
+
+
+
+
+Datensicherheit
+Störungen (inklusive Stromausfall) werden systemseitig durch eine automatische
+#on("b")#Fixpoint-Rerun-Logik#off("b")# aufgefangen, indem zum Zeitpunkt eines Fixpunkts der Inhalt
+des RAM Speichers, der seit dem letzten #ib#Fixpunkt#ie# verändert wurde auf den
+permanenten Speicher (Festplatte) geschrieben wird. Somit kann nach einer Störung
+immer auf den Systemzustand des letzten Fixpunktes aufgesetzt werden und die
+Datenverluste halten sich in erträglichen Grenzen.
+
+Der Zeitraum zwischen zwei Fixpunkten beträgt standardmäßig 15 Minuten, kann aber
+vom Benutzer anders eingestellt werden.
+
+Auch bei dieser Sicherung wird das Copy-on-write-Prinzip angewendet, so daß
+Platz- und Zeitaufwand gering sind und den normalen Ablauf nicht stören.
+
+#page#
+
+1.4 Wichtige Begriffe
+
+- #on("b")##ib#archive#ie##off("b")#. Spezielle Task zur Verwaltung des Diskettenlaufwerks. Da für die
+ längerfristige Datenhaltung und zur zusätzlichen Datensicherung Dateien auf
+ Disketten geschrieben werden, besitzt das EUMEL-System für diese Aufgabe
+ eine besondere Task, die die Bedienung vereinfacht und exklusiven Zugriff auf das
+ Laufwerk garantiert.
+
+- #on("b")##ib#configurator#ie##off("b")#. Besondere Task im Systemzweig des EUMEL-Systems. In
+ dieser Task ist die #ib#Konfiguration#ie# von Kanälen möglich, d.h. Kanal und
+ angeschlossenenes Gerät werden aufeinander abgestimmt.
+
+- #on("b")##ib#editor#ie##off("b")#. Programm zur Dateibearbeitung am Bildschirm. Das Programm wird
+ durch das ( Monitor- ) Kommando 'edit' und die Eingabe des Namens der ge­
+ wünschten Datei als Parameter gestartet.
+
+ Da ein Bildschirm normalerweise auf 80 Zeichen Zeilenbreite und 24 Zeilen be­
+ schränkt ist, kann der Editor als Fenster betrachtet werden, das über die mögli­
+ cherweise weitaus größere Datei bewegt wird und durch das der betrachtete Aus­
+ schnitt der Datei bearbeitet werden kann.
+
+- #on("b")##ib#manager task#ie##off("b")#. Task, die Aufträge von anderen Tasks entgegennehmen und
+ ausführen #on("u")#kann#off("u")#. Beispielsweise ist die Verwaltung von Dateien, die mehreren
+ Benutzern (= anderen Tasks) zugänglich sein sollen, eine typische Aufgabe für
+ einen Manager.
+
+- #on("b")##ib#Monitor#ie##off("b")#. Der Empfänger von Kommandos innerhalb einer Task ist der Monitor. Der
+ Monitor ist sichtbar durch eine Zeile, in der 'gib kommando' steht. In diese Zeile
+ werden #ib#Kommando#ie#s und erforderliche Parameter eingegeben.
+
+- #on("b")##ib#Supervisor#ie##off("b")#. Spezielle Task zur Überwachung eines EUMEL-Systems. Ein
+ Benutzer kann durch die Supervisor-Kommandos Leistungen von dieser Task
+ fordern: neue Task einrichten, Task wiederaufnehmen und diverse Informationen.
+
+- #on("b")##ib#Task#ie##off("b")#. Beliebig langlebiger Prozeß im EUMEL-System, der die Arbeits­
+ umgebung für Benutzer bildet. Jede Task besitzt einen #ib#Standard-Datenraum#ie#, der
+ Code und Compilertabellen der Task enthält und kann weitere Datenräume
+ (Dateien) besitzen.
+
+#page#
+
+1.5 Die Notation in diesem Buch
+
+Beachten Sie bitte folgende Regeln der Aufschreibung:
+
+- Funktionstasten werden ebenso wie besondere Tastenkombinationen explizit als
+ Tasten dargestellt:
+
+ <SV> <ESC> <e>
+
+
+- Alles, was Sie am Bildschirm Ihres Rechners schreiben oder lesen sollen, ist in
+ Textbereiche, die einen Bildschirm darstellen, eingefaßt.
+
+ Beispiel:
+
+____________________________________________________________________________
+ gib kommando:
+ edit ("mein programm")
+
+____________________________________________________________________________
+
+
+- Innerhalb des Handbuchs sind in der Aufschreibung die Konventionen der Pro­
+ grammiersprache ELAN berücksichtigt. Dabei sind folgende Besonderheiten zu
+ beachten:
+
+ 1) Kommandos werden grundsätzlich klein geschrieben.
+
+ 2) Dateinamen u.ä. sind Textdenoter und werden somit in Klammern und Anfüh­
+ rungsstriche gesetzt. In diesem Buch steht an den Stellen, wo ein Dateiname
+ auftaucht #on("i")# 'dateiname' #off("i")#; den Namen, den Sie tatsächlich verwenden, können
+ Sie frei wählen.
+
+ 3) Falls besondere Begriffe oder Beispiele innerhalb eines normalen Textes
+ auftreten, werden sie in einfache Anführungsstriche gesetzt.
+
+
+#page#
+
+1.6 Die Funktionstasten des EUMEL-Systems
+
+Die Lage der EUMEL-Funktionstasten entnehmen Sie bitte der speziellen Installa­
+tionsanleitung zu dem von Ihnen benutzten Gerät. #l pos (0.0)##l pos(4.0)#
+
+
+<v> <^> <>> <<> Positionierungstasten
+#table#
+
+<SHIFT> Umschalttaste
+
+<CR> Eingabe-/ Absatztaste
+
+<ESC> Kommandotaste
+
+<SV> Supervisortaste
+
+<HOP> Verstärkertaste
+
+<RUBOUT> Löschtaste
+
+<RUBIN> Einfügetaste
+
+<TAB> Tabulatortaste
+
+<MARK> Markiertaste
+
+<STOP> Stoptaste
+
+<WEITER> Weitertaste
+#tableend##clear pos#
+
+Weitere Informationen hierzu finden Sie in der Installationsanleitung zu dem von Ihnen
+benutzten Rechner oder Terminal.
+#page#
+
+1.7 Eine Beispielsitzung
+
+Im Folgenden wird eine Beispielsitzung skizziert, in der ein ELAN-Programm erstellt
+und getestet wird.
+
+ <SV> SUPERVISOR aufrufen
+
+
+
+____________________________________________________________________________
+
+ Terminal 2
+
+
+ EUMEL Version 1.8/M
+
+
+ gib supervisor kommando:
+ begin("meine erste Task")
+
+
+
+ ESC ? --> help
+ ESC b --> begin("") ESC h --> halt
+ ESC c --> continue("") ESC s --> storage info
+ ESC q --> break ESC t --> task info
+
+____________________________________________________________________________
+
+
+
+
+Durch das Kommando 'begin ("meine erste Task")', welches durch <CR> abgeschlos­
+sen werden muß, wird eine Task mit dem Namen 'meine erste Task' im Benutzer­
+zweig, also unterhalb von 'PUBLIC' angelegt. Würde diese Task bereits existieren, so
+könnten Sie sie mit 'continue ("meine erste Task")' an das Terminal holen.
+
+____________________________________________________________________________
+
+ gib kommando :
+ edit ("mein erstes Programm")
+
+____________________________________________________________________________
+
+
+In der Task eröffnen Sie eine Datei mit dem Kommando 'edit ("dateiname")'.
+
+
+____________________________________________________________________________
+
+ gib kommando :
+ edit ("mein erstes Programm")
+ "mein erstes Programm" neu einrichten (j/n) ? j
+
+____________________________________________________________________________
+
+
+Falls diese Datei neu ist, erfolgt eine Kontrollfrage (zur Kontrolle der gewünschten
+Schreibweise des Dateinamens), die Sie durch <j> bejahen.
+
+
+____________________________________________________________________________
+ ............ mein erstes Programm ............... Zeile 1 #markon#
+_
+____________________________________________________________________________
+
+
+
+
+
+
+In die noch leere Datei tippen Sie nun den Programmtext ein.
+
+
+____________________________________________________________________________
+ ............ mein erstes Programm ............... Zeile 1
+ _INT PROC ggt (INT CONST a, b):
+ INT VAR b kopie :: abs (b), a kopie :: abs (a);
+ WHILE b kopie <> 0 REPEAT
+ INT VAR rest := a kopie MOD b kopie;
+ a kopie := b kopie;
+ b kopie := rest
+ END REPEAT;
+ a kopie
+ END PROC gt;
+
+ REP
+ lies 2 zahlen ein;
+ gib groessten gemeinsamen teiler aus
+ UNTIL no ("weitertesten") PER.
+
+ lies 2 zahlen ein:
+ line; put ("2 Zahlen eingeben:");
+ INT VAR a, b;
+ get (a); get (b).
+
+ gib groessten gemeinsamen teiler aus:
+ put ("der größte gemeinsame Teiler von");
+ put (a); put ("und"); put (b); put ("ist"); put (ggt (a,b));
+ line.
+
+____________________________________________________________________________
+
+
+In dem Programmbeispiel wird ein Prozedur 'ggt' definiert, die den größten gemein­
+samen Teiler zweier Zahlen bestimmt. Die Prozedur soll für verschiedene Beispiele
+getestet werden; dies geschieht in dem Hauptprogramm, das solange Zahlen einliest
+und den größten gemeinsamen Teiler ausgibt, bis der Benutzer auf die Frage 'weiter­
+testen (j/n) ?' mit <n> antwortet.
+
+Haben Sie das Programm eingegeben, so können Sie die Bearbeitung dieser Pro­
+grammdatei durch Drücken der Tasten <ESC> <q> (nacheinander!) beenden.
+
+
+____________________________________________________________________________
+
+ gib kommando :
+ run ("mein erstes Programm")
+
+____________________________________________________________________________
+
+
+Um Ihr Programm zu übersetzen und auszuführen, geben Sie das Kommando
+'run ("dateiname")'.
+
+Der Verlauf der Übersetzung, die zwei Läufe über das Programm erfordert, ist am
+Zähler, der an der linken Seite des Bildschirms ausgegeben wird, zu erkennen.
+
+Werden beim Übersetzen des Programms Fehler entdeckt, so werden diese im 'note­
+book' parallel zur Programmdatei gezeigt. In dem Beispielprogramm wurde ein
+Schreibfehler in Zeile 9 gemacht.
+
+
+____________________________________________________________________________
+ ............ mein erstes Programm ............... Zeile 1
+ _INT PROC ggt (INT CONST a, b):
+ INT VAR b kopie :: abs (b), a kopie :: abs (a);
+ WHILE b kopie <> 0 REPEAT
+ INT VAR rest := a kopie MOD b kopie;
+ a kopie := b kopie;
+ b kopie := rest
+ END REPEAT;
+ a kopie
+ END PROC gt;
+
+ REP
+ .................. notebook ..................... Zeile 1 #markon#
+ Zeile 9 FEHLER bei >> gt <<
+ ist nicht der PROC Name
+
+
+____________________________________________________________________________
+
+
+
+Diesen Fehler müssen Sie nun verbessern.
+
+____________________________________________________________________________
+ ............ mein erstes Programm ............... Zeile 9
+ INT PROC ggt (INT CONST a, b):
+ INT VAR b kopie :: abs (b), a kopie :: abs (a);
+ WHILE b kopie <> 0 REPEAT
+ INT VAR rest := a kopie MOD b kopie;
+ a kopie := b kopie;
+ b kopie := rest
+ END REPEAT;
+ a kopie
+ END PROC ggt;_
+
+ REP
+ .................. notebook ..................... Zeile 1
+ Zeile 9 FEHLER bei >> gt <<
+ ist nicht der PROC Name
+
+____________________________________________________________________________
+
+
+
+
+Haben Sie das Programm korrigiert, so können Sie die Datei durch Drücken der
+Tasten <ESC> <q> (nacheinander!) wieder verlassen.
+
+
+____________________________________________________________________________
+
+ gib kommando :
+ run ("mein erstes Programm")
+
+____________________________________________________________________________
+
+
+Nach Eingabe von <R> wird das Programm erneut übersetzt.
+
+
+____________________________________________________________________________
+
+ Keine Fehler gefunden, 136 B Code, 82 B Paketdaten generiert
+
+
+ ******* ENDE DER UEBERSETZUNG *******
+
+
+ 2 Zahlen eingeben: _
+
+____________________________________________________________________________
+
+
+Das Programm war jetzt fehlerfrei. Nach der Übersetzung wurde die Ausführung
+gestartet. Nun können Beispiele getestet werden.
+
+____________________________________________________________________________
+
+ 2 Zahlen eingeben: 125 250
+ der größte gemeinsame Teiler von 125 und 225 ist 25
+ weitertesten (j/n) ?
+
+____________________________________________________________________________
+
+
+Beantwortet man die Frage mit <n>, so wird die Ausführung des Programms beendet.
+
+
+____________________________________________________________________________
+
+ gib kommando :
+
+____________________________________________________________________________
+
+
+Um die Arbeit in der Task zu beenden, geben Sie auch an dieser Stelle <ESC> <q>
+(nacheinander!) ein.
+
+Nach Verlassen der Task ist wiederum die EUMEL-Tapete auf dem Bildschirm. Jede
+weitere Aktion wird wiederum von hier aus durch <SV> begonnen. Insbesondere vor
+dem #ib#Ausschalten des Geräts#ie# muß nach <SV> eine Task des priviliegierten System­
+zweigs (oft: '#ib#shutup#ie#') mit <ESC> <c> an das Terminal gekoppelt werden, in der das
+Kommando 'shutup' gegeben wird.
+
diff --git a/doc/programmer-manual/1.8.7/doc/programmierhandbuch.2a b/doc/programmer-manual/1.8.7/doc/programmierhandbuch.2a
new file mode 100644
index 0000000..a204091
--- /dev/null
+++ b/doc/programmer-manual/1.8.7/doc/programmierhandbuch.2a
@@ -0,0 +1,1845 @@
+#headandbottom("1","EUMEL-Benutzerhandbuch","TEIL 2 : ELAN","2")#
+#pagenr("%",1)##setcount(1)##block##pageblock#
+#headeven#
+#center#EUMEL-Benutzerhandbuch
+#center#____________________________________________________________
+
+#end#
+#headodd#
+#center#TEIL 2 : ELAN
+#center#____________________________________________________________
+
+#end#
+#bottomeven#
+#center#____________________________________________________________
+2 - % #right#GMD
+#end#
+#bottomodd#
+#center#____________________________________________________________
+GMD #right# 2 - %
+#end#
+
+TEIL 2: ELAN
+
+2.1 Besondere Eigenschaften von ELAN
+
+Kerneigenschaften von ELAN sind das #ib#Paketkonzept#ie# und die Methode des
+#ib#Refinements#ie#.
+
+#on("b")#Paketkonzept:#off("b")#
+ELAN bietet die Möglichkeit, neue Datentypen sowie Prozeduren und Operatoren auf
+diesen Datentypen zu definieren. Eine solche Definition von Algorithmen und Daten­
+typen kann zu einer logischen Einheit, einem Paket, zusammengefaßt werden. Pakete
+können in einer Task vorübersetzt werden und erweitern damit automatisch den
+Sprachumfang.
+
+#on("b")#Methode des Refinements:#off("b")#
+Die Methode des Refinements erlaubt das schrittweise Herleiten von Problemlösungen
+von der jeweils geeigneten Terminologie herunter zu den von ELAN standardmäßig
+angebotenen Sprachelementen. Durch diese Vorgehensweise wird in äußerst starkem
+Maße ein strukturierter Programmentwurf gemäß dem Top-Down-Prinzip gefördert.
+
+Die Programmiersprache ELAN wird im EUMEL-System zu folgenden Zwecken
+eingesetzt:
+
+- Systemimplementationssprache
+- Kommandosprache
+- Anwenderprogrammiersprache
+#page#
+
+2.2 Lexikalische Elemente
+
+Unter lexikalischen Elementen einer Programmiersprache versteht man die Elemente,
+in denen ein Programm notiert wird.
+
+In ELAN sind dies:
+
+- Schlüsselwörter
+- Bezeichner
+- Sonderzeichen
+- Kommentare
+
+
+
+
+2.2.1 Schlüsselwörter
+
+Einige Wörter haben in ELAN eine feste Bedeutung und können somit nicht frei
+gewählt werden. Solche Wörter werden im EUMEL-System in Großbuchstaben
+geschrieben, Leerzeichen dürfen nicht enthalten sein.
+
+Beispiele:
+
+
+VAR
+INT
+WHILE
+
+
+Wie später beschrieben wird, gibt es in ELAN auch die Möglichkeit, neue Schlüssel­
+wörter einzuführen.
+
+
+#page#
+
+2.2.2 Bezeichner
+
+Bezeichner oder Namen werden benutzt, um Objekte in einem Programmtext zu
+benennen und zu identifizieren (z.B: Variablennamen, Prozedurnamen).
+
+Namen werden in ELAN folgendermaßen formuliert:
+
+Das erste Zeichen eines Namens muß immer ein Kleinbuchstabe sein. Danach dürfen
+bis zu 254 Kleinbuchstaben, aber auch Ziffern folgen. Zur besseren Lesbarkeit können
+Leerzeichen in einem Namen erscheinen, die aber nicht zum Namen zählen. Sonder­
+zeichen sind in Namen nicht erlaubt.
+
+Beispiele für #on("b")#korrekte#off("b")# Bezeichner:
+
+
+das ist ein langer name
+x koordinate
+nr 1
+
+
+
+Beispiele für #on("b")#falsche#off("b")# Bezeichner:
+
+
+x*1
+1 exemplar
+Nr 1
+#page#
+
+2.2.3 Sonderzeichen
+
+Sonderzeichen sind Zeichen, die weder Klein- oder Großbuchstaben, noch Ziffern
+sind. Sie werden in ELAN als Trennzeichen oder als Operatoren benutzt.
+
+In ELAN gibt es folgende Trennungszeichen:
+
+- das Semikolon (';') trennt Anweisungen
+- der Doppelpunkt (':') trennt Definiertes und Definition
+- der Punkt ('.') wird als Endezeichen für bestimmte Programmabschnitte, als Dezi­
+ malpunkt und als Selektor-Zeichen für Datenstrukturen benutzt
+- das Komma (',') trennt Parameter
+- Klammernpaare ('(', ')') werden zum Einklammern von Parameterlisten oder Teil­
+ ausdrücken benutzt
+- mit Anführungszeichen ('"') werden Text-Denoter umrahmt
+- eckige Klammernpaare ('[', ']') werden zur Subskription benutzt.
+
+
+Als Operatornamen sind folgende Sonderzeichen erlaubt:
+
+- ein Sonderzeichen, sofern es nicht als Trennzeichen benutzt wird:
+ ! $ % & ' * + - / < = > ? § ^ ' ~
+- eine Kombination von zwei Sonderzeichen. Diese Kombination muß jedoch bereits
+ in ELAN existieren:
+ := <= >= <> **
+
+#page#
+
+2.2.4 Kommentare
+
+Kommentare dienen ausschließlich der Dokumentation eines Programms. Sie werden
+vom Compiler überlesen und haben somit keinen Einfluß auf die Ausführung eines
+Programms. Sie dürfen an beliebigen Stellen eines Programmtextes geschrieben
+werden, jedoch nicht innerhalb von Schlüsselwörtern und Namen. Ein Kommentar darf
+über mehrere Zeilen gehen. In ELAN sind Kommentare nur in wenigen Fällen notwen­
+dig, da Programme durch andere Mittel gut lesbar geschrieben werden können.
+
+Ein Kommentar in ELAN wird durch Kommentarklammern eingeschlossen. Es gibt
+folgende Formen von Kommentarklammern:
+
+(* Kommentar *)
+{ Kommentar }
+\#( Kommentar )#
+
+Die letzte Version '\#( Kommentar )\#' wird im EUMEL-System nicht
+unterstützt; statt dessen gibt es noch folgende Möglichkeit:
+
+\# Kommentar \#
+
+Da bei der Kommentarkennzeichnung mit \# für Kommentaranfang und -ende das
+gleiche Zeichen benutzt wird, ist eine Schachtelung hier nicht möglich.
+#page#
+
+2.3 Datenobjekte
+
+Eine Klasse von Objekten mit gleichen Eigenschaften wird in Programmiersprachen
+Datentyp genannt. Dabei hat ein Datentyp immer einen Namen, der die Klasse von
+Objekten sinnvoll kennzeichnet. Als ein Datenobjekt wird ein Exemplar eines Daten­
+typs (also ein spezielles Objekt einer Klasse) bezeichnet.
+
+Datentypen sind in ELAN ein zentrales Konzept. Jedes der in einem ELAN-
+Programm verwandten Datenobjekte hat einen Datentyp; somit kann man Datentypen
+auch als Eigenschaften von Datenobjekten ansehen. Für jeden Datentyp sind nur
+spezielle Operationen sinnvoll. Man kann nun Compilern die Aufgabe überlassen zu
+überprüfen, ob stets die richtige Operation auf einen Datentyp angewandt wird.
+
+
+
+2.3.1 Elementare Datentypen
+
+Einige Datentypen spielen bei der Programmierung eine besondere Rolle, weil sie
+häufig benötigt werden.
+
+In ELAN sind das die Datentypen für
+
+- ganze Zahlen (INT)
+- reelle Zahlen (REAL)
+- Zeichen und Zeichenfolgen (TEXT)
+- Wahrheitswerte (BOOL).
+
+Diese Datentypen sind von der Sprache ELAN vorgegeben und werden elementare
+Datentypen genannt. Für effiziente Rechnungen mit elementaren Datentypen gibt es
+in den meisten Rechnern spezielle Schaltungen, so daß die Hervorhebung und be­
+sondere Rolle, die sie in Programmiersprachen spielen, gerechtfertigt ist. Zudem hat
+man Werte-Darstellungen (Denoter) innerhalb von Programmen für die elementaren
+Datentypen vorgesehen.
+
+
+
+2.3.1.1 Denoter für elementare Datentypen
+
+Die Darstellung eines Werts in einem Rechner zur Laufzeit eines Programms wird
+Repräsentation genannt. Wenn es eindeutig ist, daß es sich nur um die Repräsenta­
+tion im Rechner handelt, spricht man kurz von Werten. Um mit Objekten elementarer
+Datentypen arbeiten zu können, muß es in einem Programm die Möglichkeit geben,
+Werte eines Datentyps zu bezeichnen (denotieren). Die Werte-Darstellungen, die in
+ELAN Denoter genannt werden, sind für jeden Datentyp unterschiedlich. Wie bereits
+erwähnt, haben alle Datenobjekte in ELAN (also auch Denoter) nur einen - vom
+Compiler feststellbaren - Datentyp. Aus der Form eines Denoters ist also der Daten­
+typ erkennbar:
+
+
+
+INT-Denoter:
+Sie bestehen aus einer Aneinanderreihung von Ziffern.
+
+Beispiele:
+
+
+17
+007
+32767
+0
+
+
+Führende Nullen spielen bei der Bildung des Wertes keine Rolle (sie werden vom
+ELAN-Compiler überlesen). Negative INT-Denoter gibt es nicht. Negative Werte
+werden durch eine Aufeinanderfolge des monadischen Operators '-' (siehe 2.4.1.1)
+und eines INT- Denoters realisiert.
+
+
+REAL-Denoter:
+Hier gibt es zwei Formen:
+Die erste besteht aus zwei INT-Denotern, die durch einen Dezimalpunkt getrennt
+werden.
+
+Beispiele:
+
+
+0.314159
+17.28
+
+
+Der Dezimalpunkt wird wie ein Komma in der deutschen Schreibweise benutzt. Nega­
+tive REAL-Denoter gibt es wiederum nicht.
+
+Die zweite Form wird als "wissenschaftliche Notation" bezeichnet. Sie findet dann
+Verwendung, wenn sehr große Zahlen oder Zahlen, die nahe bei Null liegen, darge­
+stellt werden müssen.
+
+Beispiele:
+
+
+3.0 e5
+3.0e-5
+
+
+Der INT-Denoter hinter dem Buchstaben #on("b")#e#off("b")# gibt an, wie viele Stellen der Dezimal­
+punkt nach rechts (positive Werte) bzw. nach links (negative Werte) zu verschieben
+ist. Dieser Wert wird Exponent und der Teil vor dem Buchstaben #on("b")#e#off("b")# Mantisse genannt.
+
+
+TEXT-Denoter:
+Sie werden in Anführungszeichen eingeschlossen.
+
+Beispiele:
+
+
+"Das ist ein TEXT-Denoter"
+"Jetzt ein TEXT-Denoter ohne ein Zeichen: ein leerer Text"
+""
+
+
+Zu beachten ist, daß das Leerzeichen ebenfalls ein Zeichen ist. Soll ein Anführungs­
+zeichen in einem TEXT erscheinen (also gerade das Zeichen, welches einen Denoter
+beendet), so muß es doppelt geschrieben werden.
+
+Beispiele:
+
+
+"Ein TEXT mit dem ""-Zeichen"
+"Ein TEXT-Denoter nur mit dem ""-Zeichen:"
+""""
+
+
+Manchmal sollen Zeichen in einem TEXT-Denoter enthalten sein, die auf dem
+Eingabegerät nicht zur Verfügung stehen. In diesem Fall kann der Code-Wert des
+Zeichens angegeben werden.
+
+Beispiel:
+
+
+"da"251""
+
+
+ist gleichbedeutend mit "daß". Der Code-Wert eines Zeichens ergibt sich aus der
+EUMEL-Code-Tabelle (siehe 5.2.4.1), in der jedem Zeichen eine ganze Zahl zuge­
+ordnet ist.
+
+
+BOOL-Denoter:
+Es gibt nur zwei BOOL-Denoter:
+TRUE für "wahr" und FALSE für "falsch".
+
+
+
+2.3.1.2 LET-Konstrukt für Denoter
+
+Neben der Funktion der Abkürzung von Datentypen (siehe 2.6.3) kann das LET-
+Konstrukt auch für die Namensgebung für Denoter verwandt werden.
+
+Die LET-Vereinbarung sieht folgendermaßen aus:
+
+
+#on("i")##on("b")#LET#off("i")##off("b")# Name #on("i")##on("b")#=#off("i")##off("b")# Denoter
+
+
+Mehrere Namensgebungen können durch Komma getrennt werden.
+
+
+____________________________________________________________________________
+ .......................... Beispiele: .........................
+ LET anzahl = 27;
+ LET pi = 3.14159,
+ blank = " ";
+____________________________________________________________________________
+
+
+Der Einsatz von LET-Namen für Denoter hat zwei Vorteile:
+
+- feste Werte im Programm sind leicht zu ändern, da nur an einer Stelle des Pro­
+ gramms der Denoter geändert werden muß
+ (z.B.: In Vereinbarungen von Reihungen (siehe 2.6.1) können LET-Denoter, im
+ Gegensatz zu Konstanten, als Obergrenze angegeben werden. Dieser
+ Wert kann dann auch an anderen Stellen des Programms, z.B. in Schlei­
+ fen (siehe 2.4.2.5), benutzt werden. Bei Änderung der Reihungsgröße
+ braucht dann nur an einer Stelle des Programms der Wert geändert zu
+ werden.)
+- der Name gibt zusätzliche Information über die Bedeutung des Denoters.
+
+
+
+2.3.2 Zugriffsrecht
+
+Von manchen Datenobjekten weiß man, daß sie nur einmal einen Wert erhalten
+sollen. Sie sollen also nicht verändert werden. Oder man weiß, daß in einem Pro­
+grammbereich ein Datenobjekt nicht verändert werden soll. Um ein unbeabsichtigtes
+Verändern zu verhindern, wird in ELAN dem Datenobjekt ein zusätzlicher Schutz
+mitgegeben: das Zugriffsrecht oder Accessrecht.
+
+In der Deklaration eines Datenobjekts können folgende Accessattribute angegeben
+werden:
+
+- #on("i")##on("b")#VAR #off("i")##off("b")# für lesenden und schreibenden (verändernden) Zugriff
+
+- #on("i")##on("b")#CONST#off("i")##off("b")# für nur lesenden Zugriff.
+
+
+
+2.3.3 Deklaration
+
+Damit man Datenobjekte in einem Programm ansprechen kann, gibt man einem
+Datenobjekt einen Namen (wie z.B. einen Personennamen, unter der sich eine wirk­
+liche Person "verbirgt"). Will man ein Datenobjekt in einem Programm verwenden, so
+muß man dem Compiler mitteilen, welchen Datentyp und welches Accessrecht das
+Objekt haben soll. Das dient u.a. dazu, nicht vereinbarte Namen (z.B. verschriebene)
+vom Compiler entdecken zu lassen. Weiterhin ist aus dem bei der Deklaration ange­
+gebenen Datentyp zu entnehmen, wieviel Speicherplatz für das Objekt zur Laufzeit zu
+reservieren ist.
+
+Eine Deklaration oder Vereinbarung besteht aus der Angabe von
+
+- Datentyp
+- Zugriffsrecht ( #on("i")##on("b")#VAR#off("i")##off("b")# oder #on("i")##on("b")#CONST#off("i")##off("b")#)
+- Name des Datenobjekts.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ INT VAR mein datenobjekt;
+
+____________________________________________________________________________
+
+
+Verschiedene Datenobjekte mit gleichem Datentyp und Accessrecht dürfen in einer
+Deklaration angegeben werden; sie werden durch Kommata getrennt. Mehrere Dekla­
+rationen werden - genauso wie Anweisungen - durch das Trennzeichen Semikolon
+voneinander getrennt.
+
+____________________________________________________________________________
+ .......................... Beispiele: .........................
+ INT VAR mein wert, dein wert, unser wert;
+ BOOL VAR listen ende;
+ TEXT VAR zeile, wort;
+
+____________________________________________________________________________
+
+
+2.3.4 Initialisierung
+
+Um mit den vereinbarten Datenobjekten arbeiten zu können, muß man ihnen einen
+Wert geben. Hat ein Datenobjekt noch keinen Wert erhalten, so sagt man, sein Wert
+sei undefiniert. Das versehentliche Arbeiten mit undefinierten Werten ist eine beliebte
+Fehlerquelle. Deshalb wird von Programmierern streng darauf geachtet, diese Fehler­
+kuelle zu vermeiden. Eine Wertgebung an ein Datenobjekt kann (muß aber nicht)
+bereits bei der Deklaration erfolgen. In ELAN wird dies Initialisierung genannt. Für mit
+CONST vereinbarte Datenobjekte ist die Initialisierung die einzige Möglichkeit, ihnen
+einen Wert zu geben. Die Initialisierung von Konstanten ist zwingend vorgeschrieben
+und wird vom Compiler überprüft.
+
+Die Initialisierung besteht aus der Angabe von
+
+- Datentyp
+- Zugriffsrecht ( #on("i")##on("b")#VAR#off("i")##off("b")# oder #on("i")##on("b")#CONST#off("i")##off("b")#)
+- Name des Datenobjekts
+- Operator #on("i")##on("b")#::#off("i")##off("b")# oder #on("i")##on("b")#:=#off("i")##off("b")#
+- Wert, den das Datenobjekt erhalten soll (Denoter, Ausdruck).
+
+____________________________________________________________________________
+ .......................... Beispiele: .........................
+ INT CONST gewuenschtes gehalt :: 12 000;
+ TEXT VAR zeile :: "";
+ REAL CONST pi :: 3.14159, zwei pi := 2.0 * pi;
+ BOOL VAR bereits sortiert :: TRUE;
+____________________________________________________________________________
+#page#
+
+2.4 Programmeinheiten
+
+Neben Deklarationen (Vereinbarungen) sind Programmeinheiten die Grundbestandteile
+von ELAN.
+
+
+Programmeinheiten können sein:
+
+#on("b")#- elementare Programmeinheiten #off("b")#
+ - Ausdruck
+ - Zuweisung
+ - Refinementanwendung
+ - Prozeduraufruf
+
+#on("b")#- zusammengesetzte Programmeinheiten #off("b")#
+ - Folge
+ - Abfrage
+ - Auswahl
+ - Wiederholung
+
+#on("b")#- abstrahierende Programmeinheiten #off("b")#
+ - Refinementbvereinbarung
+ - Prozedurvereinbarung
+ - Operatorvereinbarung
+ - Paketvereinbarung.
+#page#
+
+2.4.1 Elementare Programmeinheiten
+
+
+2.4.1.1 Ausdruck
+
+Ausdrücke sind eine Zusammenstellung von Datenobjekten (Denoter, VAR- oder
+CONST-Objekte) und Operatoren. Jeder korrekte Ausdruck liefert einen Wert. Der
+Typ des Ausdrucks wird bestimmt durch den Typ des Wertes, den der Ausdruck
+liefert.
+
+
+Operatoren
+
+Operatoren werden in ELAN durch ein oder zwei Sonderzeichen oder durch Groß­
+buchstaben als Schlüsselwort dargestellt (siehe 2.4.3.3).
+
+Als Operanden (also die Datenobjekte, auf die ein Operator "wirken" soll) dürfen
+VAR- und CONST-Datenobjekte, Denoter oder Ausdrücke verwendet werden. Typ
+der Operanden und des Resultats eines Operators werden in der Operatorvereinba­
+rung festgelegt (siehe 2.4.3.3).
+
+Man unterscheidet zwei Arten von Operatoren:
+
+#on("b")#- monadische Operatoren #off("b")#
+ Monadischen Operatoren haben nur einen Operanden, der rechts vom Operator­
+ zeichen geschrieben werden muß.
+
+ Beispiel:
+
+
+ - a
+ NOT x
+
+
+ Der '-' - Operator liefert den Wert von a mit umgekehrten Vorzeichen. a muß
+ dabei vom Datentyp INT oder REAL sein.
+ Der Operator 'NOT' realisiert die logische Negation. y muß vom Datentyp BOOL
+ sein.
+
+
+#on("b")#- dyadische Operatoren #off("b")#
+ Dyadische Operatoren haben zwei Operanden. Das Operatorzeichen steht zwi­
+ schen den beiden Operanden.
+
+ Beispiele:
+
+
+ a + b
+ a - b
+ a * b
+ a DIV b
+ a ** b
+ x < y
+ x <> y
+ x AND y
+ x OR y
+
+
+ In den ersten fünf Beispielen werden jeweils die Werte von zwei INT-Objekten a
+ und b addiert (Operatorzeichen: '+'), subtrahiert ('-'), multipliziert ('*'), dividiert
+ (ganzzahlige Division ohne Rest: 'DIV') und potenziert ('**').
+ Im sechsten und siebten Beispiel werden zwei BOOL-Werte x und y verglichen
+ und im achten und neunten Beispiel die logische Operation 'und' (Operator 'AND')
+ bzw. 'oder' (Operator 'OR') durchgeführt.
+
+
+Priorität von Operatoren
+
+Es ist erlaubt, einen Ausdruck wiederum als Operanden zu verwenden. Praktisch
+bedeutet dies, daß mehrere Operatoren und Datenobjekte zusammen in einem Aus­
+druck geschrieben werden dürfen.
+
+Beispiele:
+
+
+a + 3 - b * c
+- a * b
+
+
+Die Reihenfolge der Auswertung kann man durch Angabe von Klammern steuern.
+
+Beispiel:
+
+
+(a + b) * (a + b)
+
+
+Es wird jeweils erst 'a + b' ausgewertet und dann erst die Multiplikation durchge­
+führt. In ELAN ist es erlaubt, beliebig viel Klammernpaare zu verwenden (Regel: die
+innerste Klammer wird zuerst ausgeführt). Es ist sogar zulässig, Klammern zu ver­
+wenden, wo keine notwendig sind, denn überflüssige Klammernpaare werden überle­
+sen. Man muß jedoch beachten, daß Ausdrücke, und damit auch z.B. #on("b")#(a)#off("b")#, immer
+Accessrecht CONST haben.
+
+Beispiel:
+
+
+((a - b)) * 3 * ((c + d) * (c - d))
+
+
+Somit können beliebig komplizierte Ausdrücke formuliert werden.
+
+Um solche Ausdrücke einfacher zu behandeln und sie so ähnlich schreiben zu kön­
+nen, wie man es in der Mathematik gewohnt ist, wird in Programmiersprachen die
+Reihenfolge der Auswertung von Operatoren festgelegt. In ELAN wurden neun Ebe­
+nen, Prioritäten genannt, festgelegt:
+
+
+#on("bold")#Priorität Operatoren
+#off("bold")#
+
+ 9 alle monadischen Operatoren
+ 8 **
+ 7 *, /, DIV, MOD
+ 6 +, -
+ 5 =, <>, <, <=, >, >=
+ 4 AND
+ 3 OR
+ 2 alle übrigen, nicht in dieser Tabelle aufgeführten
+ dyadischen Operatoren
+ 1 :=
+
+(Die erwähnten Operatoren in der Tabelle werden in der Beschreibung der Standard­
+prozeduren und -Operatoren besprochen).
+
+Operatoren mit der höchsten Priorität werden zuerst ausgeführt, dann die mit der
+nächst niedrigeren Priorität usw.. Operatoren mit gleicher Priorität werden von links
+nach rechts ausgeführt. Dadurch ergibt sich die gewohnte Abarbeitungsfolge wie beim
+Rechnen.
+
+Beispiel:
+
+
+-2 + 3 * 2 ** 3
+
+a) -2
+b) 2 ** 3
+c) 3 * (2 ** 3)
+d) ((-2)) + (3 * (2 ** 3))
+
+
+Wie bereits erwähnt, ist es immer erlaubt, Klammern zu setzen. Ist man sich also
+über die genaue Abarbeitungsfolge nicht im Klaren, so kann man Klammern verwen­
+den.
+
+
+
+2.4.1.2 Zuweisung
+
+Ein spezieller Operator ist die Zuweisung.
+
+Form:
+
+
+Variable #on("i")##on("b")#:=#off("i")##off("b")# Wert
+
+
+Dieser Operator hat immer die geringste Priorität, wird also immer als letzter einer
+Anweisung ausgeführt. Die Zuweisung wird verwendet, um einer Variablen einen
+neuen Wert zu geben. Der Operator ':=' liefert kein Resultat (man sagt auch, er
+liefert keinen Wert) und verlangt als linken Operanden ein VAR-Datenobjekt, an den
+der Wert des rechten Operanden zugewiesen werden soll). Der Wert des linken Oper­
+anden wird also verändert. Der rechte Operand wird nur gelesen.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ a := b;
+
+____________________________________________________________________________
+
+
+Hier wird der Wert von 'b' der Variablen 'a' zugewiesen. Der vorher vorhandene Wert
+von 'a' geht dabei verloren. Man sagt auch, der Wert wird überschrieben.
+
+Als rechter Operand des ':='-Operators darf auch ein Ausdruck stehen.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ a := b + c;
+
+____________________________________________________________________________
+
+
+Hier wird das Resultat von 'b + c' an die Variable 'a' zugewiesen. Man beachte
+dabei die Prioritäten der Operatoren '+' (Priorität 6) und ':=' (Priorität 1): die Addition
+wird vor der Zuweisung ausgeführt. Die Auswertung von Zuweisungen mit Ausdrücken
+muß immer so verlaufen, da die Zuweisung stets die niedrigste Priorität aller Operato­
+ren hat.
+
+Oft kommt es vor, daß ein Objekt auf der linken und rechten Seite des Zuweisungs­
+operators erscheint, z.B. wenn ein Wert erhöht werden soll.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ a := a + 1;
+
+____________________________________________________________________________
+
+
+Hier wird der "alte", aktuelle Wert von 'a' genommen, um '1' erhöht und dem Objekt
+'a' zugewiesen. Man beachte, daß hier in einer Anweisung ein Datenobjekt unter­
+schiedliche Werte zu unterschiedlichen Zeitpunkten haben kann.
+
+
+
+2.4.1.3 Refinementanwendung
+
+In ELAN ist es möglich, Namen für Ausdrücke oder eine bzw. mehrere Anweisungen
+zu vergeben. Das Sprachelement, das diese Namensgebung ermöglicht, heißt Refi­
+nement. Die Ausführung eines solchen Namens heißt Refinementanwendung, die
+Namensgebung heißt Refinementvereinbarung (siehe 2.4.3.1). Die Ausdrücke oder
+Anweisungen bilden den Refinementrumpf. Ein Refinement kann man in einem Pro­
+gramm unter dem Refinementnamen ansprechen. Man kann sich die Ausführung so
+vorstellen, als würden der Refinementrumpf immer dort eingesetzt, wo der Name des
+Refinements als Operation benutzt wird.
+
+
+
+2.4.1.4 Prozeduraufruf
+
+Eine Prozedur ist eine Sammlung von Anweisungen und Daten, die zur Lösung einer
+bestimmten Aufgabe benötigt werden. Eine Prozedur wird in einer Prozedurvereinba­
+rung definiert (siehe 2.4.3.2). Eine solche Prozedur kann man in einem Programm
+unter einem Namen (eventuell unter Angabe von Parametern) ansprechen. Man
+spricht dann vom Aufruf einer Prozedur oder einer Prozeduranweisung.
+
+Formen des Prozeduraufrufs:
+
+- #on("b")#Prozeduren ohne Parameter#off("b")# werden durch den Prozedurnamen angesprochen.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ pause;
+
+____________________________________________________________________________
+
+
+ (Die Prozedur 'pause' wartet bis ein Zeichen eingegeben wird)
+
+
+- #on("b")#Prozeduren mit Parameter#off("b")# werden durch
+
+
+ Prozedurnamen #on("i")##on("b")#(#off("i")##off("b")# aktuelle Parameterliste #on("i")##on("b")#)#off("i")##off("b")#
+
+
+ aufgerufen. Eine Parameterliste ist entweder ein Datenobjekt oder mehrere durch
+ Kommata getrennte Datenobjekte.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ pause (10);
+
+____________________________________________________________________________
+
+
+ (Mit der Prozedur 'pause (INT CONST zeitgrenze)' kann für eine Zeitdauer von
+ 'zeitgrenze' in Zehntel-Sekunden gewartet werden. Die Wartezeit wird durch
+ Erreichen der Zeitgrenze oder durch Eingabe eines Zeichens abgebrochen)
+
+
+ Bei den aktuellen Parametern ist folgendes zu beachten:
+
+ a) Wird ein VAR-Parameter in der Definition der Prozedur vorgeschrieben, darf
+ kein Ausdruck als aktueller Parameter "übergeben" werden, weil an einen
+ Ausdruck nichts zugewiesen werden kann. Ausdrücke haben - wie bereits
+ erwähnt - das Accessrecht CONST.
+
+____________________________________________________________________________
+ ........................ Gegenbeispiel: .......................
+ TEXT VAR text1, text2;
+ text1 := "Dieses Beispiel ";
+ text2 := "Fehlermeldung";
+ insert char (text1 + text2, "liefert eine", 17);
+
+____________________________________________________________________________
+
+
+ (Die Prozedur 'insert char (TEXT VAR string, TEXT CONST char, INT CONST
+ pos)' fügt das Zeichen 'char' in den Text 'string' an der Position 'pos' ein)
+
+ b) Wird ein CONST-Parameter verlangt, dann darf in diesem Fall ein Ausdruck
+ als aktueller Parameter geschrieben werden. Aber auch ein VAR-Datenobjekt
+ darf angegeben werden. In diesem Fall wird eine Wandlung des Accessrechts
+ (CONSTing) vorgenommen: der aktuelle Parameter erhält sozusagen für die
+ Zeit der Abarbeitung der Prozedur das Accessrecht CONST.
+
+
+ In ELAN sind auch Prozeduren als Parameter erlaubt. Die Prozedur als aktueller
+ Parameter wird in der Parameterliste folgendermaßen angegeben:
+
+
+ Resultattyp #on("i")##on("b")#PROC#off("i")##off("b")# #on("i")##on("b")#(#off("i")##off("b")# virtuelle Parameterliste #on("i")##on("b")#)#off("i")##off("b")# Procname
+
+
+ Die Angabe des Resultattyps entfällt, wenn es sich nicht um eine wertliefernde
+ Prozedur handelt. Die virtuelle Parameterliste inklusive der Klammern entfällt, falls
+ die Prozedur keine Parameter hat. Die virtuelle Parameterliste beschreibt die
+ Parameter der Parameterprozedur. Es werden Datentyp und Zugriffsrecht eines
+ jeden Parameters angegeben, jedoch ohne Namen.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ wertetabelle (REAL PROC (REAL CONST) sin,
+ untergrenze, obergrenze, schrittweite);
+
+
+ (Die Prozedur 'sin' wird an die Prozedur 'wertetabelle' übergeben)
+
+____________________________________________________________________________
+
+
+2.4.2 Zusammengesetzte Programmeinheiten
+
+
+2.4.2.1 Folge
+
+Mehrere in einer bestimmten Reihenfolge auszuführende Anweisungen werden als
+Folge bezeichnet. In ELAN kann man eine oder mehrere Anweisungen in eine Pro­
+grammzeile schreiben oder eine Anweisung über mehrere Zeilen. Das setzt jedoch
+voraus, daß die Anweisungen voneinander getrennt werden. Die Trennung von Anwei­
+sungen erfolgt in ELAN durch das Trennsymbol Semikolon. Es bedeutet soviel wie:
+"führe die nächste Anweisung aus".
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ put ("mein");
+ put (1);
+ put (". Programm")
+
+____________________________________________________________________________
+
+
+(Die Prozedur 'put' gibt den als Parameter angegebenen Wert auf dem Ausgabegerät
+aus)
+
+
+
+2.4.2.2 Abfrage
+
+Mit Abfragen steuert man die bedingte Ausführung von Anweisungen. Abhängig von
+einer Bedingung wird in zwei verschiedene Programmabschnitte verzweigt.
+
+Der formale Aufbau einer Abfrage sieht folgendermaßen aus:
+
+
+#on("i")##on("b")#IF#off("i")##off("b")# Bedingung
+ #on("i")##on("b")#THEN#off("i")##off("b")# Abschnitt
+ #on("i")##on("b")#ELSE#off("i")##off("b")# Abschnitt
+#on("i")##on("b")#END IF#off("i")##off("b")#
+
+
+Der ELSE-Teil darf dabei auch fehlen. Anstelle von #on("i")##on("b")#END IF#off("i")##off("b")# darf auch die Abkürzung #on("i")##on("b")#FI#off("i")##off("b")# (IF von hinten gelesen) benutzt werden.
+
+In folgenden Beispielen wird der Absolutbetrag von 'a' ausgegeben:
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ INT VAR a;
+ get (a);
+ IF a < 0
+ THEN a := -a
+ END IF;
+ put (a)
+
+____________________________________________________________________________
+
+
+Die Umkehrung des Vorzeichens von a im THEN-Teil wird nur durchgeführt, wenn
+der BOOLesche Ausdruck ('a < 0') den Wert TRUE liefert. Liefert er den Wert
+FALSE, wird die Anweisung, die der bedingten Anweisung folgt (nach END IF), ausge­
+führt. Das obige Programm kann auch anders geschrieben werden:
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ INT VAR a;
+ get (a);
+ IF a < 0
+ THEN put (-a)
+ ELSE put (a)
+ END IF
+
+____________________________________________________________________________
+
+
+Der THEN-Teil wird wiederum ausgeführt, wenn die BOOLesche Bedingung erfüllt
+ist. Liefert sie dagegen FALSE, wird der ELSE-Teil ausgeführt.
+
+Die bedingte Anweisung ermöglicht es, abhängig von einer Bedingung eine oder
+mehrere Anweisungen ausführen zu lassen. Dabei können im THEN- bzw. ELSE-
+Teil wiederum bedingte Anweisungen enthalten sein.
+
+
+Abfragekette
+Bei Abfrageketten kann das ELIF-Konstrukt eingesetzt werden. (ELIF ist eine Zu­
+sammenziehung der Worte ELSE und IF).
+
+Anstatt
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ IF bedingung1
+ THEN aktion1
+ ELSE IF bedingung2
+ THEN aktion2
+ ELSE aktion3
+ END IF
+ END IF;
+
+____________________________________________________________________________
+
+
+kann man besser
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ IF bedingung1
+ THEN aktion1
+ ELIF bedingung2
+ THEN aktion2
+ ELSE aktion3
+ END IF;
+
+____________________________________________________________________________
+
+
+schreiben.
+
+
+
+2.4.2.3 Auswahl
+
+Die Auswahl wird benutzt, wenn alternative Anwendungen in Abhängikeit von Werten
+eines Datenobjekts ausgeführt werden sollen.
+
+Der formale Aufbau der Auswahl sieht folgendermaßen aus:
+
+
+#on("i")##on("b")#SELECT#off("i")##off("b")# INT-Ausdruck #on("i")##on("b")#OF#off("i")##off("b")#
+ #on("i")##on("b")#CASE#off("i")##off("b")# 1. Liste von INT-Denotern #on("i")##on("b")#:#off("i")##off("b")# Abschnitt
+ #on("i")##on("b")#CASE#off("i")##off("b")# 2. Liste von INT-Denotern #on("i")##on("b")#:#off("i")##off("b")# Abschnitt
+ .
+ .
+ .
+ #on("i")##on("b")#CASE#off("i")##off("b")# n. Liste von INT-Denotern #on("i")##on("b")#:#off("i")##off("b")# Abschnitt
+ #on("i")##on("b")#OTHERWISE#off("i")##off("b")# Abschnitt
+#on("i")##on("b")#END SELECT#off("i")##off("b")#
+
+
+Eine Liste von INT-Denotern besteht aus einem oder mehreren durch Kommata ge­
+trennten INT-Denotern. Der OTHERWISE-Teil darf auch fehlen. Man sollte ihn
+jedoch verwenden, um Fehlerfälle abzufangen.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ SELECT monat OF
+ CASE 2: IF schaltjahr
+ THEN tage := 29
+ ELSE tage := 28
+ END IF
+ CASE 4, 6, 9, 11: tage := 30
+ CASE 1, 3, 5, 7, 8, 10 ,12: tage := 31
+ OTHERWISE kein monat
+ END SELECT;
+
+____________________________________________________________________________
+
+
+(In diesem Programmausschnitt werden die Tage eines Monats bestimmt)
+
+
+
+2.4.2.4 Wertliefernde Abfrage und
+ wertliefernde Auswahl
+
+
+Soll eine Abfrage oder eine Auswahl einen Wert liefern, dann darf der ELSE- bzw.
+der OTHERWISE-Teil nicht fehlen und alle Zweige müssen einen Wert liefern.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ SELECT monat OF
+ CASE 2: IF schaltjahr
+ THEN 29
+ ELSE 28
+ END IF
+ CASE 4, 6, 9, 11: 30
+ CASE 1, 3, 5, 7, 8, 10 ,12: 31
+ OTHERWISE kein monat; 0
+ END SELECT;
+
+____________________________________________________________________________
+
+
+2.4.2.5 Wiederholung
+
+Die Wiederholung dient zur mehrfachen Ausführung von Anweisungen, meist in Ab­
+hängigkeit von einer Bedingung. Darum wird die Wiederholungsanweisung oft auch
+Schleife genannt und die in ihr enthaltenen Anweisungen Schleifenrumpf.
+
+Es gibt verschiedene Schleifentypen:
+
+- Endlosschleife
+- abweisende Schleife
+- nicht abweisende Schleife
+- Zählschleife.
+
+
+Endlosschleife
+Bei der Endlosschleife wird nicht spezifiziert, wann die Schleife beendet werden soll.
+
+Form:
+
+
+#on("i")##on("b")#REPEAT#off("i")##off("b")#
+ Abschnitt
+#on("i")##on("b")#END REPEAT#off("i")##off("b")#
+
+
+Anstelle von #on("i")##on("b")#REPEAT#off("i")##off("b")# darf die Abkürzung #on("i")##on("b")#REP#off("i")##off("b")# und anstelle von #on("i")##on("b")#END REPEAT#off("i")##off("b")#
+das Schlüsselwort #on("i")##on("b")#PER#off("i")##off("b")# (REP von hinten gelesen)
+benutzt werden.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ break;
+ REPEAT
+ fixpoint;
+ pause (18000)
+ END REPEAT
+
+____________________________________________________________________________
+
+
+Wird dieses Programm in einer Task im SYSUR-Zweig ausgeführt, so führt diese
+Task Fixpunkte im Abstand von 30 Minuten durch.
+
+
+
+Abweisende Schleife
+Bei der abweisenden Schleife wird die Abbruchbedingung an den Anfang der Schleife
+geschrieben.
+
+Form:
+
+
+#on("i")##on("b")#WHILE#off("i")##off("b")# Bedingung #on("i")##on("b")#REPEAT#off("i")##off("b")#
+ Abschnitt
+#on("i")##on("b")#END REPEAT#off("i")##off("b")#
+
+
+Bei jedem erneuten Durchlauf der Schleife wird überprüft, ob der BOOLesche Aus­
+druck den Wert TRUE liefert. Ist das nicht der Fall, wird die Bearbeitung mit der
+Anweisung fortgesetzt, die auf das Schleifenende folgt. Die Schleife wird abweisende
+Schleife genannt, weil der Schleifenrumpf nicht ausgeführt wird, wenn die Bedingung
+vor Eintritt in die Schleife bereits FALSE liefert.
+
+
+Nicht abweisende Schleife
+Anders verhält es sich bei der nicht abweisenden Schleife. Bei der nicht abweisenden
+Schleife wird die Abbruchbedingung an das Ende der Schleife geschrieben.
+
+Form:
+
+
+#on("i")##on("b")#REPEAT#off("i")##off("b")#
+ Abschnitt
+#on("i")##on("b")#UNTIL#off("i")##off("b")# Bedingung #on("i")##on("b")#END REPEAT#off("i")##off("b")#
+
+
+Hier wird der Schleifenrumpf auf jeden Fall einmal bearbeitet. Am Ende des Rumpfes
+wird die BOOLesche Bedingung abgefragt. Liefert sie den Wert FALSE, wird die
+Schleife erneut abgearbeitet. Liefert die Bedingung den Wert TRUE, wird die Schleife
+abgebrochen und mit der ersten Anweisung hinter der Schleife in der Bearbeitung
+fortgefahren.
+
+Bei den beiden letztgenannten Arten der Wiederholungsanweisung ist es wichtig, daß
+Elemente der BOOLeschen Bedingung in der Schleife verändert werden, damit das
+Programm terminieren kann, d.h. die Schleife abgebrochen wird.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ TEXT VAR wort, satz :: "";
+ REPEAT
+ get (wort);
+ satz CAT wort;
+ satz CAT " "
+ UNTIL wort = "." PER;
+
+____________________________________________________________________________
+
+
+Dises Programm liest solange Wörter ein und verbindet diese zu einem Satz, bis ein
+Punkt eingegeben wurde.
+
+
+
+Zählschleife
+Zählschleifen werden eingesetzt, wenn die genaue Anzahl der Schleifendurchläufe
+bekannt ist.
+
+Form:
+
+
+#on("i")##on("b")#FOR#off("i")##off("b")# Laufvariable #on("i")##on("b")#FROM#off("i")##off("b")# Anfangswert #on("i")##on("b")#UPTO#off("i")##off("b")# Endwert #on("i")##on("b")#REPEAT#off("i")##off("b")#
+ Abschnitt
+#on("i")##on("b")#END REPEAT#off("i")##off("b")#
+
+
+Bei Zählschleifen wird eine Laufvariable verwendet, die die INT-Werte von 'Anfangs­
+wert' bis 'Endwert' in Schritten von 1 durchläuft. 'Anfangswert' und 'Endwert' können
+beliebige INT-Ausdrücke sein. Diese Schleife zählt "aufwärts". Wird anstatt #on("i")##on("b")#UPTO#off("i")##off("b")#
+das Schlüsselwort #on("i")##on("b")#DOWNTO#off("i")##off("b")# verwendet, wird mit Schritten von 1 "abwärts" gezählt.
+
+Form:
+
+
+#on("i")##on("b")#FOR#off("i")##off("b")# Laufvariable #on("i")##on("b")#FROM#off("i")##off("b")# Endwert #on("i")##on("b")#DOWNTO#off("i")##off("b")# Anfangswert #on("i")##on("b")#REPEAT#off("i")##off("b")#
+ Abschnitt
+#on("i")##on("b")#END REPEAT#off("i")##off("b")#
+
+
+Die Laufvariable darf in der Schleife nicht verändert werden. Nach dem normalen
+Schleifenende ist der Wert der Laufvariablen nicht definiert.
+
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ INT VAR summe :: 0, i;
+ FOR i FROM 1 UPTO 100 REPEAT
+ summe INCR i
+ END REPEAT
+
+____________________________________________________________________________
+
+
+Dieses Programm berechnet die Summe der natürlichen Zahlen von 1 bis 100.
+
+
+Die verschiedenen Schleifenarten können kombiniert werden:
+
+
+#on("i")##on("b")#FOR#off("i")##off("b")# Laufvariable #on("i")##on("b")#FROM#off("i")##off("b")# Anfangswert #on("i")##on("b")#UPTO#off("i")##off("b")# Endwert
+#on("i")##on("b")#WHILE#off("i")##off("b")# Bedingung #on("i")##on("b")#REPEAT#off("i")##off("b")#
+ Abschnitt
+#on("i")##on("b")#END REPEAT#off("i")##off("b")#
+
+
+
+#on("i")##on("b")#FOR#off("i")##off("b")# Laufvariable #on("i")##on("b")#FROM#off("i")##off("b")# Anfangswert #on("i")##on("b")#UPTO#off("i")##off("b")# Endwert #on("i")##on("b")#REPEAT#off("i")##off("b")#
+ Abschnitt
+#on("i")##on("b")#UNTIL#off("i")##off("b")# Bedingung #on("i")##on("b")#END REPEAT#off("i")##off("b")#
+
+
+
+
+
+#on("i")##on("b")#WHILE#off("i")##off("b")# Bedingung #on("i")##on("b")#REPEAT#off("i")##off("b")#
+ Abschnitt
+#on("i")##on("b")#UNTIL#off("i")##off("b")# Bedingung #on("i")##on("b")#END REPEAT#off("i")##off("b")#
+
+#page#
+
+2.4.3 Abstrahierende Programmeinheiten
+
+
+2.4.3.1 Refinementvereinbarung
+
+In ELAN ist es möglich, Namen für Ausdrücke oder eine bzw. mehrere Anweisungen
+zu vergeben. Das Sprachelement, das diese Namensgebung ermöglicht, heißt Refi­
+nement. Die Ausführung eines solchen Namens heißt Refinementanwendung (siehe
+2.4.1.3), die Namensgebung heißt Refinementvereinbarung. Die Ausdrücke oder
+Anweisungen bilden den Refinementrumpf.
+
+Werden in einem Programm Refinements benutzt, dann wird der Programmteil bis
+zum ersten Refinement durch einen Punkt abgeschlossen. Die Refinementvereinba­
+rung sieht folgendermaßen aus:
+
+
+Name #on("i")##on("b")#:#off("i")##off("b")#
+ Abschnitt #on("i")##on("b")#.#off("i")##off("b")#
+
+
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ INT VAR a, b, x;
+ einlesen von a und b;
+ vertauschen von a und b;
+ vertauschte werte ausgeben.
+
+ einlesen von a und b:
+ get (a);
+ get (b).
+
+ vertauschen von a und b:
+ x := a;
+ a := b;
+ b := x.
+
+ vertauschte werte ausgeben:
+ put (a);
+ put (b).
+
+____________________________________________________________________________
+
+
+Für den Namen 'einlesen von a und b' werden die Anweisungen 'get (a); get (b)' vom
+ELAN-Compiler eingesetzt. Man kann also die ersten vier Zeilen des Programms als
+eigentliches Programm ansehen, wobei die Namen durch die betreffenden Anwei­
+sungen ersetzt werden. Ein Refinement hat also keinen eigenen Datenbereich, d.h.
+Vereinbarungen, die in Refinements gemacht werden, gelten auch außerhalb des
+Refinements.
+
+
+
+Vorteile der Refinementanwendung
+Durch die sinnvolle Verwendung von Refinements wird ein Programm im Programm
+und nicht in einer separaten Beschreibung dokumentiert. Weiterhin kann ein Pro­
+gramm "von oben nach unten" ("top down") entwickelt werden: Das obige - zuge­
+geben einfache - Beispielprogramm wurde in drei Teile zerlegt und diese durch
+Namen beschrieben. Bei der Beschreibung von Aktionen durch Namen wird gesagt
+was gemacht werden soll. Es wird noch nicht beschrieben wie, denn auf dieser Stufe
+der Programmentwicklung braucht man sich um die Realisierung der Refinements
+(noch) keine Sorgen zu machen. Das erfolgt erst, wenn das Refinement programmiert
+werden muß. Dabei können wiederum Refinements verwendet werden usw., bis man
+auf eine Ebene "heruntergestiegen" ist, bei der eine (jetzt: Teil-) Problemlösung sehr
+einfach ist und man sie direkt hinschreiben kann. Man beschäftigt sich also an jedem
+Punkt der Problemlösung nur mit einem Teilaspekt des gesamten Problems. Zudem
+sieht man - wenn die Refinements einigermaßen vernünftig verwendet werden -
+dem Programm an, wie die Problemlösung entstanden ist.
+
+Die Verwendung von Refinements hat also eine Anzahl von Vorteilen.
+Refinements ermöglichen:
+
+- "top down" - Programmierung
+- Strukturierung von Programmen und damit effiziente Fehlersuche und gute Wart­
+ barkeit
+- Dokumentation im Programmtext.
+
+
+Wertliefernde Refinements
+Refinements können auch dort verwendet werden, wo ein Wert erwartet wird, z.B. in
+einem Ausdruck oder einer 'put'-Anweisung. In diesem Fall muß die letzte Anwei­
+sung des Refinements einen Wert liefert.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ INT VAR a :: 1, b :: 2, c :: 3;
+ put (resultat).
+
+ resultat:
+ (a * b + c) ** 3.
+
+____________________________________________________________________________
+
+
+Man kann auch ein wertlieferndes Refinement mit mehreren Anweisungen schrei­
+ben.
+
+Allgemeine Regel:
+Die letzte Anweisung eines Refinements bestimmt, ob es einen Wert liefert - und
+wenn ja, von welchen Datentyp.
+
+
+
+2.4.3.2 Prozedurvereinbarung
+
+Eine Prozedur ist eine Sammlung von Anweisungen und Daten, die zur Lösung einer
+bestimmten Aufgabe benötigt werden.
+
+Der formale Aufbau einer Prozedur sieht folgendermaßen aus:
+
+
+#on("i")##on("b")#PROC#off("i")##off("b")# Prozedurname #on("i")##on("b")#:#off("i")##off("b")#
+ Prozedurrumpf
+#on("i")##on("b")#END PROC#off("i")##off("b")# Prozedurname
+
+
+Der Prozedurrumpf kann Deklarationen, Anweisungen und Refinements enthalten.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ PROC loesche bildschirm ab aktueller cursorposition:
+ out (""4"")
+ END PROC loesche bildschirm ab aktueller cursorposition
+
+____________________________________________________________________________
+
+
+Verwendung von Prozeduren
+Prozeduren werden verwendet, wenn
+
+- Anweisungen und Datenobjekte unter einem Namen zusammengefaßt werden
+ sollen ("Abstraktion")
+- gleiche Anweisungen von mehreren Stellen eines Programms verwandt werden
+ sollen (Codereduktion), u.U. mit verschieden Datenobjekten (Parameter)
+- Datenobjekte nur innerhalb eines Programmteils benötigt werden und diese nicht
+ von dem gesamten Programm angesprochen werden sollen.
+
+In den folgenden Programmfragmenten werden zwei Werte vertauscht. In der ersten
+Lösung wird ein Refinement, in der zweiten eine Prozedur verwandt.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ IF a > b
+ THEN vertausche a und b
+ END IF;
+ put (a);
+ put (b);
+ vertausche a und b.
+
+ vertausche a und b:
+ INT CONST x :: a;
+ a := b;
+ b := x.
+
+____________________________________________________________________________
+
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ PROC vertausche a und b:
+ INT CONST x :: a;
+ a := b;
+ b := x
+ END PROC vertausche a und b;
+
+ IF a > b
+ THEN vertausche a und b
+ END IF;
+ put (a);
+ put (b);
+ vertausche a und b;
+
+____________________________________________________________________________
+
+
+Beim ersten Hinsehen leisten beide Programme das Gleiche. Es gibt jedoch drei
+wichtige Unterschiede:
+
+1) Das Refinement 'vertausche a und b' wird zweimal (vom ELAN-Compiler) ein­
+ gesetzt, d.h. der Code ist zweimal vorhanden. Die Prozedur dagegen ist vom Code
+ nur einmal vorhanden, wird aber zweimal - durch das Aufführen des Prozedur­
+ namens - aufgerufen.
+
+2) Die Variable 'x' ist in der ersten Programmversion während des gesamten Ablauf
+ des Programms vorhanden, d.h. ihr Speicherplatz ist während dieser Zeit belegt.
+ Solche Datenobjekte nennt man statische Datenobjekte oder auch (aus Gründen,
+ die erst etwas später offensichtlich werden) Paket-Objekte. Das Datenobjekt 'x'
+ der rechten Version dagegen ist nur während der Bearbeitung der Prozedur vor­
+ handen, sein Speicherplatz wird danach freigegeben. Solche Datenobjekte, die nur
+ kurzfristig Speicher belegen, werden dynamische Datenobjekte genannt.
+
+ Prozeduren sind also ein Mittel, um die Speicherbelegung zu beeinflussen.
+
+3) Da Refinements keinen eigenen Datenbereich haben, kann die Variable 'x' in der
+ ersten Programmversion - obwohl sie in einem Refinement deklariert wurde -
+ von jeder Stelle des Programms angesprochen werden. Solche Datenobjekte
+ werden globale Datenobjekte genannt. Das Datenobjekt 'x' der Prozedur dagegen
+ kann nur innerhalb der Prozedur angesprochen werden, es ist also ein lokales
+ Datenobjekt der Prozedur. Innerhalb der Prozedur dürfen globale Datenobjekte
+ (also Objekte, die außerhalb von Prozeduren deklariert wurden) auch angespro­
+ chen werden.
+
+ Eine Prozedur in ELAN bildet im Gegensatz zu Refinements einen eigenen Gültig­
+ keitsbereich hinsichtlich Datenobjekten und Refinements, die innerhalb der Pro­
+ zedur deklariert werden. Prozeduren sind somit ein Mittel, um die in ihr dekla­
+ rierten Datenobjekte hinsichtlich der Ansprechbarkeit nach Außen "abzuschotten".
+
+
+
+Prozeduren mit Parametern
+Prozeduren mit Parametern erlauben es, gleiche Anweisungen mit unterschiedlichen
+Datenobjekten auszuführen.
+
+Form:
+
+
+#on("i")##on("b")#PROC#off("i")##off("b")# Prozedurname #on("i")##on("b")#(#off("i")##off("b")# formale Parameterliste #on("i")##on("b")#)#off("i")##off("b")# #on("i")##on("b")#:#off("i")##off("b")#
+ Prozedurrumpf
+#on("i")##on("b")#END PROC#off("i")##off("b")# Prozedurnamen
+
+
+Die Parameterliste besteht aus einem oder mehreren durch Kommata getrennten Para­
+metern. Ein Parameter wird mit Datentyp, Accessrecht und Namen angegeben.
+Ähnlich wie bei der Datendeklaration braucht man für aufeinanderfolgende Parameter
+mit gleichem Datentyp und gleichem Accessrecht die Attribute nur einmal anzugeben.
+Parameter mit Accessrecht #on("i")##on("b")#CONST#off("i")##off("b")# sind Eingabeparameter, Parameter mit Access­
+recht #on("i")##on("b")#VAR#off("i")##off("b")# realisieren Ein-/Ausgabeparameter.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ PROC vertausche (INT VAR a, b):
+ INT VAR x :: a;
+ a := b;
+ b := x
+ END PROC vertausche;
+
+ INT VAR eins :: 1,
+ zwei :: 2,
+ drei :: 3;
+ vertausche (eins, zwei);
+ vertausche (zwei, drei);
+ vertausche (eins, zwei);
+ put (eins); put (zwei); put (drei)
+
+____________________________________________________________________________
+
+
+Die Datenobjekte 'a' und 'b' der Prozedur 'vertausche' werden formale Parameter
+genannt. Sie stehen als Platzhalter für die bei einem Prozeduraufruf einzusetzenden
+aktuellen Parameter (in obigen Beispiel die Datenobjekte 'eins', 'zwei' und 'drei').
+
+
+
+Prozeduren als Parameter
+Es ist auch möglich, Prozeduren als Parameter zu definieren.
+
+Eine Prozedur als Parameter wird folgendermaßen in der Parameterliste spezifiziert:
+
+Resultattyp #on("i")##on("b")#PROC#off("i")##off("b")# #on("i")##on("b")#(#off("i")##off("b")# virtuelle Parameterliste #on("i")##on("b")#)#off("i")##off("b")# Prozedurname
+
+
+Die Angabe des Resultattyps entfällt, wenn es sich nicht um eine wertliefernde Proze­
+dur handelt. Die virtuelle Parameterliste inklusive der Klammern entfällt, falls die
+Prozedur keine Parameter hat. Die virtuelle Parameterliste beschreibt die Parame­
+ter der Parameterprozedur. Es werden Datentyp und Zugriffsrecht eines jeden Para­
+meters angegeben, jedoch ohne Namen.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ PROC wertetabelle (REAL PROC (REAL CONST) funktion,
+ REAL CONST untergrenze, obergrenze,
+ schrittweite):
+
+ REAL VAR wert;
+ putline ("W E R T E T A B E L L E");
+ putline ("-----------------------");
+ wert := untergrenze;
+ REPEAT
+ put (text (wert, 10, 5));
+ put (text (funktion (wert), 10, 5));
+ line;
+ wert INCR schrittweite
+ UNTIL wert > obergrenze PER
+
+ END PROC wertetabelle;
+
+ (* Prozeduraufruf: *)
+ wertetabelle (REAL PROC (REAL CONST) sin, 0.0, pi, 0.2)
+
+____________________________________________________________________________
+
+
+Wertliefernde Prozeduren
+Eine wertliefernde Prozedur sieht folgendermaßen aus:
+
+
+Resultattyp #on("i")##on("b")#PROC#off("i")##off("b")# Prozedurname #on("i")##on("b")#(#off("i")##off("b")# formale Parameterliste #on("i")##on("b")#)#off("i")##off("b")# #on("i")##on("b")#:#off("i")##off("b")#
+ wertliefernder Prozedurrumpf
+#on("i")##on("b")#END PROC#off("i")##off("b")# Prozedurnamen
+
+
+
+Die Parameterliste inklusive Klammerung kann fehlen. Der Prozedurrumpf muß einen
+Wert mit dem in Resultattyp angegeben Datentyp liefern.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ INT PROC max (INT CONST a, b):
+ IF a > b
+ THEN a
+ ELSE b
+ END IF
+ END PROC max;
+
+ put (max (3, 4))
+
+____________________________________________________________________________
+
+
+(In diesem Beispiel wird das Maximum von 'a' und 'b' ermittelt und ausgegeben)
+
+#page#
+
+2.4.3.3 Operatorvereinbarung
+
+Operatoren können in ELAN ähnlich wie Prozeduren definiert werden. Operatoren
+müssen einen und können maximal zwei Operatoren besitzen (monadische und dyadi­
+sche Operatoren).
+
+Form:
+
+
+Resultattyp #on("i")##on("b")#OP#off("i")##off("b")# Opname #on("i")##on("b")#(#off("i")##off("b")# ein oder zwei Parameter #on("i")##on("b")#)#off("i")##off("b")# #on("i")##on("b")#:#off("i")##off("b")#
+ Operatorrumpf
+#on("i")##on("b")#END OP#off("i")##off("b")# Opname
+
+
+Der Resultattyp wird nur bei wertliefernden Operatoren angegeben.
+
+Als Operatornamen sind erlaubt:
+
+- ein Sonderzeichen, sofern es nicht als Trennzeichen benutzt wird:
+ ! $ % & ' * + - / < = > ? § ^ ' ~
+- eine Kombination von zwei Sonderzeichen. Diese Kombination muß jedoch bereits
+ in ELAN existieren:
+ := <= >= <> **
+- ein Schlüsselwort (siehe 2.2.1).
+
+
+
+Vereinbarung eines monadischen Operators
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ INT OP SIGN (REAL CONST argument):
+ IF argument < 0.0 THEN -1
+ ELIF argument = 0.0 THEN 0
+ ELSE 1
+ FI
+ END OP SIGN
+
+____________________________________________________________________________
+
+
+(Der Operator 'SIGN' liefert abhängig vom Vorzeichen des übergebenen Wertes den
+INT-Wert -1, 0 oder 1)
+
+
+
+Vereinbarung eines dyadischen Operators
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ TEXT OP * (INT CONST anzahl, TEXT CONST t):
+ INT VAR zaehler :: anzahl;
+ TEXT VAR ergebnis :: "";
+ WHILE zaehler > 0 REP
+ ergebnis := ergebnis + t;
+ zaehler := zaehler - 1
+ END REP;
+ ergebnis
+ END OP *;
+
+____________________________________________________________________________
+
+
+(Der Operator '*' verkettet 'anzahl'- mal den Text 't')
+
+
+
+2.4.3.4 Paketvereinbarung
+
+Pakete sind in ELAN eine Zusammenfassung von Datenobjekten, Prozeduren, Opera­
+toren und Datentypen. Diese bilden den Paketrumpf. Elemente eines Pakets (Prozedu­
+ren, Operatoren, Datentypen) können außerhalb des Pakets nur angesprochen werden,
+wenn sie in der Schnittstelle des Pakets, die auch "interface" genannt wird, aufge­
+führt werden. Mit anderen Worten: es können alle Elemente eines Pakets von außen
+nicht angesprochen werden, sofern sie nicht über die Schnittstelle "nach außen ge­
+reicht" werden. Pakete können separat übersetzt werden, so daß der "Zusammen­
+bau" eines umfangreichen Programms aus mehreren Paketen möglich ist.
+
+Der formale Aufbau eines Pakets sieht folgendermaßen aus:
+
+
+#on("i")##on("b")#PACKET#off("i")##off("b")# Paketname #on("i")##on("b")#DEFINES#off("i")##off("b")# Schnittstelle #on("i")##on("b")#:#off("i")##off("b")#
+ Paketrumpf
+#on("i")##on("b")#END PACKET#off("i")##off("b")# Paketname
+
+
+In der Schnittstelle werden Prozeduren und Operatoren nur mit ihrem Namen, durch
+Kommata getrennt, angegeben. Weiterhin können Datentypen und mit CONST verein­
+barte Datenobjekte in der Schnittstelle aufgeführt werden, aber keine VAR-Datenob­
+jekte, weil diese sonst über Paket-Grenzen hinweg verändert werden könnten.
+
+Im Gegensatz zu einer Prozedur kann ein PACKET nicht aufgerufen werden (nur die
+Elemente der Schnittstelle können benutzt werden).
+
+Pakete werden zu folgenden Zwecken eingesetzt:
+
+- Spracherweiterung
+- Schutz vor fehlerhaftem Zugriff auf Datenobjekte
+- Realisierung von abstrakten Datentypen.
+
+
+
+Spracherweiterung
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ PACKET fuer eine prozedur DEFINES swap:
+
+ PROC swap (INT VAR a, b):
+ INT CONST x :: a;
+ b := a;
+ a := x
+ END PROC swap
+
+ END PACKET fuer eine prozedur
+
+____________________________________________________________________________
+
+
+Dies ist ein Paket, das eine Tausch-Prozedur für INT-Datenobjekte bereitstellt. Das
+PACKET kann übersetzt und dem ELAN-Compiler bekannt gemacht werden
+(EUMEL: "insertieren"). Ist das geschehen, kann man 'swap' wie alle anderen Proze­
+duren (z.B. 'put', 'get') in einem Programm verwenden. Tatsächlich werden die mei­
+sten Prozeduren und Operatoren (aber auch einige Datentypen), die in ELAN zur
+Verfügung stehen, nicht durch den ELAN-Compiler realisiert, sondern durch solche
+PACKETs. Um solche Objekte einigermaßen zu standardisieren, wurde in der
+ELAN-Sprachbeschreibung festgelegt, welche Datentypen, Prozeduren und Operato­
+ren in jedem ELAN-System vorhanden sein müssen. Solche Pakete werden Stan­
+dard-Pakete genannt. Jeder Installation - aber auch jedem Benutzer - steht es
+jedoch frei, zu den Standard-Paketen zusätzliche Pakete dem Compiler bekannzu­
+geben, und damit den ELAN-Sprachumfang zu erweitern.
+
+
+
+Schutz vor fehlerhaftem Zugriff auf Datenobjekte
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ PACKET stack handling DEFINES push, pop, init stack:
+
+ LET max = 1000;
+ ROW max INT VAR stack; (* siehe Kapitel Reihung, 2.6.1. *)
+ INT VAR stack pointer;
+
+ PROC init stack:
+ stack pointer := 0
+ END PROC init stack;
+
+ PROC push (INT CONST dazu wert):
+ stack pointer INCR 1;
+ IF stack pointer > max
+ THEN errorstop ("stack overflow")
+ ELSE stack [stack pointer] := dazu wert
+ END IF
+ END PROC push;
+
+ PROC pop (INT VAR von wert):
+ IF stack pointer = 0
+ THEN errorstop ("stack empty")
+ ELSE von wert := stack [stack pointer];
+ stack pointer DECR 1
+ END IF
+ END PROC pop
+
+ END PACKET stack handling;
+
+____________________________________________________________________________
+
+
+Dieses Packet realisiert einen Stack. Den Stack kann man über die Prozeduren 'init
+stack', 'push' und 'pop' benutzen.
+#page#
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ init stack;
+ werte einlesen und pushen;
+ werte poppen und ausgeben.
+
+ werte einlesen und pushen:
+ INT VAR anzahl :: 0, wert;
+ REP
+ get (wert);
+ push (wert);
+ anzahl INCR 1
+ UNTIL ende kriterium END REP.
+
+ werte poppen und ausgeben:
+ INT VAR i;
+ FOR i FROM 1 UPTO anzahl REP
+ pop (wert);
+ put (wert)
+ END REP.
+
+____________________________________________________________________________
+
+
+Die Datenobjekte 'stack' und 'stack pointer' haben nur Gültigkeit innerhalb des
+PACKETs 'stack handling'.
+
+Anweisungen wie z.B.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ put (stack [3]);
+ stack [27] := 5
+
+____________________________________________________________________________
+
+
+
+außerhalb des PACKETs 'stack handling' sind also verboten und werden vom
+ELAN-Compiler entdeckt.
+
+Ein PACKET bietet also auch einen gewissen Schutz vor fehlerhafter Verwendung von
+Programmen und Datenobjekten. Wichtig ist weiterhin, daß die Realisierung des
+Stacks ohne weiteres geändert werden kann, ohne daß Benutzerprogramme im 'main
+packet' geändert werden müssen, sofern die Schnittstelle nicht verändert wird. Bei­
+spielsweise kann man sich entschließen, den Stack nicht durch eine Reihung, son­
+dern durch eine Struktur zu realisieren. Davon bleibt ein Benutzerprogramm unbe­
+rührt.
+
+
+
+Realisierung von abstrakten Datentypen
+Der Vollständigkeit halber wird folgendes Beispiel hier gezeigt. Wie neue Datentypen
+definiert werden, wird in Kapitel 2.7.1. erklärt.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ PACKET widerstaende DEFINES WIDERSTAND, REIHE, PARALLEL,
+ :=, get, put:
+
+ TYPE WIDERSTAND = INT;
+
+ OP := (WIDERSTAND VAR l, WIDERSTAND CONST r):
+ CONCR (l) := CONCR (r)
+ END OP :=;
+
+ PROC get (WIDERSTAND VAR w):
+ INT VAR i;
+ get (i);
+ w := WIDERSTAND : (i)
+ END PROC get;
+
+ PROC put (WIDERSTAND CONST w):
+ put (CONCR (w))
+ END PROC put;
+
+ WIDERSTAND OP REIHE (WIDERSTAND CONST l, r):
+ WIDERSTAND : ( CONCR (l) + CONCR (r))
+ END OP REIHE;
+
+ WIDERSTAND OP PARALLEL (WIDERSTAND CONST l, r):
+ WIDERSTAND :
+ ((CONCR (l) * CONCR (r)) DIV (CONCR (l) + CONCR (r)))
+ END OP PARALLEL
+
+ END PACKET widerstaende
+
+____________________________________________________________________________
+
+
+Dieses Programm realisiert den Datentyp WIDERSTAND und mit den Operationen
+eine Fachsprache.
+
+
+
+2.4.4 Terminatoren für Refinements,
+ Prozeduren und Operatoren
+
+
+Das LEAVE-Konstrukt wird verwendet, um eine benannte Anweisung (Refinement,
+Prozedur oder Operator) vorzeitig zu verlassen. Es ist auch möglich, geschachtelte
+Refinements zu verlassen.
+
+Form:
+
+#on("i")##on("b")#LEAVE#off("i")##off("b")# Name
+
+
+Durch eine (optionale) WITH-Angabe kann auch eine wertliefernde benannte Anwei­
+sung verlassen werden.
+
+Form:
+
+#on("i")##on("b")#LEAVE#off("i")##off("b")# Name #on("i")##on("b")#WITH#off("i")##off("b")# Ausdruck
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ INT OP ** (INT CONST basis, exp):
+ IF exp = 0
+ THEN LEAVE ** WITH 1
+ ELIF exp < 0
+ THEN LEAVE ** WITH 0
+ FI;
+
+ INT VAR zaehler, ergebnis;
+ ergebnis := basis;
+ FOR zaehler FROM 2 UPTO exp REP
+ ergebnis := ergebnis * basis
+ PER;
+ ergebnis
+ END OP **
+
+____________________________________________________________________________
+
+
+(Diese Operation realisiert die Exponentiation für INT-Werte)
+
+
+
+2.4.5 Generizität von Prozeduren
+ und Operatoren
+
+
+In ELAN ist es möglich, unterschiedlichen Prozeduren bzw. Operatoren gleiche
+Namen zu geben. Solche Prozeduren (Operatoren) werden generische Prozeduren
+(Operatoren) genannt. Die Identifizierung erfolgt durch Anzahl, Reihenfolge und Daten­
+typ der Parameter (Operanden).
+
+Deshalb werden Prozeduren und Operatoren unter Angabe des Prozedur- bzw. des
+Operatorkopfes dokumentiert.
+
+Beispiele:
+
+
+INT OP MOD (INT CONST l, r)
+REAL OP MOD (REAL CONST l, r)
+
+
+Der MOD-Operator liefert den Rest einer Division. Er ist sowohl für INT- wie auch
+für REAL-Datenobjekte definiert.
+
+
+
+PROC put (INT CONST wert)
+PROC put (REAL CONST wert)
+PROC put (TEXT CONST wert)
+
+
+Die put-Prozedur ist für INT-, REAL- und TEXT-Datenobjekte definiert.
+
+
+
+Priorität von generischen Operatoren
+Bei der Neudefinition von Operatoren kann man bereits benutzte Sonderzeichen oder
+Schlüsselwörter benutzen. In diesem Fall bekommt der neudefinierte Operator die
+gleiche Priorität wie der bereits vorhandene Operator.
+
+
+
+2.4.6 Rekursive Prozeduren
+ und Operatoren
+
+
+Alle Prozeduren und Operatoren dürfen in ELAN rekursiv sein.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ INT PROC fakultaet (INT CONST n):
+ IF n > 0
+ THEN fakultaet (n-1) * n
+ ELSE 1
+ END IF
+ END PROC fakultaet
+
+____________________________________________________________________________
+
+
+Die Fakultätsfunktion ist kein gutes Beispiel für eine Rekursion, denn das Programm
+kann leicht in eine iterative Version umgewandelt werden:
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ INT PROC fakultaet (INT CONST n):
+ INT VAR prod :: 1, i;
+ FOR i FROM 2 UPTO n REP
+ prod := prod * i
+ END REP;
+ prod
+ END PROC fakultaet
+
+____________________________________________________________________________
+
+
+Die Umwandlung von einem rekursiven Programm in ein iteratives ist übrigens immer
+möglich, jedoch oft nicht so einfach, wie in dem Beispiel der Ackermann-Funktion:
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ INT PROC acker (INT CONST m, n):
+ IF m = 0
+ THEN n + 1
+ ELIF n = 0
+ THEN acker (m-1, 0)
+ ELSE acker (m - 1, acker (m, n - 1))
+ ENDIF
+ END PROC acker
+
+____________________________________________________________________________
+
+
+Das eigentliche Einsatzgebiet von rekursiven Algorithmen liegt aber bei den 'back­
+track'-Verfahren. Diese werden eingesetzt, wenn eine exakte algorithmische Lösung
+nicht bekannt ist oder nicht gefunden werden kann und man verschiedene Versuche
+machen muß, um zu einem Ziel (oder Lösung) zu gelangen.
+
diff --git a/doc/programmer-manual/1.8.7/doc/programmierhandbuch.2b b/doc/programmer-manual/1.8.7/doc/programmierhandbuch.2b
new file mode 100644
index 0000000..c2103ba
--- /dev/null
+++ b/doc/programmer-manual/1.8.7/doc/programmierhandbuch.2b
@@ -0,0 +1,1395 @@
+#headandbottom("52","EUMEL-Benutzerhandbuch","TEIL 2 : ELAN","2")#
+#pagenr ("%", 52)##setcount(1)##block##pageblock#
+#headeven#
+#center#EUMEL-Benutzerhandbuch
+#center#____________________________________________________________
+
+#end#
+#headodd#
+#center#TEIL 2 : ELAN
+#center#____________________________________________________________
+
+#end#
+#bottomeven#
+#center#____________________________________________________________
+2 - % #right#GMD
+#end#
+#bottomodd#
+#center#____________________________________________________________
+GMD #right#2 - %
+#end#
+
+
+2.5 Programmstruktur
+
+Ein ELAN-Programm kann aus mehreren Moduln (Bausteinen) aufgebaut sein, die in
+ELAN PACKETs genannt werden. Das letzte PACKET wird "main packet" genannt,
+weil in diesem das eigentliche Benutzerprogramm (Hauptprogramm) enthalten ist.
+Dies soll eine Empfehlung sein, in welcher Reihenfolge die Elemente eines PACKETs
+geschrieben werden sollen:
+
+Ein "main packet" kann aus folgenden Elementen bestehen:
+
+a) Deklarationen und Anweisungen. Diese müssen nicht in einer bestimmten Reihen­
+ folge im Programm erscheinen, sondern es ist möglich, erst in dem Augenblick zu
+ deklarieren, wenn z.B. eine neue Variable benötigt wird. Es ist jedoch gute Pro­
+ grammierpraxis, die meisten Deklarationen an den Anfang eines Programms oder
+ Programmteils (Refinement, Prozedur) zu plazieren.
+
+ <Deklarationen> ;
+ <Anweisungen>
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ INT VAR erste zahl, zweite zahl;
+
+ page;
+ put ("erste Zahl = "); get (erste zahl);
+ put ("zweite Zahl ="); get (zweite zahl)
+
+____________________________________________________________________________
+
+
+b) Deklarationen, Refinements und Anweisungen. In diesem Fall ist es notwendig, die
+ Refinements hintereinander zu plazieren. Refinement-Aufrufe und/oder
+ Anweisungen sollten textuell vorher erscheinen.
+
+ <Deklarationen> ;
+ <Refinement-Aufrufe und/oder Anweisungen> .
+ <Refinements>
+
+ Innerhalb der Refinements sind Anweisungen und/oder Deklarationen möglich.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ INT VAR erste zahl, zweite zahl;
+
+ loesche bildschirm;
+ lies zwei zahlen ein.
+
+ loesche bildschirm:
+ page.
+
+ lies zwei zahlen ein:
+ put ("erste Zahl = "); get (erste zahl);
+ put ("zweite Zahl ="); get (zweite zahl).
+
+____________________________________________________________________________
+
+
+c) Deklarationen, Prozeduren und Anweisungen. Werden Prozeduren vereinbart,
+ sollte man sie nach den Deklarationen plazieren. Danach sollten die Anweisungen
+ folgen:
+
+ <Deklarationen> ;
+ <Prozeduren> ;
+ <Anweisungen>
+
+ Mehrere Prozeduren werden durch ";" voneinander getrennt. In diesem Fall sind
+ die Datenobjekte aus den Deklarationen außerhalb von Prozeduren statisch, d.h.
+ während der gesamten Laufzeit des Programm vorhanden. Solche Datenobjekte
+ werden auch PACKET-Daten genannt. Im Gegensatz dazu sind die Datenobjekte
+ aus Deklarationen in Prozeduren dynamische Datenobjekte, die nur während der
+ Bearbeitungszeit der Prozedur existieren. Innerhalb einer Prozedur dürfen wieder­
+ um Refinements verwendet werden. Ein Prozedur-Rumpf hat also den formalen
+ Aufbau wie unter a) oder b) geschildert.
+
+ Die Refinements und Datenobjekte, die innerhalb einer Prozedur deklariert wurden,
+ sind lokal zu dieser Prozedur, d.h. können von außerhalb nicht angesprochen
+ werden.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ INT VAR erste zahl, zweite zahl;
+
+ PROC vertausche (INT VAR a, b):
+ INT VAR x;
+
+ x := a;
+ a := b;
+ b := x
+ END PROC vertausche;
+
+ put ("erste Zahl = "); get (erste zahl);
+ put ("zweite Zahl ="); get (zweite zahl);
+ IF erste zahl > zweite zahl
+ THEN vertausche (erste zahl, zweite zahl)
+ FI
+
+____________________________________________________________________________
+
+
+d) Deklarationen, Prozeduren, Anweisungen und PACKET-Refinements. Zusätzlich
+ zu der Möglichkeit c) ist es erlaubt, neben den Anweisungen außerhalb einer
+ Prozedur auch Refinements zu verwenden:
+
+ <Deklarationen> ;
+ <Prozeduren> ;
+ <Anweisungen> .
+ <Refinements>
+
+ Diese Refinements können nun in Anweisungen außerhalb der Prozeduren benutzt
+ werden oder auch durch die Prozeduren (im letzteren Fall spricht man analog zu
+ globalen PACKET-Daten auch von PACKET-Refinements oder globalen Refine­
+ ments). In PACKET-Refinements dürfen natürlich keine Datenobjekte verwandt
+ werden, die lokal zu einer Prozedur sind.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ INT VAR erste zahl, zweite zahl;
+
+ PROC vertausche (INT VAR a, b):
+ INT VAR x;
+
+ x := a;
+ a := b;
+ b := x
+ END PROC vertausche;
+
+ loesche bildschirm;
+ lies zwei zahlen ein;
+ ordne die zahlen.
+
+ loesche bildschirm:
+ page.
+
+ lies zwei zahlen ein:
+ put ("erste Zahl = "); get (erste zahl);
+ put ("zweite Zahl ="); get (zweite zahl).
+
+ ordne die zahlen:
+ IF erste zahl > zweite zahl
+ THEN vertausche (erste zahl, zweite zahl)
+ FI
+
+____________________________________________________________________________
+#page#
+
+2.6 Zusammengesetzte Datentypen
+
+In ELAN gibt es die Möglichkeit, gleichartige oder ungleichartige Datenobjekte zu
+einem Objekt zusammenzufassen.
+
+
+2.6.1 Reihung
+
+Die Zusammenfassung gleichartiger Datenobjekte, wird in ELAN eine Reihung (ROW)
+genannt. Die einzelnen Objekte einer Reihung werden Elemente genannt.
+
+Eine Reihung wird folgendermaßen deklariert:
+
+- Schlüsselwort #on("i")##on("b")#ROW#off("i")##off("b")#
+- Anzahl der zusammengefaßten Elemente
+ (INT-Denoter oder durch LET definierter Name)
+- Datentyp der Elemente
+- Zugriffsrecht ( #on("i")##on("b")#VAR#off("i")##off("b")# oder #on("i")##on("b")#CONST#off("i")##off("b")# )
+- Name der Reihung.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ ROW 10 INT VAR feld
+
+____________________________________________________________________________
+
+
+Im obigen Beispiel wird eine Reihung von 10 INT-Elementen deklariert. ROW 10 INT
+ist ein (neuer, von den elementaren unterschiedlicher) Datentyp, für den keine Opera­
+tionen definiert sind, außer der Zuweisung. Das Accessrecht (VAR im obigen Bei­
+spiel) und der Name ('feld') gilt - wie bei den elementaren Datentypen - für diesen
+neuen Datentyp, also für alle 10 Elemente.
+
+Warum gibt es keine Operationen außer der Zuweisung? Das wird sehr schnell
+einsichtig, wenn man bedenkt, daß es ja sehr viele Datentypen (zusätzlich zu den
+elementaren) gibt, weil Reihungen von jedem Datentyp gebildet werden können:
+
+
+ROW 1 INT ROW 1 REAL
+ROW 2 INT ROW 2 REAL
+ : :
+ROW maxint INT ROW maxint REAL
+
+ROW 1 TEXT ROW 1 BOOL
+ROW 2 TEXT ROW 2 BOOL
+ : :
+ROW maxint TEXT ROW maxint BOOL
+
+
+Für die elementaren INT-, REAL-, BOOL- und TEXT-Datentypen sind unter­
+schiedliche Operationen definiert. Man müßte nun für jeden dieser zusammengesetz­
+ten Datentypen z.B. auch 'get'- und 'put'-Prozeduren schreiben, was allein vom
+Schreibaufwand sehr aufwendig wäre. Das ist der Grund dafür, daß es keine vorgege­
+bene Operationen auf zusammengesetzte Datentypen gibt.
+
+Zugegebenermaßen könnte man mit solchen Datentypen, die nur über eine Operation
+verfügen (Zuweisung), nicht sehr viel anfangen, wenn es nicht eine weitere vorgege­
+bene Operation gäbe, die Subskription. Sie erlaubt es, auf die Elemente einer Reih­
+ung zuzugreifen und den Datentyp der Elemente "aufzudecken".
+
+Form:
+
+Rowname #on("i")##on("b")#[#off("i")##off("b")# Indexwert #on("i")##on("b")#]#off("i")##off("b")#
+
+Beispiel:
+
+
+feld [3]
+
+
+bezieht sich auf das dritte Element der Reihung 'feld' und hat den Datentyp INT. Für
+INT-Objekte haben wir aber einige Operationen, mit denen wir arbeiten können.
+
+____________________________________________________________________________
+ ........................... Beispiele: ........................
+ feld [3] := 7;
+ feld [4] := feld [3] + 4;
+
+____________________________________________________________________________
+
+
+Eine Subskription "schält" also vom Datentyp ein ROW ab und liefert ein Element der
+Reihung. Die Angabe der Nummer des Elements in der Reihung nennt man Subskript
+oder Index (in obigem Beispiel '3'). Der Subskript wird in ELAN in eckigen Klammern
+angegeben, um eine bessere Unterscheidung zu den runden Klammern in Ausdrücken
+zu erreichen. Ein subskribiertes ROW-Datenobjekt kann also überall da verwendet
+werden, wo ein entsprechender Datentyp benötigt wird (Ausnahme: nicht als Schlei­
+fenvariable).
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ PROC get (ROW 10 INT VAR feld):
+ INT VAR i;
+ FOR i FROM 1 UPTO 10 REP
+ put (i); put ("tes Element bitte:");
+ get (feld [i]);
+ line
+ END REP
+ END PROC get;
+
+ PROC put (ROW 10 INT CONST feld):
+ INT VAR i;
+ FOR i FROM 1 UPTO 10 REP
+ put (i); put ("tes Element ist:");
+ put (feld [i]);
+ line
+ END REP
+ END PROC put
+
+____________________________________________________________________________
+
+
+In diesen Beispielen werden Reihungen als Parameter benutzt.
+
+Diese beiden Prozeduren werden im folgenden Beispiel benutzt um 10 Werte einzu­
+lesen und die Summe zu berechnen:
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ ROW 10 INT VAR werte;
+ lies werte ein;
+ summiere sie;
+ drucke die summe und einzelwerte.
+
+ lies werte ein:
+ get (werte).
+
+ summiere sie:
+ INT VAR summe :: 0, i;
+ FOR i FROM 1 UPTO 10 REP
+ summe INCR werte [i]
+ END REP.
+
+ drucke die summe und einzelwerte:
+ put (werte);
+ line;
+ put ("Summe:"); put (summe).
+
+____________________________________________________________________________
+
+
+Da es möglich ist, von jedem Datentyp eine Reihung zu bilden, kann man natürlich
+auch von einer Reihung eine Reihung bilden:
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ ROW 5 ROW 10 INT VAR matrix
+
+____________________________________________________________________________
+
+
+Für eine "doppelte" Reihung gilt das für "einfache" Reihungen gesagte. Wiederum
+existieren keine Operationen für dieses Datenobjekt (außer der Zuweisung), jedoch ist
+es durch Subskription möglich, auf die Elemente zuzugreifen:
+
+
+matrix [3]
+
+
+liefert ein Datenobjekt mit dem Datentyp ROW 10 INT.
+
+Subskribiert man jedoch 'matrix' nochmals, so erhält man ein INT:
+
+
+matrix [2] [8]
+
+
+(jede Subskription "schält" von Außen ein ROW vom Datentyp ab).
+#page#
+
+2.6.2 Struktur
+
+Strukturen sind Datenverbunde wie Reihungen, aber die Komponenten können unglei­
+chartige Datentypen haben. Die Komponenten von Strukturen heißen Felder (Reihun­
+gen: Elemente) und der Zugriff auf ein Feld Selektion (Reihungen: Subskription). Eine
+Struktur ist - genauso wie bei Reihungen - ein eigener Datentyp, der in einer
+Deklaration angegeben werden muß.
+
+Die Deklaration einer Struktur sieht folgendermaßen aus:
+
+- Schlüsselwort #schl ("STRUCT#off("i")##off("b")#
+- unterschiedliche Datenobjekte in Klammern. Die Datenobjekte werden mit Datentyp und Namen angegeben
+- Zugriffsrecht ( #on("i")##on("b")#VAR#off("i")##off("b")# oder #on("i")##on("b")#CONST#off("i")##off("b")# )
+- Name der Struktur.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ STRUCT (TEXT name, INT alter) VAR ich
+
+____________________________________________________________________________
+
+
+Wiederum existieren keine Operationen auf Strukturen außer der Zuweisung und der
+Selektion, die es erlaubt, Komponenten aus einer Struktur herauszulösen.
+
+Die Selektion hat folgende Form:
+
+Objektname #on("i")##on("b")#.#off("i")##off("b")# Feldname
+
+Beispiele:
+
+
+ich . name
+ich . alter
+
+
+Die erste Selektion liefert einen TEXT-, die zweite ein INT-Datenobjekt. Mit diesen
+(selektierten) Datenobjekten kann - wie gewohnt - gearbeitet werden (Ausnahme:
+nicht als Schleifenvariable).
+
+Zum Datentyp einer Struktur gehören auch die Feldnamen:
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ STRUCT (TEXT produkt name, INT artikel nr) VAR erzeugnis
+
+____________________________________________________________________________
+
+
+Die obige Struktur ist ein anderer Datentyp als im ersten Beispiel dieses Abschnitts,
+da die Namen der Felder zur Unterscheidung hinzugezogen werden. Für Strukturen -
+genauso wie bei Reihungen - kann man sich neue Operationen definieren.
+
+Im folgenden Programm werden eine Struktur, die Personen beschreibt, die Prozedu­
+ren 'put', 'get' und der dyadische Operator HEIRATET definiert. Anschließend werden
+drei Paare verHEIRATET.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ PROC get (STRUCT (TEXT name, vorname, INT alter) VAR p):
+ put ("bitte Nachname:"); get ( p.name);
+ put ("bitte Vorname:"); get ( p.vorname);
+ put ("bitte Alter:"); get ( p.alter);
+ line
+ END PROC get;
+
+ PROC put (STRUCT (TEXT name, vorname, INT alter) CONST p):
+ put (p.vorname); put (p.name);
+ put ("ist");
+ put (p.alter);
+ put ("Jahre alt");
+ line
+ END PROC put;
+
+ OP HEIRATET
+ (STRUCT (TEXT name, vorname, INT alter) VAR w,
+ STRUCT (TEXT name, vorname, INT alter) CONST m):
+ w.name := m.name
+ END OP HEIRATET;
+
+____________________________________________________________________________
+
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ ROW 3 STRUCT (TEXT name, vorname, INT alter) VAR frau,
+ mann;
+
+ personendaten einlesen;
+ heiraten lassen;
+ paardaten ausgeben.
+
+ personendaten einlesen:
+ INT VAR i;
+ FOR i FROM 1 UPTO 3 REP
+ get (frau [i]);
+ get (mann [i])
+ END REP.
+
+ heiraten lassen:
+ FOR i FROM 1 UPTO 3 REP
+ frau [i] HEIRATET mann [i]
+ END REP.
+
+ paardaten ausgeben:
+ FOR i FROM 1 UPTO 3 REP
+ put (frau [i]);
+ put ("hat geheiratet:"); line;
+ put (mann [i]); line
+ END REP.
+
+____________________________________________________________________________
+
+
+Reihungen und Strukturen dürfen miteinander kombiniert werden, d.h. es darf eine
+Reihung in einer Struktur erscheinen oder es darf eine Reihung von einer Struktur
+vorgenommen werden. Selektion und Subskription sind in diesen Fällen in der Reihen­
+folge vorzunehmen, wie die Datentypen aufgebaut wurden (von außen nach innen).
+#page#
+
+2.6.3 LET-Konstrukt für zusammengesetzte Datentypen
+
+
+Die Verwendung von Strukturen oder auch Reihungen kann manchmal schreibauf­
+wendig sein. Mit dem LET-Konstrukt darf man Datentypen einen Namen geben.
+Dieser Name steht als Abkürzung und verringert so die Schreibarbeit. Zusätzlich wird
+durch die Namensgebung die Lesbarkeit des Programms erhöht.
+
+Form:
+
+#on("i")##on("b")#LET#off("i")##off("b")# Name #on("i")##on("b")#=#off("i")##off("b")# Datentyp
+
+Der Name darf nur aus Großbuchstaben (ohne Blanks) bestehen.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ LET PERSON = STRUCT (TEXT name, vorname, INT alter);
+
+ PROC get (PERSON VAR p):
+ put ("bitte Nachname:"); get ( p.name);
+ put ("bitte Vorname:"); get ( p.vorname);
+ put ("bitte Alter:"); get ( p.alter);
+ line
+ END PROC get;
+
+ PROC put (PERSON CONST p):
+ put (p.vorname); put (p.name); put ("ist");
+ put (p.alter); put ("Jahre alt"); line
+ END PROC put;
+
+ OP HEIRATET (PERSON VAR f, PERSON CONST m):
+ f.name := m.name
+ END OP HEIRATET;
+
+ ROW 3 PERSON VAR mann, frau;
+
+____________________________________________________________________________
+
+
+Überall, wo der abzukürzende Datentyp verwandt wird, kann stattdessen der Name
+PERSON benutzt werden. Wohlgemerkt: PERSON ist kein neuer Datentyp, sondern
+nur ein Name, der für STRUCT (....) steht. Der Zugriff auf die Komponenten des
+abgekürzten Datentyps bleibt erhalten (was bei abstrakten Datentypen, die später
+erklärt werden, nicht mehr der Fall ist).
+
+Neben der Funktion der Abkürzung von Datentypen kann das LET-Konstrukt auch
+zur Namensgebung für Denoter verwandt werden (siehe 2.3.1.2).
+
+
+
+2.6.4 Denoter für zusammengesetzte
+ Datentypen (Konstruktor)
+
+
+Oft ist es notwendig, Datenverbunden Werte zuzuweisen (z.B.: bei der Initialisierung).
+Dies kann durch normale Zuweisungen erfolgen:
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ LET PERSON = STRUCT (TEXT name, vorname, INT alter);
+
+ PERSON VAR mann;
+
+ mann.name := "meier";
+ mann.vorname := "egon";
+ mann.alter := 27
+
+____________________________________________________________________________
+
+
+Eine andere Möglichkeit für die Wertbesetzung von Datenverbunden ist der Konstruk­
+tor:
+
+Form:
+
+Datentyp #on("i")##on("b")#:#off("i")##off("b")# #on("i")##on("b")#(#off("i")##off("b")# Wertliste #on("i")##on("b")#)#off("i")##off("b")#
+
+In der Wertliste wird für jede Komponente des Datentyps, durch Kommata getrennt,
+ein Wert aufgeführt. Besteht eine der Komponenten wiederum aus einem Datenver­
+bund, muß innerhalb des Konstruktors wiederum ein Konstruktor eingesetzt werden.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ LET PERSON = STRUCT (TEXT name, vorname, INT alter);
+
+ PERSON VAR mann, frau;
+
+ frau := PERSON : ( "niemeyer", "einfalt", 65);
+ frau HEIRATET PERSON : ( "meier", "egon", 27)
+
+____________________________________________________________________________
+
+
+Ein Konstruktor ist also ein Mechanismus, um ein Datenobjekt eines Datenverbundes
+in einem Programm zu notieren.
+
+Konstruktoren sind natürlich für Reihungen auch möglich:
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ ROW 7 INT VAR feld;
+ feld := ROW 7 INT : ( 1, 2, 3, 4, 5, 6, 7);
+____________________________________________________________________________
+#page#
+
+2.7 Abstrakte Datentypen
+
+
+2.7.1 Definition neuer Datentypen
+
+Im Gegensatz zur LET-Vereinbarung für Datentypen, bei der lediglich ein neuer
+Name für einen bereits vorhandenen Datentyp eingeführt wird und bei der somit auch
+keine neuen Operationen definiert werden müssen (weil die Operationen für den
+abzukürzenden Datentyp verwandt werden können), wird durch eine TYPE-Verein­
+barung ein gänzlich neuer Datentyp eingeführt.
+
+Form:
+
+#on("i")##on("b")#TYPE#off("i")##off("b")# Name #on("i")##on("b")#=#off("i")##off("b")# Feinstruktur
+
+Der Name darf nur aus Großbuchstaben (ohne Blanks) bestehen. Die Feinstruktur
+(konkreter Typ, Realisierung des Datentyps) kann jeder bereits definierte Datentyp
+sein.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ TYPE PERSON = STRUCT (TEXT name, vorname, INT alter)
+
+____________________________________________________________________________
+
+
+Der neudefinierte Datentyp wird abstrakter Datentyp genannt. Im Gegensatz zu
+Strukturen und Reihungen stehen für solche Datentypen noch nicht einmal die Zuwei­
+sung zur Verfügung. Ein solcher Datentyp kann genau wie alle anderen Datentypen
+verwendet werden (Deklarationen, Parameter, wertliefernde Prozeduren, als Kompo­
+nenten in Reihungen und Strukturen usw.).
+
+Wird der Datentyp über die Schnittstelle des PACKETs anderen Programmteilen zur
+Verfügung gestellt, so müssen Operatoren und/oder Prozeduren für den Datentyp
+ebenfalls "herausgereicht" werden. Da dann der neudefinierte Datentyp genauso wie
+alle anderen Datentypen verwandt werden kann, aber die Komponenten (Feinstruktur)
+nicht zugänglich sind, spricht man von abstrakten Datentypen.
+
+Welche Operationen sollten für einen abstrakten Datentyp zur Verfügung stehen?
+Obwohl das vom Einzelfall abhängt, werden meistens folgende Operationen und
+Prozeduren definiert:
+
+- 'get'- und 'put'-Prozeduren.
+- Zuweisung (auch für die Initialisierung notwendig).
+- Denotierungs-Prozedur (weil kein Konstruktor für den abstrakten Datentyp außer­
+ halb des definierenden PACKETs zur Verfügung steht)
+
+
+
+2.7.2 Konkretisierung
+
+Um neue Operatoren und/oder Prozeduren für einen abstrakten Datentyp zu schrei­
+ben, ist es möglich, auf die Komponenten des Datentyps (also auf die Feinstruktur)
+mit Hilfe des Konkretisierers zuzugreifen. Der Konkretisierer arbeitet ähnlich wie die
+Subskription oder Selektion: er ermöglicht eine typmäßige Umbetrachtung vom ab­
+strakten Typ zum Datentyp der Feinstruktur.
+
+Form:
+
+#on("i")##on("b")#CONCR#off("i")##off("b")# #on("i")##on("b")#(#off("i")##off("b")# Ausdruck #on("i")##on("b")#)#off("i")##off("b")#
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ TYPE MONAT = INT;
+
+ PROC put (MONAT CONST m):
+ put ( CONCR (m))
+ END PROC put;
+
+____________________________________________________________________________
+
+
+Der Konkretisierer ist bei Feinstrukturen notwendig, die von elementarem Datentyp
+sind. Besteht dagegen die Feinstruktur aus Reihungen oder Strukturen, dann wird
+durch eine Selektion oder Subskription eine implizite Konkretisierung vorgenommen.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ TYPE LISTE = ROW 100 INT;
+
+ LISTE VAR personal nummer;
+ ...
+ personal nummer [3] := ...
+ (* das gleiche wie *)
+ CONCR (personal nummer) [3] := ...
+
+____________________________________________________________________________
+
+
+2.7.3 Denoter für abstrakte
+ Datentypen (Konstruktor)
+
+
+Denoter für neudefinierte Datentypen werden mit Hilfe des Konstruktors gebildet:
+
+Form:
+
+Datentyp #on("i")##on("b")#:#off("i")##off("b")# #on("i")##on("b")#(#off("i")##off("b")# Wertliste #on("i")##on("b")#)#off("i")##off("b")#
+
+In der Wertliste wird für jede Komponente des Datentyps, durch Kommata getrennt,
+ein Wert aufgeführt. Besteht eine der Komponenten wiederum aus einem Datenver­
+bund, muß innerhalb des Konstruktors wiederum ein Konstruktor eingesetzt werden.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ TYPE GEHALT = INT;
+
+ GEHALT VAR meins :: GEHALT : (10000);
+
+____________________________________________________________________________
+
+
+Besteht die Feinstruktur aus einem Datenverbund, muß der Konstruktor u.U. mehrfach
+geschachtelt angewandt werden:
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ TYPE KOMPLEX = ROW 2 REAL;
+
+ KOMPLEX CONST x :: KOMPLEX : ( ROW 2 REAL : ( 1.0, 2.0));
+
+____________________________________________________________________________
+
+
+Auf die Feinstruktur über den Konkretisierer eines neudefinierten Datentyps darf nur in
+dem PACKET zugegriffen werden, in dem der Datentyp definiert wurde. Der Konstruk­
+tor kann ebenfalls nur in dem typdefinierenden PACKET verwandt werden.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ PACKET widerstaende DEFINES WIDERSTAND, REIHE, PARALLEL,
+ :=, get, put:
+
+ TYPE WIDERSTAND = INT;
+
+ OP := (WIDERSTAND VAR l, WIDERSTAND CONST r):
+ CONCR (l) := CONCR (r)
+ END OP :=;
+
+ PROC get (WIDERSTAND VAR w):
+ INT VAR i;
+ get (i);
+ w := WIDERSTAND : (i)
+ END PROC get;
+
+ PROC put (WIDERSTAND CONST w):
+ put (CONCR (w))
+ END PROC put;
+
+ WIDERSTAND OP REIHE (WIDERSTAND CONST l, r):
+ WIDERSTAND : ( CONCR (l) + CONCR (r))
+ END OP REIHE;
+
+ WIDERSTAND OP PARALLEL (WIDERSTAND CONST l, r):
+ WIDERSTAND :
+ ((CONCR (l) * CONCR (r)) DIV (CONCR (l) + CONCR (r)))
+ END OP PARALLEL
+
+ END PACKET widerstaende
+
+____________________________________________________________________________
+
+
+Dieses Programm realisiert den Datentyp WIDERSTAND und mit den Operationen
+eine Fachsprache, mit dem man nun leicht WIDERSTANDs-Netzwerke berechnen
+kann, wie z.B. folgendes:
+
+
+
+ +---R4---+
+ | |
+ +---R1---+ +---R5---+
+ | | | |
+ ---+ +---R3---+ +---
+ | | | |
+ +---R2---+ +---R6---+
+ | |
+ +---R7---+
+
+
+Zur Berechnung des Gesamtwiderstandes kann nun folgendes Programm geschrieben
+werden:
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ ROW 7 WIDERSTAND VAR r;
+ widerstaende einlesen;
+ gesamtwiderstand berechnen;
+ ergebnis ausgeben.
+
+ widerstaende einlesen:
+ INT VAR i;
+ FOR i FROM 1 UPTO 7 REP
+ put ("bitte widerstand R"); put (i); put (":");
+ get (r [i]);
+ END REP.
+
+ gesamtwiderstand berechnen:
+ WIDERSTAND CONST rgesamt :: (r [1] PARALLEL r [2]) REIHE
+ r [3] REIHE (r [4] PARALLEL r [5] PARALLEL r [6]
+ PARALLEL r [7]).
+
+ ergebnis ausgeben:
+ line;
+ put (rgesamt).
+____________________________________________________________________________
+#page#
+
+2.8 Dateien
+
+Dateien werden benötigt, wenn
+
+- Daten über die Abarbeitungszeit eines Programms aufbewahrt werden sollen;
+- der Zeitpunkt oder Ort der Datenerfassung nicht mit dem Zeitpunkt oder Ort der
+ Datenverarbeitung übereinstimmt;
+- die gesamte Datenmenge nicht auf einmal in den Zentralspeicher eines Rechners
+ paßt;
+- die Anzahl und/oder Art der Daten nicht von vornherein bekannt sind.
+
+Eine Datei ("file") ist eine Zusammenfassung von Daten, die auf Massenspeichern
+aufbewahrt wird. Dateien sind in bestimmten Informationsmengen, den Sätzen ("re­
+cords") organisiert.
+
+
+
+2.8.1 Datentypen FILE und DIRFILE
+
+In ELAN gibt es zwei Arten von Dateien. Sie werden durch die Datentypen FILE
+und DIRFILE realisiert:
+
+
+
+FILE:
+sequentielle Dateien. Die Sätze können nur sequentiell gelesen bzw. geschrieben
+werden. Eine Positionierung ist nur zum nächsten Satz möglich.
+
+
+DIRFILE:
+indexsequentielle Dateien. Die Positionierung erfolgt direkt mit Hilfe eines Schlüssels
+("key") oder Index, kann aber auch sequentiell vorgenommen werden.
+
+#on("b")#Wichtig: #off("b")#
+DIRFILEs sind auf dem EUMEL-System standardmäßig nicht implementiert! Deswe­
+gen wird auf diesen Dateityp hier nicht weiter eingegangen.
+#page#
+
+2.8.2 Deklaration und Assoziierung
+
+Dateien müssen in einem ELAN-Programm - wie alle anderen Objekte auch -
+deklariert werden.
+
+Form:
+
+#on("i")##on("b")#FILE#off("i")##off("b")# #on("i")##on("b")#VAR#off("i")##off("b")# interner Dateibezeichner
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ FILE VAR f
+
+____________________________________________________________________________
+
+
+Dabei ist zu beachten, daß im EUMEL-System alle FILEs als VAR deklariert werden
+müssen, denn jede Lese/Schreib-Operation verändert einen FILE.
+
+Dateien werden normalerweise vom Betriebsystem eines Rechners aufbewahrt und
+verwaltet. Somit ist eine Verbindung von einem ELAN-Programm, in dem eine Datei
+unter einem Namen - wie jedes andere Datenobjekt auch - angesprochen werden
+soll, und dem Betriebssystem notwendig. Dies erfolgt durch die sogenannte Assozi­
+ierungsprozedur. Die Assoziierungsprozedur 'sequential file' hat die Aufgabe, eine in
+einem Programm deklarierte FILE VAR mit einer bereits vorhandenen oder noch
+einzurichtenden Datei des EUMEL-Systems zu koppeln.
+
+Form:
+
+#on("i")##on("b")#sequential file#off("i")##off("b")# #on("i")##on("b")#(#off("i")##off("b")# Betriebsrichtung, Dateiname #on("i")##on("b")#)#off("i")##off("b")#
+
+Es gibt folgende Betriebsrichtungen (TRANSPUTDIRECTIONs):
+
+
+input:
+Die Datei kann vom Programm nur gelesen werden. Durch 'input' wird bei der Asso­
+ziierung automatisch auf den ersten Satz der Datei positioniert. Ist die zu lesende
+Datei nicht vorhanden, wird ein Fehler gemeldet.
+
+
+output:
+Die Datei kann vom Programm nur beschrieben werden. Durch 'output' wird bei der
+Assoziierung automatisch hinter den letzten Satz der Datei positioniert (bei einer
+leeren Datei also auf den ersten Satz). Ist die Datei vor der Assoziierung nicht vor­
+handen, wird sie automatisch eingerichtet.
+
+
+modify:
+Im EUMEL-System gibt es noch die Betriebsrichtung 'modify'.
+Die Datei kann vom Programm in beliebiger Weise gelesen und beschrieben werden.
+Im Gegensatz zu den Betriebsrichtungen 'input' und 'output', bei denen ausschließlich
+ein rein sequentielles Lesen oder Schreiben erlaubt ist, kann bei 'modify' beliebig
+positioniert, gelöscht, eingefügt und neu geschrieben werden.
+
+Nach erfolgter Assoziiierung ist auf den zuletzt bearbeiteten Satz positioniert. Die
+Datei wird automatisch eingerichtet, wenn sie vor der Assoziierung nicht vorhanden
+war.
+
+Der zweite Parameter der Assoziierungsprozedur gibt an, unter welchem Namen die
+Datei in der Task existiert oder eingerichtet werden soll.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ FILE VAR meine datei :: sequential file (output, "xyz");
+
+____________________________________________________________________________
+
+
+Folgendes Beispiel zeigt ein Programm, welches eine Datei liest und auf dem Ausga­
+bemedium ausgibt:
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ FILE VAR f :: sequential file (input, "datei1");
+ TEXT VAR satz;
+ WHILE NOT eof (f) REP
+ getline (f, satz);
+ putline (satz);
+ END REP.
+
+____________________________________________________________________________
+
+
+Eine genau Übersicht der für Dateien existierende Operatoren und Prozeduren finden
+Sie im Teil 5.3.
+#page#
+
+2.9 Abstrakte Datentypen
+ im EUMEL-System
+
+
+
+2.9.1 Datentyp TASK
+
+Tasks müssen im Rechnersystem eindeutig identifiziert werden; sogar im EUMEL-
+Rechner-Netz sind Tasks eindeutig identifizierbar. Dazu wird der spezielle Datentyp
+'TASK' benutzt, denn die Identifizierung einer Task über den Namen ist nicht eindeu­
+tig. Der Benutzer kann ja einen Tasknamen ändern, eine Task löschen und eine
+neue Task mit gleichem Namen einrichten, die jedoch nicht gleich reagiert. Somit
+werden Tasks eindeutig über Variablen vom Datentyp TASK identifiziert.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ TASK VAR plotter := task ("PLOTTER 1")
+
+____________________________________________________________________________
+
+
+Die Taskvariable 'plotter' bezeichnet jetzt die Task im System, die augenblicklich den
+Namen "PLOTTER 1" hat. Die Prozedur 'task' liefert den systeminternen Taskbe­
+zeichner.
+
+Nun sind Taskvariablen auch unter Berücksichtigung der Zeit und nicht nur im aktuel­
+len Systemzustand eindeutig. Der Programmierer braucht sich also keine Sorgen
+darüber zu machen, daß seine Taskvariable irgendwann einmal eine "falsche" Task
+(nach Löschen von "PLOTTER 1" neu eingerichtete gleichen oder anderen Namens)
+identifiziert. Wenn die Task "PLOTTER 1" gelöscht worden ist, bezeichnet 'plotter'
+keine gültige Task mehr.
+
+Unbenannte Tasks haben alle den Pseudonamen "-". Sie können nur über Taskvari­
+ablen angesprochen werden.
+
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ PROC generate shutup manager:
+ TASK VAR son;
+ begin ("shutup", PROC shutup manager, son)
+ END PROC generate shutup manager;
+
+ PROC shutup manager:
+ disable stop;
+ command dialogue (TRUE);
+ REP
+ break;
+ line;
+ IF yes ("shutup")
+ THEN clear error;
+ shutup
+ FI
+ PER
+ END PROC shutup manager
+
+____________________________________________________________________________
+
+
+Ein Taskvariable wird zum Beispiel als Parameter für die Prozedur 'begin' benötigt.
+
+begin
+ #on("b")#PROC begin (TEXT CONST son name, PROC start,
+ TASK VAR new task)#off("b")#
+ Die Prozedur richtet eine Sohntask mit Namen 'son name' (im Beispiel: shutup)
+ ein, die mit der Prozedur 'start' (im Beispiel: shutup manager) gestartet wird. 'new
+ task' (im Beispiel: son) identifiziert den Sohn, falls die Sohntask korrekt eingerich­
+ tet wurde.
+#page#
+
+2.9.2 Datentyp THESAURUS
+
+Ein Thesaurus ist ein Namensverzeichnis, das bis zu 200 Namen beinhalten kann.
+Dabei muß jeder Name mindestens ein Zeichen und höchstens 100 Zeichen lang sein.
+Steuerzeichen (code < 32) werden im Namen folgendermaßen umgesetzt:
+
+#on("i")##on("b")#steuerzeichen#off("b")##off("i")# wird umgesetzt in #on("i")##on("b")#"""" + code(steuerzeichen) + """"#off("b")##off("i")#
+
+Ein Thesaurus ordnet jedem eingetragenen Namen einen Index zwischen 1 und 200
+(einschließlich) zu. Diese Indizes bieten dem Anwender die Möglichkeit, Thesauri zur
+Verwaltung benannter Objekte zu verwenden. (Der Zugriff erfolgt dann über den Index
+eines Namens in einem Thesaurus). So werden Thesauri u.a. von der Dateiverwaltung
+benutzt. Sie bilden die Grundlage der ALL- und SOME-Operatoren.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ initialisiere;
+ arbeite thesaurus ab.
+
+ initialisiere:
+ THESAURUS VAR eine auswahl :: SOME (myself);
+ TEXT VAR thesaurus element;
+ INT VAR index :: 0.
+
+ arbeite thesaurus ab:
+ REPEAT
+ get (eine auswahl, thesaurus element, index);
+ IF thesaurus element = ""
+ THEN LEAVE arbeite thesaurus ab
+ FI;
+ fuehre aktionen durch
+ PER.
+
+ fuehre aktionen durch:
+ edit (thesaurus element);
+ lineform (thesaurus element);
+ pageform (thesaurus element);
+ print (thesaurus element).
+
+____________________________________________________________________________
+
+
+Dieses Beispiel führt für eine Auswahl der in der Task befindlichen Dateien nachein­
+ander die Kommandos 'edit', 'lineform', 'pageform' und 'print' aus.
+
+Die benutzten Operatoren und Prozeduren leisten folgendes:
+
+#ix("SOME")#
+ #on("b")#THESAURUS OP SOME (TASK CONST task) #off("b")#
+ Der Operator bietet das Verzeichnis der in der angegeben Task befindlichen
+ Dateien zum Editieren an. Namen, die nicht gewünscht sind, müssen aus dem
+ Verzeichnis gelöscht werden.
+
+
+#ix("get")#
+ #on("b")#PROC get (THESAURUS CONST t, TEXT VAR name, INT VAR index)
+ #off("b")# Die Prozedur liefert den nächsten Eintrag aus dem angegebenen Thesaurus 't'.
+ 'Nächster' heißt hier, der kleinste vorhandene mit einem Index größer als 'index'.
+ Dabei wird in 'name'der Name und in 'index'der Index des Eintrags geliefert.
+#page#
+
+2.9.3 Datenräume
+
+Datenräume sind die Grundlage von Dateien im EUMEL-System. Einen Datenraum
+kann man sich als eine Sammlung von Daten vorstellen (u.U. leer). Man kann einem
+Datenraum durch ein Programm einen Datentyp "aufprägen". Nach einem solchen
+"Aufpräge"-Vorgang kann der Datenraum wie ein "normaler" Datentyp behandelt
+werden.
+
+Standarddateien (FILEs) sind eine besondere Form von Datenräumen. Sie können nur
+Texte aufnehmen, da sie ja hauptsächlich für die Kommunikation mit dem Menschen
+(vorwiegend mit Hilfe des Editors bzw. Ein-/ Ausgabe) gedacht sind. Will man Zahlen
+in einen FILE ausgeben, so müssen diese zuvor in Texte umgewandelt werden. Hier­
+für stehen Standardprozeduren zur Verfügung (z.B. 'put (f, 17)').
+
+Will man aber Dateien zur Kommunikation zwischen Programmen verwenden, die
+große Zahlenmengen austauschen, verursachen die Umwandlungen von Zahlen in
+TEXTe und umgekehrt unnötigen Rechenaufwand. Zu diesem Zweck werden im
+EUMEL-System Datenräume eingesetzt, die es gestatten, beliebige Strukturen
+(Typen) in Dateien zu speichern. Solche Datenräume kann man weder mit dem Editor
+noch mit dem Standarddruckprogramm (print) bearbeiten, da diese ja den Typ des in
+dem Datenraum gespeicherten Objektes nicht kennen.
+
+
+
+2.9.3.1 Datentyp DATASPACE
+
+Datenräume können als eigener Datentyp (DATASPACE) in einem Programm behan­
+delt werden. Somit können Datenräume (als Ganzes) ohne Kenntnis eines eventuell
+(vorher oder später) aufgeprägten Typs benutzt werden.
+
+Als Operationen auf DATASPACE-Objekte sind nur Transporte, Löschen und Zuwei­
+sung zugelassen.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ DATASPACE VAR ds
+
+____________________________________________________________________________
+
+
+Für Datenräume ist die Zuweisung definiert. Der Zuweisungsoperator (':=') bewirkt
+eine Kopie des Datenraums vom rechten auf den linken Operanden.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ DATASPACE VAR datenraum :: nilspace;
+
+____________________________________________________________________________
+
+
+Die Prozedur 'nilspace' liefert einen leeren Datenraum. Der Datenraum 'datenraum' ist
+also eine Kopie des leeren Datenraums.
+
+Die Prozeduren und Operatoren für Datenräume werden im Teil 5.4.7 beschrieben.
+#page#
+
+2.9.3.2 BOUND-Objekte
+
+Wie bereits erwähnt, kann man einem Datenraum einen Datentyp aufprägen. Dazu
+werden #ib#BOUND#ie#-Objekte benutzt. Mit dem Schlüsselwort #on("i")##on("b")#BOUND#off("i")##off("b")#, welches in der
+Deklaration vor den Datentyp gestellt wird, teilt man dem ELAN-Compiler mit, daß
+die Werte eines Datentyps in einem Datenraum gespeichert sind bzw. gespeichert
+werden sollen.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ BOUND ROW 1000 REAL VAR liste
+
+____________________________________________________________________________
+
+
+Die Ankopplung des BOUND-Objekts an eine Datei erfolgt mit dem Operator #on("i")##on("b")#:=#off("i")##off("b")#.
+
+Form:
+
+BOUND-Objekt #on("i")##on("b")#:=#off("i")##off("b")# Datenraum
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ BOUND ROW 1000 REAL VAR gehaltsliste := new ("Gehälter")
+
+____________________________________________________________________________
+
+
+Die Prozedur 'new' kreiert dabei einen leeren Datenraum (hier mit dem Namen 'Ge­
+hälter'), der mit Hilfe der Zuweisung (hier: Initialisierung) an die Variable 'gehaltsliste'
+gekoppelt wird.
+
+Nun kann man mit der 'gehaltsliste' arbeiten wie mit allen anderen Feldern auch. Die
+Daten, die in 'gehaltsliste' gespeichert, werden eigentlich im Datenraum 'Gehälter'
+abgelegt.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ gehaltsliste [5] := 10 000.0; (* Traumgehalt *)
+ gehaltsliste [index] INCR 200.0; (* usw. *)
+
+____________________________________________________________________________
+
+
+Man kann auch Prozeduren schreiben, die auf der Gehaltsliste arbeiten.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ PROC sort (ROW 1000 REAL VAR liste):
+ ...
+ END PROC sort;
+ ...
+ sort (CONCR (gehaltsliste));
+ ...
+
+____________________________________________________________________________
+
+
+Man beachte, daß der formale Parameter der Prozedur 'sort' nicht mit BOUND spezi­
+fiziert werden darf (BOUND wird nur bei der Deklaration des Objekts angegeben). Das
+ist übrigens ein weiterer wichtiger Vorteil von BOUND-Objekten: man kann alle
+Prozeduren des EUMEL-Systems auch für BOUND-Objekte verwenden, nur die
+Datentypen müssen natürlich übereinstimmen.
+
+
+Häufige Fehler bei der Benutzung von Datenräumen
+
+- Wenn man an ein DATASPACE-Objekt zuweist (z.B.: DATASPACE VAR ds :=
+ new ("mein datenraum")), so erhält man, wie bereits erwähnt, eine Kopie des
+ Datenraums in 'ds'. Koppelt man jetzt 'ds' an ein BOUND-Objekt an und führt
+ Änderungen durch, so wirken diese nur auf die Kopie und nicht auf die Quelle.
+ Für Änderungen in der Quelle, also in der vom Datei-Manager verwalteten Datei,
+ ist stets direkt anzukoppeln.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ BOUND ROW 10 INT VAR reihe;
+ INT VAR i;
+
+ PROC zeige dsinhalt (TEXT CONST datenraum):
+ BOUND ROW 10 INT VAR inhalt := old (datenraum);
+ INT VAR j;
+ line;
+ putline ("Inhalt:" + datenraum);
+ FOR j FROM 1 UPTO 10 REP
+ put (inhalt (j))
+ PER
+ END PROC zeige dsinhalt;
+
+ (* falsch: es wird auf der Kopie gearbeitet: *)
+ DATASPACE VAR ds := new ("Gegenbeispiel: Zahlen 1 bis 10");
+ reihe := ds;
+ besetze reihe;
+ zeige dsinhalt ("Gegenbeispiel: Zahlen 1 bis 10");
+
+ (* richtig: es wird auf dem Datenraum gearbeitet: *)
+ reihe := new ("Beispiel: Zahlen 1 bis 10");
+ besetze reihe;
+ zeige dsinhalt ("Beispiel: Zahlen 1 bis 10").
+
+ besetze reihe:
+ FOR i FROM 1 UPTO 10 REP
+ reihe (i) := i
+ PER.
+
+____________________________________________________________________________
+
+
+ Der Datenraum 'Gegenbeispiel: Zahlen 1 bis 10' wird nicht mit Werten besetzt,
+ sondern die Kopie dieses Datenraums, der unbenannte Datenraum 'ds'. Auf dem
+ direkt angekoppelten Datenraum 'Beispiel: Zahlen 1 bis 10' werden die Werte
+ gespeichert.
+
+
+- Wenn man ein DATASPACE-Objekt benutzt, ohne den Datei-Manager zu
+ verwenden, so muß man selbst dafür sorgen, daß dieses Objekt nach seiner
+ Benutzung wieder gelöscht wird. Das Löschen geschieht durch die Prozedur
+ 'forget'. Ein automatisches Löschen von DATASPACE-Objekten erfolgt nicht bei
+ Programmende (sonst könnten sie ihre Funktion als Datei nicht erfüllen). Nur
+ durch 'forget' oder beim Löschen einer Task werden alle ihr gehörenden
+ DATASPACE-Objekte gelöscht und der belegte Speicherplatz freigegeben.
+
+
+- Ferner ist zu beachten, daß vor der Ankopplung an ein BOUND-Objekt das
+ DATASPACE-Objekt initialisiert wird (im Normalfall mit 'nilspace').
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ DATASPACE VAR ds := nilspace;
+ BOUND ROW 1000 REAL VAR real feld := ds;
+ ....
+ real feld [index] := wert;
+ ....
+ forget (ds) (* Datenraum löschen,
+ damit der Platz wieder verwendet wird *)
+
+____________________________________________________________________________
+
+
+- Will man auf die Feinstruktur eines BOUND-Objekts zugreifen, so muß man
+ strenggenommen den Konkretisierer benutzen:
+
+ Form:
+
+ #on("i")##on("b")#CONCR#off("i")##off("b")# #on("i")##on("b")#(#off("i")##off("b")# Ausdruck #on("i")##on("b")#)#off("i")##off("b")#
+
+ Der Konkretisierer ermöglicht eine typmäßige Umbetrachtung vom BOUND-Objekt
+ zum Datentyp der Feinstruktur. Ist der Zugriff jedoch eindeutig, so wird 'CONCR'
+ automatisch vom Compiler ergänzt.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ BOUND INT VAR i := old ("i-Wert");
+ INT VAR x;
+ x := wert.
+
+ wert:
+ IF x < 0
+ THEN 0
+ ELSE CONCR (i)
+ FI.
+
+____________________________________________________________________________
+
+
+In diesem Beispiel muß der Konkretisierer benutzt werden, da sonst der Resultattyp
+des Refinements nicht eindeutig ist (BOUND oder INT?).
+
+
+
+2.9.3.3 Definition neuer Dateitypen
+
+Durch die Datenräume und die Datentyp-Definition von ELAN ist es für Programmie­
+rer relativ einfach, neue Datei-Datentypen zu definieren. In der Regel reicht der
+Datentyp FILE für "normale" Anwendungen aus, jedoch kann es manchmal sinnvoll
+und notwendig sein, neue Datei-Typen für spezielle Aufgaben zu definieren.
+
+In diesem Abschnitt soll an dem Beispiel DIRFILE (welcher zwar im ELAN-Standard
+definiert, aber nicht im EUMEL-System realisiert ist) gezeigt werden, wie ein neuer
+Datei-Datentyp definiert wird:
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ PACKET dirfiles DEFINES DIRFILE, :=, dirfile, getline, ...:
+
+ LET maxsize = 1000;
+
+ TYPE DIRFILE = BOUND ROW maxsize TEXT;
+ (* DIRFILE besteht aus TEXTen; Zugriff erfolgt ueber einen
+ Schluessel, der den Index auf die Reihung darstellt *)
+
+ OP := (DIRFILE VAR dest, DATASPACE CONST space):
+ CONCR (dest) := space
+ END OP :=;
+
+ DATASPACE PROC dirfile (TEXT CONST name):
+ IF exists (name)
+ THEN old (name)
+ ELSE new (name)
+ FI
+ END PROC dirfile;
+
+ PROC getline (DIRFILE CONST df, INT CONST index,
+ TEXT VAR record):
+ IF index <= 0
+ THEN errorstop ("access before first record")
+ ELIF index > maxsize
+ THEN errorstop ("access after last record")
+ ELSE record := df [index]
+ FI
+ END PROC getline;
+
+ PROC putline (DIRFILE CONST df, INT CONST index,
+ TEXT VAR record):
+ ...
+ END PROC putline;
+
+ ...
+ END PACKET dirfiles;
+
+____________________________________________________________________________
+
+
+Die Prozedur 'dirfile' ist die Assoziierungsprozedur für DIRFILEs (analog 'sequential
+file' bei FILEs). 'dirfile' liefert entweder einen bereits vorhandenen Datenraum oder
+richtet einen neuen ein. Um eine Initialisierung mit der 'dirfile'-Prozedur vorneh­
+men zu können, braucht man auch einen Zuweisungsoperator, der den Datenraum an
+den DIRFILE-Datentyp koppelt.
+
+Zugriffe auf einen DIRFILE sind nun relativ einfach zu schreiben. Im obigen Beispiel
+wird nur die Prozedur 'getline' gezeigt.
+
+Nun ist es möglich, Programme zu schreiben, die den DIRFILE-Datentyp benut­
+zen.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ DIRFILE VAR laeufer :: dirfile ("Nacht von Borgholzhausen");
+ INT VAR nummer;
+ TEXT VAR name;
+
+ REP
+ put ("Startnummer bitte:");
+ get (nummer);
+ line;
+ put ("Name des Laeufers:");
+ get (name);
+ putline (laeufer, nummer, name);
+ line
+ UNTIL no ("weiter") END REP;
+ ...
+
+____________________________________________________________________________
+#page#
+
+2.9.4 Datentyp INITFLAG
+
+Im Multi-User-System ist es oft notwendig, Pakete beim Einrichten einer neuen
+Task in dieser neu zu initialisieren. Das muß z.B. bei der Dateiverwaltung gemacht
+werden, da die neue Task ja nicht die Dateien des Vaters erbt. Mit Hilfe von
+INITFLAG-Objekten kann man zu diesem Zweck feststellen, ob ein Paket in dieser
+Task schon initialisiert wurde.
+
+
+INITFLAG
+ #on("b")#TYPE INITFLAG #off("b")#
+ Erlaubt die Deklaration entsprechender Flaggen.
+
+:=
+ #on("b")#OP := (INITFLAG VAR flag, BOOL CONST flagtrue) #off("b")#
+ Erlaubt die Initialisierung von INITFLAGs
+
+initialized
+ #on("b")#BOOL PROC initialized (INITFLAG VAR flag) #off("b")#
+ Wenn die Flagge in der Task A auf TRUE oder FALSE gesetzt wurde, dann liefert
+ sie beim ersten Aufruf den entsprechenden Wert, danach immer TRUE (in der
+ Task A!).
+
+ Beim Einrichten von Söhnen wird die Flagge in den Sohntasks automatisch auf
+ FALSE gesetzt. So wird erreicht, daß diese Prozedur in den neu eingerichteten
+ Söhnen und Enkeltasks genau beim ersten Aufruf FALSE liefert.
+
+____________________________________________________________________________
+ ........................... Beispiel: .........................
+ PACKET stack DEFINES push, pop:
+
+ INITFLAG VAR in this task := FALSE ;
+ INT VAR stack pointer ;
+ ROW 1000 INT VAR stack ;
+
+ PROC push (INT CONST value) :
+
+ initialize stack if necessary ;
+ ....
+
+ END PROC push ;
+
+ PROC pop (INT VAR value) :
+
+ initialize stack if necessary ;
+ ....
+
+ END PROC pop ;.
+
+ initialize stack if necessary :
+ IF NOT initialized (in this task)
+ THEN stack pointer := 0
+
+ FI .
+
+ END PACKET stack
+____________________________________________________________________________
+
diff --git a/doc/programmer-manual/1.8.7/doc/programmierhandbuch.3 b/doc/programmer-manual/1.8.7/doc/programmierhandbuch.3
new file mode 100644
index 0000000..eade335
--- /dev/null
+++ b/doc/programmer-manual/1.8.7/doc/programmierhandbuch.3
@@ -0,0 +1,728 @@
+#headandbottom("1","EUMEL-Benutzerhandbuch","TEIL 3 : Editor","3")#
+#pagenr("%",1)##setcount##block##pageblock#
+#headeven#
+#center#EUMEL-Benutzerhandbuch
+#center#____________________________________________________________
+
+#end#
+#headodd#
+#center#TEIL 3 : Editor
+#center#____________________________________________________________
+
+#end#
+#bottomeven#
+#center#____________________________________________________________
+3 - % #right#GMD
+#end#
+#bottomodd#
+#center#____________________________________________________________
+GMD #right#3 - %
+#end#
+
+TEIL 3: Der Editor
+
+Mit dem #ib#EUMEL-Editor#ie# steht für den Teil der Programmierung, der aus der Eingabe
+von Programmtext besteht, dasselbe komfortable Werkzeug zur Verfügung, wie für die
+Textverarbeitung. Merkmale des EUMEL-Editors sind die einfache Fenstertechnik
+und die übersichtliche Bedienung durch wenige Funktionstasten.
+
+Eine mit dem Editor erzeugte Textdatei ist maximal 4075 Zeilen lang, die maximale
+Breite einer Zeile beträgt 16000 Zeichen.
+
+
+
+3.1 Ein- und Ausschalten des Editors
+
+Der Editor wird eingeschaltet durch Eingabe von:
+
+____________________________________________________________________________
+ gib kommando :
+ #ib#edit#ie# ("dateiname")
+
+____________________________________________________________________________
+
+
+Falls eine Datei unter dem eingegebenen Namen existiert, wird ein Fenster auf dieser
+Datei an der Stelle geöffnet, an der zuletzt ein Zugriff auf diese Datei stattfand.
+
+Existiert noch keine Datei unter dem angegebenen Namen in der Task, folgt eine
+Anfrage, ob eine Datei unter dem eingegebenen Namen neu eingerichtet werden soll:
+
+____________________________________________________________________________
+ gib kommando :
+ edit("dateiname")
+ "dateiname" neu einrichten (j/n) ?
+
+____________________________________________________________________________
+
+
+Die Abfrage dient der Kontrolle der Schreibweise. Man kann ggf. das Einrichten der
+Datei ablehnen, den Dateinamen verbessern und das Kommando erneut geben.
+
+Bei korrekter Schreibweise bejahen Sie die Kontrollfrage#u# 1)#e#mit
+
+#center#<j> <J> <y> oder <Y>
+
+
+Es erscheint ein leerer Editorbildschirm. Die oberste Zeile des Bildschirms ist die
+#ib#Titelzeile#ie#. In ihr kann nicht geschrieben werden. Sie zeigt jedoch verschiedene nütz­
+liche Dinge an: den Namen der Datei, die Nummer der aktuellen Zeile, in der gerade
+geschrieben wird, Tabulatormarken, Einfügemodus, Lernmodus usw.
+
+____________________________________________________________________________
+ #mark on# ............... dateiname ....................#mark off# Zeile 1 #mark on# #mark off#
+ _
+
+____________________________________________________________________________
+
+
+
+Wollen Sie die #ib#Schreibarbeit beenden#ie# und den #ib#Editor ausschalten#ie#, so drücken Sie die
+beiden Tasten
+
+<ESC> <q>
+
+nacheinander. Sie haben damit den #ib#Editor verlassen#ie# und befinden sich wieder auf
+Monitor-Ebene.
+#page#
+
+3.2 Die Funktionstasten
+
+Die Funktionstasten realisieren diejenigen Fähigkeiten des Editor, die über die reine
+Zeicheneingabe hinausgehen. Wo die Tasten auf Ihrem Gerät liegen, hängt von dem
+jeweiligen Gerätetyp ab. Die Wirkung der Tasten ist im Weiteren erläutert.
+
+#l pos (0.0)##l pos(4.0)#
+#table#
+#free(0.5)#
+#taste1(" SHIFT ")# Umschalttaste
+#tableend#
+#free(0.5)#
+<v> <^> <>> <<> Positionierungstasten
+#table#
+#free(0.5)#
+<CR> Eingabe-/ Absatztaste
+#free(0.5)#
+<ESC> Kommandotaste
+#free(0.5)#
+<HOP> Verstärkertaste
+#free(0.5)#
+<TAB> Tabulatortaste
+#free(0.5)#
+<MARK> Markiertaste
+#free(0.5)#
+<RUBOUT> Löschtaste
+#free(0.5)#
+<RUBIN> Einfügetaste
+#free(0.5)#
+<SV> Supervisortaste
+#free(0.5)#
+<STOP> Stoptaste
+#free(0.5)#
+<WEITER> Weitertaste
+#tableend##clear pos#
+#free(0.5)#
+Es kann sein, daß Tasten nicht richtig beschriftet sind. Die Installations-anleitung
+muß dann die Entsprechungen beschreiben. Natürlich können sich weitere Funktions­
+tasten außer den im folgenden beschriebenen auf Ihrer Tastatur befinden. Diese
+haben standardmäßig jedoch keine besondere Bedeutung für den Editor.
+
+#page#
+
+3.3 Die Wirkung der Funktionstasten
+
+<SHIFT>
+
+#ib#Umschalttaste#ie#
+
+Wird diese Taste gleichzeitig mit einer anderen betätigt, so wird ein Buchstabe in
+Großschreibung, bei den übrigen Tasten das obere Zeichen, ausgegeben. So wird z.B.
+anstelle der "9" das Zeichen ")" ausgegeben.
+#free(0.5)#
+<>> <<>
+
+<v> <^>
+
+Positionierungstasten
+
+#ib#Positionierung des Cursors#ie# um eine Spalten-/Zeilenposition in die jeweilige Richtung.
+#free(0.5)#
+<CR>
+
+#ib#Eingabetaste / Absatztaste#ie#, Carriage Return, kurz: 'CR'
+
+Diese Taste schließt die aktuelle Zeile explizit ab und es wird an den Beginn der
+nächsten Zeile positioniert. Einrückungen werden beibehalten.
+
+Der EUMEL-Editor ist auf automatischen Wortumbruch voreingestellt, d.h. ein Wort,
+das über das 77. Zeichen der aktuellen Zeile herausreichen würde, wird automatisch
+in die nächste Zeile gerückt (siehe 'word wrap' 4.2.5). Die Absatztaste wird also
+benötigt, um explizite Zeilenwechsel und Einrückungen bei der Textformatierung zu
+erhalten. Eine Absatzmarke wird durch ein 'blank' hinter dem letzten Zeichen der
+Zeile erzeugt und ist im Editor an der Inversmarkierung am rechten Bildschirmrand zu
+erkennen.
+
+Im EUMEL-System werden Kommandos auf einer Kommandozeile, auf der alle
+Editorfunktionen zur Verfügung stehen, eingegeben. Auf dieser Ebene beendet die
+Taste also ausdrücklich die Kommandoeingabe, das gegebene Kommando wird an­
+schließend analysiert und ausgeführt.
+
+<HOP>
+
+"#ib#Verstärkertaste#ie#"; wird als Vorschalttaste bedient.
+
+In Kombination mit anderen Funktionstasten wird deren Wirkung verstärkt.
+
+
+<HOP> <v>
+
+Steht der Cursor nicht am unteren Bildrand, so wird er dorthin positioniert. Steht er
+am unteren Bildrand, so wird um einen Bildschirminhalt "weitergeblättert".
+
+Entsprechend werden auch die Tasten : <^> <>> <<> mit der HOP-Taste verstärkt.
+
+#page#
+<HOP> <RUBIN>
+
+#ib#Einfügen von Textpassagen#ie#. Die HOP-Taste in Verbindung mit RUBIN und RUBOUT
+wird zum 'verstärkten' Löschen und Einfügen verwendet.
+
+Ab der aktuellen Position des Cursors 'verschwindet' der restliche Text. Es kann wie
+bei der anfänglichen Texteingabe fortgefahren werden. Die Anzeige '#ib#REST#ie#' in der
+Titelzeile erinnert daran, daß noch ein Resttext existiert. Dieser erscheint nach einem
+neuerlichen Betätigen der beiden Tasten HOP RUBIN wieder auf dem Bildschirm (die
+Anzeige 'REST' verschwindet dann wieder).
+
+____________________________________________________________________________
+ ................ dateiname ..................... Zeile 4
+ In diesem Text soll vor dem zweiten Satz 
+ etwas eingefügt werden. Hierzu wird der
+ Cursor an die Position geführt, an der 
+ ein beliebiger Text eingefügt werden soll.#absatz#
+
+____________________________________________________________________________
+
+
+Nach Betätigen der Taste #on("i")##on("b")#HOP#off("i")##off("b")# und #on("i")##on("b")#RUBIN#off("i")##off("b")#sieht der Bildschirm wie folgt aus:
+
+____________________________________________________________________________
+ .............. dateiname ........REST.......... Zeile 4
+ In diesem Text soll vor dem zweiten Satz 
+ etwas eingefügt werden.
+
+
+____________________________________________________________________________
+
+
+
+Nun kann beliebig viel Text eingefügt werden. Nochmaliges Betätigen von HOP und
+RUBIN führt den Text-Rest wieder bündig heran.
+
+#page#
+<HOP> <RUBOUT>
+
+Löscht die Zeile ab Cursor-Position bis Zeilenende.
+
+____________________________________________________________________________
+ ................ dateiname ..................... Zeile 4
+ Soll eine ganze Zeile oder ein Textrest 
+ gelöscht werden, so positioniert man an die 
+ Stelle, ab der gelöscht werden soll. Rest löschen....
+ Nach HOP RUBOUT ist der Zeilenrest gelöscht.#absatz#
+
+____________________________________________________________________________
+
+
+
+Nach Betätigen der Tasten #on("i")##on("b")#HOP#off("i")##off("b")# und #on("i")##on("b")#RUBOUT#off("i")##off("b")# sieht der Bildschirm wie folgt aus.
+
+____________________________________________________________________________
+ ............... dateiname .................... Zeile 4
+ Soll eine ganze Zeile oder ein Textrest 
+ gelöscht werden, so positioniert man an die 
+ Stelle, ab der gelöscht werden soll.
+ Nach HOP RUBOUT ist der Zeilenrest gelöscht.#absatz#
+
+____________________________________________________________________________
+
+
+
+Steht der Cursor am Zeilenanfang, wird nach HOP RUBOUT dementsprechend die
+ganze Zeile gelöscht und die Lücke durch Nachrücken der Folgezeilen geschlossen
+(HOP RUBOUT betätigen).
+#page#
+<TAB>
+
+#ib#Tabulatortaste#ie#
+
+Mit der Tabulatortaste werden die eingestellten Tabulatorpositionen angesprungen.
+Jeder Tastendruck läßt den Cursor auf die nächste eingestellte Tabulatorposition
+springen.
+
+#on("i")#Voreingestellte#off("i")# Tabulatorpositionen sind die beiden Schreibgrenzen, Textanfang in der
+Zeile und Ende der Zeile.
+
+Weitere Tabulatorpositionen können durch Positionierung auf die gewünschte Spalte
+und #on("i")##on("b")#HOP#off("i")##off("b")# #on("i")##on("b")#TAB#off("i")##off("b")# gesetzt werden. Sie können gelöscht werden, indem sie mit #on("i")##on("b")#TAB#off("i")##off("b")#
+angesprungen und mit #on("i")##on("b")#HOP#off("i")##off("b")# #on("i")##on("b")#TAB#off("i")##off("b")#
+ausgeschaltet werden.
+
+Die gesamte eingestellte Tabulalation kann durch #on("i")##on("b")#ESC#off("i")##off("b")# #on("i")##on("b")#TAB#off("i")##off("b")# ein-/ und ausge­
+schaltet werden.
+
+Die eingestellten Tabulatorpositionen erkennen Sie an den Tabulatorzeichen (Dachzei­
+chen) in der obersten Bildschirmzeile.
+#page#
+<MARK>
+
+#ib#Ein- bzw. Ausschalten der Markierung#ie#.
+
+Bei Betätigung dieser Taste wird in einen speziellen #ib#Markierzustand#ie# geschaltet. Alles,
+was Sie jetzt schreiben bzw. durch Bewegen des Cursors in Richtung Dateiende
+kennzeichnen, steht als #on("i")#markierter#off("i")# Bereich für die Bearbeitung zur Verfügung. Zur
+besseren Sichtbarkeit wird der markierte Bereich invers zum übrigen Text dargestellt.
+
+Wird der Cursor in eine Richtung bewegt, wird das gesamte Textstück zwischen
+Einschaltpunkt der Markierung und aktueller Cursorposition markiert. Rückwärtsbewe­
+gungen des Cursors verkürzen den markierten Bereich wieder.
+
+Durch erneutes Betätigen der MARK-Taste schalten Sie den Markier-Zustand
+wieder aus.
+
+Mit weiteren Kommandos kann der Bereich nun bearbeitet werden:
+
+<ESC> <d> Markierten Abschnitt in 'Scratch'-Datei kopieren.
+
+<ESC> <p> Markierten Abschnitt herauskopieren.
+
+<ESC> <RUBOUT> Markierten Abschnitt löschen.
+
+
+Der mit #on("i")##on("b")#ESC#off("i")##off("b")# #on("i")##on("b")#p#off("i")##off("b")# oder#on("i")##on("b")#d#off("i")##off("b")# kopierte Bereich kann beliebig oft in derselben oder einer
+anderen Datei ein/angefügt werden.
+
+Der mit #on("i")##on("b")#ESC#off("i")##off("b")# #on("i")##on("b")#RUBOUT#off("i")##off("b")# gelöschte Abschnitt kann genau einmal durch #on("i")##on("b")#ESC#off("i")##off("b")# #on("i")##on("b")#RUBOUT#off("i")##off("b")#
+an anderer Stelle derselben Datei eingefügt werden.
+
+(vgl. ESC-Taste, Operationen auf Markierungen, 3-#topage("ESC")#)
+#page#
+<RUBIN>
+
+#ib#Ein- bzw. Ausschalten des Einfügemodus.#ie#
+
+Das Betätigen der Taste schaltet in den Einfügemodus. Der Zustand wird durch das
+Wort "RUBIN" im linken Drittel der Titelzeile der Datei angezeigt. Vor dem Zeichen,
+auf dem der Cursor steht, wird eingefügt. Nochmaliges Betätigen der Taste schaltet
+den Einfügemodus aus.
+#free(1.0)#
+<RUBOUT>
+
+#ib#Löschtaste#ie#
+
+Das Zeichen, auf dem der Cursor steht, wird gelöscht. Wenn der Cursor, wie bei
+fortlaufender Eingabe üblich, hinter dem letzten Zeichen einer Zeile steht, wird das
+letzte Zeichen gelöscht.
+
+#page#
+
+3.4 ESC Kommandos
+
+<ESC>
+
+#ib#Kommandotaste#ie#
+
+Mit der ESC-Taste in Kombination mit einer Folgetaste werden vordefinierte Aktionen
+ausgelöst. Es gibt Aktionen, die vorprogrammiert zur Verfügung stehen, und Sie selbst
+können weitere hinzufügen.
+
+Der Kommandodialog wird eingeschaltet durch:
+
+<ESC> <ESC>
+
+
+____________________________________________________________________________
+ ............... Beispiel ..................... Zeile 4
+
+ gib kommando:                                             
+
+____________________________________________________________________________
+
+
+Der Kommandodialog ermöglicht die Eingabe von beliebigen Kommandos ohne den
+Editor verlassen zu müssen. Insbesondere Such- und Kopieroperationen stellen auch
+für den Programmierer nützliches Werkzeug dar (siehe 3.5).
+
+Auf der Kommandozeile kann jedes Kommando gegeben werden. Die Kommandozeile
+kann wie eine normale Textzeile editiert werden. Nach #on("i")##on("b")#CR#off("i")##off("b")# verschwindet die Kom­
+mandozeile und das Kommando wird ausgeführt.
+
+Falls ein Fehler auftritt erfolgt eine entsprechende Fehlermeldung in der Kopfzeile und
+die Kommandozeile erscheint erneut.
+
+Um ein weiteres Editor-Fenster zu 'öffnen', betätigt man im Editor
+
+<ESC>  <e>
+
+Betätigt man ESC e ungefähr in der Mitte des Bildschirms, hat man das Fenster auf
+die neue Datei in der unteren Hälfte des Bildschirms und die 'alte' Datei in der
+oberen Bildschirmhälfte. Zunächst wird der Dateiname erfragt. Nach dessen Eingabe
+und #on("i")##on("b")#CR#off("i")##off("b")# wird ein Fenster auf eröffnet. Die obere linke Ecke des Fensters befindet
+sich an der aktuellen Cursor-Position. Dabei darf sich der Cursor nicht zu sehr am
+rechten oder unteren Rand befinden, weil das Fenster sonst zu klein würde. In diesem
+'Fenster' kann man dann genauso arbeiten wie im 'normalen' Editor.
+
+Mit der Tastenfolge
+
+<ESC>  <w>
+
+wechselt man von einem Fenster (zyklisch) in das benachbarte. Es gibt eine Hier­
+archie zwischen den Fenstern in der Reihenfolge, in der eines im anderen einge­
+richtet worden ist. Gibt man
+
+<ESC>  <q>
+
+in einem Fenster, so verschwindet dieses und alle darin eingeschachtelten Fenster,
+und man befindet sich im übergeordneten Fenster.
+
+Durch
+
+<ESC>  <p> oder <ESC>  <d>
+
+schreibt man einen markierten Teil in eine 'Scratch'-Datei (nicht editierbarer
+Zwischenspeicher); durch ESC p wird ein markierter Text aus der Ursprungsdatei
+entfernt und in die 'Scratch'-Datei geschrieben. Im Gegensatz dazu wird er durch
+ESC d kopiert. Durch
+
+<ESC>  <g>
+
+fügt man ihn in eine andere (oder dieselbe) Datei ein. Im Unterschied zu ESC RUBIN
+wird die temporäre Datei dadurch nicht entleert.
+
+Die für ESC p, bzw. ESC d benutzte #ib#'Scratch'-Datei#ie#, die nicht editierbar ist, ist nicht
+mit dem sogenannten Notizbuch zu verwechseln. Das Notizbuch ist eine Datei, in der
+alle Editorfunktionen benutzt werden können, auf die jedoch ohne Angabe eines
+Dateinamens durch
+
+<ESC> <n>
+
+ab der aktuellen Cursorposition ein Fenster eröffnet wird. Das Notizbuch nimmt
+insbesondere Fehlermeldungen und Meldungen bei der Übersetzung von Programmen
+auf.
+
+<ESC> <v>
+
+erlaubt vom äußeren Fenster aus alle eingeschachtelten Fenster zu verlassen.
+#page#
+
+Vorbelegte Tasten
+
+#ib#ESC q#ie# Verlassen des Editors bzw. der eingeschachtelten Fenster.
+
+#ib#ESC e#ie# Weiteres Editorfenster einschalten.
+
+#ib#ESC n#ie# Notizbuch 'anzeigen'.
+
+#ib#ESC v#ie# Dateifenster auf ganzen Bildschirm vergrößern
+ bzw. Bildschirm rekonstruieren (eingeschachteltes Fenster verlas­
+ sen).
+
+#ib#ESC w#ie# Dateiwechsel beim Fenstereditor.
+
+#ib#ESC f#ie# Nochmalige Ausführung des letzten Kommandos.
+
+#ib#ESC b#ie# Das Fenster wird auf den linken Rand der aktuellen (ggf. verscho­
+ benen) Zeile gesetzt.
+
+ESC > Zum nächsten Wortanfang.
+
+ESC < Zum vorherigen Wortanfang.
+
+#ib#ESC 1#ie# Zum Anfang der Datei.
+
+#ib#ESC 9#ie# Zum Ende der Datei.
+#page#
+
+Operationen auf Markierungen
+
+
+#goalpage("ESC")#
+#ib#ESC RUBOUT#ie# Markiertes "vorsichtig" löschen.
+
+#ib#ESC RUBIN#ie# Mit ESC RUBOUT vorsichtig Gelöschtes einfügen.
+
+#ib#ESC p#ie# Markiertes löschen und in die Notiz-Datei schreiben. Kann mit ESC
+ g an anderer Stelle reproduziert werden.
+
+#ib#ESC d#ie# Duplizieren:
+ Markiertes in die Notiz-Datei kopieren, anschließend die
+ Markierung abschalten. Kann mit ESC g beliebig oft reproduziert
+ werden.
+
+#ib#ESC g#ie# Mit ESC p gelöschten oder mit ESC d duplizierten Text an aktuelle
+ Cursor-Stelle schreiben, d.h. Notiz-Datei an aktueller Stelle einfü­
+ gen.
+#page#
+
+Zeichen schreiben
+Diese Tasten sind standardmäßig so vorbelegt wie hier aufgeführt, sie können aber
+von Benutzern und in Anwenderprogrammen geändert werden.
+
+#ib#ESC a#ie# Schreibt ein ä.
+#ib#ESC A#ie# Schreibt ein Ä.
+#ib#ESC o#ie# Schreibt ein ö.
+#ib#ESC O#ie# Schreibt ein Ö.
+#ib#ESC u#ie# Schreibt ein ü.
+#ib#ESC U#ie# Schreibt ein Ü.
+#ib#ESC s#ie# Schreibt ein ß.
+#ib#ESC (#ie# Schreibt eine [.
+#ib#ESC )#ie# Schreibt eine ].
+#ib#ESC <#ie# Schreibt eine {.
+#ib#ESC >#ie# Schreibt eine }.
+#ib#ESC \##ie# Schreibt ein \#, das auch gedruckt werden kann.
+#ib#ESC ­#ie# Schreibt einen (geschützten) Trennstrich, siehe Textverarbeitung.
+#ib#ESC k#ie# Schreibt ein (geschütztes) "k", siehe Textverarbeitung.
+#ib#ESC blank#ie# Schreibt ein (geschütztes) Leerzeichen, siehe Textverarbeitung.
+#free(0.7)#
+
+Kommando auf Taste legen
+
+#ib#ESC ESC#ie# Kommandodialog einschalten
+
+#ib#ESC ! taste#ie# Im Kommandodialog:
+ Geschriebenes Kommando auf Taste legen.
+
+#ib#ESC ? taste#ie# Im Kommandodialog:
+ Auf 'taste' gelegtes Kommando zum Editieren anzeigen.
+
+#ib#ESC k#ie# Im Kommandodialog:
+ Das zuletzt editierte Kommando (einzeilige ELAN-Programm)
+ anzeigen.
+
+
+Der Lernmodus
+Der Lernmodus ermöglicht beliebige Tastensequenzen zu speichern und auf eine
+Taste 't' zu legen. Durch #on("i")##on("b")#ESC#off("i")##off("b")# #on("i")##on("b")#t#off("i")##off("b")# wird die gesamte Sequenz ausgeführt.
+
+Nicht belegt werden können die vom System vorbelegten Tasten (3-14).
+
+Beispielsweise könnte es für einen Programmierer sinnvoll sein die Tastenfolge
+'THEN' 'CR' '>' '>' '>' '>' auf die Taste #on("i")##on("b")#T#off("i")##off("b")# zu legen. Durch #on("i")##on("b")#ESC#off("i")##off("b")# #on("i")##on("b")#T#off("i")##off("b")# wird 'THEN' in
+die aktuelle Zeile geschrieben und der Cursor mit passender Einrückung in die
+Einrückung in die Folgezeile gesetzt.
+
+
+#ib#ESC HOP#ie# #ib#Lernen einschalten#ie#.
+
+#ib#ESC HOP taste#ie# #ib#Lernen ausschalten#ie# und Lernsequenz auf 'taste'legen.
+
+#ib#ESC HOP HOP#ie# #ib#Gelerntes vergessen#ie#. Bedingung ist, daß man die Lernsequenz in
+ der Task löscht, in der man sie hat lernen lassen.
+
+
+#on("b")#
+#center#A C H T U N G :
+Der Lernmodus bleibt eingeschaltet, auch wenn der Editor beendet wird. Dann werden
+die folgenden Monitor-Kommandos usw. usf. 'gelernt'. Durch unsinniges 'Lernen'
+lassen sich schlimmstenfalls beliebige Verwüstungen anrichten.
+
+Der Lernmodus wird in der Editor-Kopfzeile angezeigt. Falls der Editor beendet wird,
+ohne den Lernmodus auszuschalten, erfolgt eine Warnung auf Monitor-Ebene.
+
+Um den Lernmodus zu beenden drücken Sie:
+
+<ESC> <HOP> <HOP>
+
+Dadurch wird der Lernmodus ausgeschaltet und nichts gelernt, die Gefahr ist gebannt.#off("b")#
+
+#page#
+<SV>
+
+#ib#SUPERVISOR-Taste#ie#
+
+Betätigen Sie diese Taste im Editor, dann unterbrechen Sie Ihre Editierarbeit und
+erhalten die Meldung
+
+____________________________________________________________________________
+
+ Terminal 2
+
+
+ EUMEL Version 1.8/M
+
+
+ gib supervisor kommando:
+
+
+
+
+ ESC ? --> help
+ ESC b --> begin("") ESC h --> halt
+ ESC c --> continue("") ESC s --> storage info
+ ESC q --> break ESC t --> task info
+
+____________________________________________________________________________
+
+
+
+Wollen Sie nun im Editor fortfahren bzw. haben Sie irrtümlich die SV-Taste betätigt,
+dann geben Sie das Kommando
+
+____________________________________________________________________________
+
+ gib supervisor kommmando :
+ continue ("meine task")
+
+____________________________________________________________________________
+
+
+
+(falls Ihre Task, in der Sie arbeiteten, wirklich "meine task" hieß!)
+
+Um Ihren in Bearbeitung befindlichen Text wieder vollständig auf dem Bildschirm zu
+sehen, betätigen die die Tasten
+
+<ESC> <b>
+
+Sie sind wieder an der Stelle, an der Sie den Text mit der SV-Taste verlassen ha­
+ben, und können normal weiterarbeiten.
+
+#on("u")#Achtung:#off("u")# Die SV-Taste kann, je nach Terminal, durch das Betätigen von zwei
+Tasten gleichzeitig realisiert sein (oft 'CTRL b'). Beachten Sie die Beschreibung Ihrer
+Tastatur!
+
+
+
+#on("b")#
+Für die Programmierung ist die Tastenfolge <SV> <ESC> <h> von Bedeutung, da hier­
+durch der Fehler 'halt vom Terminal' erzeugt wird. Dadurch können unerwünscht
+laufende Programme abgebrochen werden.
+#off("b")#
+#page#
+<STOP>
+
+#ib#Unterbrechen einer Ausgabe#ie# (oft auch als CTRL a realisiert).
+
+Haben Sie diese Taste aus Versehen betätigt, erkennen Sie dies daran, daß der
+Editor nicht "reagiert". Betätigen Sie die WEITER-Taste (oft auch CTRL c).
+#free(1.0)#
+<WEITER>
+
+Unterbrochene Ausgabe fortsetzen.
+
+Ein mit der STOP-Taste angehaltene Ausgabe können Sie durch Betätigen der
+#ib#WEITER-Taste#ie# fortsetzen.
+
+
+#on("u")#VORSICHT:#off("u")# Die STOP-Taste unterbricht nur die Ausgabe auf den Bildschirm. Zei­
+ chen, die während des STOP eingegeben werden, werden gespeichert
+ und nach 'WEITER' ausgegeben!
+
+
+#page#
+
+3.5 Positionieren, Suchen, Ersetzen
+ im Kommandodialog
+
+
+Um das Editorfenster auf eine bestimmte Zeile zu positionieren wird einfach diese
+Zeilennummer angegeben.
+
+____________________________________________________________________________
+ ............... Beispiel ..................... Zeile 4
+
+ gib kommando: 123                                          
+
+____________________________________________________________________________
+
+
+
+Falls die Zeilenzahl der Datei geringer als die angegebene Zeilennummer ist, wird auf
+die letzte Zeile positioniert.
+
+
+Um das Editorfenster auf ein bestimmtes Textstück zu positionieren, wird der gesuch­
+te Text, ggf. mit Suchrichtung angegeben.
+
+____________________________________________________________________________
+ ............... Beispiel ..................... Zeile 4
+
+ gib kommando: "END PROC"                                  
+
+____________________________________________________________________________
+
+
+Die Suchrichtung kann durch 'D' (down) oder 'U' (up) zusätzlich spezifiziert werden.
+
+____________________________________________________________________________
+ ............... Beispiel ..................... Zeile 4
+
+ gib kommando: U "INT VAR schleifenzaehler"                 
+
+____________________________________________________________________________
+
+
+
+Um beliebige Texte durch andere zu ersetzen, dienen die Operatoren 'C' (change)
+bzw. 'CA' (change all).
+
+Bei Ausführung dieses Kommandos wird zunächst nach #on("u")#unten#off("u")# in der editierten Datei
+nach dem zu ersetzenden Text gesucht. Wenn der Text gefunden wird, wird er durch
+den hinter dem Operator stehenden Text ersetzt.
+
+____________________________________________________________________________
+ ............... Beispiel ..................... Zeile 4
+
+ gib kommando: "lb" C "lange bezeichnung"                   
+
+____________________________________________________________________________
+
+
+
+Bei Anwendung von 'CA' wird jedes Auftreten des gesuchten Textes ab der
+Cursorposition durch den Ersatztext ersetzt, bis das Dateiende errreicht ist.
+
+Weitere Erklärungen zum Suchen und Ersetzen in 5.5.
+#page#
+
+Weitere Hilfen
+
+
+Textabschnitt an anderer Stelle der Datei einsetzen:
+
+- Abschnitt markieren und mit #on("i")##on("b")#ESC#off("i")##off("b")# #on("i")##on("b")#d#off("i")##off("b")# zwischenspeichern.
+
+- Zweites Editorfenster auf die Datei mit #on("i")##on("b")#ESC#off("i")##off("b")# #on("i")##on("b")#e#off("i")##off("b")# öffnen.
+
+- Nach #on("i")##on("b")#ESC#off("i")##off("b")# #on("i")##on("b")#ESC#off("i")##off("b")# Zeilennummer oder Suchbegriff angeben und mit #on("i")##on("b")#ESC#off("i")##off("b")# #on("i")##on("b")#g#off("i")##off("b")# Abschnitt an der gewünschte Stelle einsetzen.
+
+
+
+Textabschnitt schnell herauskopieren und sichern:
+
+- Gewünschten Abschnitt markieren
+
+- #on("i")##on("b")#ESC#off("i")##off("b")# #on("i")##on("b")#ESC#off("i")##off("b")# PUT("dateiname") #on("i")##on("b")#CR#off("i")##off("b")#
+ Der Abschnitt wird in die Datei 'dateiname' geschrieben. Falls die Frage 'dateina­
+ me' löschen (j/n) verneint wird, wird der Abschnitt, an das Ende der Datei angefügt.
+ Dadurch können Textabschnitte schnell gesammelt werden.
+
+
+Komplette Datei in die editierte Datei einfügen:
+
+- #on("i")##on("b")#ESC#off("i")##off("b")# #on("i")##on("b")#ESC#off("i")##off("b")# GET("dateiname") #on("i")##on("b")#CR#off("i")##off("b")#
+ Der komplette Inhalt von 'dateiname' wird an die aktuelle Position geschrieben.
+
+
+Breitere Zeile erzeugen:
+
+- #on("i")##on("b")#ESC#off("i")##off("b")# #on("i")##on("b")#ESC#off("i")##off("b")# limit(123) #on("i")##on("b")#CR#off("i")##off("b")#
+ Die Zeilenbreite wird auf 123 Zeichen geändert. Der maximal zulässige Wert ist
+ 16000. Dieser Wert bezieht sich auf den Zeilenumbruch. Bei Zeilenbreite > 77 wird
+ nur die aktuelle Zeile verschoben. Um für den ganzen Bildschirm die rechte Seite
+ der Datei zu sehen, kann die linken Spalte des Bildschirmfenster neu gesetzt wer­
+ den:
+
+ #on("i")##on("b")#ESC#off("i")##off("b")# #on("i")##on("b")#ESC#off("i")##off("b")# margin(60) #on("i")##on("b")#CR#off("i")##off("b")#
+
+ Die Normaleinstellung wird durch 'limit(77)' und 'margin(1)' wiederhergestellt.
+
diff --git a/doc/programmer-manual/1.8.7/doc/programmierhandbuch.4 b/doc/programmer-manual/1.8.7/doc/programmierhandbuch.4
new file mode 100644
index 0000000..650d945
--- /dev/null
+++ b/doc/programmer-manual/1.8.7/doc/programmierhandbuch.4
@@ -0,0 +1,1692 @@
+#headandbottom("1","EUMEL-Benutzerhandbuch","TEIL 4 : Kommandosprache","4")#
+#pagenr("%",1)##setcount(1)##block##pageblock#
+#headeven#
+#center#EUMEL-Benutzerhandbuch
+#center#____________________________________________________________
+
+#end#
+#headodd#
+#center#TEIL 4 : Kommandosprache
+#center#____________________________________________________________
+
+#end#
+#bottomeven#
+#center#____________________________________________________________
+4 - % #right#GMD
+#end#
+#bottomodd#
+#center#____________________________________________________________
+GMD #right#4 - %
+#end#
+TEIL 4: Kommandosprache
+
+In Teil 4 sind diejenigen Kommandos beschrieben, die erfahrungsgemäß eher der
+Handhabung der Arbeitsumgebung zuzurechnen sind. Es ist den Verfassern bewußt,
+daß Auswahl und Zusammenstellung recht willkürlich sind, weil eine klare Abgrenzung
+zum Teil 5, welcher die Kommandos, die dem Thema: 'Programmierung' zugeordnet
+werden, nicht möglich ist.
+
+Der Teil 4 ist in die Themen:
+
+- 4.1. Supervisor-Kommandos
+
+- 4.2.1 Hilfs- und Informationsprozeduren
+
+- 4.2.2 Thesaurus
+
+- 4.2.3 Tasks
+
+- 4.2.4 Handhabung von Dateien
+
+- 4.2.5 Editor
+
+- 4.2.6 Dateitransfer
+
+- 4.2.7 Passwortschutz
+
+- 4.2.8 Archiv
+
+gegliedert. Insbesondere zu 4.2.4 ist anzumerken, daß nur Kommandos, die ganze
+Dateien betreffen hier erläutert sind. Kommandos, die Dateiinhalte betreffen (Suchen,
+Ersetzen etc.) sind in 3.5, bzw. 5.3 beschrieben.
+#page#
+
+4.1 Supervisor
+
+Es gibt genau sieben vom Supervisor akzeptierte Kommandos. Diese Kommandos
+können gegeben werden wenn nach dem Einschalten des Geräts oder dem Abkoppeln
+einer Task die SV-Taste gedrückt wurde und die sogenannte EUMEL-Tapete
+erscheint.
+
+____________________________________________________________________________
+
+ Terminal 2
+
+
+ EUMEL Version 1.8.1/M
+
+
+ gib supervisor kommando:
+
+
+
+
+ ESC ? --> help
+ ESC b --> begin("") ESC h --> halt
+ ESC c --> continue("") ESC s --> storage info
+ ESC q --> break ESC t --> task info
+
+____________________________________________________________________________
+
+
+
+
+Desweiteren kann <SV> in einer Task gedrückt werden, um durch <ESC> <h> einen
+Programmabbruch einzuleiten.
+
+Im Gegensatz zu den im weiteren beschriebenen, durch ELAN Prozeduren realisierten
+Kommandos, sind diese Supervisor-Kommandos nicht als Prozeduren im System und
+mithin nicht durch 'help (...)' anzeigbar.
+#page#
+'begin'
+ #on("b")#PROC begin (TEXT CONST taskname) #off("b")#
+ Richtet eine neue Task als Sohn von PUBLIC ein.
+
+
+ #on("b")#PROC begin (TEXT CONST taskname, vatertask) #off("b")#
+ Richtet eine neue Task als Sohn der Task 'vatertask' ein, falls die Vater-Task
+ eine Manager-Task ist. Falls diese Task keinen Managerstatus besitzt, passiert
+ nichts! In diesem Falle muß das Kommando durch <SV> abgebrochen werden.
+
+
+ FEHLER : "taskname" existiert bereits
+ "vatertask" gibt es nicht
+
+
+
+
+'continue'
+ #on("b")#PROC continue (TEXT CONST taskname) #off("b")#
+ Eine existierende Task wird an das Terminal des Benutzers angekoppelt.
+
+ FEHLER : "taskname" gibt es nicht
+
+
+ Falls 'begin' oder 'continue' trotz korrekter Voraussetzungen kein Resultat zeigen,
+ 'hängt' die betroffene Task. Beim 'begin' Kommando kann das der Fall sein, falls
+ die Vater-Task nicht durch 'break' abgekoppelt wurde, sondern mit < SV > verlas­
+ sen wurde. In diesem Fall muß das Kommando durch <SV> abgebrochen werden,
+ die Vater-Task angekoppelt und mit <ESC> <q> korrekt abgekoppelt werden.
+#page#
+'break'
+ #on("b")#PROC break #off("b")#
+ Das Terminal wird vom Rechner abgekoppelt.
+
+
+
+'halt'
+ #on("b")#PROC halt #off("b")#
+ Das laufende Programm der dem Terminal aktuell zugeordneten Task wird abge­
+ brochen.
+
+ Falls in der an das Terminal gekoppelten Task ein laufendes Programm abgebro­
+ chen werden soll, muß zunächst durch <SV> der Supervisor aufgerufen werden.
+ Durch das Supervisor-Kommando 'halt' wird der Fehler 'halt from terminal'
+ induziert. Das Programm wird wie durch jeden anderen Fehler abgebrochen, falls
+ nicht 'disable stop' gesetzt wurde!
+
+
+
+#page#
+'storage info'
+ #on("b")#PROC storage info #off("b")#
+ Informationsprozedur über den belegten und den verfügbaren Hintergrund-Spei­
+ cher des gesamten Systems in KByte#u#1)#e#.
+
+#foot#
+
+ 1) Bei der derzeit aktuellen '+' Version EUMEL 1.8.1/M+ sind die beiden Anga­
+ ben mit 4 zu multiplizieren !
+#end#
+ Das Terminal wird unmittelbar abgekoppelt!
+
+
+
+'task info'
+ #on("b")#PROC task info #off("b")#
+ Informiert über alle Tasknamen im System unter gleichzeitiger Angabe der Vater/
+ Sohn-Beziehungen durch Einrückungen.
+
+
+
+
+'help'
+ #on("b")#PROC help #off("b")#
+ Kurzbeschreibung der SV-Kommandos.
+#page#
+
+4.2 Monitor
+
+Unter dem Stichwort Monitor-Kommandos sind an dieser Stelle Kommandos be­
+schrieben, die ständig zur Handhabung der Arbeitsumgebung benutzt werden.
+Gleichwohl sei sofort darauf hingewiesen, daß jedes ELAN Programm dem Monitor zur
+Ausführung übergeben werden kann. Es gibt also keine speziellen Monitor-
+Kommandos, sondern nur eine Reihe von Prozeduren (=Kommandos), die in dieser
+Umgebung erfahrungsgemäß besonders häufig benutzt werden.
+
+
+#on("u")#4.2.1 Hilfs- und Informationsprozeduren#off("u")#
+
+- Pakete, Prozeduren : packets, bulletin , help
+ Parameter
+
+- Tasksystem zeigen : task info , task status
+
+- Speicherplatz zeigen : storage , storage info
+
+
+#on("u")#4.2.2 Thesaurus #off("u")#
+
+- besondere Thesauri : ALL , all , SOME , remainder
+
+- Verknüpfung : + , - , /
+
+
+#on("u")#4.2.3 Taskoperationen#off("u")#
+
+- besondere Tasknamen : archive , brother , father , myself
+ printer , public , son , supervisor
+- Terminal abkoppeln : break
+- Task löschen : end
+- Manager-Task : global manager , free global manager
+- Umbenennen der Task : rename myself
+
+#page#
+#on("u")#4.2.4 Handhabung von Dateien #off("u")#
+
+ : copy , edit , forget , list , rename , show
+
+
+#on("u")#4.2.5 Editor #off("u")#
+
+- Editieren : edit , editget , show
+- Tastenbelegung : kommando auf taste (legen) ,
+ lernsequenz auf taste (legen) ,
+ std tastenbelegung ,
+ taste enthält kommando ,
+ word wrap
+
+
+#on("u")#4.2.6 Transfer #off("u")#
+
+- Datei holen : fetch , fetchall
+- Datei senden : save , saveall
+- Drucken : print
+- Datei löschen : erase
+
+
+#on("u")#4.2.7 Passwortschutz #off("u")#
+
+- 'begin' absichern : begin password
+- 'continue' absichern : task password
+- Dateien absichern : enter password
+- Systemzweig sichern : family password
+
+
+#on("u")#4.2.8 Das Archiv #off("u")#
+
+- Reservieren/freigeben : archive , release
+- Formatieren : format
+- Löschen : clear
+- Kontrollesen : check
+
+
+#page#
+
+4.2.1 Hilfsprozeduren
+
+Die drei Prozeduren listen ihre Ausgabe jeweils in eine temporäre Datei, die mit
+'show' (s. 4.2.5) gezeigt wird.
+
+
+'packets'
+ #on("b")#PROC packets #off("b")#
+ Auflisten der Namen aller insertierten Pakete in der Task.
+
+
+
+
+
+
+'bulletin'
+ #on("b")#PROC bulletin (TEXT CONST paket name) #off("b")#
+ Listen aller in der DEFINES-Liste des Pakets mit dem Namen "paket name"
+ enthaltenen Prozeduren.
+
+ FEHLER : ... ist kein Paketname
+
+
+ #on("b")#PROC bulletin #off("b")#
+ Es wird eine Liste aller bisher insertierten Objekte erstellt. Diese Liste ist paket­
+ weise sortiert. 'bulletin' zeigt also eine Liste #on("u")#aller#off("u")# Prozeduren an, die in der Task
+ benutzt werden können.
+#page#
+'help'
+ #on("b")#PROC help (TEXT CONST name) #off("b")#
+ Listen aller Prozeduren / Operatoren mit dem Namen "name". Der Name des
+ Packets in dessen Schnittstelle die Prozedur steht wird mit ausgegeben.
+
+ Falls es kein Objekt des erfragten Namens gibt, erfolgt die Ausgabe:
+
+ unbekannt "name".
+
+ Beispiel:
+____________________________________________________________________________
+
+ gib kommando :
+ help("save")
+
+____________________________________________________________________________
+
+
+ liefert:
+
+____________________________________________________________________________
+
+PACKET nameset:
+
+ save........... (THESAURUS CONST, TASK CONST)
+ save........... (THESAURUS CONST)
+
+PACKET globalmanager:
+
+ save........... (DATASPACE CONST, TEXT CONST, TASK CONST)
+ save........... (TEXT CONST, TASK CONST)
+ save........... (TEXT CONST)
+ save...........
+
+____________________________________________________________________________
+
+
+
+ Desweiteren kann auch nach Prozedurnamen gesucht werden, die nur annähernd
+ bekannt sind, indem ein Suchmuster spezifiziert wird. Das Suchmuster besteht aus
+ dem bekannten Teil des Namens und dem Operator '*', der vor und/oder nach
+ dem Suchbegriff gesetzt werden kann. '*' bezeichnet eine beliebige (auch leere)
+ Zeichenkette.
+
+ Beispiel: Gesucht werden die verschiedenen 'info' Prozeduren:
+
+____________________________________________________________________________
+ gib kommando :
+ help("*info*")
+
+____________________________________________________________________________
+
+
+
+____________________________________________________________________________
+
+ taskinfo....... (INT CONST, INT CONST)
+ taskinfo....... (INT CONST, FILE VAR)
+ taskinfo....... (INT CONST)
+ taskinfo.......
+ editinfo....... (FILE VAR, INT CONST)
+ editinfo....... (FILE CONST) --> INT
+ storageinfo....
+
+____________________________________________________________________________
+
+
+
+ Dieser Stern darf nicht mit dem 'joker' des 'Pattern Matching' verwechselt werden.
+ In der 'help' Prozedur darf '*' #on("u")#nicht#off("u")# in den Suchbegriff eingesetzt werden, sondern
+ nur an Wortanfang und -Ende gesetzt werden.
+
+
+#page#
+
+Informationsprozeduren
+
+'storage'
+ #on("b")#INT PROC storage (TASK CONST task) #off("b")#
+ Informationsprozedur über den logisch belegten Hintergrund-Speicher der Task.
+ (Angabe in KByte, bzw. 4KB Einheiten bei der '+'-Version)
+
+
+____________________________________________________________________________
+
+ gib kommando :
+ put(storage(myself))
+ 1234
+
+ gib kommando :
+
+____________________________________________________________________________
+
+
+'storage info'
+ #on("b")#PROC storage info #off("b")#
+ Informationsprozedur über den belegten und den verfügbaren Hintergrund-Spei­
+ cher des gesamten Systems. Die Ausgabe erfolgt in KByte, bei der aktuellen
+ '+'-Version in 4 KByte Einheiten.
+
+
+____________________________________________________________________________
+
+ gib kommando :
+ storage info
+ 1234K von 12000K
+
+ gib kommando :
+____________________________________________________________________________
+#page#
+
+'task info'
+ #on("b")#PROC task info #off("b")#
+ Informiert über alle Tasknamen im System unter gleichzeitiger Angabe der Vater/
+ Sohn-Beziehungen (Angabe durch Einrückungen).
+
+
+ #on("b")#PROC task info (INT CONST art) #off("b")#
+ Informiert über alle Tasks im System. Mit 'art' kann man die Art der Zusatz-
+ Information auswählen.
+
+ art=1: entspricht 'task info' ohne Parameter, d.h. es gibt nur die Tasknamen
+ unter Angabe der Vater/Sohn-Beziehungen aus.
+
+ art=2: gibt die Tasknamen aus. Zusätzlich erhalten Sie Informationen über die
+ verbrauchte CPU-Zeit der Task, die Priorität, den Kanal, an dem die
+ Task angekoppelt ist, und den eigentlichen Taskstatus. Hierbei bedeuten:
+
+ 0 -busy- Task ist aktiv.
+ 1 i/o Task wartet auf Beendigung des Outputs oder auf
+ Eingabe.
+ 2 wait Task wartet auf Sendung von einer anderen Task.
+ 4 busy-blocked Task ist rechenwillig, aber blockiert#u#1)#e#.
+ 5 i/o -blocked Task wartet auf I/O, ist aber blockiert.
+ 6 wait-blocked Task wartet auf Sendung, ist aber blockiert. Ach­
+ tung: Die Task wird beim Eintreffen einer Sendung
+ automatisch entblockiert.
+ > 6 dead
+
+ art=3: wie 2, aber zusätzlich wird der belegte Speicher angezeigt. (Achtung:
+ Prozedur ist zeitaufwendig!).
+
+#foot#
+
+1) Eine Blockierung kann von 'Scheduler' veranlaßt werden
+ (siehe Systemhandbuch)
+#end#
+
+#page#
+____________________________________________________________________________
+
+ gib kommando :
+ task info(2)
+
+____________________________________________________________________________
+
+
+
+ liefert:
+
+____________________________________________________________________________
+
+ ............................ ...............................
+ 15.05.87 10:39 CPU PRIO CHAN STATUS
+ SUPERVISOR.......................... 0000:19:47 0 - wait
+ -................................ 0000:07:54 0 - wait
+ SYSUR............................ 0000:34:02 0 - wait
+ shutup dialog................ 0000:05:26 0 - i/o
+ configurator................. 0000:04:17 0 - wait
+ OPERATOR..................... 0000:00:14 0 - i/o
+ ARCHIVE...................... 0000:10:33 0 31 wait
+ net.......................... 0006:41:56 0 - wait
+ net timer................ 0000:02:48 2 - i/o
+ net port................. 0000:40:23 0 7 wait
+ PRINTER...................... 0000:05:59 0 - wait
+ -........................ 0000:00:11 0 - wait
+ UR.................................. 0000:02:11 0 - wait
+ PUBLIC........................... 0002:02:03 0 - wait
+ task1........................ 0000:41:50 0 - -busy-
+ task2........................ 0000:03:10 0 - i/o
+ task3........................ 0000:57:28 0 1 -busy-
+
+____________________________________________________________________________
+
+
+#page#
+
+
+ #on("b")#PROC task info (INT CONST art, FILE VAR infodatei) #off("b")#
+ Wie oben, die Ausgabe wird jedoch in die Datei 'infodatei' geschrieben.
+
+____________________________________________________________________________
+
+ FILE VAR info := sequential file(output,"infodatei") ;
+ taskinfo(3, info);
+
+____________________________________________________________________________
+
+
+ #on("b")#PROC task info ( INT CONST art, stationsnr) #off("b")#
+ Ermöglicht im Netzbetrieb 'task info' über die Station mit der Nummer 'stationsnr'.
+
+____________________________________________________________________________
+
+ gib kommando :
+ taskinfo(1,12) ;
+
+____________________________________________________________________________
+#page#
+'task status'
+
+ #on("b")#PROC task status #off("b")#
+ Informationsprozedur über den Zustand der eigenen Task. Informiert über
+ - Name der Task, Datum und Uhrzeit;
+ - verbrauchte CPU-Zeit;
+ - belegten Speicherplatz;
+ - Kanal, an den die Task angekoppelt ist;
+ - Zustand der Task (rechnend u.a.m.);
+ - Priorität.
+
+ #on("b")#PROC task status (TASK CONST t) #off("b")#
+ Wie obige Prozedur, aber über die Task mit dem internen Tasknamen 't'.
+
+
+____________________________________________________________________________
+
+ gib kommando :
+ task status (public)
+
+ 15.05.87 10:30 TASK: PUBLIC
+
+ Speicher: 1234K
+ CPU Zeit: 0011.12:23
+ Zustand : wait, (Prio 0), Kanal -
+
+____________________________________________________________________________
+#page#
+
+4.2.2 Thesaurus
+
+Ein #ib#Thesaurus#ie# ist ein #ib#Namensverzeichnis#ie#, das bis zu 200 Namen beinhalten kann.
+Dabei muß jeder Namen mindestens ein Zeichen und darf höchstens 100 Zeichen
+lang sein. Steuerzeichen (code < 32) in Namen werden umgesetzt (siehe 2.9.2).
+
+Thesauri werden unter anderem von der Dateiverwaltung benutzt, um das Dateiver­
+zeichnis einer Task zu führen.
+
+Man kann einen Thesaurus selbst erstellen, indem eine Datei z.B. mit Namen von
+Dateien gefüllt wird. Diese Datei kann dann als Thesaurus für weitere Aktionen die­
+nen.
+
+
+
+- Thesaurus liefern : ALL , all , SOME , remainder
+- Auswählen : LIKE
+- Verknüpfen : + , - , /
+
+
+
+#on("b")#ACHTUNG#off("b")# : Bei der Verwendung von Thesaurus Operationen in Verbindung mit
+'fetch', 'save' etc. ist zu beachten, daß mit 'SOME', 'ALL' und 'all' zunächst nur eine
+Auswahl aus einer Liste getroffen wird. Zusätzlich muß das Ziel oder die Quelle des
+Dateitransfers vereinbart werden.
+
+Ein beliebter Fehler ist z.B.: 'fetch (ALL archive)'.
+
+Hier ist nicht weiter spezifiziert, von wo Dateien geholt werden sollen - also werden
+sie von 'father' geholt! (s. 4.2.5)
+
+Falls die Dateien vom Archiv geholt werden sollen, ist das Archiv als Quelle zu be­
+nennen:
+
+Also : 'fetch (ALL archive, archive)' = Hole alle Dateien, die in dem Thesaurus von
+ 'archive' sind von der Task 'archive'.
+#page#
+'ALL'
+ THESAURUS OP ALL (TASK CONST task)
+ Liefert einen Thesaurus, der alle Dateinamen der angegebenen Task enthält.
+
+
+
+ #on("b")#THESAURUS OP ALL (TEXT CONST dateiname) #off("b")#
+ Liefert einen Thesaurus, der die in der angegebenen Datei vorhandenen Namen
+ (jede Zeile ein Name) enthält.
+
+
+
+
+'all'
+ #on("b")#THESAURUS PROC all #off("b")#
+ Liefert einen Thesaurus, der alle Dateinamen der eigenen Task enthält. Entspricht
+ 'ALL myself'.
+
+
+
+
+'SOME'
+ #on("b")#THESAURUS OP SOME (THESAURUS CONST thesaurus) #off("b")#
+ Bietet den angegebenen Thesaurus zum editieren an. Dort können nicht erwünsch­
+ te Namen gestrichen werden.
+
+
+
+ #on("b")#THESAURUS OP SOME (TASK CONST task) #off("b")#
+ Aufruf von: SOME ALL task.
+
+
+ #on("b")#THESAURUS OP SOME (TEXT CONST dateiname) #off("b")#
+ Aufruf von: SOME ALL dateiname.
+
+#page#
+'remainder'
+ #on("b")#PROC remainder #off("b")#
+ Liefert nach einem 'errorstop' die noch nicht bearbeiteten Dateien.
+
+____________________________________________________________________________
+
+ gib kommando :
+ save all (archive)
+
+ '"....." kann nicht geschrieben werden (Archiv voll)'
+
+____________________________________________________________________________
+
+
+
+ Nachdem man eine neue Floppy ins Archivlaufwerk gelegt hat, kann man mit
+
+
+____________________________________________________________________________
+ gib kommando :
+ save (remainder, archive)
+
+____________________________________________________________________________
+
+ den Rest der Dateien auf die nächste Floppy sichern.
+#page#
+'LIKE'
+ #on("b")#THESAURUS OP LIKE (THESAURUS CONST thesaurus, TEXT CONST muster) #off("b")#
+ Alle im Thesaurus enthaltenen Dateien, die dem 'muster' entsprechen sind im
+ Ergebnisthesaurus enthalten.
+
+ (Die Syntax von 'muster' ist bei der Beschreibung des Pattern-Matching (5.4)
+ beschrieben)
+
+
+____________________________________________________________________________
+
+ gib kommando :
+ print (all LIKE "*.p")
+
+____________________________________________________________________________
+
+
+ Alle Dateien, deren Name mit '.p' endet, werden gedruckt.
+
+#page#
+'+'
+ #on("b")#THESAURUS OP + (THESAURUS CONST links, rechts) #off("b")#
+ Liefert die Vereinigungsmenge von 'links' und 'rechts'.
+ Achtung: Die Vereinigungsmenge enthält keine Namen mehrfach.
+
+ #on("b")#THESAURUS OP + (THESAURUS CONST links, TEXT CONST rechts)#off("b")#
+ Fügt dem Thesaurus 'rechts' zu, wenn 'rechts' noch nicht im Thesaurus enthal­
+ ten ist.
+
+
+
+
+'-'
+ #on("b")#THESAURUS OP - (THESAURUS CONST links, rechts) #off("b")#
+ Liefert die Differenzmenge. Achtung: Die Differenzmenge enthält keine Namen
+ mehrfach.
+
+ #on("b")#THESAURUS OP - (THESAURUS CONST links, TEXT CONST rechts)#off("b")#
+ Nimmt den Namen 'rechts' aus dem Thesaurus.
+
+____________________________________________________________________________
+
+ gib kommando :
+ fetch(ALL father - ALL myself)
+
+____________________________________________________________________________
+
+
+'/'
+ #on("b")#THESAURUS OP / (THESAURUS CONST links, rechts) #off("b")#
+ Liefert die Schnittmenge
+ Achtung: Die Schnittmenge enthält keine Namen mehrfach.
+
+
+#page#
+
+4.2.3 Tasks
+
+Zur Identifizierung von Tasks dienen sogenannte 'interne Taskbezeichner'. Ein solcher
+Taskbezeichner wird beim Einrichten einer neuen Task vergeben. Interne Taskbe­
+zeichner sind auch unter Berücksichtigung der Zeit eindeutig.
+
+Der Zugriff auf interne Taskbezeichner erfolgt über Prozeduren und Operatoren, die
+auf Objekte des Datentyps TASK (siehe 2.9.1) angewandt werden.
+
+Zusätzlich zum internen Tasknamen, der nicht auszugeben ist, haben Tasks meistens
+einen Namen#u#1) #e#.
+#foot#
+
+1) Unbenannte Tasks haben den Pseudonamen "-".
+#end#
+
+Aus Benutzersicht können benannte Tasks innerhalb eines Rechners vollständig und
+eindeutig über ihren Namen identifiziert werden.
+
+
+- Task liefern : / , task , niltask
+
+- Verwandtschaften : brother , father , myself , son
+
+- Ausgezeichnete Tasks : archive , printer , public , supervisor
+
+- Namen liefern : name
+
+- Tasknamen ändern : rename myself
+
+- Reservieren bes. Tasks : reserve
+
+#page#
+'/'
+ #on("b")#TASK OP / (TEXT CONST taskname) #off("b")#
+ Liefert die Task des angegebenen Namens, falls sie existiert. Der eigene Katal­
+ og wird automatisch aktualisiert
+
+ (identisch mit der PROC task (TEXT CONST taskname).
+
+ FEHLER : "taskname" gibt es nicht
+
+
+ #on("b")#TASK OP / (INT CONST station number, TEXT CONST name) #off("b")#
+ Liefert im Netzbetrieb die Task des angegebenen Namen von der Station mit der
+ angegebenen Nummer.
+
+
+
+'niltask'
+ #on("b")#TASK CONST niltask #off("b")#
+ Bezeichner für "keine Task". So liefern die Prozeduren 'son', 'brother' und 'father'
+ als Resultat 'niltask', wenn keine Sohn-, Bruder- oder Vatertask existiert.
+
+
+
+'task'
+ #on("b")#TASK PROC task (TEXT CONST taskname) #off("b")#
+ Liefert die Task des angegebenen Namens, falls sie existiert. Der eigene Katal­
+ og wird automatisch aktualisiert.
+
+ FEHLER : "taskname" gibt es nicht
+
+
+ #on("b")#TASK PROC task (INT CONST channel number) #off("b")#
+ Liefert den Namen der Task, die an dem angegebenen Kanal hängt.
+#page#
+'brother'
+ #on("b")#TASK PROC brother (TASK CONST task) #off("b")#
+ Liefert den nächsten Bruder von 'task'. Falls kein Bruder existiert, wird 'niltask'
+ geliefert. Aktualisiert den eigenen Katalog nicht automatisch!
+
+
+
+'father'
+ #on("b")#TASK PROC father #off("b")#
+ Liefert die eigene Vatertask.
+
+
+ #on("b")#TASK PROC father (TASK CONST task) #off("b")#
+ Liefert den Vater von 'task'. Existiert kein Vater (z.B. bei UR), wird niltask gelie­
+ fert. Aktualisiert den eigenen Katalog nicht automatisch!
+
+
+
+'myself'
+ #on("b")#TASK PROC myself #off("b")#
+ Liefert eigenen Task-Bezeichner.
+
+
+
+'son'
+ #on("b")#TASK PROC son (TASK CONST task) #off("b")#
+ Liefert den ersten Sohn von 'task'. Falls keiner im Katalog vermerkt ist, wird
+ 'niltask' geliefert. Aktualisiert den eigenen Katalog nicht automatisch!
+
+
+#page#
+'archive'
+ #on("b")#TASK PROC archive #off("b")#
+ Liefert den internen Taskbezeichner der aktuellen Task mit Namen ARCHIVE.
+ Diese Prozedur dient zum schnellen und bequemen Ansprechen der Archivtask.
+
+
+
+'printer'
+ #on("b")#TASK PROC printer #off("b")#
+ Liefert den internen Taskbezeichner der aktuellen Task mit Namen #ib#PRINTER#ie#.
+ Diese Prozedur dient zum schnellen und bequemen Ansprechen des Druckspoo­
+ lers.
+
+
+'public'
+ #on("b")#TASK PROC public #off("b")#
+ Liefert den internen Taskbezeichner der Task #ib#PUBLIC#ie#.
+
+
+
+
+'supervisor'
+ #on("b")#TASK PROC supervisor #off("b")#
+ Liefert den internen Taskbezeichner des Supervisors.
+
+
+#page#
+'name'
+ #on("b")#TEXT PROC name (TASK CONST task) #off("b")#
+ Liefert den Namen von 'task'. Die Task muß noch im System existieren, sonst ist
+ der Name nicht mehr bekannt. Falls die 'task' noch nicht im eigenen Katalog
+ enthalten ist, wird er aktualisiert.
+
+
+
+'rename myself'
+ #on("b")#PROC rename myself (TEXT CONST neuer name) #off("b")#
+ Name der eigenen Task wird in 'neuer name' geändert. Wirkt wie Löschung und
+ Wiedereinrichten der Task in Bezug auf alle TASK VAR's die sich auf diese Task
+ beziehen.
+
+ FEHLER : Task existiert bereits
+ Name unzulässig
+ => anderen Namen wählen
+
+
+
+'reserve'
+ #on("b")#PROC reserve (TASK CONST task) #off("b")#
+ Reservieren einer Task für den ausschließlichen Dialog mit der Task, in der das
+ Kommando gegeben wurde.
+
+ #on("b")#PROC reserve (TEXT CONST message, TASK CONST task) #off("b")#
+ Wie 'reserve (TASK CONST task)' mit Übergabe einer 'message'.
+
+
+ Die reservierte Task muß ein spezieller Manager, (z.B. /"DOS" aus dem Werkzeug
+ MS-DOS-DAT) sein !
+#page#
+
+4.2.4 Handhabung von Dateien
+
+'copy'
+ #on("b")#PROC copy (TEXT CONST quelle, ziel) #off("b")#
+ Kopiert die Datei 'quelle' in eine neue Datei mit dem Namen 'ziel' in der Benut­
+ zer-Task.
+
+ FEHLER : "ziel" existiert bereits
+ "quelle" gibt es nicht
+ zu viele Dateien
+
+
+
+'forget'
+ #on("b")#PROC forget (TEXT CONST dateiname) #off("b")#
+ Löschen einer Datei mit dem Namen 'dateiname' in der Benutzer-Task.
+
+ FEHLER : "datei" gibt es nicht
+
+
+ #on("b")#PROC forget (THESAURUS CONST thesaurus) #off("b")#
+ Löscht die im 'thesaurus' enthaltenen Dateien in der Benutzer-Task.
+
+ Im Dialog erfolgt vor dem Löschen einer Datei standardmäßig die Abfrage:
+
+
+____________________________________________________________________________
+
+ gib kommando :
+ forget("einedatei")
+ "einedatei" löschen(j/n) ?
+
+____________________________________________________________________________
+
+#page#
+'list'
+ #on("b")#PROC list #off("b")#
+ Listet alle Dateien der Benutzer-Task mit Namen und Datum des letzten Zugriffs
+ auf dem Terminal auf.
+
+
+ #on("b")#PROC list (TASK CONST task) #off("b")#
+ Listet alle Dateien der angegebenen 'task' mit Namen und Datum der letzten
+ Änderung auf dem Terminal auf. Die Task muß Manager sein.
+
+
+ #on("b")#PROC list (FILE VAR liste) #off("b")#
+ Listet alle Dateinamen in die Datei 'liste', die mit 'output'(s. 5.3.5) assoziiert sein
+ muß.
+
+
+ #on("b")#PROC list (FILE VAR liste, TASK CONST manager) #off("b")#
+ Listet alle Dateien der Task 'manager' mit Namen und Datum der letzten Ände­
+ rung in die Datei 'liste'.
+
+
+____________________________________________________________________________
+
+ gib kommando :
+ FILE VAR f:= sequential file (output,"list");list(f,archive)
+
+____________________________________________________________________________
+
+#page#
+'rename'
+ #on("b")#PROC rename (TEXT CONST altername, neuername) #off("b")#
+ Umbenennen einer Datei von 'altername' in 'neuername'.
+
+
+
+ FEHLER : "neuername" gibt es bereits
+ "altername" gibt es nicht
+#page#
+
+4.2.5 Editor-Prozeduren
+
+'edit'
+ #on("b")#PROC edit (TEXT CONST dateiname) #off("b")#
+ Ruft den Editor mit 'dateiname' auf.
+
+
+ #on("b")#PROC edit #off("b")#
+ a) Im Monitor:
+ Ruft den Editor mit den zuletzt verwandten Dateinamen auf.
+
+ b) Im Editor:
+ Der Dateiname wird erfragt.
+
+ Für jedes 'edit' gilt:
+ Wurde 'edit' zum ersten Mal aufgerufen, nimmt das Fenster den gesamten Bild­
+ schirm ein. Bei erneutem 'edit'-Aufruf wird ein Fenster nach rechts unten ab der
+ aktuellen Cursor-Position eröffnet.
+
+
+ #on("b")#PROC edit (THESAURUS CONST t) #off("b")#
+ Editieren aller in dem Thesaurus 't' enthaltenen Dateien nacheinander.
+
+
+ Weitere 'edit-Prozeduren', die z.B. Variation der Fenstergröße etc. zulassen, sind
+ in 5.4.6 beschrieben.
+
+#page#
+'editget'
+ #on("b")#PROC editget (TEXT VAR editsatz) #off("b")#
+ Ausgabe einer (Kommando)zeile, in der Editorfunktionen zur Verfügung
+ stehen siehe Teil 5.5.1.4.
+
+
+
+'show'
+ #on("b")#PROC show (TEXT CONST dateiname) #off("b")#
+ Die Datei wird am Bildschirm gezeigt. Positionierung und Suchen funktionieren wie
+ in 'edit', Aktionen die Änderungen in der Datei bewirken würden, werden nicht
+ angenommen.
+
+
+
+ #on("b")#PROC show #off("b")#
+ 'show' auf der zuletzt bearbeiteten Datei.
+
+#page#
+'kommando auf taste legen'
+ #on("b")#PROC kommando auf taste legen (TEXT CONST taste, elan programm)#off("b")#
+ Die Taste 'taste' wird mit dem angegebenen ELAN-Programm belegt. Durch <ESC>
+ <taste> wird das Programm direkt ausgeführt.
+
+____________________________________________________________________________
+
+ gib kommando :
+ kommando auf taste legen ("a","fetch (SOME archive,archive)")
+
+____________________________________________________________________________
+
+
+
+'kommando auf taste'
+ #on("b")#TEXT PROC kommando auf taste (TEXT CONST taste)#off("b")#
+ Falls 'taste' mit einem ELAN-Programm belegt ist, liefert die Prozedur den
+ Programmtext, andernfalls den leeren Text niltext.
+
+____________________________________________________________________________
+
+ gib kommando :
+ put (kommando auf taste("f"))
+
+____________________________________________________________________________
+
+
+
+'taste enthaelt kommando'
+ #on("b")#BOOL PROC taste enthaelt kommando (TEXT CONST taste)#off("b")#
+ Liefert TRUE falls 'taste' mit einem ELAN-Programm belegt ist.
+
+
+'lernsequenz auf taste legen'
+ #on("b")#PROC lernsequenz auf taste legen (TEXT CONST taste, sequenz)#off("b")#
+ 'taste' wird mit der Zeichenfolge 'sequenz' belegt. Durch <ESC> <taste> wird die
+ Zeichenfolge an der aktuellen Position ausgegeben.
+
+ Als Zeichenfolge sind natürlich auch einzelne Zeichen und EUMEL-Codes zuläs­
+ sig.
+
+ Die vom System vorbelegten Tasten sind in 3.4 'Zeichen schreiben' aufgelistet.
+
+____________________________________________________________________________
+
+ gib kommando :
+ lernsequenz auf taste legen ("x","gib kommando :"13""2""2"")
+
+____________________________________________________________________________
+
+
+
+'lernsequenz auf taste'
+ #on("b")#TEXT PROC lernsequenz auf taste (TEXT CONST taste) #off("b")#
+ Liefert die auf 'taste' gelegte Zeichenfolge.
+
+
+'std tastenbelegung'
+ #on("b")#PROC std tastenbelegung #off("b")#
+ Die Standard-Tastenbelegung (s.3.4) wird (wieder) hergestellt.
+
+
+'word wrap'
+ #on("b")#PROC word wrap (BOOL CONST b) #off("b")#
+ Der automatische Zeilenumbruch wird durch 'word wrap (FALSE)' aus- und durch
+ 'word wrap (TRUE)' eingeschaltet. Wird diese Prozedur während des Editierens
+ aufgerufen, gilt die Einstellung für die aktuelle Textdatei. Wird die Prozedur als
+ Monitor-Kommando gegeben, so gilt die Eingabe als Voreinstellung für neue
+ Dateien.
+#page#
+
+4.2.6 Dateitransfer
+
+Unter diesem Abschnitt sind diejenigen Prozeduren beschrieben, die der simplen
+Kommunikation mit Manager-Tasks dienen: Holen oder Senden einer Dateikopie,
+Löschen in der Manager-Task.
+
+#on("b")#ACHTUNG : Für alle Prozeduren gilt: falls die Manager-Task nicht existiert, wird eine
+Fehlermeldung erzeugt, existiert eine Task des angegebenen Namens, die aber nicht
+Managertask ist, so terminieren die Prozeduren nicht!
+#off("b")#
+
+
+'fetch'
+ #on("b")#PROC fetch (TEXT CONST dateiname, TASK CONST manager) #off("b")#
+ Kopiert die Datei 'dateiname' aus der Task 'manager'
+
+
+ #on("b")#PROC fetch (THESAURUS CONST th, TASK CONST manager) #off("b")#
+ Kopiert alle Dateien, deren Namen im Thesaurus th enthalten sind, aus der Task
+ 'manager'.
+
+
+____________________________________________________________________________
+
+ gib kommando :
+ fetch(ALL(12/"PUBLIC"), 12/"PUBLIC")
+
+____________________________________________________________________________
+
+
+
+ Mit diesem Kommando werden (in einem EUMEL Netz) alle Dateien der Task
+ 'PUBLIC' des Rechners mit der Stationsnummer 12 in diesem Netz kopiert.
+
+#page#
+____________________________________________________________________________
+
+ gib kommando :
+ fetch(SOME archive , archive)
+
+____________________________________________________________________________
+
+
+
+ Bietet den Thesaurus von 'ARCHIVE' an, nach Auswahl werden alle Dateien deren
+ Namen nicht gelöscht wurden, von der Diskette kopiert.
+
+
+ #on("b")#PROC fetch (TEXT CONST dateiname) #off("b")#
+ Kopiert die Datei 'dateiname' aus der Task 'father'
+
+
+ #on("b")#PROC fetch (THESAURUS CONST th) #off("b")#
+ Kopiert alle Dateien, deren Namen in 'th' sind aus der Task 'father'.
+
+
+
+'fetchall'
+
+ #on("b")#PROC fetchall #off("b")#
+ entspricht: fetch (ALL father, father)
+
+
+ #on("b")#PROC fetchall (TASK CONST manager)#off("b")#
+ entspricht: fetch(ALL manager, manager)
+
+#page#
+'save'
+ #on("b")#PROC save (TEXT CONST dateiname, TASK CONST manager) #off("b")#
+ Kopiert die Datei 'dateiname' in die Task 'manager'
+
+
+ #on("b")#PROC save (THESAURUS CONST th, TASK CONST manager) #off("b")#
+ Kopiert alle Dateien, deren Namen im Thesaurus th enthalten sind, in die Task
+ 'manager'.
+
+____________________________________________________________________________
+
+ gib kommando :
+ save(all, (12/"PUBLIC"))
+
+____________________________________________________________________________
+
+
+ Mit diesem Kommando werden (in einem EUMEL Netz) alle Dateien der eigenen
+ Task in die Task 'PUBLIC' des Rechners mit der Stationsnummer 12 in diesem
+ Netz kopiert.
+
+____________________________________________________________________________
+
+ gib kommando :
+ save(SOME myself, manager)
+
+____________________________________________________________________________
+
+
+ Bietet den eigenen Thesaurus an, nach Auswahl werden alle Dateien deren
+ Namen nicht gelöscht wurden, zur Task 'manager' kopiert.
+
+
+ #on("b")#PROC save (TEXT CONST dateiname) #off("b")#
+ Kopiert die Datei 'dateiname' in die Task 'father'
+
+
+ #on("b")#PROC save (THESAURUS CONST th) #off("b")#
+ Kopiert alle Dateien, deren Namen in 'th' enthalten sind, in die Task 'father'.
+
+
+ #on("b")#PROC save #off("b")#
+ Kopiert die zuletzt bearbeitete Datei in die Task 'father'
+
+
+
+
+'saveall'
+ #on("b")#PROC saveall #off("b")#
+ entspricht: save (all, father)
+
+
+ #on("b")#PROC saveall (TASK CONST manager) #off("b")#
+ entspricht: save (ALL myself, manager)
+
+#page#
+'erase'
+ #on("b")#PROC erase (TEXT CONST dateiname, TASK CONST manager) #off("b")#
+ Löscht die Datei 'dateiname' aus der Task 'manager'
+
+
+ #on("b")#PROC erase (THESAURUS CONST th, TASK CONST manager) #off("b")#
+ Löscht alle Dateien, deren Namen im Thesaurus th enthalten sind, aus der Task
+ 'manager'.
+
+
+ #on("b")#PROC erase (TEXT CONST dateiname) #off("b")#
+ Löscht die Datei 'dateiname' aus der Task 'father'
+
+
+ #on("b")#PROC erase (THESAURUS CONST th) #off("b")#
+ Löscht alle Dateien, deren Namen in 'th' sind, aus der Task 'father'
+
+
+ #on("b")#PROC erase #off("b")#
+ Löscht die zuletzt bearbeitete Datei aus der Task 'father'
+
+
+#page#
+'print'
+ Das Kommando 'print' beinhaltet den Auftrag an die Task 'PRINTER' die enthal­
+ tene(n) Datei(en) auszudrucken.
+
+ Voraussetzung ist natürlich, daß die Druckersoftware ordnungsgemäß benutzt
+ wurde, um 'PRINTER' einzurichten. Siehe dazu Systemhandbuch Teil 6.
+
+
+ #on("b")#PROC print (TEXT CONST dateiname) #off("b")#
+ Kopiert die Datei 'dateiname' in die Task 'PRINTER'.
+
+
+ #on("b")#PROC print (THESAURUS CONST th) #off("b")#
+ Kopiert alle Dateien, deren Namen im Thesaurus 'th' enthalten sind, in die Task
+ 'PRINTER'.
+
+
+ #on("b")#PROC print #off("b")#
+ Kopiert die zuletzt bearbeitete Datei in die Task 'PRINTER'.
+
+
+#page#
+
+4.2.7 Passwortschutz
+
+Der Passwortschutz im EUMEL-System ist in verschiedener Ausprägung möglich.
+Einfachste Möglichkeit ist der Schutz einer Task durch ein Passwort. Falls diese Task
+nicht Manager ist, können alle Daten und Programme, die nur in dieser Task zur
+Verfügung stehen, auch nur vom Besitzer der Task benutzt werden.
+
+Ähnlich kann auch von einer Manager-Task aus der gesamte Zweig unterhalb dieser
+Task mit einem Passwort geschützt werden: beispielsweise kann es empfehlenswert
+sein, den Systemzweig komplett zu schützen, indem in SYSUR ein entsprechendes
+Passwort vereinbart wird.
+
+Ein Umgehen des Passwortschutzes bei Manager-Tasks (durch Einrichten einer
+Sohn-Task und 'fetchall') wird durch ein 'begin password' verhindert.
+
+Auch einzelne Dateien lassen sich schützen, indem Lese/Schreibpasswörter für den
+Dateitransfer vereinbart werden.
+
+Generell gilt für die Verwendung von Passworten:
+
+- Passworte, die zu naheliegend gewählt sind (Vorname des Lebenspartners o.ä.)
+ sind meistens sinnlos, falls wirklich Datenschutz bezweckt ist.
+
+- Passworte, die so raffiniert sind, daß sogar ihr Schöpfer sie vergißt, führen zu
+ 100%igem Datenverlust, da die betroffene Task oder Datei nur noch gelöscht
+ werden kann.
+
+- Die Vereinbarung von "-" als Passwort bewirkt, daß die entsprechende Aktion
+ nicht mehr durchgeführt werden kann. Wird z.B. '-' als 'task password'
+ eingegeben, so kann die Task nie wieder an ein Terminal gekoppelt werden.
+
+- Passwörter können geändert werden, indem das entsprechende Kommando noch
+ einmal mit dem neuen Passwort gegeben wird.
+
+#page#
+'begin password'
+
+ #on("b")#PROC begin password (TEXT CONST passwort) #off("b")#
+
+ Auf Supervisor-Ebene wird vor Einrichten einer neuen Task als Sohn der Task in
+ der das 'begin password' gegeben wurde, dieses erfragt.
+
+ Das Password vererbt sich auf die hinzukommenden Sohn-Tasks.
+
+____________________________________________________________________________
+
+ #on("b")#SYSUR#off("b")#
+ maintenance :
+ begin password ("alles dicht")
+
+____________________________________________________________________________
+
+
+bewirkt:
+
+____________________________________________________________________________
+
+ Terminal 2
+
+
+ EUMEL Version 1.8.1/M
+
+
+ gib supervisor kommando:
+ begin ("sabotage","SYSUR")
+ Passwort:
+
+
+ ESC ? --> help
+ ESC b --> begin("") ESC h --> halt
+ ESC c --> continue("") ESC s --> storage info
+ ESC q --> break ESC t --> task info
+
+
+____________________________________________________________________________
+
+
+#page#
+'enter password'
+ #on("b")#PROC enter password (TEXT CONST datei, schreibpass, lesepass)
+ #off("b")#
+ Hiermit können ausgewählte Dateien einer Manager-Task geschützt werden. Die
+ angegebene Datei wird mit Schreib- und Lesepassword versehen. Die Pass­
+ wörter werden in der eigenen Task nicht berücksichtigt.
+
+ Bei einem lesenden Zugriff (fetch) von irgendeiner Task aus auf die entsprechende
+ Datei in der Manager-Task muß das Lesepasswort, bei schreibendem Zugriff
+ (save/erase) das Schreibpasswort vereinbart sein.
+
+
+____________________________________________________________________________
+
+ maintenance :
+ enter password ("wichtige datei","sicher","heit")
+
+____________________________________________________________________________
+
+
+
+
+ #on("b")#PROC enter password (TEXT CONST password) #off("b")#
+ Passwort für den Dateitransfer einstellen. Falls zwei verschiedene Passwörter für
+ Lesen und Schreiben vereinbart werden sollen, so sind sie als ein Text durch "/"
+ getrennt einzugeben.
+
+____________________________________________________________________________
+
+ gib kommando :
+ enter password ("sicher/heit")
+
+ gib kommando :
+ save(SOME all)
+
+____________________________________________________________________________
+#page#
+'family password'
+ #on("b")#PROC family password (TEXT CONST geheim) #off("b")#
+ Einstellen eines Passworts für den Zweig des Systems , der unterhalb der (Mana­
+ ger) Task liegt, in der das 'family password' eingegeben wurde. Dabei erhalten
+ alle Tasks, die kein Password oder dasselbe wie diese Manager-Task haben, das
+ 'family password'. Tasks in dem Zweig, die ein eigenes anderes besitzen, behal­
+ ten dieses.
+
+____________________________________________________________________________
+
+ PUBLIC
+
+ Task1 ""
+
+ Task2 family password("fingerweg")
+ Task21 geheim
+ Task22 ""
+
+ Task3 ""
+ Task31 ""
+
+____________________________________________________________________________
+
+
+
+
+bewirkt:
+
+____________________________________________________________________________
+ PUBLIC
+
+ Task1 ""
+
+ Task2 fingerweg
+ Task21 geheim
+ Task22 fingerweg
+
+ Task3 ""
+ Task31 ""
+
+____________________________________________________________________________
+
+
+#page#
+
+'task password'
+
+ #on("b")#PROC task password (TEXT CONST geheim) #off("b")#
+ Einstellen eines Passworts für die Task in der es gegeben wird. Ist eine Task mit
+ einem Passwort geschützt, so wird durch den Supervisor nach dem 'continue'-
+ Kommando das Passwort angefragt (Entsprechend dem 'begin password'). Nur
+ nach Eingabe des richtigen Passworts gelangt man in die gewünschte Task. Das
+ Passwort kann durch nochmaligen Aufruf von 'task password' geändert werden,
+ z.B. wenn es in regelmäßigen Abständen geändert werden muß, um personenbe­
+ zogene Daten zu schützen.
+
+#page#
+
+4.2.8 Das Archiv
+
+Mit dem Terminus 'Archiv' wird beim EUMEL-System ein Diskettenlaufwerk bezeich­
+net, das nur Datensicherungsaufgaben dient. Falls ein Rechner eins von zwei vorhan­
+denen Diskettenlaufwerk als Arbeitsspeicher benutzt, so wird dieses als Hintergrund
+bezeichnet. Falls Sie einen derartigen Rechner benutzen, können Sie der Installa­
+tionsanleitung entnehmen, welches Laufwerk welcher Aufgabe zugeordnet ist.
+
+Das #ib#Archiv#ie# übernimmt im EUMEL-System die Verwaltung der langfristigen Daten­
+haltung. Das Archiv sollen Sie benutzen, um:
+
+- Sicherungskopien wichtiger Dateien außerhalb des Rechners zu besitzen;
+
+- nicht benötigte Dateien außerhalb einer Task zu halten (Speicherplatzersparnis!);
+
+- Dateien auf andere Rechner zu übertragen.
+
+Das Archiv wird im EUMEL-System durch die Task 'ARCHIVE', die das Disketten­
+laufwerk des Rechners verwaltet, realisiert.
+
+- reservieren : archive
+
+- freigeben : release
+
+- löschen : clear , format
+
+- prüfen : check
+
+#page#
+'archive'
+ #on("b")#PROC archive (TEXT CONST archivname) #off("b")#
+ Reservierung der Task ARCHIVE für den exklusiven Dialog mit der aufrufenden
+ Task. 'archivname' wird bei allen folgenden Archivoperationen mit dem der Disket­
+ te zugewiesenen (und hoffentlich auf dem Aufkleber vermerkten) Namen abgegli­
+ chen.
+
+
+
+'release'
+ #on("b")#PROC release (TASK CONST archive) #off("b")#
+ Nach diesem Kommando kann die Task 'ARCHIVE' mit ihren Leistungen von einer
+ anderen Task in Anspruch genommen werden. Falls dieses Kommando nicht
+ gegeben wird, aber seit 5 Minuten kein Dialog mit 'archive' stattfand, kann eine
+ andere Task durch die Anforderung 'archive("diskettenname")' das Archiv reser­
+ vieren. Durch diese Maßnahme wird verhindert, daß ein vergeßlicher Benutzer bei
+ einem System mit mehreren Benutzern das Archiv blockiert.
+
+#page#
+
+'clear'
+ #on("b")#PROC clear (TASK CONST archive) #off("b")#
+ Löschen des Disketten-Inhaltsverzeichnisses und Zuweisung des in der Reservie­
+ rung eingegebenen Namens.
+
+____________________________________________________________________________
+
+ gib kommando :
+ archive("name"); #ib#clear#ie# (archive)
+
+____________________________________________________________________________
+
+
+ Durch die Ausführung des Kommandos erhält die eingelegte Diskette den in der
+ Reservierung angegebenen Namen. #on("b")#Das Inhaltsverzeichnis, das sich auf der
+ Diskette befindet, wird gelöscht. Damit sind die Daten, die sich eventuell auf
+ dieser Diskette befanden, nicht mehr auffindbar#off("b")#. Die Diskette entspricht einer neu
+ formatierten Diskette#u#1)#e#.
+
+ Man kann also eine beschriebene Diskette nicht umbenennen, ohne die darauf
+ befindlichen Daten zu löschen.
+
+ #foot#
+
+ #u#1)#e# Das Kommando 'format' enthält implizit 'clear'.
+#end#
+
+ Eine Neuformatierung ist demnach bei Wiederverwendung der Diskette nicht
+ notwendig.
+
+#page#
+'format'
+ #on("b")#PROC format (TASK CONST archive) #off("b")#
+ Formatieren einer Diskette. Vor der erstmaligen Benutzung einer Archivdiskette
+ muß diese formatiert, d.h. in Spuren und Sektoren für die Positionierung des
+ Schreib-/Lesekopfes des Diskettenlaufwerks eingeteilt werden, um überhaupt ein
+ Beschreiben der Diskette zu ermöglichen. Die Einteilung ist geräteabhängig, häufi­
+ ge Formate sind:
+
+ 40 Spuren zu je 9 Sektoren (360 K)
+ 80 Spuren zu je 9 Sektoren (720 K).
+
+ Die #on("b")#Erst#off("b")#benutzung einer #ib#Archivdiskette#ie# erfordert nach der Reservierung des Ar­
+ chivs das Kommando:
+
+____________________________________________________________________________
+
+ gib kommando :
+ archive("diskname");
+
+ gib kommando :
+ format (archive);
+
+____________________________________________________________________________
+
+
+Erst nach einer Kontrollabfrage:
+
+____________________________________________________________________________
+
+ gib kommando:
+ format (archive)
+
+ Archiv "diskname" formatieren ? (j/n)
+
+____________________________________________________________________________
+
+
+
+ wird tatsächlich formatiert und die Diskette steht mit dem Namen "diskname" für
+ Archivoperationen zur Verfügung.
+
+#page#
+
+ #on("b")#PROC format (INT CONST code, TASK CONST archive) #off("b")#
+ Bei einigen Rechnern ist es möglich, die Formatierung zu variieren. Falls beim
+ Formatieren auf einem solchen Rechner ein anderes als das Standardformat
+ erzeugt werden soll, so ist die Codierung des gewünschten Formats mitanzuge­
+ ben.
+
+
+ Beispiel: Für ein Gerät mit 5,25 Zoll Disketten wäre z.B. einstellbar:
+ code 0 : Standardformat
+ code 1 : 2D , 40 Spuren , 9 Sektoren
+ code 2 : 2D , 80 Spuren , 9 Sektoren
+ code 3 : HD , 80 Spuren ,15 Sektoren
+
+ 'format (archive)' erzeugt ebenso wie 'format (0,archive)' eine
+ standardformatierte Diskette, 'format (3,archive)' erzeugt eine High
+ Density Formatierung (HD Floppy benutzen!).
+
+#on("b")#
+ ACHTUNG: Wird eine bereits beschriebene Diskette noch einmal formatiert, so
+ sind alle Daten, die auf der Diskette waren, verloren.
+
+ Die Umformatierung einer Diskette (z.B. von 720K auf 360K) auf
+ unterschiedlichen Laufwerken kann zu Problemen führen.
+#off("b")#
+#page#
+'check'
+ #on("b")#PROC check (TEXT CONST dateiname, TASK CONST task) #off("b")#
+ Überprüft, ob die Datei 'dateiname' auf dem Archiv lesbar ist.
+
+
+ #on("b")#PROC check (THESAURUS CONST t, TASK CONST task) #off("b")#
+ Überprüft, ob die in dem Thesaurus 't' enthaltenen Dateien auf dem Archiv lesbar
+ sind.
+
+
+ Mit diesem Kommando kann nach dem Beschreiben einer Diskette überprüft wer­
+ den, ob die Datei(en) lesbar sind. Hierdurch können also verschmutzte oder
+ beschädigte Disketten erkannt werden.
+
+
+____________________________________________________________________________
+
+ gib kommando :
+ save (all , archive)
+
+ gib kommando :
+ check (ALL archive, archive)
+
+____________________________________________________________________________
+
+#page#
+
+Beispiel:
+
+
+____________________________________________________________________________
+
+ gib kommando :
+ archive ("neu")
+
+ gib kommando :
+ format (archive)
+
+____________________________________________________________________________
+
+
+liefert zunächst die Kontollfrage:
+
+____________________________________________________________________________
+
+ gib kommando :
+ format (archive)
+
+ Archiv "neu" formatieren ? (j/n)
+
+____________________________________________________________________________
+
+
+Nach Eingabe 'j'
+
+____________________________________________________________________________
+
+ gib kommando :
+ saveall (archive)
+
+ gib kommando :
+ archive("alt") (* nächste Diskette *)
+
+ gib kommando :
+ fetch(SOME archive ,archive)
+
+____________________________________________________________________________
+
+
+Der Thesaurus des Archivs wird angezeigt:
+#page#
+____________________________________________________________________________
+
+ .................alt (100 K belegt von 720 K)...............
+
+ 01.02.87 25 K "handbuch teil 1"
+ 01.03.87 23 K "handbuch teil 2"
+ 01.04.87 20 K "handbuch teil 3"
+ 01.05.87 32 K "handbuch teil 4"
+
+____________________________________________________________________________
+
+
+
+
+
+Zum Abschluß Archiv freigeben!
+____________________________________________________________________________
+
+ gib kommando :
+ release(archive)
+
+____________________________________________________________________________
+#page#
+
+Fehlermeldungen des Archivs
+Versucht man, eine Datei vom Archiv zu holen, kann es vorkommen, daß das Ar­
+chiv-System
+
+____________________________________________________________________________
+
+ gib kommando :
+ fetch ("datei", archive)
+ #ib#Lese-Fehler (Archiv)#ie#
+
+____________________________________________________________________________
+
+
+
+meldet und den Lese-Vorgang abbricht. Dies kann auftreten, wenn die Floppy
+beschädigt oder aus anderen Gründen nicht lesbar ist (z.B. nicht justierte Disket­
+ten-Geräte). In einem solchen Fall vermerkt das Archiv-System intern, daß die Datei
+nicht korrekt gelesen werden kann. Das sieht man z.B. bei 'list (archive)'. Dort ist der
+betreffende Datei-Name mit dem Zusatz 'mit Lese-Fehler' gekennzeichnet. Um
+diese Datei trotzdem zu lesen, muß man sie unter ihrem Dateinamen mit dem Zusatz
+'mit Lese-Fehler' lesen.
+
+____________________________________________________________________________
+
+ gib kommando:
+ fetch ("datei mit Lese-Fehler", archive)
+
+____________________________________________________________________________
+
+
+
+Die Datei wird in diesem Fall trotz Lese-Fehler (Informationsverlust!) vom Archiv
+gelesen.
+#page#
+
+Weitere Fehlermeldungen des Archivs:
+
+
+FEHLER : Lesen unmöglich (Archiv)
+ Die Archiv-Diskette ist nicht eingelegt oder die Tür des Laufwerks ist nicht
+ geschlossen.
+ => Diskette einlegen bzw. Tür schließen.
+
+FEHLER : Schreiben unmöglich (Archiv)
+ Die Diskette ist schreibgeschützt.
+ => falls wirklich gewünscht, Schreibschutz entfernen.
+
+FEHLER : Archiv nicht angemeldet
+ Das Archiv wurde nicht angemeldet
+ => 'archive ("name")' geben.
+
+FEHLER : Lese-Fehler (Archiv)
+ Siehe Lesen unmöglich
+
+FEHLER : Schreibfehler (Archiv)
+ Die Diskette kann nicht (mehr) beschrieben werden.
+ => Andere Diskette verwenden.
+
+FEHLER : Speicherengpass
+ Im System ist nicht mehr genügend Platz, um eine Datei vom Archiv zu
+ laden.
+ => ggf. Dateien löschen.
+
+FEHLER : RERUN bei Archiv-Zugriff Das System wurde bei einer Archiv-Operation
+ durch Ausschalten bzw. Reset unterbrochen.
+
+FEHLER : "dateiname" gibt es nicht
+ Die Datei "dateiname" gibt es nicht auf dem Archiv.
+ => mit 'list(archive)' Archiv prüfen.
+
+FEHLER : Archiv heißt ...
+ Die eingelegte Diskette hat einen anderen als den eingegebenen Archivna­
+ men.
+ => Kommando 'archive' mit korrektem Namen geben.
+
+FEHLER : Archiv wird von Task ... benutzt
+ Das Archiv wurde von einem anderen Benutzer reserviert.
+ => Abwarten.
+
+FEHLER : "dateiname" kann nicht geschrieben werden (Archiv voll)
+ Die Datei ist zu groß für die eingelegte Diskette.
+ => Andere Diskette für diese Datei nehmen.
+
+FEHLER : Archiv inkonsistent
+ Die eingelegte Diskette hat nicht die Struktur einer Archiv-Diskette.
+ => 'format (archive)' vergessen.
+
+FEHLER : save/erase wegen Lese-Fehler verboten
+ Bei Archiven mit Lese-Fehler sind Schreiboperationen verboten, weil ein
+ Erfolg nicht garantiert werden kann.
+
diff --git a/doc/programmer-manual/1.8.7/doc/programmierhandbuch.5 b/doc/programmer-manual/1.8.7/doc/programmierhandbuch.5
new file mode 100644
index 0000000..a921572
--- /dev/null
+++ b/doc/programmer-manual/1.8.7/doc/programmierhandbuch.5
@@ -0,0 +1,1329 @@
+#pagenr("%",1)##setcount(1)##block##pageblock#
+#headeven#
+#center#EUMEL-Benutzerhandbuch
+#center#____________________________________________________________
+
+#end#
+#headodd#
+#center#TEIL 5 : Programmierung
+#center#____________________________________________________________
+
+#end#
+#bottomeven#
+#center#____________________________________________________________
+5 - % #right#GMD
+#end#
+#bottomodd#
+#center#____________________________________________________________
+GMD #right#5 - %
+#end#
+
+TEIL 5: Programmierung
+
+
+5.1 Der ELAN-Compiler
+
+Der ELAN-Compiler des EUMEL-Systems dient zweierlei Aufgaben: zum einen der
+Übersetzung von ELAN-Programmen, zum anderen der Verwaltung der taskeigenen
+Modulbibliothek.
+
+Diese Moduln, in ELAN Pakete (siehe 2.4.3.4ff.) genannt, stellen als vorübersetzte,
+und damit abrufbereite#u#1)#e# Prozeduren den Kommandovorrat einer Task dar.
+
+Der Codebereich einer Task liegt in ihrem Standarddatenraum (ds4). Die Größe dieses
+Codebereiches beträgt 256K. Der Inhalt besteht zunächst aus den von der Vatertask
+ererbten (durch Kopie des ds4 dieser Task) Moduln, im weiteren allen in dieser Task
+neu hinzu insertierten Packeten.
+#on("b")#
+
+
+ACHTUNG: Durch ständiges Neuinsertieren eines Packets kann der
+ Codebereich der betroffenen Task zum Überlaufen
+ gebracht werden!
+
+
+#foot#
+
+1) Die von anderen Systemen her gewohnten Phasen 'Binden' und 'Laden' sind
+ durch das EUMEL-ELAN-Compiler-Konzept unnötig.
+#end#
+Jedes Kommando im EUMEL-System ist der Aufruf einer, in der Schnittstelle eines
+bereits insertierten Packetes stehenden, Prozedur.
+
+Kommandos für den ELAN-Compiler:
+
+- Übersetzen : do , insert , run , runagain
+
+- Protokollieren : check , checkon/off ,
+ prot , protoff , warnings on/off
+
+
+#page#
+'do'
+ #on("b")#PROC do (TEXT CONST program)#off("b")#
+ Übersetzen und Ausführen von 'program' von einem Programm aus. 'program'
+ muß ein ausführbares ELAN Programm sein.
+
+
+____________________________________________________________________________
+
+ ........................... Beispiel ..........................
+ PACKET reo DEFINES reorganize all:
+
+ PROC reorganize all(THESAURUS CONST thes):
+ do (PROC (TEXT CONST) reorganize ,thes)
+ (* Die Prozedur 'reorganize' (siehe 5-52), die einen*)
+ (* Dateinamen als Parameter verlangt, wird auf alle *)
+ (* Dateien des Thesaurus 'thes' angewandt. *)
+ END PROC reorganize all;
+ END PACKET reo;
+
+____________________________________________________________________________
+
+
+'insert'
+ #on("b")#PROC insert (TEXT CONST dateiname) #off("b")#
+ Insertieren eines oder mehrerer PACKETs aus der Datei 'dateiname'. Der Pro­
+ grammtext muß sich in #on("u")#einer#off("u")# Datei befinden.
+
+
+ #on("b")#PROC insert #off("b")#
+ Insertieren eines oder mehrerer PACKETs. Der Dateiname ist der zuletzt benutzte
+ Dateiname.
+
+
+ #on("b")#PROC insert (THESAURUS CONST t) #off("b")#
+ Insertieren aller PACKETs, die in den Dateien des Thesaurus 't' enthalten sind.
+
+
+#page#
+'run'
+ #on("b")#PROC run #off("b")#
+ Übersetzen und Ausführen eines ELAN-Programms. Der Programmtext muß sich
+ in einer Datei befinden. Der Dateiname ist der zuletzt benutzte Dateiname.
+
+
+ #on("b")#PROC run (TEXT CONST dateiname) #off("b")#
+ Wie oben. Der Programmtext wird aus der Datei mit dem Namen 'dateiname'
+ geholt.
+
+
+
+'runagain'
+ #on("b")#PROC runagain #off("b")#
+ Nochmaliges Ausführen des zuletzt mit 'run' übersetzten ELAN-Programms.
+ Wurde in der letzten Übersetzung ein Fehler gefunden, erfolgt die Meldung:
+
+ FEHLER : "run again nicht möglich"
+
+#page#
+'check'
+ #on("b")#BOOL PROC check #off("b")#
+ Informationsprozedur, die TRUE liefert, wenn 'check' eingeschaltet ist.
+
+ #on("b")#PROC check on #off("b")#
+ Einschalten der Generierung von Zeilennummern durch den ELAN-Compiler. Der
+ bei der Übersetzung erzeugte Code wird ca. 25% umfangreicher!
+ Voreinstellung im 'PUBLIC'- Zweig: 'check on'.
+
+ #on("b")#PROC check off #off("b")#
+ Ausschalten der Generierung von Zeilennummern durch den ELAN-Compiler.
+ Voreinstellung im 'SYSUR' - Zweig: 'check off.
+
+
+'prot'
+ #on("b")#BOOL PROC prot #off("b")#
+ Informationsprozedur, die TRUE liefert, gdw. 'prot' eingeschaltet ist.
+
+ #on("b")#PROC prot (TEXT CONST dateiname) #off("b")#
+ Einschalten des Compilerlistings auf dem Bildschirm. Das Listing wird gleichzeitig
+ in die Datei 'dateiname' geschrieben.
+
+ #on("b")#PROC prot off #off("b")#
+ Ausschalten des Listings.
+
+
+'warnings'
+ #on("b")#BOOL PROC warnings #off("b")#
+ Informationsprozedur, die TRUE liefert gdw. 'warnings' eingeschaltet ist.
+
+ #on("b")#PROC warnings on #off("b")#
+ Warnungen werden wie Fehlermeldungen ins Notizbuch ausgegeben.
+
+ #on("b")#PROC warnings off#off("b")#
+ Warnungen werden nicht mit in das Notizbuch ausgegeben.
+#page#
+
+5.1.1 Fehlermeldungen des ELAN-Compilers
+erfolgen stets in der Form:
+
+#ib#COMPILER ERROR#ie#: <zahl>
+
+wobei <zahl> folgende Werte annehmen kann:
+
+#on("bold")#<zahl> Bedeutung und eventuelle Abhilfe#off ("bold")#:
+
+ 101 Überlauf der Namenstabelle
+ Die Anzahl der Namen aller sichtbaren Pakete ist zu groß oder es wurden
+ die Anführungstriche eines TEXT-Denoters vergessen.
+ => Keine Abhilfe.
+
+ 102 Überlauf der Symboltabelle
+ Die Anzahl der deklarierten Objekte ist zu groß.
+ => Programm in Pakete unterteilen.
+
+ 103 Überlauf des Zwischencodebereiches
+ => Programm in Pakete unterteilen.
+
+ 104 Überlauf der Permanenttabelle
+ Zu viele Pakete insertiert.
+ => Keine (neue Task beginnen).
+
+ 106 Paketdatenadresse zu groß
+ Im Paket wird zuviel Platz ( > 64K ) von globalen Datenobjekten und
+ Denotern eingenommen.
+ => Keine Abhilfe.
+
+ 107 Lokale Datenadresse zu groß
+ Im Paket wird zuviel Platz ( > 32K ) von lokalen Datenobjekten belegt.
+ => Keine Abhilfe.
+ #page#
+ 204 Überlauf des Compilerstack
+ => Keine Abhilfe.
+
+ 301 Modulnummern-Überlauf
+ Zu viele sichtbare Pakete, Prozeduren und Operatoren ( > 2048 ).
+ => Keine Abhilfe.
+
+ 303
+ siehe 304
+
+ 304 Zu viele Ansprungadressen
+ In dem gerade übersetzten Modul (Prozedur, Operator oder Paketrumpf)
+ werden vom Compiler zu viele Marken benötigt (mehr als 2000). Marken
+ werden z.B. für die Codegenerierung von Auswahl (IF ...) und Wieder­
+ holung (REP ...) gebraucht. Insbesondere bei SELECT-Anweisungen
+ werden 'casemax - casemin + 2' Marken benötigt, wobei 'casemax' der
+ INT-Wert des maximalen, 'casemin' der des minimalen CASE-Wertes
+ ist. Dieser Fehler ist somit fast immer auf zu viele und/oder zu weit ge­
+ spannte SELECT-Anweisungen zurückzuführen.
+ => SELECT-Anweisungen über mehrere Prozeduren verteilen oder
+ Spannweiten verringern.
+
+ 305 Codeüberlauf
+ Der insgesamt erzeugte sichtbare Code ist zu umfangreich ( > 256K ).
+ => Keine Abhilfe.
+
+ 306 Paketdatenadresse zu groß
+ Insgesamt zu viele Datenobjekte in den Paketen ( > 128K ).
+ => Keine Abhilfe.
+
+ 307 Temporäre Datenadresse zu groß
+ Zu viele (lokale) Datenobjekte in einer Prozedur ( > 32K ).
+ => Prozedur in mehrere unterteilen, so daß die Datenobjekte sich über
+ mehrere Prozeduren verteilen.
+
+ 308 Modulcode-Überlauf
+ Ein Modul (Prozedur, Operator oder Paket-Initialisierungsteil) ist zu groß
+ ( > 7.5 KB Code).
+ => In mehrere Prozeduren oder Pakete zerlegen.
+
+ 309 Zuviele Paketdaten
+ (Insgesamt mehr als 128K Paketdaten)
+ => Keine Abhilfe
+
+
+#page#
+
+5.2 Standardtypen
+
+
+5.2.1 Bool
+
+Der Wertebereich für Datenobjekte vom Typ BOOL besteht aus den Werten TRUE
+und FALSE.
+
+'AND'
+ #on("b")#BOOL OP AND (BOOL CONST a, b) #off("b")#
+ Logisches UND, liefert TRUE gdw. a und b TRUE sind.
+
+
+'CAND'
+ #on("b")#BOOL OP CAND #off("b")#
+ Bedingtes logisches UND, entspricht: 'IF a THEN b ELSE false FI'. Der zweite
+ Operand wird nicht ausgewertet, falls er für das Ergebnis nicht relevant ist.
+
+
+'COR'
+ #on("b")#BOOL OP COR #off("b")#
+ Bedingtes logisches ODER, entspricht: 'IF a THEN true ELSE b FI'. Der zweite
+ Operand wird nicht ausgewertet, falls er für das Ergebnis nicht relevant ist.
+
+
+'false'
+ #on("b")#BOOL CONST false #off("b")#
+
+
+'NOT'
+ #on("b")#BOOL OP NOT (BOOL CONST a) #off("b")#
+ Logische Negation.
+
+
+'OR'
+ #on("b")#BOOL OP OR (BOOL CONST a, b) #off("b")#
+ Logisches ODER, liefert TRUE gdw. a und/oder b TRUE ist.
+
+
+'true'
+ #on("b")#BOOL CONST true #off("b")#
+
+
+'XOR'
+ #on("b")#BOOL OP XOR (BOOL CONST a, b) #off("b")#
+ Exklusives ODER, liefert TRUE gdw. entweder a oder b TRUE ist.
+
+#page#
+
+5.2.2 Integer-Arithmetik
+
+Ein Datenobjekt vom Typ INT belegt im Speicher 2 Bytes. Zulässige INT - Werte
+sind die ganzen Zahlen von -32768 bis +32767 einschließlich.
+
+Falls größere ganze Zahlen benötigt werden, muß das Packet 'LONGINT', welches
+sich auf dem Archive 'std.zusatz' befindet, nachinsertiert werden (siehe 6.1.2).
+
+Operationen für Integers:
+
+- Vergleich : = , <> , < , <= , > , >=
+
+- Verknüpfung : + , - , * , ** , DECR , DIV , INCR
+
+- Sonstiges : abs , ABS , initialize random , max , maxint , min ,
+ minint , MOD , random , sign , SIGN , text
+#page#
+':='
+ #on("b")#INT OP := (INT VAR a, INT CONST b) #off("b")#
+ Zuweisung.
+
+
+'='
+ #on("b")#BOOL OP = (INT CONST a, b) #off("b")#
+ Vergleich.
+
+
+'<>'
+ #on("b")#BOOL OP <> (INT CONST a, b) #off("b")#
+ Vergleich auf Ungleichheit.
+
+
+'<'
+ #on("b")#BOOL OP < (INT CONST a, b) #off("b")#
+ Vergleich auf kleiner.
+
+
+'<='
+ #on("b")#BOOL OP <= (INT CONST a, b) #off("b")#
+ Vergleich auf kleiner gleich.
+
+
+'>'
+ #on("b")#BOOL OP > (INT CONST a, b) #off("b")#
+ Vergleich auf größer.
+
+
+'>='
+ #on("b")#BOOL OP >= (INT CONST a, b) #off("b")#
+ Vergleich auf größer gleich.
+
+#page#
+'+'
+ #on("b")#INT OP + (INT CONST a) #off("b")#
+ Monadischer Operator (Vorzeichen, ohne Wirkung).
+
+ #on("b")#INT OP + (INT CONST a, b) #off("b")#
+ Addition.
+
+
+'-'
+ #on("b")#INT OP - (INT CONST a) #off("b")#
+ Vorzeichen-Umkehrung.
+
+
+ #on("b")#INT OP - (INT CONST a, b) #off("b")#
+ Subtraktion.
+
+
+'*'
+ #on("b")#INT OP * (INT CONST a, b) #off("b")#
+ Multiplikation.
+
+
+'**'
+ #on("b")#INT OP ** (INT CONST arg, exp) #off("b")#
+ Exponentiation mit 'exp' >= 0
+
+
+'DECR'
+ #on("b")#OP DECR (INT VAR links, INT CONST rechts) #off("b")#
+ Wirkt wie links := links - rechts
+
+
+'DIV'
+ #on("b")#INT OP DIV (INT CONST a, b) #off("b")#
+ INT-Division.
+
+ FEHLER :
+ - DIV durch 0
+
+
+'INCR'
+ #on("b")#OP INCR (INT VAR links, INT CONST rechts) #off("b")#
+ Wirkt wie links := links + rechts
+
+#page#
+'abs'
+ #on("b")#INT PROC abs (INT CONST argument) #off("b")#
+ Absolutbetrag eines INT-Wertes.
+
+
+ #on("b")#INT OP ABS (INT CONST argument) #off("b")#
+ Absolutbetrag eines INT-Wertes.
+
+
+'initialize random'
+ #on("b")#PROC initialize random (INT CONST wert) #off("b")#
+ Initialisieren der 'random'-Prozedur, um nicht reproduzierbare Zufallszahlen zu
+ bekommen. Diese 'initialize random'-Prozedur gilt für den "INT-Random Gene­
+ rator".
+
+
+'max'
+ #on("b")#INT PROC max (INT CONST links, rechts) #off("b")#
+ Liefert den Größten der beiden INT-Werte.
+
+
+'maxint'
+ #on("b")#INT CONST maxint #off("b")#
+ Größter INT-Wert im EUMEL-System (32 767).
+
+
+'min'
+ #on("b")#INT PROC min (INT CONST links, rechts) #off("b")#
+ Liefert den Kleinsten der beiden INT-Werte.
+
+
+ min ( 3.0, 2.0) ==> 2.0
+ min (-2.0, 3.0) ==> -2.0
+
+
+
+'minint'
+ #on("b")#INT CONST minint #off("b")#
+ Kleinster INT-Wert im EUMEL-System (-32768).
+
+
+'MOD'
+ #on("b")#INT OP MOD (INT CONST links, rechts) #off("b")#
+ Liefert den Rest einer INT-Division.
+
+
+ 3 MOD 2 ==> 1
+ -3 MOD 2 ==> 1
+
+
+ FEHLER :
+ - DIV durch 0
+
+
+'random'
+ #on("b")#INT PROC random (INT CONST lower bound, upper bound) #off("b")#
+ Pseudo-Zufallszahlen-Generator im Intervall 'upper bound' und 'lower bound'
+ einschließlich. Es handelt sich hier um den "INT Random Generator".
+
+
+'real'
+ #on("b")#REAL PROC real (INT CONST a) #off("b")#
+ Konvertierungsprozedur.
+
+#page#
+'sign'
+ #on("b")#INT PROC sign (INT CONST argument) #off("b")#
+ Feststellen des Vorzeichens eines INT-Wertes. Folgende Werte werden geliefert:
+
+
+ argument > 0 ==> 1
+ argument = 0 ==> 0
+ argument < 0 ==> -1
+
+
+
+ #on("b")#INT OP SIGN (INT CONST argument) #off("b")#
+ Feststellen des Vorzeichens eines INT-Wertes.
+
+
+'text'
+ #on("b")#TEXT PROC text (INT CONST zahl) #off("b")#
+ Konvertierung des INT Wertes 'zahl' in den kürzest möglichen Text. Das Vorzei­
+ chen bleibt erhalten.
+
+ #on("b")#TEXT PROC text (INT CONST zahl, länge) #off("b")#
+ Konvertierung des INT Wertes 'zahl' in einen Text der Länge 'länge'. Das
+ Vorzeichen bleibt erhalten. Falls der Text kürzer als 'länge' ist, wird er links
+ (vorne) mit Leerzeichen aufgefüllt, falls er länder ist wird 'länge' mal "*"
+ ausgegeben.
+
+____________________________________________________________________________
+
+ out ("X:"); out(text(12345,7)) ; line;
+ out ("Y:"); out(text(12345,3)) ;
+ (* ergibt *)
+ X: 12345
+ Y:***
+
+____________________________________________________________________________
+#page#
+
+5.2.3 Real-Arithmetik
+
+Für den Datentyp REAL gibt es außer den üblichen Verknüpfungs- und Vergleichs­
+operationen noch eine Anzahl mathematischer Prozeduren und Operationen. Teilweise
+stehen diese in mehr als einer Version zur Verfügung.
+
+Jedes Datenobjekt vom Typ REAL belegt im Speicher 8 Byte.
+
+REALs haben eine 13-stellige #ib#Mantisse#ie#, die im Rechner dezimal geführt wird. (Das
+heißt, bei Konversionen zwischen interner und TEXT-Darstellung treten keine Run­
+dungsfehler auf.) Der Wertebereich wird durch folgende Eckwerte abgegrenzt:
+#dpos(0.5,".")##lpos(4.5)#
+
+#table#
+ 9.999999999999e+126 größter REAL-Wert
+ 0.000000000001 kleinster positiver REAL-Wert mit x + 1.0 > 1.0
+ 9.999999999999e-126 kleinster positiver REAL-Wert > 0.0
+ -9.999999999999e-126 größter negativer REAL-Wert
+ -9.999999999999e+126 kleinster REAL-Wert
+
+#clearpos#
+#tableend#
+
+- Vergleiche : = , <> , < , <= , > , >=
+
+- Verknüpfungen : + , - , * , / , ** , DECR , INCR
+
+- Diverse : abs , arctan , arctand , cos , cosd , decimal
+ exponent , e , exp , floor , frac , initialize
+ random , int , ln , log2 , log10 , max ,
+ maxreal , min , MOD , pi , random , round ,
+ sign , SIGN , sin , sind , smallreal , sqrt ,
+ tan , tand , text
+
+#page#
+':='
+ #on("b")#REAL OP := (REAL VAR a, REAL CONST b) #off("b")#
+ Zuweisung.
+
+
+'='
+ #on("b")#BOOL OP = (REAL CONST a, b) #off("b")#
+ Vergleich.
+
+
+'<>'
+ #on("b")#BOOL OP <> (REAL CONST a, b) #off("b")#
+ Vergleich auf Ungleichheit.
+
+
+'<'
+ #on("b")#BOOL OP < (REAL CONST a, b) #off("b")#
+ Vergleich auf kleiner.
+
+
+'<='
+ #on("b")#BOOL OP <= (REAL CONST a, b) #off("b")#
+ Vergleich auf kleiner gleich.
+
+
+'>'
+ #on("b")#BOOL OP > (REAL CONST a, b) #off("b")#
+ Vergleich auf größer.
+
+
+'>='
+ #on("b")#BOOL OP >= (REAL CONST a, b) #off("b")#
+ Vergleich auf größer gleich.
+
+#page#
+'+'
+ #on("b")#REAL OP + (REAL CONST a) #off("b")#
+ Monadischer Operator (Vorzeichen, ohne Wirkung).
+
+
+ #on("b")#REAL OP + (REAL CONST a, b) #off("b")#
+ Addition.
+
+
+'-'
+ #on("b")#REAL OP - (REAL CONST a) #off("b")#
+ Vorzeichen-Umkehrung.
+
+
+ #on("b")#REAL OP - (REAL CONST a, b) #off("b")#
+ Subtraktion.
+
+
+'*'
+ #on("b")#REAL OP * (REAL CONST a, b) #off("b")#
+ Multiplikation.
+
+
+'/'
+ #on("b")#REAL OP / (REAL CONST a, b) #off("b")#
+ Division.
+
+ FEHLER :
+ - Division durch 0
+
+
+'**'
+ #on("b")#REAL OP ** (REAL CONST arg, exp) #off("b")#
+ Exponentiation.
+
+ #on("b")#REAL OP ** (REAL CONST arg, INT CONST exp) #off("b")#
+ Exponentiation.
+
+
+'DECR'
+ #on("b")#OP DECR (REAL VAR links, REAL CONST rechts) #off("b")#
+ Wirkt wie links := links - rechts
+
+
+'INCR'
+ #on("b")#OP INCR (REAL VAR links, REAL CONST rechts) #off("b")#
+ Wirkt wie links := links + rechts
+
+#page#
+'abs'
+ #on("b")#REAL PROC abs (REAL CONST wert) #off("b")#
+ Absolutbetrag eines REAL-Wertes.
+
+ #on("b")#REAL OP ABS (REAL CONST wert) #off("b")#
+ Absolutbetrag eines REAL-Wertes.
+
+
+'arctan'
+ #on("b")#REAL PROC arctan (REAL CONST x) #off("b")#
+ Arcus Tangens-Funktion. Liefert einen Wert in Radiant.
+
+
+'arctand'
+ #on("b")#REAL PROC arctand (REAL CONST x) #off("b")#
+ Arcus Tangens-Funktion. Liefert einen Wert in Grad.
+
+
+'cos'
+ #on("b")#REAL PROC cos (REAL CONST x) #off("b")#
+ Cosinus-Funktion. 'x' muß in Radiant angegeben werden.
+
+
+'cosd'
+ #on("b")#REAL PROC cosd (REAL CONST x) #off("b")#
+ Cosinus-Funktion. 'x' muß in Winkelgrad angegeben werden.
+
+
+'decimal exponent'
+ #on("b")#INT PROC decimal exponent (REAL CONST mantisse) #off("b")#
+ Liefert aus einem REAL-Wert den dezimalen Exponenten als INT-Wert.
+
+
+'e'
+ #on("b")#REAL PROC e #off("b")#
+ Eulersche Zahl (2.718282).
+
+
+'exp'
+ #on("b")#REAL PROC exp (REAL CONST z) #off("b")#
+ Exponentialfunktion.
+
+
+'floor'
+ #on("b")#REAL PROC floor (REAL CONST real) #off("b")#
+ Schneidet die Nachkommastellen des REAL-Wertes 'real' ab.
+
+
+'frac'
+ #on("b")#REAL PROC frac (REAL CONST z) #off("b")#
+ Liefert die Stellen eines REAL-Wertes hinter dem Dezimalpunkt.
+
+
+'initialize random'
+ #on("b")#PROC initialize random (REAL CONST z) #off("b")#
+ Initialisieren der 'random'-Prozedur mit verschiedenen Werten für 'z', um nicht
+ reproduzierbare Zufallszahlen zu bekommen. Diese Prozedur gilt für den
+ 'REAL-Random Generator'.
+
+
+'int'
+ #on("b")#INT PROC int (REAL CONST a) #off("b")#
+ Konvertierungsprozedur. Die Nachkommastellen werden abgeschnitten.
+ Bsp: int (3.9) => 3
+
+
+'ln'
+ #on("b")#REAL PROC ln (REAL CONST x) #off("b")#
+ Natürlicher Logarithmus.
+
+ FEHLER :
+ - ln mit negativer Zahl
+ Nur echt positive Argumente sind zulässig.
+
+
+'log2'
+ #on("b")#REAL PROC log2 (REAL CONST z) #off("b")#
+ Logarithmus zur Basis 2.
+
+ FEHLER :
+ - log2 mit negativer zahl
+ Nur echt positive Argumente sind zulässig.
+
+
+'log10'
+ #on("b")#REAL PROC log10 (REAL CONST x) #off("b")#
+ Logarithmus zur Basis 10.
+
+ FEHLER :
+ - log10 mit negativer zahl
+ Nur echt positive Argumente sind zulässig.
+
+
+'max'
+ #on("b")#REAL PROC max (REAL CONST links, rechts) #off("b")#
+ Liefert den Größten der beiden REAL-Werte.
+
+
+'maxreal'
+ #on("b")#REAL CONST maxreal #off("b")#
+ Größter REAL-Wert im EUMEL-System (9.999999999999e126).
+
+
+'min'
+ #on("b")#REAL PROC min (REAL CONST links, rechts) #off("b")#
+ Liefert den Kleinsten der beiden REAL-Werte.
+
+
+'MOD'
+ #on("b")#REAL OP MOD (REAL CONST links, rechts) #off("b")#
+ Modulo-Funktion für REALs (liefert den Rest). Beispiele:
+
+
+ 5.0 MOD 2.0 ==> 1.0
+ 4.5 MOD 4.0 ==> 0.5
+
+
+
+'pi'
+ #on("b")#REAL CONST pi #off("b")#
+ Die Zahl pi (3.141593).
+
+
+'random'
+ #on("b")#REAL PROC random #off("b")#
+ Pseudo-Zufallszahlen-Generator im Intervall 0 und 1. Es handelt sich hier um
+ den "REAL Random Generator".
+
+
+'round'
+ #on("b")#REAL PROC round (REAL CONST real, INT CONST digits) #off("b")#
+ Runden eines REAL-Wertes auf 'digits' Stellen. Für positive Werte wird auf
+ Nachkommastellen gerundet. Beispiel:
+
+
+ round (3.14159, 3)
+
+
+ liefert '3.142'. Für negative 'digits'-Werte wird auf Vorkommastellen gerundet.
+
+
+ round (123.456, -2)
+
+
+ liefert '100.0'. Abweichung vom Standard: Es wird mit 'digits'-Ziffern gerundet.
+
+
+'sign'
+ #on("b")#INT PROC sign (REAL CONST argument) #off("b")#
+ Feststellen des Vorzeichens eines REAL-Wertes.
+
+ #on("b")#INT OP SIGN (REAL CONST argument) #off("b")#
+ Feststellen des Vorzeichens eines REAL-Wertes.
+
+
+'sin'
+ #on("b")#REAL PROC sin (REAL CONST x) #off("b")#
+ Sinus-Funktion. 'x' muß in Radiant (Bogenmaß) angegeben werden.
+
+
+'sind'
+ #on("b")#REAL PROC sind (REAL CONST x) #off("b")#
+ Sinus-Funktion. 'x' muß im Winkelgrad angegeben werden.
+
+
+'smallreal'
+ #on("b")#REAL PROC smallreal #off("b")#
+ Kleinster darstellbarer REAL-Wert im EUMEL-System für den
+
+
+ 1.0 - smallreal <> 1.0
+ 1.0 + smallreal <> 1.0
+
+
+ gilt (1.0E-12).
+
+
+'sqrt'
+ #on("b")#REAL PROC sqrt (REAL CONST z) #off("b")#
+ Wurzel-Funktion.
+
+ FEHLER :
+ - sqrt von negativer Zahl
+ Das Argument muß größer gleich 0.0 sein.
+
+
+'tan'
+ #on("b")#REAL PROC tan (REAL CONST x) #off("b")#
+ Tangens-Funktion. 'x' muß in Radiant angegeben werden.
+
+
+'tand'
+ #on("b")#REAL PROC tand (REAL CONST x) #off("b")#
+ Tangens-Funktion. 'x' muß in Winkelgrad angegeben werden.
+
+
+'text'
+ #on("b")#TEXT PROC text (REAL CONST real) #off("b")#
+ Konvertierung eines REAL-Wertes in einen TEXT. Ggf. wird der TEXT in Expo­
+ nenten-Darstellung geliefert.
+
+ #on("b")#TEXT PROC text (REAL CONST real, laenge) #off("b")#
+ Konvertierung eines REAL-Wertes in einen TEXT. Der TEXT wird in Exponen­
+ ten-Darstellung geliefert. Um diese Darstellung zu ermöglichen ist der Wert
+ 'laenge' größer oder gleich 8 anzugeben.
+
+ #on("b")#TEXT PROC text (REAL CONST real, INT CONST laenge, fracs)#off("b")#
+ Konvertierung eines REAL-Wertes in einen TEXT. Dabei gibt 'laenge' die Länge
+ des Resultats einschließlich des Dezimalpunktes und 'fracs' die Anzahl der Dezi­
+ malstellen an. Kann der REAL-Wert nicht wie gewünscht dargestellt werden, wird
+
+
+ laenge * "*"
+
+
+ geliefert.
+
+#page#
+
+5.2.4 Text
+
+Jedes Datenobjekt vom Typ TEXT besteht aus einem festen Teil von 16 Bytes und
+möglicherweise aus einem flexiblen Teil auf dem #on("i")##on("b")#Heap#off("i")##off("b")#. Im festen Teil werden Texte
+bis zur Länge von 13 Zeichen untergebracht. Wenn eine TEXT-Variable einen Wert
+mit mehr als 13 Zeichen Länge annimmt, werden alle Zeichen auf dem Heap unterge­
+bracht. Genauer ergibt sich folgendes Bild:
+
+ kurzer Text (Länge <= 13):
+
+ Heap-Link 2 Bytes
+ Textlänge 1 Byte
+ Text 13 Bytes
+
+ langer Text (Länge > 13):
+
+ Heap-Link 2 Bytes
+ 255 1 Byte
+ Länge 2 Bytes
+ ungenutzt 11 Bytes
+
+Wenn eine Variable einmal Platz auf dem Heap bekommen hat, behält sie diesen
+vorbeugend auch dann, wenn sie wieder einen kurzen Text als Wert erhält. So muß
+wahrscheinlich kein neuer Platz auf dem Heap zugewiesen werden, wenn sie wieder
+länger wird. Das gilt allerdings nur bis zur nächsten #ib#Garbage Collection#ie# auf den
+TEXT-Heap, denn dabei werden alle Heap-Container minimal gemacht bzw. ge­
+löscht, wenn sie nicht mehr benötigt werden. Der Platz auf dem Heap wird in Vielfa­
+chen von 16 Bytes vergeben. In Fremddatenräumen wird in jedem #ib#Container#ie# neben
+dem eigentlichen Text auch die Containerlänge untergebracht.
+#page#
+Beispiele: TEXT-Länge Speicherbedarf (Byte)
+
+ 0 16
+ 13 16
+ 14 32
+ 15 48
+ 30 48
+ 31 64
+ 46 64
+ 47 80
+ 62 80
+
+
+Die Heapgröße eines Fremddatenraums berechnet sich als:
+
+ 1024 * 1024 = 1048056 - stat Bytes
+
+'stat' ist dabei die statische Größe der Datenstruktur, die dem Datenraum aufgeprägt
+wurde. Bei einem BOUND ROW 1000 TEXT ergibt sich also eine Heapgröße von
+
+ 1048056 - (1000 * 16) = 1032056 Bytes.
+
+
+
+'heap size'
+ #on("b")#INT PROC heap size #off("b")#
+ Informationsprozedur für die Größe (in KB) des TEXT-Heaps.
+
+#page#
+
+TEXT- Operationen:
+
+- Vergleich : = , <> , < , <= , > , >=
+ LEXEQUAL , LEXGREATER ,
+ LEXGREATEREQUAL
+
+- Verkettung : + , * , CAT
+
+- Veränderung : change , change all , code , compress , delete
+ char , insert char , length , LENGTH , max
+ text length , pos , real , replace , SUB ,
+ subtext , text
+#page#
+
+Der EUMEL-Zeichensatz
+#goalpage("codetab")#
+Das EUMEL System definiert einen Zeichensatz, der gewährleistet, daß gleiche Text­
+zeichen auf allen Maschinen gleich codiert werden.
+ Die interne Darstellung wird durch die folgende EUMEL-Codetabelle
+beschrieben. Der Zeichensatz beruht auf dem ASCII-Zeichensatz mit Erweiterungen.
+Der in der Tabelle freie Bereich (z.B code(127) bis code(213)) ist nicht einheitlich
+verfügbar und wird deshalb nicht beschrieben. Die Codierung bildet mithin auch
+Grundlage für Vergleiche und Sortierungen.
+
+Die Korrekte Darstellung dieser Zeichen auf Bildschirm, Drucker etc. setzt natürlich
+eine korrekte Konfiguration der Geräte voraus. Die Anpassung eines Geräts an diesen
+Zeichensatz ist im EUMEL-Systemhandbuch in Teil 2 beschrieben.
+
+
+ I 0 1 2 3 4 5 6 7 8 9
+---+--------------------------------------
+3 I SP ! " \# $ % & '
+ I
+4 I ( ) * + , - . / 0 1
+ I
+5 I 2 3 4 5 6 7 8 9 : ;
+ I
+6 I < = > ? § A B C D E
+ I
+7 I F G H I J K L M N O
+ I
+8 I P Q R S T U V W X Y
+ I
+9 I Z [ \ ] ^ _ ` a b c
+ I
+10 I d e f g h i j k l m
+ I
+11 I n o p q r s t u v w
+ I
+12 I x y z { | } ~
+ I
+13 I
+. I
+. I
+. I
+20 I
+ I
+21 I Ä Ö Ü ä ö ü
+ I
+22 I k ­ \# SP
+ I
+23 I
+ I
+24 I
+ I
+25 I ß
+#page#
+':='
+ #on("b")#TEXT OP := (TEXT VAR a, TEXT CONST b) #off("b")#
+ Zuweisung.
+
+
+'='
+ #on("b")#BOOL OP = (TEXT CONST links, rechts) #off("b")#
+ Vergleich von zwei Texten auf Gleichheit (Texte mit ungleichen Längen sind
+ immer ungleich).
+
+
+'<>'
+ #on("b")#BOOL OP <> (TEXT CONST links, rechts) #off("b")#
+ Vergleich von zwei Texten auf Ungleichheit (Texte mit ungleichen Längen sind
+ stets ungleich).
+
+
+'<'
+ #on("b")#BOOL OP < (TEXT CONST links, rechts) #off("b")#
+ Vergleich zweier Texte auf kleiner ('links' kommt lexikographisch vor 'rechts').
+
+
+'<='
+ #on("b")#BOOL OP <= (TEXT CONST links, rechts) #off("b")#
+ Vergleich von zwei Texten auf kleiner gleich ('links' kommt lexikographisch vor
+ oder ist gleich 'rechts').
+
+
+'>'
+ #on("b")#BOOL OP > (TEXT CONST links, rechts) #off("b")#
+ Vergleich zweier Texte auf größer ('links' kommt lexikographisch nach 'rechts').
+
+
+'>='
+ #on("b")#BOOL OP >= (TEXT CONST links, rechts) #off("b")#
+ Vergleich zweier Texte auf größer gleich ('links' kommt lexikographisch nach oder
+ ist gleich 'rechts').
+
+#page#
+'LEXEQUAL'
+ #on("b")#BOOL OP LEXEQUAL (TEXT CONST links, rechts) #off("b")#
+ Prüfung auf lexikalische Gleichheit.
+
+
+'LEXGREATER'
+ #on("b")#BOOL OP LEXGREATER (TEXT CONST links, rechts) #off("b")#
+ Prüfung ob der Text 'links' lexikalisch größer als 'rechts' ist.
+
+
+'LEXGREATEREQUAL'
+ #on("b")#BOOL OP LEXGREATEREQUAL (TEXT CONST links, rechts) #off("b")#
+ Prüfung ob der Text 'links' lexikalisch größer oder gleich dem Text 'rechts' ist.
+
+
+
+ Die drei Operatoren prüfen nach folgenden Regeln:
+
+ - Buchstaben haben die aufsteigende Reihenfolge 'A' bis 'Z'. Dabei werden kleine
+ und große Buchstaben gleich behandelt.
+
+ - Umlaute werden wie üblich ausgeschrieben. (Ä = Ae usw.)
+ (ß = ss)
+
+ - Alle Sonderzeichen (auch Ziffern) außer ' '(Leerzeichen) und '-' werden igno­
+ riert, diese beiden Zeichen werden gleich behandelt.
+
+#page#
+'+'
+ #on("b")#TEXT OP + (TEXT CONST links, rechts) #off("b")#
+ Verkettung der Texte 'links' und 'rechts' in dieser Reihenfolge. Die Länge des
+ Resultats ergibt sich aus der Addition der Längen der Operanden.
+
+
+'*'
+ #on("b")#TEXT OP * (INT CONST faktor, TEXT CONST quelle) #off("b")#
+ 'faktor' fache Erstellung von 'quelle' und Verkettung. Dabei muß
+
+
+ times >= 0
+
+
+ sein, sonst wird 'niltext' geliefert.
+
+
+'CAT'
+ #on("b")#OP CAT (TEXT VAR links, TEXT CONST rechts) #off("b")#
+ hat die gleiche Wirkung wie
+
+
+ links := links + rechts
+
+
+ Hinweis: Der Operator 'CAT' hat eine geringere Heap-Belastung als die Opera­
+ tion mit expliziter Zuweisung.
+
+#page#
+'change'
+ #on("b")#PROC change (TEXT VAR senke, TEXT CONST alt, neu) #off("b")#
+ Ersetzung des (Teil-) TEXTes 'alt' in 'senke' durch 'neu' bei dem erstmaligen
+ Auftreten. Ist 'alt' nicht in 'senke' vorhanden, so wird keine Meldung abgesetzt
+ (Abweichung vom Standard). Die Länge von 'senke' kann sich dabei verändern.
+ Beispiel:
+
+
+ TEXT VAR mein text :: "EUMEL-Benutzerhandbuch";
+ change (mein text, "Ben", "N");
+ (* EUMEL-Nutzerhandbuch *)
+
+
+ #on("b")#PROC change (TEXT VAR senke, INT CONST von, bis, TEXT CONST neu) #off("b")#
+ Der TEXT 'neu' wird in den TEXT 'senke' anstatt des TEXTes, der zwischen 'von'
+ und 'bis' steht, eingesetzt. Die Länge von 'senke' kann sich dabei verändern.
+ Beispiel:
+
+
+ TEXT VAR mein text :: "EUMEL-Benutzerhandbuch";
+ change (mein text, 7, 9, "N"); (* wie oben *)
+
+
+
+'change all'
+ #on("b")#PROC change all (TEXT VAR senke, TEXT CONST alt, neu) #off("b")#
+ Der Teiltext 'alt' wird durch 'neu' in 'senke' ersetzt. Im Unterschied zur 'chan­
+ ge'-Prozedur findet die Ersetzung nicht nur bei dem erstmaligen Auftreten von
+ 'alt' statt, sondern so oft, wie 'alt' in 'senke' vorhanden ist. Beispiel:
+
+
+ TEXT VAR x :: "Das ist ein Satz";
+ change all (x, " ", ""); (* DasisteinSatz *)
+
+#page#
+'code'
+ #on("b")#TEXT PROC code (INT CONST code) #off("b")#
+ Wandelt einen INT-Wert 'code' in ein Zeichen um. 'code' muß
+
+
+ 0 <= code <= 255
+
+
+ sein.
+
+ #on("b")#INT PROC code (TEXT CONST text) #off("b")#
+ Wandelt ein Zeichen 'text' in einen INT-Wert um. Ist
+
+
+ LENGTH text <> 1
+
+
+ dann wird der Wert -1 geliefert (also bei mehr als ein Zeichen oder niltext).
+ (Codetabelle auf Seite 5- #topage("codetab")#)
+
+
+'compress'
+ #on("b")#TEXT PROC compress (TEXT CONST text) #off("b")#
+ Liefert den TEXT 'text' ohne führende und nachfolgende Leerzeichen.
+
+
+'delete char'
+ #on("b")#PROC delete char (TEXT VAR string, INT CONST delete pos)#off("b")#
+ Löscht ein Zeichen aus dem Text 'string' an der Position 'delete pos'. Für
+
+
+ delete pos <= 0
+
+
+ oder
+
+
+ delete pos > LENGTH string
+
+
+ wird keine Aktion vorgenommen.
+
+#page#
+'insert char'
+ #on("b")#PROC insert char (TEXT VAR string, TEXT CONST char,INT CONST insert pos)#off("b")#
+ Fügt ein Zeichen 'char' in den Text 'string' an der Position 'insert pos' ein. Für
+
+
+ insert pos > LENGTH string + 1
+
+
+ wird keine Aktion vorgenommen. Daher ist es möglich, mit dieser Prozedur auch
+ am Ende eines Textes (Position: LENGTH string + 1) ein Zeichen anzufügen.
+
+
+'length'
+ #on("b")#INT PROC length (TEXT CONST text) #off("b")#
+ Anzahl von Zeichen ("Länge") von 'text' einschließlich Leerzeichen.
+
+
+'LENGTH'
+ #on("b")#INT OP LENGTH (TEXT CONST text) #off("b")#
+ Anzahl von Zeichen ("Länge") von 'text' einschließlich Leerzeichen.
+
+
+'max text length'
+ #on("b")#INT CONST max text length #off("b")#
+ Maximale Anzahl von Zeichen in einem TEXT (32 000).
+
+#page#
+'pos'
+ #on("b")#INT PROC pos (TEXT CONST quelle, pattern) #off("b")#
+ Liefert die erste Position des ersten Zeichens von 'pattern' in 'quelle', falls 'pat­
+ tern' gefunden wird. Wird 'pattern' nicht gefunden oder ist 'pattern' niltext, so wird
+ der Wert '0' geliefert. Beispiel:
+
+
+ TEXT VAR t1 :: "abcdefghijk...xyz",
+ t2 :: "cd";
+ ... pos (t1, t2) ... (* liefert 3 *)
+ ... pos (t2, t1) ... (* liefert 0 *)
+
+
+
+ #on("b")#INT PROC pos (TEXT CONST quelle, pattern, INT CONST von)#off("b")#
+ Wie obige Prozedur, jedoch wird erst ab der Position 'von' ab gesucht. Dabei gilt
+ folgende Einschränkung:
+
+
+ length (pattern) < 255
+
+
+
+ #on("b")#INT PROC pos (TEXT CONST quelle, low char, high char, INT CONST von#off("b")#
+ Liefert die Position des ersten Zeichens 'x' in 'quelle' ab der Position 'von', so daß
+
+
+ low char <= x <= high char
+
+
+ 'low char' und 'high char' müssen TEXTe der Länge 1 sein. Wird kein Zeichen in
+ 'quelle' in dem Bereich zwischen 'low char' und 'high char' gefunden, wird der
+ Wert '0' geliefert. Beispiel:
+
+____________________________________________________________________________
+
+ (*Suche nach dem ersten Zeichen <> blank nach einer Leerspalte*)
+ TEXT VAR zeile :: "BlaBla Hier gehts weiter";
+ INT VAR pos erstes blank :: pos (zeile, " "),
+ ende leerspalte ::
+ pos (zeile, ""33"",""254"", pos erstes blank);
+
+____________________________________________________________________________
+
+#page#
+'real'
+ #on("b")#REAL PROC real (TEXT CONST text) #off("b")#
+ Konvertierung eines TEXTes 'text' in einen REAL-Wert. Achtung: Zur Zeit werden
+ keine Überprüfungen vorgenommen, d.h. in dem TEXT muß ein REAL-Wert
+ stehen.
+
+
+'replace'
+ #on("b")#PROC replace (TEXT VAR senke, INT CONST position, TEXT CONST quelle)#off("b")#
+ Ersetzung eines Teiltextes in 'senke' durch 'quelle' an der Position 'position' in
+ 'senke'. Es muß gelten
+
+
+ 1 <= position <= LENGTH senke
+
+
+ d.h. 'position' muß innerhalb von 'senke' liegen und 'quelle' muß von der Posi­
+ tion 'position' ab in 'senke' einsetzbar sein. Dabei bleibt die Länge von 'senke'
+ unverändert.
+
+
+'SUB'
+ #on("b")#TEXT OP SUB (TEXT CONST text, INT CONST pos) #off("b")#
+ Liefert ein Zeichen aus 'text' an der Position 'pos'. Entspricht
+
+
+ subtext (text, pos, pos)
+
+
+ Anmerkung: Effizienter als obiger Prozedur-Aufruf. Für
+
+
+ pos <= 0
+ pos > LENGTH text
+
+
+ wird niltext geliefert.
+
+#page#
+'subtext'
+ #on("b")#TEXT PROC subtext (TEXT CONST quelle, INT CONST von) #off("b")#
+ Teiltext von 'quelle', der bei der Position 'von' anfängt. Die Länge des Resultats
+ ergibt sich also zu
+
+
+ LENGTH quelle - von + 1
+
+
+ d.h. von der Position 'von' bis zum Ende von 'quelle'. 'von' muß innerhalb von
+ 'quelle' liegen. Ist von < 1, dann wird 'quelle' geliefert. Falls von > LENGTH
+ quelle ist, wird niltext geliefert.
+
+
+ #on("b")#TEXT PROC subtext (TEXT CONST quelle, INT CONST von, bis)#off("b")#
+ Teiltext von 'quelle' von der Position 'von' bis einschließlich der Position 'bis'. Die
+ Länge des Resultats ist also
+
+
+ bis - von + 1
+
+
+ Dabei muß gelten
+
+
+ 1 <= von <= bis <= LENGTH quelle
+
+
+ d.h. die Positionen 'von' und 'bis' müssen in dieser Reihenfolge innerhalb von
+ 'quelle' liegen. Ist
+
+
+ bis >= LENGTH quelle
+
+
+ wird 'subtext (quelle, von)' ausgeführt. Für die Bedingungen für 'von' siehe vor­
+ stehende Beschreibung von 'subtext'.
+
+
+'text'
+ #on("b")#TEXT PROC text (TEXT CONST quelle, INT CONST laenge) #off("b")#
+ Teiltext aus 'quelle' mit der Länge 'laenge', beginnend bei der Position 1 von
+ 'quelle'. Es muß gelten
+
+
+ 1 <= laenge <= LENGTH quelle
+
+
+ d.h. der gewünschte Teiltext muß aus 'quelle' ausblendbar sein.
+ Wenn gilt:
+
+ laenge > LENGTH quelle
+
+
+ wird der zu liefernde TEXT mit der an 'laenge' fehlenden Zeichen mit Leerzeichen
+ aufgefüllt.
+
+ #on("b")#TEXT PROC text (TEXT CONST quelle, INT CONST laenge, von)#off("b")#
+ Teiltext aus 'quelle' mit der Länge 'laenge', beginnend an der Position 'von' in
+ dem TEXT 'quelle'. Entspricht
+
+
+ text (subtext (quelle, von, LENGTH quelle),laenge)
+
+
+ Es muß
+
+
+ laenge >= 0
+ 1 <= von <= LENGTH quelle
+
+
+ gelten, d.h. 'von' muß eine Position angeben, die innerhalb von 'quelle' liegt. Für
+
+
+ laenge > LENGTH quelle - von + 1
+
+
+ also wenn die angegebene Länge 'laenge' größer ist als der auszublendende Text,
+ wird das Resultat rechts mit Leerzeichen aufgefüllt. Wenn
+
+
+ laenge < LENGTH quelle - von + 1
+
+
+ d.h. wenn die angegebene Länge kleiner ist als der Teiltext von 'von' bis zum
+ letzten Zeichen von 'quelle', wird das Resultat mit der Länge
+
+
+ LENGTH quelle - von + 1
+
+
+ geliefert.
+
diff --git a/doc/programmer-manual/1.8.7/doc/programmierhandbuch.5b b/doc/programmer-manual/1.8.7/doc/programmierhandbuch.5b
new file mode 100644
index 0000000..d91bcc9
--- /dev/null
+++ b/doc/programmer-manual/1.8.7/doc/programmierhandbuch.5b
@@ -0,0 +1,1481 @@
+#pagenr("%",40)##setcount(1)##block##pageblock#
+#headeven#
+#center#EUMEL-Benutzerhandbuch
+#center#____________________________________________________________
+
+#end#
+#headodd#
+#center#TEIL 5 : Programmierung
+#center#____________________________________________________________
+
+#end#
+#bottomeven#
+#center#____________________________________________________________
+5 - % #right#GMD
+#end#
+#bottomodd#
+#center#____________________________________________________________
+GMD #right#5 - %
+#end#
+
+5.3 Der Datentyp FILE (Textdateien)
+
+Der Datentyp FILE definiert Dateien von sequentieller Struktur, die Texte enthalten.
+Ein Objekt vom Datentyp FILE ist charakterisiert durch:
+
+1) seine Betriebsrichtung : input = nur lesender Zugriff
+ (TRANSPUTDIRECTION) output= nur schreibender Zugriff
+ modify= lesender und schreibender Zugriff.
+2) seinen Namen.
+
+Betriebsrichtung und Name werden in der Assoziierungsprozedur 'sequential file'
+(siehe Kap 2.8.2) festgelegt.
+
+
+____________________________________________________________________________
+
+ ........................... Beispiel ..........................
+ TEXT VAR name := ausgabe ;
+
+ FILE VAR f := sequential file(output,name) ;
+
+
+____________________________________________________________________________
+
+
+
+Das Festlegen einer Betriebsrichtung impliziert eine Kontrolle der Benutzung der
+betreffenden Datei, hilft somit Programmierfehler zu vermeiden.
+
+ACHTUNG : #on("b")##on("u")#Alle#off("b")##off("u")# Prozeduren, die auf FILEs zugreifen, verlangen Objekte vom Typ
+ FILE VAR, da die Lese/Schreiboperationen als ändernd betrachtet wer­
+ den (müssen).
+
+#page#
+
+5.3.1 Assoziierung
+
+'sequential file'
+ #on("b")#FILE PROC sequential file (TRANSPUTDIRECTION CONST mode, DATASPACE VAR ds) #off("b")#
+ Assoziierung einer sequentiellen Datei mit dem Dataspace 'ds' und der Betriebs­
+ richtung 'mode' (vergl. 'modify', 'input' bzw. 'output'). Diese Prozedur dient zur
+ Assoziierung eines temporären Datenraums in der Benutzer-Task, der nach der
+ Beendigung des Programmlaufs nicht mehr zugriffsfähig ist (weil der Name des
+ Datenraums nicht mehr ansprechbar ist). Somit muß der Datenraum explizit vom
+ Programm gelöscht werden.
+
+
+ #on("b")#FILE PROC sequential file (TRANSPUTDIRECTION CONST mode,TEXT CONST name)#off("b")#
+ Assoziierung einer sequentiellen Datei mit dem Namen 'name' und der Betriebs­
+ richtung 'mode' (vergl. 'input' bzw. 'output'). Existiert der FILE bereits, dann wird
+ mit 'input' auf den Anfang des FILEs, bei 'output' hinter den letzten Satz der datei
+ positioniert. Existiert dagagen der FILE noch nicht und ist die
+ TRANSPUTDIRECTION 'output' oder 'modify', wird ein neuer FILE eingerich­
+ tet.
+
+ FEHLER : "name" gibt es nicht"
+ Es wurde versucht, einen nicht vorhandenen FILE mit 'input' zu asso­
+ ziieren.
+
+#page#
+
+'input'
+ #on("b")#PROC input (FILE VAR f) #off("b")#
+ Ändern der Verarbeitungsart von 'modify' oder 'output' in 'input'. Dabei wird auf
+ den ersten Satz der Datei positioniert.
+
+ #on("b")#TRANSPUTDIRECTION CONST input #off("b")#
+ Assoziierung in Zusammenhang mit der Prozedur 'sequential file' einer sequentiel­
+ len Datei mit der 'TRANSPUTDIRECTION' 'input' (nur lesen).
+
+
+'output'
+ #on("b")#PROC output (FILE VAR file) #off("b")#
+ Ändern der Verarbeitungsart von 'input' oder 'modify' in 'output'. Dabei wird hinter
+ den letzten Satz der Datei positioniert.
+
+ #on("b")#TRANSPUTDIRECTION CONST output #off("b")#
+ In Verbindung mit der Prozedur 'sequential file' kann eine Datei assoziiert werden
+ mit der Betriebsrichtung 'output' (nur schreiben).
+
+
+'modify'
+ #on("b")#PROC modify (FILE VAR f) #off("b")#
+ Ändern der Betriebsrichtung von 'input' oder 'output' in die Betriebsrichtung 'mo­
+ dify'.
+
+ #on("b")#TRANSPUTDIRECTION CONST modify #off("b")#
+ Diese Betriebsrichtung erlaubt das Vorwärts- und Rückwärts-Positionieren und
+ das beliebige Einfügen und Löschen von Sätzen. 'modify' wird für die Assoziie­
+ rungsprozedur 'sequential file' benötigt.
+
+
+
+#page#
+
+5.3.2 Informationsprozeduren
+
+'eof'
+ #on("b")#BOOL PROC eof (FILE CONST file) #off("b")#
+ Informationsprozedur auf das Ende eines FILEs. Liefert den Wert TRUE, sofern
+ hinter den letzten Satz eines FILEs positioniert wurde.
+
+
+'line no'
+ #on("b")#INT PROC line no (FILE CONST file) #off("b")#
+ Liefert die aktuelle Zeilennummer.
+
+
+'lines'
+ #on("b")#PROC lines (FILE VAR f) #off("b")#
+ Liefert die Anzahl der Zeilen der Datei 'f'.
+
+
+'headline'
+ #on("b")#TEXT PROC headline (FILE CONST f) #off("b")#
+ Liefert den Inhalt der Kopfzeile der Datei 'f'.
+
+ #on("b")#PROC headline (FILE VAR f, TEXT CONST ueberschrift) #off("b")#
+ Setzt #ib#'ueberschrift' in die Kopfzeile#ie# der Datei 'f'.
+#page#
+
+5.3.3 Betriebsrichtung INPUT
+
+In der Betriebsrichtung 'input' sind nur Leseoperationen auf der Datei zugelassen. Die
+Assoziierungsprozedur 'sequential file' bewirkt:
+
+1) Falls die Eingabedatei noch nicht existiert, wird eine Fehlermeldung ausgegeben.
+
+2) Falls es eine Datei des Namens gibt, wird auf das erste Zeichen des ersten
+ Satzes positioniert.
+
+
+
+'get'
+ #on("b")#PROC get (FILE VAR f, INT VAR number) #off("b")#
+ Lesen des nächsten Wortes aus der Datei 'f' und Konvertierung des Wortes zu
+ einem Integer-Objekt.
+
+ #on("b")#PROC get (FILE VAR f, REAL VAR number) #off("b")#
+ Lesen des nächsten Wortes aus der Datei 'f' und Konvertierung des Wortes zu
+ einem Real-Objekt.
+
+
+ #on("b")#PROC get (FILE VAR f, TEXT VAR text) #off("b")#
+ Lesen des nächsten Wortes aus der Datei 'f'.
+
+ #on("b")#PROC get (FILE VAR f, TEXT VAR text, TEXT CONST delimiter)#off("b")#
+ Lesen eines TEXT-Wertes 'text' von der Datei 'f', bis das Zeichen 'delimiter'
+ angetroffen wird. Ein eventueller Zeilenwechsel in der Datei wird dabei übergan­
+ gen.
+
+ #on("b")#PROC get (FILE VAR f, TEXT VAR text, INT CONST maxlength)#off("b")#
+ Lesen eines TEXT-Wertes 'text' von der Datei 'f' mit 'maxlength' Zeichen. Ein
+ eventueller Zeilenwechsel in der Datei wird dabei nicht übergangen.
+
+
+
+'getline'
+ #on("b")#PROC get line (FILE VAR file, TEXT VAR record) #off("b")#
+ Lesen der nächsten Zeile aus der sequentiellen Datei 'file'.
+ Mögliche Fehler bei Betriebsrichtung 'input':
+
+ "Datei zu"
+ Die Datei 'file' ist gegenwärtig nicht assoziiert.
+
+ "Leseversuch nach Dateiende"
+ Es wurde versucht, über die letzte Zeile einer Datei zu lesen.
+
+ "Leseversuch auf output file"
+ Es wurde versucht, von einem mit 'output' assoziierten FILE zu lesen.
+
+ "Unzulässiger Zugriff auf modify-FILE"
+
+#page#
+
+5.3.4 Betriebsrichtung OUTPUT
+
+In der Betriebsrichtung 'output' sind nur Schreiboperationen auf der Datei zugelassen.
+Die Assoziierungsprozedur 'sequential file' bewirkt:
+
+1) Falls die Ausgabedatei noch nicht existiert, wird sie angelegt und auf den ersten
+ Satz positioniert.
+
+2) Falls es bereits eine Datei des Namens gibt, wird hinter den letzten Satz positio­
+ niert, die Datei wird also fortgeschrieben.
+
+
+'put'
+ #on("b")#PROC put (FILE VAR f, INT CONST number) #off("b")#
+ Ausgabe eines INT-Wertes 'number' in die Datei 'f'. Dabei wird ein Leerzeichen
+ an die Ausgabe angefügt.
+
+ #on("b")#PROC put (FILE VAR f, REAL CONST number) #off("b")#
+ Ausgabe eines REAL-Wertes 'number' in die Datei 'f'. Dabei wird ein Leerzei­
+ chen an die Ausgabe angefügt.
+
+ #on("b")#PROC put (FILE VAR f, TEXT CONST text) #off("b")#
+ Ausgabe eines TEXT-Wertes 'text' in die Datei 'f'. Dabei wird ein Leerzeichen an
+ die Ausgabe angefügt.
+
+
+
+'putline'
+ #on("b")#PROC putline (FILE VAR file, TEXT CONST record) #off("b")#
+ Ausgabe eines TEXTes 'record' in die Datei 'file'. Danach wird auf die nächste
+ Zeile positioniert. 'file' muß mit 'output' assoziiert sein.
+
+
+'write'
+ #on("b")#PROC write (FILE VAR f, TEXT CONST text) #off("b")#
+ Schreibt 'text' in die Datei 'f' (analog 'put (f, text)'), aber ohne Trennblank.
+
+
+'line'
+ #on("b")#PROC line (FILE VAR file) #off("b")#
+ Positionierung auf die nächste Zeile der Datei 'file'. Wird versucht, über das Ende
+ eines mit 'input' assoziierten FILEs zu positionieren, wird keine Aktion vorgenom­
+ men.
+
+ #on("b")#PROC line (FILE VAR file, INT CONST lines) #off("b")#
+ Positionierung mit 'lines' Zeilen Vorschub in der Datei 'file'.
+
+
+ FEHLER: "Datei zu!"
+ Die Datei 'file' ist gegenwärtig nicht assoziiert.
+
+ "Schreibversuch auf input-File"
+ Es wurde versucht, auf einen mit 'input' assoziierten FILE zu
+ schreiben.
+
+
+ Bei Textdateien, die mit dem Editor weiterbearbeitet werden sollen, ist also zu
+ beachten: ine Ausgabe mit 'put' setzt ein 'blank' hinter die Ausgabe. Falls dieses
+ Leerzeichen das letzte Zeichen in der Zeile ist, wird eine Absatzmarke in der Zeile
+ gesetzt. Wird mit 'write' oder 'putline' ausgegeben, steht kein Leerzeichen und
+ somit keine Absatzmarke am Zeilenende.
+#page#
+
+5.3.5 Betriebsrichtung MODIFY
+
+In der Betriebsrichtung 'modify' sind Lese- und Schreiboperationen auf der Datei
+zugelassen. Desweiteren ist beliebiges Positionieren in der Datei erlaubt. Neue Sätze
+können an beliebiger Stelle in die Datei eingefügt werden, die sequentielle Struktur
+der Datei bleibt erhalten. Die Assoziierungsprozedur 'sequential file' bewirkt:
+
+1) Falls die Ausgabedatei noch nicht existiert, wird sie angelegt.
+
+2) Falls es bereits eine Datei des Namens gibt, ist undefiniert wo positioniert ist. Die
+ erste Positionierung muß explizit vorgenommen werden!
+
+
+
+'col'
+ #on("b")#PROC col (FILE VAR f, INT CONST position) #off("b")#
+ Positionierung auf die Spalte 'position' innerhalb der aktuellen Zeile.
+
+ #on("b")#INT PROC col (FILE CONST f) #off("b")#
+ Liefert die aktuelle Position innerhalb der aktuellen Zeile.
+
+
+'down'
+ #on("b")#PROC down (FILE VAR f) #off("b")#
+ Positionieren um eine Zeile vorwärts.
+
+ #on("b")#PROC down (FILE VAR f, INT CONST number) #off("b")#
+ Positionieren um 'number' Zeilen vorwärts.
+
+
+'to line'
+ #on("b")#PROC to line (FILE VAR f, INT CONST number) #off("b")#
+ Positionierung auf die Zeile 'number'.
+
+
+'up'
+ #on("b")#PROC up (FILE VAR f) #off("b")#
+ Positionieren um eine Zeile rückwärts.
+
+ #on("b")#PROC up (FILE VAR f, INT CONST number) #off("b")#
+ Positionieren um 'number' Zeilen rückwärts.
+
+#page#
+'delete record'
+ #on("b")#PROC delete record (FILE VAR file) #off("b")#
+ Der aktuelle Satz der Datei 'file' wird gelöscht. Der folgende Satz wird der aktuelle
+ Satz.
+
+
+'insert record'
+ #on("b'PROC insert record (FILE VAR file) #off("b")#
+ Es wird ein leerer Satz in die Datei 'file' vor die aktuelle Position eingefügt. Dieser
+ Satz kann anschließend mit 'write record' beschrieben werden (d.h. der neue Satz
+ ist jetzt der aktuelle Satz).
+
+
+
+'read record'
+ #on("b")#PROC read record (FILE CONST file, TEXT VAR record) #off("b")#
+ Liest den aktuellen Satz der Datei 'file' in den TEXT 'record'. Die Position wird
+ dabei nicht verändert.
+
+
+
+'write record'
+ #on("b")#PROC write record (FILE VAR file, TEXT CONST record) #off("b")#
+ Schreibt einen Satz in die Datei 'file' an die aktuelle Position. Dieser Satz muß
+ bereits vorhanden sein, d.h. mit 'write record' kann keine leere Datei beschrieben
+ werden, sondern es wird der Satz an der aktuellen Position überschrieben. Die
+ Position in der Datei wird nicht verändert.
+
+
+#page#
+
+5.3.6 FILE -Ausschnitte
+
+Ähnlich den Editorfunktionen 'ESC RUBOUT' und 'ESC RUBIN', die erlauben ganze
+Abschnitte einer Datei zu löschen und das Gelöschte an anderer Stelle wiedereinzu­
+fügen, gibt es die Möglichkeit per Programm solche Segmente
+eines 'modify-FILEs' zu verschieben.
+
+
+'clear removed'
+ #on("b")#PROC clear removed (FILE VAR f) #off("b")#
+ Das mit 'remove' entfernte Segment wird gelöscht und nicht an anderer Stelle
+ eingefügt.
+
+
+'reinsert'
+ #on("b")#PROC reinsert (FILE VAR f) #off("b")#
+ Das mit 'remove' entfernte Segment wird vor die aktuelle Zeile wiedereingefügt.
+
+
+'remove'
+ #on("b")#PROC remove (FILE VAR f, INT CONST size) #off("b")#
+ Löscht 'size' Zeilen vor der aktuellen Position aus 'f'. Das Segment wird in einen
+ internen Puffer geschrieben.
+
+
+'reorganize'
+ #on("b")#PROC reorganize (TEXT CONST datei)#off("b")#
+ Reorganisation von 'datei'. Die durch Löschen und Einfügen aus vielen
+ Segmenten bestehende Datei wird zu einem Segment zusammengefügt, die
+ aktuelle Position ist danach das erste Zeichen der ersten Zeile.
+
+ Durch diese Prozedur kann ggf. Speicherplatz gespart werden.
+
+ #on("b")#PROC reorganize#off("b")#
+ Reorganisation der zuletzt bearbeiteten Datei.
+
+
+'segments'
+ #on("b")#PROC segments (FILE VAR f) #off("b")#
+ Liefert die Anzahl der Segmente von 'f'. Eine große Anzahl von Segmenten kann
+ langsamere Zugriffe zur Folge haben.
+
+#page#
+
+5.4 Suchen und Ersetzen in Textdateien
+
+Such- und Ersetzungsprozeduren können sowohl interaktiv beim Editieren (siehe
+dazu 3.3), als auch in Prozeduren, die auf FILEs (siehe 5.3) arbeiten, angewandt
+werden.
+
+Die dazu dienenden Prozeduren sind im Paket 'pattern match' enthalten. Mit 'Pattern
+Matching' (Muster treffen) wird ein Verfahren bezeichnet Gleichheit von Objekten
+anhand von Regeln, denen diese Objekte genügen, zu überprüfen.
+
+Da oft nach Texten gesucht werden muß, deren genaue Ausprägung nicht bekannt ist,
+oder deren Auftreten nur in einem bestimmten Zusammenhang interessiert, gibt es die
+Möglichkeit feststehende Textelemente mit Elementen ungewisser Ausprägung zu
+kombinieren, also Textmuster zu erzeugen.
+
+Um einen Text zu suchen, muß die Suchrichtung und der gesuchte Text oder ein
+Muster, welches diesen Text beschreibt, angegeben werden.
+
+- Aufbauen von Textmustern : + , - , OR , any , bound , notion
+
+- Suchen nach Textmustern : down , downety , up , uppety
+
+- Treffer registrieren : LIKE , UNLIKE , at , pattern found
+
+- Treffer herausnehmen : ** , match , matchend , matchpos ,
+ somefix , word
+
+- Ändern in Dateien : change
+
+
+Nach einem erfolgreichen Suchvorgang ist stets auf das erste Zeichen der zu such­
+enden Zeichenkette positioniert.
+
+
+Eine besondere Funktion kommt dem 'joker' zu: Dieses Symbol (Defaultwert: '*') steht
+für eine beliebige Zeichenkette beliebiger Länge. Insbesondere bei Ersetzungsaktionen
+in denen dieses Zeichen zur Musterbeschreibung verwendet wird, ist daher Vorsicht
+geboten und sorgfältig zu testen.
+
+#page#
+
+5.4.1 Aufbau von Textmustern
+
+'+'
+ #on("b")#TEXT OP + (TEXT CONST links, rechts) #off("b")#
+ Verkettung der Texte 'links' und 'rechts' zu 'linksrechts'. Falls das Ergebnis länger
+ als die maximal zulässige Textlänge ist, ist es undefiniert.
+
+ Wenn 'muster1' einen beliebigen Text finden sollte, ( Siehe: PROC any) wird das
+ Ende des von 'muster1' erkannten Textes durch den Anfang des von 'muster2'
+ erkannten Textes im Nachhinein definiert.
+
+
+
+'-'
+ #on("b")#TEXT OP - (TEXT CONST alphabet) #off("b")#
+ Der Operator liefert das zu 'alphabet' komplementäre Alphabet, also alle Zeichen
+ gemäß der EUMEL Codetabelle (5.2.4), die nicht in 'alphabet' enthalten sind.
+ Sinnvoll im Zusammenhang mit der Textprozedur 'any'.
+
+
+'OR'
+ #on("b")#TEXT OP OR (TEXT CONST links, rechts) #off("b")#
+ Liefert die Alternative von 'links' und 'rechts'. Die Reihenfolge spielt beim Suchen
+ keine Rolle.
+
+
+
+'any'
+ Die Textprozedur 'any' liefert einen unbekannten Text unbestimmter Länge.
+ Dieser Text sollte entweder durch festen Text sinnvoll eingegrenzt werden, oder
+ direkt eingeschränkt werden.
+
+
+ #on("b")#TEXT PROC any #off("b")#
+ Beschreibt einen beliebigen Text.
+
+ #on("b")#TEXT PROC any (INT CONST laenge) #off("b")#
+ Beschreibt einen beliebigen Text der angebenen Länge.
+
+
+ #on("b")#TEXT PROC any (TEXT CONST alphabet) #off("b")#
+ Beschreibt einen beliebigen Text, der nur aus Zeichen besteht, die in 'alphabet'
+ enthalten sind.
+
+
+ #on("b")#TEXT PROC any (INT CONST laenge, TEXT CONST alphabet) #off("b")#
+ Beschreibt einen Text der vorgegebenen Länge, der nur aus den in 'alphabet'
+ vorgegebenen Zeichen besteht.
+
+
+____________________________________________________________________________
+
+ ........................... Beispiel ..........................
+ Die Textprozedur 'any' liefert einen unbekannten Text unbe­
+ stimmter Länge. Dieser Text sollte entweder durch festen Text
+ sinnvoll eingegrenzt werden, oder direkt eingeschränkt werden.
+gib kommando: D("D" OR "d" + any (2,"aeirs")
+ Sucht nach bestimmten Artikeln: 'der', 'die', 'das' etc.
+
+____________________________________________________________________________
+
+
+
+'bound'
+ #on("b")#TEXT PROC bound #off("b")#
+ Bezeichnet ein Muster der Länge null, das nur am Zeilenanfang oder am Zeilenen­
+ de gefunden wird. Ein Präfix 'bound' fordert, daß das gesuchte Muster in der
+ ersten Spalte beginnen muß, ein Postfix 'bound' fordert, daß das Muster mit dem
+ Zeilenende abschließt.
+
+____________________________________________________________________________
+
+ ........................... Beispiel ..........................
+ Die Textprozedur 'any' liefert einen unbekannten Text unbe­
+ stimmter Länge. Dieser Text sollte entweder durch festen
+ Textsinnvoll eingegrenzt werden, oder direkt eingeschränkt
+ werden.
+gib kommando: U(bound + any (" "))
+
+____________________________________________________________________________
+
+
+
+ liefert Treffer bei eingerückten Zeilen.
+
+
+
+'notion'
+ #on("b")#PROC notion (TEXT CONST suchwort) #off("b")#
+ Mit dieser Prozedur kann ein #on("u")#Wort#off("u")# spezifiziert werden, nach dem gesucht werden
+ soll. Bei der Suche nach 'suchwort' wird nur dann ein Treffer geliefert, wenn
+ 'suchwort' als Wort, also begrenzt von ' ' (blank), '.' , ',' oder anderen Sonderzei­
+ chen ist.
+
+ #on("b")#PROC notion (TEXT CONST suchwort, INT CONST reg) #off("b")#
+ Wie oben, der Treffer wird im Register 'reg' gespeichert.
+
+#page#
+
+5.4.2 Suche nach Textmustern
+
+'down'
+ #on("b")#PROC down (FILE VAR f, TEXT CONST muster) #off("b")#
+ Suche nach 'muster' in der Datei 'f' in Richtung Dateiende. Wird 'muster' gefun­
+ den, ist die Position das erste Zeichen von 'muster'. Andernfalls steht man hinter
+ dem letzten Zeichen der Datei.
+
+ Achtung: 'down' sucht vom nächsten Zeichen rechts ab, so daß wiederholtes
+ Suchen keine Endlosschleife ergibt.
+
+
+ #on("b")#PROC down (FILE VAR f, TEXT CONST muster, INT CONST number)#off("b")#
+ Wie obiges 'down', es wird aber maximal nur 'number'-Zeilen weit nach 'muster'
+ gesucht.
+
+
+
+'downety'
+ #on("b")#PROC downety (FILE VAR f, TEXT CONST muster) #off("b")#
+ Suche nach 'muster' in der Datei 'f' in Richtung Dateiende. Wird 'muster' gefun­
+ den, ist die Position das erste Zeichen von 'muster'. Andernfalls steht man auf
+ dem letzten Zeichen der Datei.
+
+ Achtung: 'downety' sucht (im Gegensatz zu 'down') vom aktuellen Zeichen an.
+ Daher muß explizit vorwärts positioniert werden.
+
+
+ #on("b")#PROC downety (FILE VAR f, TEXT CONST muster, INT CONST number) #off("b")#
+ Wie obiges 'downety', aber maximal nur 'number'-Zeilen weit.
+#page#
+'up'
+ #on("b")#PROC up (FILE VAR f, TEXT CONST muster) #off("b")#
+ Suche nach 'muster' in der Datei 'f' in Richtung Dateianfang. Wird 'muster'
+ gefunden, ist die Position das erste Zeichen von 'muster'. Andernfalls steht man
+ auf dem ersten Zeichen der Datei.
+
+ Achtung: 'up' sucht vom nächsten Zeichen links ab, so daß wiederholtes Suchen
+ keine Endlosschleife ergibt.
+
+
+ #on("b")#PROC up (FILE VAR f, TEXT CONST muster, INT CONST number)#off("b")#
+ Wie obiges 'up', aber maximal nur 'number'-Zeilen weit.
+
+
+
+'uppety'
+ #on("b")#PROC uppety (FILE VAR f, TEXT CONST muster) #off("b")#
+ Suche nach 'muster' in der Datei 'f' in Richtung Dateianfang. Wird 'muster'
+ gefunden, ist die Position das erste Zeichen von 'muster'. Andernfalls steht man
+ auf dem ersten Zeichen der Datei.
+
+ Achtung: 'uppety' sucht (im Gegensatz zu 'up') vom aktuellen Zeichen.
+
+
+ #on("b")#PROC uppety (FILE VAR f, TEXT CONST muster, INT CONST number)#off("b")#
+ Wie obiges 'uppety', aber maximal nur 'number'-Zeilen weit.
+
+#page#
+
+5.4.3 Treffer registrieren
+
+'LIKE'
+ #on("b")#BOOL OP LIKE (TEXT CONST text , muster) #off("b")#
+ Liefert TRUE, falls der Text 'text' 'muster' entspricht. In 'muster' kann das
+ Spezialzeichen '*' verwandt werden, das abkürzend für die Konkatenation mit
+ 'any' steht.
+
+ Daraus folgt, daß das Suchen oder Ersetzen des Zeichens '*' nur durch
+ any (1,"*") zu bewerkstelligen ist.
+
+
+____________________________________________________________________________
+
+ ........................... Beispiel ..........................
+ \#Druckdateien aus Thesaurus löschen\#
+ gib kommando:"*.p" C ""
+ 16.04.87 "Handbuch teil1"
+ 04.05.87 "Handbuch teil1.p"
+ 16.04.87 "Handbuch teil2"
+ 06.05.87 "Handbuch teil2.p"
+
+____________________________________________________________________________
+
+
+
+ aber:
+
+____________________________________________________________________________
+
+ ........................... Beispiel ..........................
+ \#Vordere Kommentarklammern löschen \#
+ gib kommando:"(" + any(1,"*") C ""
+ lernsequenz auf taste legen("a" , "archive") ;
+ (* lernsequenz auf taste legen("(" , ""91"") ; *)
+ (* lernsequenz auf taste legen(")" , ""93"") ; *)
+ kommando auf taste legen("P" , "print("""")"8""8""11"") .
+
+____________________________________________________________________________
+
+
+
+'UNLIKE'
+ #on("b")#BOOL OP UNLIKE (TEXT CONST text , muster) #off("b")#
+ Wirkt wie: '(NOT text LIKE muster)'
+#page#
+
+5.4.4 Treffer herausnehmen
+
+Mit Hilfe der 'Register' ist es möglich identifizierte Texte zwischenzuspeichern und in
+weiteren Aktionen weiterzuverwenden.
+
+
+'**'
+ #on("b")#TEXT OP ** (TEXT CONST muster, INT CONST register)#off("b")#
+ Der als 'muster' erkannte Text wird einem 'Register' mit der Nummer 'register'
+ zugeordnet. Es können 256 Register (1 bis 256) benutzt werden.
+
+
+'match'
+ #on("b")#TEXT PROC match (INT CONST nr) #off("b")#
+ Liefert den Text der dem Register 'nr' zuletzt zugeordnet wurde.
+
+
+'matchpos'
+ #on("b")#INT PROC matchpos (INT CONST nummer) #off("b")#
+ Liefert die Spaltennummer, auf der das dem Register 'nummer' zugeordnete Mu­
+ ster in der Zeile beginnt.
+
+____________________________________________________________________________
+
+ ........................... Beispiel ..........................
+
+ gib kommando:D("file"+any+"("+(any ** (1)...
+
+____________________________________________________________________________
+#page#
+
+5.4.5 Ändern in Dateien
+
+'change'
+ #on("b")#PROC change (FILE VAR datei, INT CONST von, bis , TEXT CONST neuertext)#off("b")#
+ In der Datei wird in der aktuellen Zeile in den Ausschnitt zwischen 'von' und 'bis'
+ der Text 'neuertext' eingesetzt.
+
+ entspricht:
+
+
+____________________________________________________________________________
+
+ ........................... Beispiel ..........................
+ FILE VAR file := sequential file (modify, name)
+ TEXT VAR zeile;
+ .
+ .
+ read record (file ,zeile);
+ change (zeile, von, bis ,"neuertext");
+ write record (file, zeile);
+ .
+
+____________________________________________________________________________
+
+#page#
+
+5.4.6 Editor-Prozeduren
+
+'edit'
+ #on("b")#edit (TEXT CONST datei)#off("b")#
+ Editieren der Datei 'datei'. Das Editorfenster ist maximal groß (von 1,1 bis
+ max,max). Der Standard-Kommandointerpreter ist gültig, so daß Eingaben, die
+ mit #schl("ESC")# beginnen, interpretiert werden, wie in 3.4 'Vorbelegte Tasten' beschrie­
+ ben.
+
+ #on("b")#edit#off("b")#
+ Wie oben, editiert wird die Datei mit dem zuletzt benutzten Namen.
+
+ #on("b")#edit (THESAURUS CONST thes)#off("b")#
+ Wie oben, editiert werden alle Dateien, deren Namen im Thesaurus 'thes' enthal­
+ ten sind.
+
+ #on("b")#edit (TEXT CONST datei, INT CONST von x, von y, bis x, bis y)#off("b")#
+ Editieren der Datei 'datei'. Das Editorfenster hat die linke obere Ecke bei 'von x,
+ von y' und die rechte untere Ecke bei 'bis x, bis y'.
+
+ #on("b")#edit (FILE VAR f)#off("b")#
+ Editieren der als 'sequential file' assoziierten Textdatei 'f'.
+
+ #on("b")#edit (FILE VAR, INT CONST von x, von y, bis x, bis y)#off("b")#
+ Editieren der als 'sequential file' assoziierten Textdatei in einem Fenster mit der
+ linken, oberen Ecke 'von x, von y' und der rechten, unteren Ecke 'bis x, bis y'.
+
+ #on("b")#edit (FILE VAR f, TEXT CONST res,
+ PROC (TEXT CONST) kdo interpreter)#off("b")#
+ Editieren der als 'sequential file' assoziierten Textdatei 'f'. In 'res' werden reser­
+ vierte Zeichen übergeben, die von der Prozedur 'kdo interpreter' als Kommandos
+ interpretiert werden, wenn sie als ESC-Sequenz eingegeben werden.
+ Beispiel : #schl("ESC ")# #schl("e")#
+
+#page#
+'editget'
+ #on("b")#editget (TEXT VAR ausgabe) #off("b")#
+ Aufruf des Zeileneditor. An der aktuellen Cursorposition wird eine Zeile ausgegeben in
+ der 'ausgabe' steht. Für diese Zeile stehen alle Editiermöglichkeiten zur
+ Verfügung, 'ausgabe' kann also beliebig überschrieben, ergänzt etc. werden. Die
+ Eingabe wird durch #schl("CR")# abgeschlossen. Im Gegensatz zur Prozedur 'get' ist auch
+ eine leere Eingabe möglich.
+
+ #on("b")#editget (TEXT VAR ausgabe, INT CONST zeile, INT CONST scroll,
+ TEXT CONST sep, TEXT CONST res, TEXT VAR exit) #off("b")#
+ Wie oben, die Zeilenlänge ist jedoch auf 'zeile' Zeichen begrenzt. Die Eingabe
+ wird durch #schl("CR")# oder durch eine Cursorbewegung über die Position 'zeile' hinaus
+ abgeschlossen.
+
+ Die Angabe 'scroll' setzt die Breite des Zeilenfensters fest, wird diese Breite
+ überschritten, so wird 'ausgabe' gerollt.
+
+ In 'sep' (Separator) können Zeichen festgesetzt werden, mit denen die Eingabe
+ beendet wird (zusätzlich zu CR !).
+
+ In 'res' (reservierte Tasten) können Tasten festgelegt werden, die in Verbindung
+ mit <ESC> die Eingabe beenden.
+
+ Wurde der Zeileneditor durch einen Separator verlassen, so steht in 'exit' dieses
+ Zeichen. Falls der Zeileneditor durch eine reservierte Taste verlassen, so enthält
+ 'exit' 'ESC' und die Taste.
+
+ #on("b")#editget (TEXT VAR ausgabe, INT CONST zeile, INT CONST scroll)#off("b")#
+ Bedeutung der Parameter siehe oben.
+
+ #on("b")#editget (TEXT VAR ausgabe, TEXT CONST sep, TEXT CONST res,
+ TEXT VAR exit) #off("b")#
+ Bedeutung der Parameter siehe oben.
+
+ #on("b")#editget (TEXT VAR ausgabe, INT CONST zeile, TEXT VAR exit) #off("b")#
+ Bedeutung der Parameter siehe oben.
+#page#
+
+5.4.7 Sortierung von Textdateien
+
+Für die Sortierung von Textdateien gibt es zwei Sortierprogramme:
+
+- Sortierung nach ASCII : sort
+
+- Sortierung nach
+ deutschem Alphabet : lexsort
+
+
+'sort'
+ #on("b")#PROC sort (TEXT CONST datei) #off("b")#
+ Diese Prozedur sortiert die Datei 'datei' zeilenweise gemäß der von der EUMEL
+ Codetabelle (siehe 5.2.4) vorgegebenen Reihenfolge. Zur Sortierung werden die
+ Zeilen vom ersten Zeichen der Zeile beginnend, zeichenweise verglichen und
+ dementsprechend sortiert.
+
+ #on("b")#PROC sort (TEXT CONST datei, INT CONST position) #off("b")#
+ Sortierkriterien wie oben, jedoch wird bei Vergleich und Sortierung der Satz erst
+ ab der Position 'position' beachtet. Sortiert wird der ganze Satz!
+
+
+'lex sort'
+ #on("b")#PROC lex sort (TEXT CONST datei) #off("b")#
+ Zeilenweise Sortierung nach lexikographischer Reihenfolge gemäß DIN 5007. Zu
+ den Vergleichen werden die Operatoren LEXEQUAL, LEXGRATER,
+ LEXGRATEREQUAL benutzt (siehe 5.2.4).
+
+ #on("b")#PROC lex sort (TEXT CONST datei, INT CONST position) #off("b")#
+ Lexikalische Sortierung durch Vergleich ab Position 'position'.
+
+#page#
+
+5.4.8 Prozeduren auf Datenräumen
+
+Neben den Textdateien gibt es im EUMEL-System den Typ Datenraum, der Objekte
+jeglichen Typs aufnehmen kann und direkten Zugriff auf die Objekte gewährt (siehe
+2.9.2).
+
+Für Objekte von Type Datenraum (nicht für die in Datenräumen enthaltenen Objekte!)
+existieren folgende Standardprozeduren:
+
+
+':='
+ #on("b")#OP := ( DATASPACE VAR ds1, DATASPACE CONST ds2)#off("b")#
+ Der Datenraum 'ds1' wird als Kopie von 'ds2' angelegt. Es handelt sich zunächst
+ um eine logische Kopie, eine physische Kopie wird erst nach einem Schreibzugriff
+ auf 'ds1' oder 'ds2' nötig.
+
+
+'new'
+ #on("b")#DATASPACE PROC new (TEXT CONST dsname) #off("b")#
+ Liefert einen neuen Datenraum namens 'dsname'.
+
+____________________________________________________________________________
+
+ DATASPACE VAR ds := new ("datenraum")
+ (* ergibt zwei Datenräume 'ds' und 'datenraum'! *)
+
+____________________________________________________________________________
+
+
+
+'nilspace'
+ #on("b")#DATASPACE PROC nilspace#off("b")#
+ Der 'nilspace' ist ein leerer Datenraum, der ausschließlich als Quelle zum Kopie­
+ ren bei der Initialisierung Verwendung finden darf.
+
+
+'old'
+ #on("b")#DATASPACE PROC old (TEXT CONST dsname) #off("b")#
+ Liefert einen bereits existierenden Datenraum (oder auch eine Datei) mit dem
+ Namen 'dsname'.
+
+ FEHLER : "dsname" gibt es nicht
+
+
+'type'
+ #on("b")#PROC type (DATASPACE CONST ds, INT CONST typ)#off("b")#
+ Der Datenraum 'ds' erhält den frei wählbaren Schlüssel 'typ'. Es muß eine positive
+ Zahl gewählt werden. Der Datenraum muß zum Zeitpunkt der Typzuweisung an
+ ein BOUND Objekt gekoppelt (gewesen) sein.
+
+ #on("b")#INT PROC type (DATASPACE CONST ds)#off("b")#
+ Liefert den Schlüssel des Datenraums 'ds'. Falls 'ds' nie an ein BOUND Objekt
+ gekoppelt war, liefert die Prozedur einen Wert < 0, sonst 0 (keine Zuweisung
+ erfolgt) oder die zugewiesene Typnummer.
+
+
+'dataspaces'
+ #on("b")#INT PROC dataspaces (TASK CONST task) #off("b")#
+ Liefert die Anzahl der Datenräume der Task 'task'.
+
+ #on("b")#INT PROC dataspaces #off("b")#
+ Anzahl der Datenräume von 'myself'.
+
+
+'ds pages'
+ #on("b")#INT PROC ds pages (DATASPACE CONST ds)#off("b")#
+ Liefert die Anzahl der durch 'ds' belegten Seiten (je 512 Byte).
+
+
+'storage'
+ #on("b")#INT PROC storage (DATASPACE CONST ds)#off("b")#
+ Liefert den von 'ds' belegten Speicherplatz in KB.
+
+#page#
+'copy'
+ #on("b")#PROC copy (DATASPACE CONST ds, TEXT CONST datei) #off("b")#
+ Eine neue Datei mit dem Namen 'datei' wird angelegt. Der Inhalt der Datei ist eine
+ Kopie des Inhalts des Datenraumes 'ds'.
+
+
+'forget'
+ #on("b")#PROC forget (DATASPACE CONST ds)#off("b")#
+ Der Datenraum 'ds' wird gelöscht#u#1)#e#.
+
+#foot#
+
+ 1) Durch diese Prozedur steht nicht unmittelbar mehr freier Speicherplatz zur
+ Verfügung. Die physische Räumung von Speicherplatz erfolgt durch die
+ 'Müllabfuhr' bei einem Fixpunkt.
+#end#
+
+'fetch'
+ #on("b")#PROC fetch (DATASPACE CONST ziel, TEXT CONST datei,
+ TASK CONST manager) #off("b")#
+ Aus der Task 'manager' wird der Datenraum der Datei 'datei' in den eigenen
+ Datenraum 'ziel' kopiert.
+
+
+'save'
+ #on("b")#PROC save (DATASPACE CONST quelle, TEXT CONST datei,
+ TASK CONST manager) #off("b")#
+ Der eigene Datenraum 'quelle' wird in die Datei 'datei' in der Task 'manager'
+ kopiert.
+#page#
+
+5.5 Eingabe/Ausgabe
+
+- Eingabesteuerzeichen : HOP , � � � � , TAB , RUBIN , RUBOUT
+ CR , MARK , ESC
+
+- Ausgabesteuerzeichen : HOME , � � � � , CL EOP , CL EOL
+ CPOS , BELL , CR , ENDMARK , BEGINMARK
+
+- Positionierung : cursor , get cursor , line , page
+
+- Eingabe : get , getline , inchar , incharety
+
+- Ausgabe : cout , out , out subtext , put , putline ,
+ TIMESOUT , write
+
+- Kontrolle : online , pause , sysin , sysout
+
+- Zeitmessung : clock , date , day , hour , pause , time
+ time of day
+
+#page#
+
+5.5.1 E/A auf Bildschirm
+
+Steuerzeichen und Standardprozeduren zur Ein- Ausgabe am Bildschirm werden
+zur Steuerung des Dialogverhaltens von Prozeduren benutzt.
+
+
+5.5.1.1 Eingabesteuerzeichen
+Eingabesteuerzeichen werden durch die Funktionstasten (s. 3.2) erzeugt. Die Wirkung
+der Tasten ist ebenfalls an dieser Stelle beschrieben.
+
+Durch die Tasten werden folgende Codes an Programme gegeben:
+
+Codierung I Bezeichnung
+-----------+--------------
+HOP I 1
+RECHTS I 2
+OBEN I 3
+LINKS I 8
+TAB I 9
+UNTEN I 10
+RUBIN I 11
+RUBOUT I 12
+CR I 13
+MARK I 16
+ESC I 27
+
+
+#page#
+
+5.5.1.2 Ausgabesteuerzeichen
+
+Die Ausgabe dieser Zeichen bewirkt folgendes Verhalten der Bildschirmausgabe.
+
+Code I Name I Wirkung
+-----+-------------+-------------------------------------------------------
+ 0 I NUL I keine Wirkung
+ 1 I HOME I Cursor in die linke obere Ecke setzen (Position 0,0!)
+ 2 I RECHTS I Cursor eine Stelle nach rechts setzen
+ 3 I OBEN I Cursor eine Zeile höher setzen
+ 4 I CL EOP I Rest der Seite löschen
+ 5 I CL EOL I Rest der Zeile löschen
+ 6 I CPOS I Cursor setzen, nächstes Ausgabezeichen bestimmt die
+ I I y-Position, das darauf folgende die x-Position.
+ 7 I BELL I akustisches Signal
+ 8 I LINKS I Cursor eine Stelle nach links setzen
+10 I UNTEN I Cursor eine Stelle nach unten setzen
+13 I CR I Cursor an den Anfang der nächsten Zeile setzen
+14 I ENDMARK I Ende des markierten Bereichs
+15 I BEGINMARK I Anfang des markierten Bereichs
+
+
+
+
+____________________________________________________________________________
+
+ ........................... Beispiel ..........................
+ TEXT VAR ausgabe := (""7""15"V O R S I C H T"14"7"");
+ out(ausgabe);
+
+____________________________________________________________________________
+
+#page#
+
+5.5.1.3 Positionierung
+
+'cursor'
+ #on("b")#PROC cursor (INT CONST column, row) #off("b")#
+ Positioniert den Cursor auf dem Bildschirm, wobei 'column' die Spalte und 'row'
+ die Zeile angibt. Die zulässigen Bereiche von 'column' und 'row' sind geräteab­
+ hängig.
+
+
+
+'get cursor'
+ #on("b")#PROC get cursor (INT VAR x, y) #off("b")#
+ Erfragung der aktuellen Cursor-Position. Die Koordinaten des Cursors werden in
+ 'x' und 'y' geliefert. Die aktuelle Cursor-Position ist nach Ausgabe von 'HOME'
+ (Code = 1) oder einer Positionierung des Cursors mit der Prozedur 'cursor' stets
+ definiert. Die Prozedur 'get cursor' liefert jedoch undefinierte Werte, wenn über
+ den rechten Rand einer Zeile hinausgeschrieben wurde (die Wirkung einer solchen
+ Operation hängt von der Hardware eines Terminals ab).
+
+
+'line'
+ #on("b")#PROC line #off("b")#
+ Es wird zum Anfang einer neuen Zeile positioniert.
+
+ #on("b")#PROC line (INT CONST number) #off("b")#
+ Es werden 'number' Zeilenwechsel vorgenommen.
+
+
+'page'
+ #on("b")#PROC page #off("b")#
+ Es wird zum Anfang einer neuen Seite positioniert (hier: linke obere Ecke (Position
+ 1,1 !) des Bildschirms, wobei der Bildschirm gelöscht wird).
+
+#page#
+
+5.5.1.4 Eingabe
+
+
+Grundlegende Prozeduren
+Die folgenden Prozeduren dienen ausschließlich der Eingabe vom Terminal.
+
+'editget'
+ Siehe 5.4.6
+
+
+'getchar'
+ #on("b")#PROC getchar (TEXT VAR zeichen)#off("b")#
+ Liest genau ein Zeichen von der Tastatur und schreibt es in die Variable 'zeichen'.
+
+
+'inchar'
+ #on("b")#PROC inchar (TEXT VAR character) #off("b")#
+ Wartet solange, bis ein Zeichen von der Tastatur eingegeben wird, und schreibt
+ dieses Zeichen in die Variable 'character'.
+
+
+'incharety'
+ #on("b")#TEXT PROC incharety #off("b")#
+ Versucht, ein Zeichen von der Tastatur zu lesen. Wurde kein Zeichen eingegeben,
+ wird niltext geliefert.
+
+ #on("b")#TEXT PROC incharety (INT CONST time limit) #off("b")#
+ Versucht, ein Zeichen vom Bildschirm zu lesen. Dabei wird maximal eine 'time
+ limit' lange Zeit auf das Zeichen gewartet (gemessen in Zehntel-Sekunden).
+
+#page#
+
+Umleitbare Eingabeprozeduren
+Die folgenden Eingabeprozeduren lesen ebenfalls vom Terminal, die Eingabequelle
+kann jedoch durch die Prozedur 'sysin' umgestellt werden. Falls in 'sysin' eine Datei
+angegeben wird wird die Eingabe statt vom Terminal aus dieser Datei gelesen.
+
+
+'sysin'
+ #on("b")#PROC sysin (TEXT CONST file name) #off("b")#
+ Eingabe-Routinen lesen nicht mehr vom Benutzer-Terminal, sondern aus der
+ Datei 'file name'.
+
+ #on("b")#TEXT PROC sysin #off("b")#
+ Liefert den Namen der eingestellten 'sysin'-Datei. "" bezeichnet das Benutzer-
+ Terminal.
+
+
+'get'
+ #on("b")#PROC get (INT VAR number) #off("b")#
+ Einlesen eines INT-Wertes vom Bildschirm. Der einzulesende INT-Wert kann
+ bei der Eingabe vom Terminal editiert werden.
+
+ #on("b")#PROC get (REAL VAR value) #off("b")#
+ Einlesen eines REAL-Wertes vom Bildschirm. Der einzulesende REAL-Wert
+ kann bei der Eingabe vom Terminal editiert werden.
+
+ #on("b")#PROC get (TEXT VAR word) #off("b")#
+ Liest einen Text in die Variable 'word' mit maximal 255 Zeichen. Es werden
+ solange Zeichen vom Terminal gelesen, bis ein Leerzeichen oder #schl("CR")# eingegeben
+ wird. Dabei werden führende Leerzeichen übergeben. Der einzulesende Text
+ kann bei der Eingabe editiert werden. Eine leere Eingabe ist nicht erlaubt.
+
+ #on("b")#PROC get (TEXT VAR word, INT CONST laenge) #off("b")#
+ Liest einen Text vom Bildschirm mit der Länge 'laenge' oder bis #schl("CR")# eingegeben
+ wird. Der einzulesende Wert kann bei der Eingabe editiert werden.
+
+ #on("b")#PROC get (TEXT VAR word, TEXT CONST separator) #off("b")#
+ Liest einen Text vom Bildschirm, bis ein Zeichen 'separator' angetroffen oder #schl("CR")#
+ eingegeben wird. Der einzulesende Text kann bei der Eingabe editiert werden.
+
+
+'getline'
+ #on("b")#PROC get line (TEXT VAR line) #off("b")#
+ Das System wartet auf eine Zeile vom Bildschirm (max. 255 Zeichen). #schl("CR")# been­
+ det die Eingabe.
+
+#page#
+
+5.5.1.5 Ausgabe
+
+
+Grundlegende Prozeduren
+Die folgenden Prozeduren dienen ausschließlich der Ausgabe auf das Terminal.
+
+
+'cout'
+ #on("b")#PROC cout (INT CONST number) #off("b")#
+ Schreibt 'number' an die aktuelle Cursor-Position auf den Bildschirm. Anschlie­
+ ßend wird an diese Position wieder zurück positioniert. 'number' muß > 0 sein.
+ Paßt 'number' nicht mehr auf die Zeile, so ist die Wirkung von 'cout' nicht de­
+ finiert. 'cout' gibt den Wert von 'number' nur aus, wenn genügend freie Kanal-
+ Kapazität für diese Ausgabe vorhanden ist. Das hat zur Folge, daß Programme
+ nicht auf die Beendigung einer Ausgabe von 'number' warten müssen und ggf.
+ Ausgaben überschlagen werden.
+
+
+'out'
+ #on("b")#PROC out (TEXT CONST text) #off("b")#
+ Ausgabe eines Textes auf dem Bildschirm. Im Unterschied zu 'put' wird kein
+ Blank an den ausgegebenen Text angefügt.
+
+
+
+'out subtext'
+ #on("b")#PROC out subtext (TEXT CONST source, INT CONST from) #off("b")#
+ Ausgabe eines Teiltextes von 'source' von der Position 'from' bis Textende. Es
+ wird keine Aktion vorgenommen für
+
+
+ from > LENGTH source
+
+
+ #on("b")#PROC out subtext (TEXT CONST source, INT CONST from, to)#off("b")#
+ Ausgabe eines Teiltextes von 'source' von der Position 'from' bis zur Position 'to'.
+ Für
+
+
+ to > LENGTH source
+
+
+ wird out subtext (source, from) ausgeführt.
+
+ #on("b")#PROC out text (TEXT CONST source, INT CONST from, to) #off("b")#
+ Ausgabe eines Teiltextes von 'source' von der Position 'from' bis zur Position 'to'.
+ Für
+
+
+ to > LENGTH source
+
+
+ wird für die fehlenden Zeichen Blanks ausgegeben.
+
+
+
+'TIMESOUT'
+ #on("b")#OP TIMESOUT (INT CONST times, TEXT CONST text) #off("b")#
+ Ausgabe eines TEXTes 'text' 'times'mal. An die Ausgabe wird im Gegensatz zu
+ 'put' kein Leerzeichen angefügt. Es wird kein Text ausgegeben für
+
+
+ times < 1
+
+
+#page#
+
+Umleitbare Ausgabeprozeduren
+Die folgenden Ausgabeprozeduren schreiben ebenfalls auf das Terminal, die Ausgabe
+kann jedoch durch die Prozedur 'sysout' umgeleitet werden. Falls in 'sysout' eine
+Datei angegeben wird wird die Ausgabe statt zum
+Terminal in die angegebene Datei geleitet.
+
+
+'sysout'
+ #on("b")#PROC sysout (TEXT CONST file name) #off("b")#
+ Ausgabe-Routinen gehen nicht mehr zum Benutzer-Terminal, sondern in die
+ Datei 'file name'.
+
+ #on("b")#TEXT PROC sysout #off("b")#
+ Liefert den Namen der eingestellten 'sysout'-Datei. "" bezeichnet das Benut­
+ zer-Terminal.
+
+
+'line'
+ #on("b")#line#off("b")#
+ Positionierung auf den Anfang einer neuen Ausgabezeile.
+
+ #on("b")#line (INT CONST faktor)#off("b")#
+ Nächste Ausgabezeile um 'faktor' Zeilen weiter positionieren.
+
+
+'put'
+ #on("b")#PROC put (INT CONST number) #off("b")#
+ Ausgabe eines INT-Wertes auf dem Bildschirm. Anschließend wird ein Leer­
+ zeichen ausgegeben.
+
+ #on("b")#PROC put (REAL CONST real) #off("b")#
+ Ausgabe eines REAL-Wertes auf dem Bildschirm. Anschließend wird ein Leer­
+ zeichen ausgegeben.
+
+ #on("b")#PROC put (TEXT CONST text) #off("b")#
+ Ausgabe eines Textes auf dem Bildschirm. Nach der Ausgabe von 'text' wird ein
+ Blank ausgegeben, um nachfolgenden Ausgaben auf der gleichen Zeile voneinan­
+ der zu trennen. Hardwareabhängig sind die Aktionen, wenn eine Ausgabe über
+ eine Zeilengrenze (hier: Bildschirmzeile) vorgenommen wird. Meist wird die Ausga­
+ be auf der nächsten Zeile fortgesetzt.
+
+
+'putline'
+ #on("b")#PROC putline (TEXT CONST text) #off("b")#
+ Ausgabe von 'text' auf dem Bildschirm. Nach der Ausgabe wird auf den Anfang
+ der nächsten Zeile positioniert. Gibt man TEXTe nur mit 'putline' aus, so ist
+ gesichert, daß jede Ausgabe auf einer neuen Zeile beginnt. Hardwareabhängig
+ sind die Aktionen, wenn eine Ausgabe über eine Zeilengrenze (hier: Bildschirm­
+ zeile) vorgenommen wird. Meist wird die Ausgabe auf der nächsten Zeile fort­
+ gesetzt.
+
+
+'write'
+ #on("b")#PROC write (TEXT CONST text) #off("b")#
+ Gibt 'text' ohne Trennblank aus ('put' mit Trennblank).
+
+#page#
+
+5.5.1.6 Kontrolle
+
+'online'
+ #on("b")#BOOL PROC online #off("b")#
+ Liefert TRUE, wenn die Task mit einem Terminal gekoppelt ist.
+
+
+'pause'
+ #on("b")#PROC pause (INT CONST time limit) #off("b")#
+ Wartet 'time limit' in Zehntel-Sekunden. Bei negativen Werten ist die Wirkung
+ nicht definiert. Die Wartezeit wird nicht nur durch das Erreichen der Grenze ab­
+ gebrochen, sondern auch durch die Eingabe eines beliebigen Zeichens.
+
+ #on("b")#PROC pause#off("b")#
+ Wartet bis zur Eingabe eines beliebigen Zeichens.
+
+
+#page#
+
+5.5.2 Zeitmessung
+
+'clock'
+ #on("b")#REAL PROC clock (INT CONST index) #off("b")#
+ Datum und Uhrzeit werden vom EUMEL-System für alle Tasks geführt. Neben
+ einer Uhr ('Realzeituhr'), die das Datum und die aktuelle Uhrzeit enthält, wird eine
+ Uhr für die von der Task verbrauchte CPU-Zeit geführt ('CPU-Zeituhr'). Beide
+ Zeiten werden vom System als REALs realisiert. Die Prozedur 'clock' liefert die
+ aktuellen Werte dieser Uhren. Bei 'index = 0' wird die akkumulierte CPU-Zeit
+ der Task, bei 'index = 1' der Wert der Realzeituhr geliefert.
+
+ Mit den REAL-Werten der Uhren kann ohne weiteres gerechnet werden, jedoch
+ sind nur Werte > 0 definiert. Die REAL-Werte der Realzeituhr beginnen beim
+ 1.1.1900 um 0 Uhr. Es sind nur Werte für dieses Jahrhundert zugelassen. Werte
+ der Realzeituhr in lesbarer Form kann man durch die Konvertierungsprozeduren
+ 'date' (vergl. 5- #topage("date")# ) (für den aktuellen Tag) und 'time of day' (Uhrzeit, vergl.
+ 5-#topage("time")#) erhalten.
+
+ Um die benötigte CPU-Zeit eines Programms zu berechnen, muß man die
+ CPU-Zeituhr zweimal abfragen. Um solche Zeiten in lesbarer Form zu erhalten,
+ kann man die Konvertierungsprozedur 'time' (vergl. 5- #topage("time")#) verwenden. Beispiel:
+
+____________________________________________________________________________
+
+ ........................... Beispiel ..........................
+ REAL CONST anfang :: clock (0);
+ berechnungen;
+ REAL CONST ende :: clock (0);
+ put ("benoetigte CPU-Zeit in Sek:");
+ put (time (ende - anfang))
+
+____________________________________________________________________________
+#page#
+'date'
+#goalpage("date")#
+ #on("b")#TEXT PROC date (REAL CONST time) #off("b")#
+ Konvertierungsprozedur für das Datum, welches sich aus dem Aufruf der Prozedur
+ 'clock (1)' ergibt. Das Datum wird in der Form 'tt.mm.jj' geliefert. Beispiel:
+
+____________________________________________________________________________
+
+ put (date (clock (1))) (* z.B.: 24.12.87 *)
+
+____________________________________________________________________________
+
+
+ #on("b")#REAL PROC date (TEXT CONST datum) #off("b")#
+ Konvertierungsprozedur für ein Datum in der Form 'tt.mm.jj'. Liefert einen
+ REAL-Wert, wie ihn die Prozedur 'clock (1)' liefern würde. Beispiel:
+
+____________________________________________________________________________
+
+ put (date ("24.12.87")) (* 6.273539e10 *)
+
+____________________________________________________________________________
+
+
+ #on("b")#TEXT PROC date#off("b")#
+ Liefert das Tagesdatum. Wirkt wie 'date (clock (1))', ist jedoch erheblich schneller.
+
+
+
+'day'
+ #on("b")#REAL CONST day #off("b")#
+ Liefert die Anzahl der Sekunden eines Tages (86 400.0).
+
+
+
+'hour'
+ #on("b")#REAL CONST hour #off("b")#
+ Liefert die Anzahl der Sekunden einer Stunde (3600.0).
+
+
+
+'pause'
+ #on("b")#PROC pause (INT CONST time limit) #off("b")#
+ Wartet 'time limit' in Zehntel-Sekunden. Bei negativen Werten ist die Wirkung
+ nicht definiert. Die Wartezeit wird nicht nur durch das Erreichen der Grenze ab­
+ gebrochen, sondern auch durch die Eingabe eines beliebigen Zeichens.
+
+
+
+'time'
+#goalpage("time")#
+ #on("b")#TEXT PROC time (REAL CONST time) #off("b")#
+ Konvertierungsprozedur für die Zeiten der CPU-Zeituhr. Liefert die Zeiten in der
+ Form 'hh:mm:ss.s'. Vergl. dazu 'clock'.
+
+ #on("b")#TEXT PROC time (REAL CONST value, INT CONST laenge) #off("b")#
+ Konvertiert die Zeit in externe Darstellung. Für die 'laenge'-Werte ergibt sich:
+
+
+ laenge = 10 (* hh:mm:ss.s *)
+ laenge = 12 (* hhhh:mm:ss.s *)
+
+
+
+ #on("b")#REAL PROC time (TEXT CONST time) #off("b")#
+ Konvertierungsprozedur für Texte der CPU-Zeituhr in REAL-Werte.
+
+
+
+'time of day'
+ #on("b")#TEXT PROC time of day (REAL CONST time) #off("b")#
+ Konvertierungsprozedur für REALs, wie sie die Realzeituhr
+ liefert. Es wird die Tageszeit in der Form 'hh:mm' geliefert. Beispiel:
+
+____________________________________________________________________________
+
+ put (time of day (clock (1))) (* z.B.: 17:25 *)
+
+____________________________________________________________________________
+
+
+ #on("b")#TEXT PROC time of day #off("b")#
+ Liefert die aktuelle Tageszeit. Entspricht
+
+____________________________________________________________________________
+
+ time of day (clock (1))
+
+____________________________________________________________________________
+#page#
+
+5.6 Scanner
+
+Der Scanner kann benutzt werden, um festzustellen, welche Art von Symbolen in
+einem TEXT enthalten sind. Die Repräsentation der Symbole müssen dabei der
+ELAN-Syntax entsprechen. Folgende #ib#Symbole#ie# kann der Scanner erkennen:
+
+ - "tags", d.h. Namen,
+ - "bolds", d.h. Schlüsselworte,
+ - "number", d.h. INT oder REAL Zahlen,
+ - Operatoren,
+ - "delimiter", d.h. Begrenzer wie z.B. ";",
+ - und das Ende des Scan-Textes.
+
+
+Der Scanner überliest Kommentare und Leerzeichen zwischen den Symbolen. Der
+(erste) zu verarbeitende Text muß mit der Prozedur
+
+
+ #ib#scan#ie#
+
+
+in den Scanner "hineingesteckt" werden. Mit der Prozedur
+
+
+ #ib#next symbol#ie#
+
+
+wird das jeweils nächste Symbol des TEXTes geholt. Am Ende wird "end of scan"
+und als Symbol 'niltext' geliefert. Falls innerhalb eines TEXT-Denoters oder eines
+Kommentars "end of scan" auftritt, wird "within text" bzw. "within comment" gemel­
+det. Der Scan-Prozeß kann dann mit dem nächsten zu scannenden TEXT (der
+nächsten Zeile) fortgesetzt werden. Dafür wird nicht die Prozedur 'scan', sondern
+
+
+ #ib#continue scan#ie#
+
+
+verwandt. Sie setzt im letzten Scan-Zustand (z.B. Kommentar oder TEXT-Deno­
+ter) wieder auf, so daß auch Folgen von TEXTen (Zeilen) wie z.B. Dateien leicht
+gescannt werden können.
+
+Mit den Prozeduren
+
+
+ scan (* meldet eine Datei zum scannen an *)
+ next symbol (* holt die Symbole *)
+
+
+kann man auch eine Datei nach ELAN-Symbolen untersuchen.
+
+____________________________________________________________________________
+
+ FILE VAR f :: ...
+ ...
+ scan (f); (* beginnt das Scanning in
+ der nächsten Zeile *)
+ TEXT VAR symbol;
+ INT VAR type;
+ REP
+ next symbol (f, symbol, type);
+ verarbeite symbol
+ UNTIL type >= 7 END REP.
+