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