Die Systemvariablen des TOS Teil 2

Heute kommen wir zum zweiten und letzten Teil der Besprechung der Systemvariablen.

Resetresidente Programme

Die Systemvariablen unterstützen eine Möglichkeit, wie Programme einen Reset überleben können (Tab. 1). Unmittelbar nach dem Reset werden zuerst alle Interrupts gesperrt und die Peripheriebausteine mit dem ‘reset’-Befehl des 68000 zurückgesetzt. Ein eventuell vorhandenes “Diagnose-ROM-Modul” wird aufgerufen. Falls es sich um einen Warmstart handelt, wird ‘memcntrl’ in das MMU-Registerübertragen, um die alte Speicherkonfiguration wieder herzustellen.

Adr. Name Gr. Std.-Wert Bedeutung
$426 resvalid L $31415926 Magic für ‘resvector’
$42A resvector L Vektor für resetresidente Programme

Tab. 1: Resetresidente Programme

Wenn ‘resvalid’ den Magiewert $31415926 enthält (hier war wohl ein Mathematiker am Werk, denn das sind die ersten Stellen der Zahl Pi), wird noch geprüft, ob der Vektor ‘resvector’ eine sinnvolle Adresse enthält (Bits 0 und 24-31 gelöscht). Dann erfolgt der Aufruf der durch ihn bezeichnten Routine.

Dabei muß man beachten, daß ansonsten noch keinerlei Systeminitialisierungen gemacht wurden.

Wenn man nicht gerade das ganze System selbst übernehmen will, möchte man wahrscheinlich nach einigen kleinen Aktionen wieder in die normale Reset-Routine zurückkehren.

Hierzu gibt es zwei Möglichkeiten. Mit ‘jmp (A6)’ springt man vor die Abfrage von ‘resvalid’. Das ist nur möglich, wenn man ‘resvalid’ vorher ungültig macht, weil man sonst immer wieder von Neuem aufgerufen wird (eine nette Form der Endlosschleife).

Nach einem ‘jmp $24(A6)’ dagegen fährt man in der normalen Reset-Routine fort.

Das weicht zwar von der Original-BIOS-Dokumentation ab, doch ist es von ATARI nun selbst so vorgeschlagen worden.

Auch hier ist es natürlich sinnvoll, eine Kette zu bilden: Bei der Installation merkt man sich, ob ‘resvalid’ gültig ist, und springt dann am Ende der eigenen Reset-Routine über den gemerkten ‘resvector’.

A6 ist übrigens das einzige Register, das einen definierten Wert hat. Benutzt werden dürfen alle Register. Da noch nicht einmal die Stackzeiger sinnvolle Werte haben, dürfen natürlich keine Unterprogrammaufrufe gemacht werden!

Vertical Blank Interrupt

Der Vertical Blank Interrupt (VBI) wird jedesmal ausgelöst, wenn der Elektronenstrahl des Monitors ein Bild fertig gezeichnet hat, d.h. 50, 60 oder ca. 72 mal pro Sekunde.

Der VBI-Handler des BIOS erledigt hauptsächlich Aufgaben, die die Bilddarstellung beeinflussen. Dazu gehören Cursor-Blinken, der Wechsel der Bildschirmadresse, der Farbpalette oder der Bildschirmauflösung. Ein wenig aus der Rolle fällt nur die Floppy-VBL-Routine.

Würde dies erledigt werden, während das Bild aufgebaut wird, käme es zu unschönen Flackererscheinungen.

Der Interrupt-Handler des BIOS benutzt die Systemvariablen aus (Tab. 2).

Adr. Name Gr. Std.-Wert Bedeutung
5466 _frclock L * Zahl der aufgetretenen VBI-Interrupts
$462 _vbclock L * Zahl der ausgeführten VBI-Routinen
$452 vblsem W 1 0 sperrt VBI-Routinen
$454 nvbls W 8 Zahl der Einträge in ‘vblqueue’
$456 _vblqueue L $4CE Zeiger auf Vektortabelle für VBI-Routinen
$4CE _vbl_list 8L * Standard-'vblqueue’

Tab. 2: Vertical Blank-Interrupt

In ‘ Jrclock’ wird die Anzahl der seit dem letzten Kaltstart registrierten VBIs mitgezählt.

‘ vbclock’ dagegen registriert die Zahl der tatsächlich ausgeführten VBI-Routi-nen. Denn wenn ‘vblsem’ auf 0 gesetzt wird, wird der VBI ignoriert (bis auf das Erhöhen von ‘Jrclock’). Normalerweise hat ‘vblsem’ den Wert 1.

Während der Abarbeitung der VBI-Rou-tine ist ‘vblsem’ automatisch auf 0 gesetzt, so daß ein VBI, der vor der Beendigung des alten auftritt, ignoriert wird. Dieser Fall kann aber ohnehin nur dann eintreten, wenn der Interrupt-Level der CPU während einer VBI-Routine heruntergesetzt wird, was normalerweise nicht der Fall ist.

Nachdem alle oben erwähnten Aufgaben des Systems erledigt wurden, werden noch von anderen Programmen gewünschte VBI-Routinen aufgerufen.

Dazu zeigt Jblqueue’ auf eine Tabelle mit Adressen von VBI-Routinen. Die Anzahl der Adressen ist durch ‘nvbls’ bestimmt. Ein Nullzeiger (0L) in der VBI-Tabelle zeigt an, daß der “VBI-Slot” unbenutzt ist.

Die korrekte Vorgehensweise, um eine eigene VBI-Routine zu installieren, ist wie folgt:

  1. die durch Jblqueue' adressierte Tabelle nach einem leeren Slot (Nullzeiger) durchsuchen (‘nvbls’-Einträge untersuchen).
  2. Wenn ein Slot frei ist, einfach gewünschte Adresse eintragen.
  3. Wenn alle Slots besetzt sind, gibt es zwei Möglichkeiten. Entweder bricht das Programm mit einer Fehlermeldung ab, oder es verschiebt die gesamte Tabelle in einen eigenen um einen Eintrag größeren Speicherbereich, trägt sich dort ein und erhöht ‘nvbls’ um Eins. Dies ist jedoch nur sinnvoll, wenn das Programm resident im Speicher verbleibt, da ein “Rückverschieben” i.allg. nicht ohne weiteres möglich ist.
  4. Um seine eigene Routine wieder zu entfernen, durchsucht man die durch das aktuelle ‘_vblqueue’ und ‘nvbls’ bestimmte Tabelle nach der Adresse der eigenen Routine und ersetzt sie durch OL (inzwischen könnte ein anderes Programm ja die Tabelle verschoben haben).

Die VBI-Routinen werden im Supervisor-Modus aufgerufen und dürfen alle Register (außer SSP und USP) verändern.

GEM installiert ebenfalls eine eigene VBI-Routine, die für das Neuzeichnen des Mauszeigers sorgt.

Dabei hält sich GEM jedoch nicht an die Spielregeln. Es benutzt nämlich immer den ersten Slot, auch wenn dieser schon besetzt sein sollte! Daher muß bei AUTO-Ordner-Programmen Punkt 1) dahingehend abgeändert werden, daß erst ab dem zweiten Slot gesucht wird.

GEM sollte einem hier also nicht als Vorbild dienen. Ebenfalls sollte man davon absehen, sich vor eine andere VBI-Routine in den gleichen Slot zu hängen (durch Verkettung), da man so dieser Routine die Möglichkeit nimmt, sich wieder auszuhängen (oder man wird selbst mit abgehängt, das ist dann Künstlerpech).

Die Standard-VBI-Tabelle liegt übrigens auch in den Systemvariablen i‘_vbl_lisf), allerdings sollte man sie nie direkt, sondern nur über ‘_vblqueue’ ansprechen.

Nach Aufruf dieser Anwender-VBI-Routinen wird noch die Hardcopy-Routine auf gerufen, falls ALT-HELP gedrückt wurde (s.u.).

Buntes oder Schwarzweißes

Auch zur Verwaltung des Monitors und des Bildes auf ihm gibt es Systemvariablen (Tab. 3).

TOS unterscheidet zwischen einem “logi-'Chen” und einem “physikalischen” Bildschirm.

Adr. Name Gr. Std.-Wert Bedeutung
$44E _v_bs_ad L * Zeiger auf logischen Bildschirm
$45A colorptr L 0 Zeiger auf neu zu setzende Farbtabelle
$45E screenpt L 0 Zeiger auf neu zu setzende Bildschirmadr.
$44C sshiftmd B * Kopie der akt. Bildschirmauflösung
$44A defshiftmd B 0 Defaultauflösung bei Wechsel S/W -> Farbe
$46E swv_vec L Vektor für Wechsel S/W <-> Farbe
$448 palmode W 0 * legt Femsehnorm fest (unbenutzt!)

Tab. 3: Bildschirm

Der physikalische Bildschirm ist derjenige, der gerade auf dem Monitor dargestellt wird. Seine Adresse ist demnach direkt in Registern des Video-Chips (Shifters) zu finden.

Auf den logischen Bildschirm beziehen sich dagegen alle gerade stattfindenden Ausgabeoperationen. Dies sind die Textausgaben des VT52-Emulators und die Grafikausgaben der Line A-Routinen. Seine Adresse ist in ‘vbsad’ abgelegt.

Dieses Konzept ermöglicht es, einen Bildschirm unabhängig von dem gerade tatsächlich angezeigten aufzubauen. In vielen Fällen werden beide Adressen natürlich gleich sein, trotzdem sollte man bei eigenen Routinen, die direkt auf den Bildschirmspeicher zugreifen, stets ‘ v bs ad’ benutzen.

Ganz böse Praxis ist es, direkt auf das vermeintliche Video-RAM zuzugreifen (auch nicht über ‘phystop’ minus 32 kB), da es keineswegs immer dort liegen muß.

Die Bildschirmadressen müssen übrigens immer Vielfache von 256 sein, d.h. die untersten 8 Bits sind immer Null.

Um eine neue Farbpalette (16 Words) zu installieren, schreibt man einfach einen Zeiger auf diese nach 'colorptr' . Bei der nächsten ausgeführten VBI-Routine wird die Farbpalette in die entsprechenden Register des Shifters übertragen. Dann wird 'colorptr' automatisch gelöscht.

Ähnlich verhält es sich mit screenpf, nur daß hier die Adressen des logischen und des physikalischen Bildschirms neu gesetzt werden. .Allerdings wird ‘screenpf anschließend nicht gelöscht, so daß dies bei jedem A BI erneut passiert. Abgesehen von einer gewissen Zeitverschwendung führt das zu Kollisionen mit der XBIOS-Funktion ‘Setscreen’. Daher sollte man entweder nur ‘screenpf oder nur ‘Setscreen’ benutzen und im ersten Fall spätestens beim Terminieren des Programms v auf 0 setzen.

Die aktuelle Bildschirmauflösung wird in ‘sshiftmd’ aufbewahrt. Dabei stehen 0,1 und 2 für die niedrige, mittlere und hohe Auflösung. Daher sollte ‘sshiftmd’ nicht verändert werden, ohne auch das entsprechende Register im Shifter neu zu setzen. Hierfür gibt es außerdem die XBIOS-Funktion ‘Setscreen’.

Der VBI-Handler erkennt an einem besonderen Signal des Video-Ports, ob der ATARI Monochrom-Monitor angeschlossen ist.

Beim Wechsel Schwarzweiß- zu Farbmonitor bestimmt ‘defshiftmd', ob die niedrige oder mittlere Auflösung eingestellt werden soll. Daher sollte hier 0 oder 1 stehen. Nach dem Kaltstart steht hier 0.

Die neue Auflösung (beim Wechsel zum Monochrom-Monitor natürlich die hohe) wird nun nach ‘sshiftmd’ und direkt in den Shifter übertragen.

Um ein Programm von den veränderten Verhältnissen zu unterrichten, wird über den Vektor ‘swv_yec’ gesprungen.

Normalerweise ist hier die Reset-Routine eingetragen, d.h. es wird ein Warmstart durchgeführt. Dabei bleiben sowohl ‘sshiftmd’ als auch ‘defshiftmd’ erhalten, so daß nach dem Reset tatsächlich die gewünschte neue Auflösung vorliegt.

Der Reset ist jedoch nur deshalb notwendig, weil das GEM sich beim Systemstart einmal auf eine bestimmte Auflösung “eingestellt” hat und daher neu initialisiert werden muß. Beim Wechsel zwischen den beiden Farbmodi über den Desktop ist dies noch möglich, aber aus der VBI-Routine heraus, wo der Monitorwechsel bemerkt wird, nicht.

Programme, die ganz ohne GEM aus-kommen (vornehmlich Spiele), können jedoch mit einem Monitorwechsel besser umgehen. Daher sollten Sie in ‘swvvec’ eine eigene Routine eintragen. Hier ist es natürlich nicht sinnvoll, eine Kette zu bilden, daher reicht es, die alte Adresse zu retten und ‘swv_vec’ beim Verlassen des Programms wieder zu restaurieren. Jetzt wird es kritisch, weil GEM nicht mit der veränderten Auflösung zurechtkommt.

Nach Abarbeitung der ‘swv vec’ -Routine wird ganz normal im VBI-Handler fortgefahren.

Die Routine wird im Supervisor-Mode aufgerufen und darf alle Register (außer SSP und USP) verändern.

In ‘palmode’ schließlich soll die Fernsehnorm festgelegt sein, mit der ein eventuell angeschlossener HF-Modulator arbeitet. 0 steht für die NTSC-Norm, alles andere bedeutet PAL-Norm. Soweit mir bekannt, steht hier immer 0. Ein ähnliches Flag findet sich stattdessen im “system header block” (Abb. 2 des 1. Teils).

Konsole - Zeichen für Zeichen

Die “Konsole” des ST, bestehend aus Tastatur und dem über den VT52-Emula-tor verwalteten Bildschirm, hat auch ihr Plätzchen im Variablendschungel gefunden (Tab. 4).

Adr. Name Gr. Std.-Wert Bedeutung
$484 conterm B 7 Bitvektor für Funktionen der Konsole
$4A8 constate L Vektor für Ausgabe auf Konsole
$4AC sav_row W * Zwischenspeicher für Cursorzeile bei ESC Y

Tab. 4: Konsole

‘conterm ist ein Bitvektor, der einige Optionen steuert. Der Standardwert ist 7.

Bei gesetztem Bit 0 ertönt bei der Ausgabe von CTRL-G die “Glocke”. Der GEM-Anwender hört diesen Sound, wenn er außerhalb einer Dialog-Box herumklickt. Sonst bleibt CTRL-G stumm.

Die automatische Tastenwiederholung läßt sich durch ein gesetztes Bit 1 aktivieren.

Der Tastenklick ertönt nur bei gesetztem Bit 2.

Normalerweise geben BIOS und GEM-DOS bei der Eingabe von der Tastatur nur ASCII- und Scan-Kode zurück. Bei gesetztem Bit 3 wird zusätzlich in den Bits 31-24 der Rückgabe werte der aktuelle Tastenstatus wie ihn auch ‘Kbshift’ liefert, abgelegt.

Über den Vektor ‘con_state’ springt das BIOS zu Beginn der ‘Bconout’ - Routine für die Konsole. In den Bits 7-0 von Dl findet man das auszugebende Zeichen, die Bits 31-8 sind immer Null (die Bits 15-8 des an ‘Bconout’ übergebenen Zeichens gehen verloren).

Die normale Routine gibt die druckbaren Zeichen aus und wertet alle CTRL-Codes und ESC-Sequenzen aus. Nach Registrierung eines ESC setzt sie einfach den ‘conjstate’-Vektor auf eine spezielle ESC-Behandlungsroutine um. Dadurch wird das nachfolgende Zeichen als zum ESC gehörig erkannt und ausgewertet, so daß das ‘A’ aus ‘ESC A’ nicht als ‘A’ auf dem Bildschirm erscheint.

Alle ESC-Sequenzen außer ESC Y bestehen nur aus einem weiteren Zeichen. Daher wird ‘constate’ wieder auf die normale Routine zurückgesetzt und die Funktion ausgeführt.

Bei ESC Y (Setzen der Cursor-Position) wird ‘con state’ auf eine weitere Routine gesetzt, die nichts weiter macht, als das nächste Zeichen, die neue Cursor-Zeile, in ‘save row’ zwischenzuspeichem und ‘con state’ erneut umzusetzen. Erst beim nächsten Zeichen, der neuen Cursor-Spalte, ist die Sequenz beendet, ‘con state’ wird wieder auf den Ausgangswert gesetzt und die Funktion ausgeführt.

Man kann hier eine eigene Routine ein-hängen, die aber dann zumindest kein ESC mehr an die Original-Routine “durchlassen” darf, da diese dann sofort den ‘con_state -Vektor umsetzt, und die eigene Routine damit nicht mehr zum Zuge kommt.

Die ‘con_state’-Routine wird im Supervisor-Modus aufgerufen und darf alle Register (außer SSP und USP) verändern.

Hardcopy oder 30 Sekunden Pause?

Adr. Name Gr. Std.-Wert Bedeutung
$4EE _dumpflg W -1 Status der Hardcopy-Routine
$502 scr_dump L Vektor für Hardcopy CScrdmp’)
$506 prvjsto L Vektor für Ausgabestatus paralleler Port
$50A prvjst L Vektor für Ausgabe auf parallelem Port
$50E prv_auxo L Vektor für Ausgabestatus serieller Port
$512 prv_aux L Vektor für Ausgabe auf seriellem Port

Tab. 5: Hardcopy

Tab. 5 gibt Aufschluß über die mit der Bildschirm-Hardcopy verbundenen Systemvariablen.

Der Zähler ‘ dumpfig’ hält den Zustand der ALT-HELP-Tastendrücke bzw. der Hardcopy-Routine fest.

Er steht auf -1 im “Normalzustand” und wird von der Interrupt-Routine, die Tastendrücke verarbeitet, um Eins höher gezählt, jedesmal wenn ALT-HELP gedrückt wird.

Demnach bedeutet eine 0, daß mit dem Ausdruck der Hardcopy begonnen werden soll.

Am Ende des VBI-Handlers wird, wenn ‘ dumpfig’ 0 ist, die Hardcopy-Routine ‘Scrdmp’ (XBIOS #20) aufgerufen. ‘Scrdmp’ ruft die eigentliche Hardcopy-Routine ‘Prtblk’ (XBIOS #36) auf.

Vorher stellt sie noch den von ‘Prtblk’ erwarteten Parameterblock zusammen und setzt ‘ dumpfig’ auf 1. Dies signalisiert somit eine laufende Hardcopy.

'Prtblk' bricht die Hardcopy ab, wenn '_dumpflg’ ungleich 1 wird, also bei einem erneuten ALT-HELP (wobei ‘_dumpflg’ ja 2 wird).

Am Ende von ‘Prtblk’ wird ‘_dumpflg’ auf jeden Fall wieder auf -1 gesetzt.

Daraus folgt, daß man vor dem Aufruf von ‘Prtblk’ über das XBIOS ‘ dumpfig’ selbst auf 1 setzen muß.

‘Scrdmp’ springt gleich zu Anfang über den Vektor ‘scr_dump’. Hier kann also eine eigene Hardcopy-Routine installiert werden.

Sie kann entweder ebenfalls ‘Prtblk’ aufrufen (mit einem anderen Parameterblock) oder ganz neugeschrieben sein. Sie muß noch nicht einmal ‘ dumpfig’ zurücksetzen, da dies von ‘Scrdmp’ nachher schon erledigt wird.

Die ‘scr_dump’-Routine wird im Supervisor-Modus aufgerufen und darf die Register D0-D2 und A0-A2 verändern.

‘Prtblk’ benutzt zur Ausgabe der einzelnen Zeichen an den Drucker nicht direkt die BIOS-Funktion ‘Bconout’, sondern hat eigene Ausgabe-Routinen, die über die Vektoren ‘prv_lst’ oder ‘prv_aux’ springen, je nachdem ob der Drucker parallel oder seriell angeschlossen ist (dies kann im Parameterblock von ‘Prtblk’ festgelegt werden).

Normalerweise sind hier die Adressen der normalen Ausgabe-Routinen eingetragen, die auch ‘Bconout’ aufruft. Bei ‘prv aux’ ist dies allerdings ein Fehler, da hier noch die Abfrage der BIOS-Konfiguration (einstellbar etwa mit dem Kontrollfeld-Accessory bzw. der XBIOS-Funktion ‘Setprt’) erfolgt. Somit ist eine Ausgabe über den seriellen Port nur möglich, wenn der serielle Drucker sowohl mit ‘Setprt’ als auch im Parameterblock angewählt wurde.

Sinnvoll wäre es, wenn alle Programme ihre Grafikausgaben an Drucker über diese Routinen leiten würden. Dann wären Druckertreiber, die sich in ‘Bconout’ einhängen und bestimmte Code-Umwandlungen vornehmen, des Problems entledigt, daß solche Umwandlungen bei Grafikdaten nicht erwünscht sind.

Ferner hat die Hardcopy-Funktion auch ihre eigenen Routinen für den Ausgabestatus (‘prvjsto’ bzw. ‘prv_auxo’). Hier stehen natürlich normalerweise die entsprechenden Routinen, die auch ‘Bcostat1 aufruft. Diese Routinen werden jedoch von ‘Prtblk’ nie aufgerufen! Das lästige Warten nach einem ALT-HELP, wenn der Drucker nicht eingeschaltet ist, könnte z.B. vermieden werden, wenn ‘Prtblk’ gleich zu Beginn mit diesen Funktionen feststellen würde, ob der Drucker überhaupt annahmebereit ist, und gegebenenfalls abbrechen würde.

Dies wäre schon eine Anwendung für eine eigene ‘scr_dump’ - Routine, die genau diese Abfrage durchführt, bevor sie in die normale ‘scr_dump’ -Routine zurückkehrt.

Eigene Hardcopy-Ausgabe-Routinen müssen sich einfach wie die entsprechenden BIOS-Funktionen verhalten, d.h. das auszugebende Zeichen steht ab 6(SP). Die normalerweise bei 4(SP) stehende Gerätenummer ist hier Undefiniert.

Für eigene Hardcopy-Ausgabestatus-Routinen gilt Entsprechendes.

Ereignisvektoren

Adr. Name Gr. Std.-Wert Bedeutung
$400 etv_timer L Anwendervektor für 50-Hz-System-Timer
$404 etv_critic L Vektor für Behandlung kritischer I/O-Fehler
$408 etv_term L Vektor für Prozeßterminierung
$40C etv_xtra 5L 0 * reserviert für zukünftige ‘etv’-Vektoren

Tab. 6: Ereignisvektoren

Es gibt einige Routinen, die beim Eintreten spezieller Ereignisse (“events”) aufgerufen werden (Tab. 6).

Der ‘etv timer’ wird gleich im Zusammenhang mit dem 200-Hz-Interrupt erklärt.

Bei Fehlern während Diskettenoperationen ruft das BIOS den “Critical Error Handler” (CEH) auf, der in ‘etv_critic‘ festgelegt ist. Er soll “kritische” Fehler handhaben und entscheiden, wie darauf reagiert werden soll.

Das TOS hat einen CEH für TOS und einen für GEM-Programme. Der letztere, vom AES installiert, gibt die bekannten Alert-Boxen wie “Floppy A: antwortet nicht..." aus.

Eigene Laufwerkstreiber oder Programme können den CEH auch ohne weiteres aufrufen.

Auf dem Stack werden dem CEH die BIOS-Fehlemummer (-1...-31) und die Laufwerkskennung (0 für A: usw.) übergeben (beides ‘words’).

Außerdem kann im Register D0 eine Default-Fehlernummer übergeben werden. Dies wird vom CEH des AES aber ignoriert.

Der CEH muß im Supervisor-Modus aufgerufen werden und darf die Register A0-A2 und D0-D2 verändern.

Er liefert ein ‘longword’ zurück. Dies kann eine BIOS-Fehlemummer sein, die der Aufrufer seinerseits zurückgeben soll. Auch 0 ist erlaubt, um zu signalisieren, daß der Fehler ignoriert werden soll. Der AES-CEH gibt hier den ihm übergebenen Fehlercode zurück, wenn der Anwender die Alert-Box mit ‘ABBRUCH’ beendet.

Ein Wert von $10000 zeigt an, daß die fehlerhafte Operation noch einmal wiederholt werden soll. Der CEH des AES liefert dies, wenn ‘WEITER’ ausgewählt wurde.

Ein eigener CEH kann auch installiert werdendst praktikabel aber nur für TOS-Programme. Dazu setzt ein residentes AUTO-Ordner-Programm ‘etv_critic’ einfach um. Der eigene CEH wird aber nur bei TOS-Programmen aktiviert.

Der CEH darf BIOS/XBIOS-, aber keine GEMDOS- oder gar AES-Aufrufe machen.

Bei der Terminierung eines Programms mit der GEMDOS-Funktion 'Pterm’l

'PtermOTPtermres’ wird eine in ‘etv_term installierte Routine aufgerufen.

Sie kann vom Programm zur Verfügung gestellt werden, um eine korrekte Terminierung auch in unerwarteten Situationen (CTRL-C oder Bomben) zu gewährleisten. Dazu gehört z.B. das Restaurieren veränderter Sprung Vektoren.

'etv_term wird im Supervisor-Modus aufgerufen, darf die Register D0-D2 und A0-A2 verändern und endet normalerweise mit ‘RTS’. Vorher sollte sie sich selbstverständlich deinstalliert haben.

Es ist allerdings auch möglich, direkt ins Programm zurückzuspringen, um das ‘Pterm’ zu ignorieren. Dazu müssen natürlich alle Register usw. restauriert werden (in C macht man das mit einem longjmp’).

Die ‘etv_term’ -Routine darf GEMDOS-Aufrufe nur machen, wenn sie nicht mehr zurückkehrt. BIOS/XBIOS-Aufrufe sind dagegen ohne weiteres möglich.

Bei ‘Pterm’/’Pterm()’wird 'etv_term' vor allem anderen aufgerufen, bei ‘Ptermres’ sind allerdings schon die dem Prozeß gehörenden Speicherbereiche vor der Freigabe geschützt worden (die Memory -Descriptoren wurden aus der Belegt-Liste entfernt).

Normalerweise zeigt ‘etv_term einfach nur auf ‘RTS’.

Ab ‘etv_xtra’ ist Platz für 5 weitere, zukünftige Event-Vektoren reserviert.

200-Hz-Interrupt

TOS erledigt noch einige weitere periodische Aufgaben, die unabhängig von der Bildwiederholfrequenz laufen oder eine höhere Priorität als der VBI haben sollen.

Daher ist der Timer C im MFP so programmiert, daß er alle 5 Millisekunden (also 200 mal pro Sekunde) einen Interrupt auslöst.

Die Variablen hierzu sind in Tab. 7 aufgeführt.

Adr. Name Gr. Std.-Wert Bedeutung
$4BA _hz_200 L * Zahl der 200-Hz-Interrupts
$442 __timer_ms W 20 * ms zwischen zwei Systemtimer-Interrupts

Tab. 7: 200-Hz-Systeminterrupt

Die Anzahl dieser Interrupts seit dem letzten Kaltstart wird in ‘_hz_200’ mitgezählt. Dies ist also das Analogon zu '_frclock’, aber wesentlich besser geeignet, um Zeitmessungen vorzunehmen, da die Frequenz hier immer die gleiche ist. Die Zeitdauer (eines Benchmarks z.B. erhält man also durch einfache Differenzbildung der '_hz_200’-Werte zu Beginn und zum Ende.

Um Überlaufprobleme braucht man sich nicht zu kümmern, da ‘_hz_200’ erst nach 248,6 Tagen einmal durchgezählt ist!

'_hz_200' wird vom BIOS selbst für verschiedene Zeitmessungen benutzt.

Direkt mit 200 Hz werden sonst keine periodischen Aufgaben durchgeführt. Bei jedem vierten 200 Hz-Interrupt, also mit 50 Hz, wird aber noch einiges erledigt. Dazu gehören die Soundverarbeitung (im Hintergrund ablaufende “Musik" einschließlich des Tastaturklicks) und die automatische Tasten Wiederholung (hier wird das Bit 1 von ‘conterm’ abgefragt).

Zum Schluß werden noch vom Anwender definierbare Routinen aufgerufen. Dazu wird über den ‘etv_timer’-Vektor gesprungen. Hier kann man sich also - in einer Kette - einhängen. Als erstes Argument auf dem Stack (Word bei 4(SP)) bekommt man die Zahl der Millisekunden seit dem letzten Interrupt übergeben. Tatsächlich handelt es sich dabei um ‘_timer_ms’, das dementsprechend immer 20 ist.

Die Anwender-Routinen werden im Supervisor-Modus aufgerufen und dürfen alle Register (außer den Stackzeigern) verändern.

Beim Systemstart hängen sich sowohl GEMDOS als auch das AES in den ‘etv_timer’-Vektor ein. GEMDOS benutzt dies, um seine Uhr weiterzusetzen (in 2-Sekunden-Schritten).

Dies ist die Uhr, die für die Erstellungszeit bei Dateien verantwortlich ist.

Sonstiges

Die bisher noch nicht besprochenen Systemvariablen sehen Sie in Tab. 8.

Adr. Name Gr. Std.-Wert Bedeutung
S4A2 savptr L Zeiger auf BlOS-Stack für Register
$4B2 Jrufl 2L 2 Zeiger auf GEMDOS-BCB-Listen
$516 pun_ptr L Zeiger auf Harddisk-Information
$51E bis_vec 8L Vektoren für 'Bconstat'
$53E bi_vec 8L Vektoren für ‘Bconin’
$55E bos_vec 8L Vektoren für "Bcostat’
$57E bo_vec 8L Vektoren für "Bconout'

Tab. 8: Sonstiges

Das BIOS ist “reentrant”, d.h. während der Abarbeitung eines TRAPs (13 oder 14) darf ein erneuter TRAP ausgelöst werden (von einer Interrupt-Routine oder einem Unterprogramm des BIOS), ohne daß es zu Konflikten beim Retten oder Restaurieren der Arbeitsumgebung der CPU kommt.

Das heißt natürlich nicht, daß z.B. mitten in einem Flopp>-Zugriff plötzlich eine weitere Floppy-Operation gestartet werden darf. Auf solche Kollisionen muß man selbst achten, so daß man sich meistens auf "harmlose" BlOS-Operationen beschränkt (z.B. 'Kbshift', ‘Physbase usw.).

Es sei noch angemerkt, daß GEMDOS und AES in keiner Weise reentrant sind, so daß ein GEMDOS-Aufruf aus einer Interrupt-Routine mehr einem Lottospiel gleicht, wobei die Gewinnchancen allerdings bedeutend höher sind.

Bei einem TRAP befinden sich auf dem Stack bekanntlich die Parameter für den jeweiligen Funktionsaufruf, daher können die zu rettenden Register nicht so ohne weiteres ebenfalls dort abgelegt werden, da sich dann die Offsets für die Parameter verschieben würden.

BIOS hat extra hierfür einen eigenen kleinen Stack, ‘savptr’ zeigt auf dessen Spitze. Bei einem TRAP 13 oder 14 werden nun einige Register (SR,PC,D3-D7,A3-A7) ab ‘savptr abwärts dort abgelegt.

Danach ist ‘savptr’ also um 46 erniedrigt worden. Am Ende des TRAPs werden dementsprechend alle Register restauriert und ‘savptr’ wird wieder erhöht.

Die maximal erlaubte Schachtelungstiefe von TRAPs liegt bei 6 (die Original-ATARI-Dokumentation spricht von 3), dies dürfte wohl mehr als genug sein.

Allerdings ist der TRAP-Aufruf von Interrupt-Routinen aus doch nicht so ohne weiteres möglich, da ein Interrupt auch während des Rettens der Register auftre-ten kann. Da ‘savptr’ noch nicht erniedrigt wurde, werden schon gerettete Register bei einem nachfolgenden TRAP überschrieben. Hier brauchten bloß während des Arbeitens mit dem ‘savptr’ alle Interrupts gesperrt zu werden.

Dieser Fehler kann umgangen werden, indem man sich in Interrupt-Routinen den ‘savptr’ merkt, auf einen eigenen kleinen Speicherbereich (46 oder sicherheitshalber 92 Byte groß) umsetzt, seine BIOS-Aufrufe macht und anschließend ‘savptr’ wieder restauriert.

Seit einiger Zeit macht der ATARI-Harddisktreiber eine Struktur über ’pun_ptr verfügbar.

Zuerst kommt ein ‘word’, das die Anzahl der gefundenen physikalischen Harddisks angibt. Danach folgen 16 Bytes (für die Laufwerke A: bis P:), die angeben, ob das Laufwerk vom Harddisktreiber verwaltet wird (gleich 0) oder nicht (ungleich 0).

Ohne ATARI-Harddisktreiber ist ‘pun_ptr’ wie zu erwarten ein Nullzeiger.

‘_bnfl’ sind zwei Zeiger auf sogenannte BCB-Listen. Dies sind Strukturen, mit denen GEMDOS gepufferte Sektoren verwaltet. Dieses Thema ist zu umfangreich, um hier behandelt zu werden. Ich verweise daher auf [1],

Seit Blitter-TOS gibt es eine einfache Möglichkeit, die BIOS-Funktionen für die zeichenrientierten Geräte (‘Bconin’, ‘Bconout’, ’Bconstat’ und 'Bcostat’) zu modifizieren bzw. durch eigene zu ersetzen.

Es gibt hierzu 4 Vektortabellen mit den Adressen der jeweiligen Routinen der BIOS-Geräte 0 bis 7.

So ist bo_vec[2] z.B. der Vektor für die Ausgabe eines Zeichens auf dem Bildschirm.

BIOS unterstützt eigentlich nur die Gerätenummern 0 bis 5 und auch die nicht bei allen Funktionen. Nicht definierte Unterfunktionen und die Routinen für die Geräte 6 und 7 bestehen nur aus einem RTS’ und geben daher Undefinierte Werte zurück.

Die Routinen werden im Supervisor-Modus aufgerufen und die Register D0-D2 und A0-A2 dürfen verändert werden. Die Parameter beginnen bei 4(SP) mit der Gerätenummer, die hier nicht mehr beachtet werden muß.

Unbenutzte System variablen...

...gibt es nämlich auch. Einige haben wir schon kennengelernt, eine komplette Übersicht bietet (Tab. 9). Da sie von ATARI alle benannt wurden, kann man spekulieren, ob sie nur geplant oder nicht mehr notwendig sind.

Adr. Name Gr. Std.-Wert Bedeutung
$486 trpl4ret L 0 * Return-Adresse für TRAP 14-Handler ?
$48A criticret L 0 * Return-Adresse für CEH ?
$49E ___md L * Platz für mehr MDs
$4AE sav_context L 0 * Beginn Post-Mortem-Bereich
$4BE the_env L 0 * Zeiger auf Default-environment
$4CA _auto_path L 0 * Zeiger auf Zugriffspfad für AUTO-Ordner
S4F0 prt_abt W 0 * Abbruch-Flag für Hardcopy ?
S4F6 _shell_p L 0 * Zeiger auf Arbeitsumgebung r Shellde

Tab. 9: Nie Benutztes

Ferner ist der Bereich von $3EC bis $3FF noch nicht genutzt.

Das Ende der benutzten Systemvariablen liegt zur Zeit bei $59E, was natürlich nicht so bleiben muß.

Abschließend möchte ich noch hinzufügen, daß mir die Auswahl und Zusammenstellung der Systemvariablen recht wahllos und unüberlegt zu sein scheint.

Bei einigen scheint die Nützlichkeit äußerst fragwürdig zu sein (wie z.B. ‘themd'), bei anderen ist die Beeinflußbarkeit des TOS geringer als erwartet (z.B. ‘seekrate’).

An andere wichtige Variablen, die man oft vermißt, kommt man meist legal überhaupt nicht heran. Hier seien als Beispiel nur der Schreibschutz-Status sowie der auf Grund dessen ermittelte Mediachange-Status der Floppies erwähnt.

Literatur:

[1] Auf der Schwelle zum Licht, Teil 3, ST-Computer 3/88


Alex Esser
Aus: ST-Computer 12 / 1988, Seite 126

Links

Copyright-Bestimmungen: siehe Über diese Seite