#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 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, call 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 ; 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 (... +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 einzulesen. #on("b")#BLOCKOUT#off("b")# A 0 bzw. 31 B 0 C Blocknummer DIV 65536 DE Blocknummer MOD 65536 HL Hauptspeicheradresse Der Hauptspeicherbereich (...+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 [] gegeben werden oder, wenn der Cursor sich im Dump befindet, mit dem Format wobei dann für die der Cursorposition entsprechende Dumpadresse (modulo 2**16) gesetzt wird (siehe '*cup*'). 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 = 0 ist, sonst der Leitblock der Task mit der Nummer . (Nur im ELAN-Miniprozeß). 'q' Die Task mit der Nummer 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 eingestellt. Ist =FF, so wird der Realspeicher eingestellt. (s:=) 'l' Dumps werden auf die Länge 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 eingestellt (p:=; wmodus:= FALSE). 'w' Dumps werden auf die Wortadresse eingestellt. Die vor jeder Dumpzeile ausgegebene Adresse ist dann auch eine Wortadresse. Ein Wort = 2 Bytes. (p:=2* ; wmodus:=TRUE) 'k' Block laden und per Dump anzeigen. Es erfolgt dabei eine Umstellung auf den Realdatenraum (s=FF). 'P' Paßworteingabe: P*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 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*return*' Neues Paßwort einstellen (max. 9 Zeichen). Dieses bleibt auch nach 'shutup' gültig. --> 'yt' Block von Archiv lesen. Dient zum Test des Archivs. Es wird eine Kachel freigemacht und der Block mit der Nummer eingelesen. Der Inhalt wird sofort angezeigt (wie Kommando 'k'). --> 'yb' Breakpoint an die Adresse 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 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 = im Datenraum 4 dieser Task. Durch die Eingabefolge: 4sw*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 = 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.