Assembler-Ecke #10 -------------------- von Tim-Philipp Müller (Naja, 'für Anfänger' kann man das nun langsam nicht mehr nennen.) Diesmal geht es darum, eigene Treiber (handler im Englischen) zu schreiben. Aber erstmal: Was sind überhaupt Treiber ?? Das sind allgemein die Programme, die uns die Arbeit der Kommunikation mit den Geräten abnehmen, so daß wir die Geräte nach dem gleichen Schema über die CIO aufrufen können. Im OS vorhanden sind bereits Treiber für Tastatur (K:), den Drucker (P:), den Bildschirm (S:), das Kassetten- gerät (C:), sowie den Bildschirmeditor (E:). Für den Betrieb mit der Floppy wird meist noch ein DOS geladen, das einen Diskettentreiber (D:) installiert. Zuerst wollen wir uns die Adresse HATABS $31A-$33C,794-828 näher anschauen: $31A: 50 30 E4 $31D: 43 40 E4 $320: 45 00 E4 ... Was für ein Zufall, daß $50 dem Atascii code für 'P' entspricht, $43 dem für 'C' und $45 dem für 'E'. Zufall? Tatsächlich sind in dieser Tabelle für jeden Handler 3 Bytes vorgesehen, leere Einträge sind durch Nullen markiert: Ein Byte für den Atascii-Code des Handlernamens, die anderen beiden zeigen auf die eigentliche Treiber- tabelle, die wie folgt aufgebaut ist: Offset +0 Adresse der OPEN-Routine minus 1 +2 Vektor zur CLOSE-Routine minus 1 +4 Vektor zur GETBYTE-Routine minus 1 +6 Vektor zur PUTBYTE-Routine minus 1 +8 Vektor zur STATUS-Routine minus 1 +10 Vektor zur SPECIAl-Routine minus 1 +12 Sprung zur INIT-Routine (JMP INIT) +15 unbenutzt Byte 12 hat somit immer den Wert $4C, was einem JMP-Befehl entspricht. Warum immer die Adresse-1? Das hat den Grund, daß die CIO die Unterroutinen wie folgt aufruft: LDA Vektor+1 PHA LDA Vektor PHA RTS Der Prozessor erhöht die Adresse beim Holen vom Stack automatisch um 1. Was muß man nun also machen, wenn man einen eigenen Treiber schreiben möchte? Zuerst sucht man sich einen freien Platz in HATABS und trägt den neuen Treiber ein, dann erstellt man einfach sechs Unterprogramme, die die einzelnen Funktionen ausführen. Folgende Routine erleichtert die Eintragung in HATABS: PHENTV $E486 58502 + Treibertabellenadresse (HI/LO) Gerätename in Atascii Rückmeldungen: Negativ: 1 Eintrag nicht vorhanden,aber kein Platz mehr für weitere. Carry: 0 Eintrag vorgenommen 1 Eintrag schon vorhanden --------- DIE INIT-ROUTINE --------- Diese Routine wird nach jedem Warmstart aufgerufen und sollte folgende Dinge erledigen: - Das Peripheriegerät initialisieren (z.B. RESET setzen etc.), - interne Buffer und Zeiger einstellen ------ DIE EINZELNEN ROUTINEN ------- Von der CIO werden beim Aufrufen der sechs Unterprogramme folgende Parameter übergeben: Enthält die Kanal-Nummer * 16 Enthält den Wert $92, also die Fehlernummer für 'Funktion nicht möglich'. Der Vektor nicht unter- stützter Routinen muß also nur mit einem RTS enden. Bei der PUTBYTE-Routine ist das auszugebende Byte im Akku. Außerdem wird der betroffene IOCB-Block von der CIO in die Zero-Page kopiert, so daß man nicht mit den Indizes hantieren muß. $20 ICHIDZ (=Gerätenamenindex in Tab.) $21 ICDNOZ (=Gerätenummer) $22 ICCOMZ = ICCOM $23 ICSTAZ = ICSTA $24,$25 ICBAZ = ICBADR $26,$27 ICPTZ (=ICPUT) $28,$29 ICBLZ = ICBLEN $2A,$2B ICAX1Z,ICAX2Z = ICAUX1,ICAUX2 $2C,$2D ICSPRZ = ICAUX3-4 $2E ICIDNO Kanal*16 Nach erfolgreichem Ausführen der Funktion sollte man im -Register eine "1" zurückmelden, was einem "OK" entspricht. Fehlerwerte sind größer als 127. Es wäre nicht schlecht, wenn diese dann auch mit den üblichen Nummern gleich sind. Doch nun zu den sechs Unterroutinen: --- OPEN Dabei stellt die CIO (siehe oben) Informationen wie Gerätenummer, Adresse der Dateispezifikation und Aux-Register zur Verfügung. --- CLOSE Diese Routine sollte z.B. in Zwischen- Buffern stehende Bytes absenden oder die Datei in der Directory installieren etc. (Die CIO gibt den Kanal auch dann frei, wenn im Y-Reg ein Error zurückgemeldet wird.) --- GETBYTE Die CIO ruft diese Routine nach einem GET RECORD- oder GET CHARACTERS (BGET)- Befehl auf und prüft vorher selbst, ob der Kanal schon offen war. Diese Routine muß nun dafür sorgen, daß ein Byte eingelesen wird, entweder direkt vom Gerät oder aus einen Zwischenpuffer (catch-Speicher). Das eingelesene Byte muß bei Rückkehr im Akku stehen. Es wäre außerdem nicht schlecht, wenn der Treiber im Falle von längeren Warteschleifen die Break- Taste abfragt und bei Drücken einen Error $80 melden. --- PUTBYTE Nach einem PUT RECORD- oder BPUT-Befehl geht diese Routine an die Arbeit. Auch hier sorgt die CIO für eine Fehler- meldung, wenn der IOCB noch nicht geöffnet war. Das zu übertragene Byte wird im Akku geliefert, von wo es entweder in einen Zwischenspeicher oder direkt an das Gerät weitergeleitet werden sollte. (Es ist klar, daß alle Zwischenspeicher von der Routine selbst verwaltet werden müssen.) Doch bei der PUTBYTE- Routine gibt es noch ein Problem: Sie darf nicht mit den Zeropage-Registern arbeiten! (im -Reg liegt bei Aufruf ja der Index.) Denn nach Öffnen eines Kanals überträgt die CIO die Adresse der PUTBYTE-Routine in das ICPUT-Register $346,$347. Manche Programme, wie z.B. ATARI-BASIC rufen nun verbotenerweise die Routine selbst direkt auf. Da die CIO dabei nicht im Spiel ist, werden auch keine Regs in die Zeropage kopiert. Außerdem muß die Routine vorher noch prüfen, ob der Kanal überhaupt schon offen ist (wenn nicht ist in ICCOM noch der CLOSE- Befehl). --- GETSTAT Diese Routine wird bei einem Status- Befehl aufgerufen und sollte 4 Bytes mit Statusinformationen ab DVSTAT $2EA einschreiben. Es kann sein, daß bei Aufruf der Kanal noch nicht geöffnet ist... --- SPECIAL An diese Routine wendet sich die CIO immer dann, wenn ein Befehl auftritt, der einen größeren Wert als 13 enthält. Beispiele sind z.B. PLOT,DRAW,DELETE... Es kann sein, daß bei Aufruf der Kanal noch nicht geöffnet ist (Implied open), falls dies Auswirkungen hat, muß das Programm sich selbst darum kümmern. Die SPECIAL-Routine muß anhand von ICCOM(Z) selbstständig zu den einzelnen Unterprogrammen verzweigen. --- FEHLERBEHANDLUNG Die CIO fängt alle logischen Fehler ab, der Treiber muß sich also nur noch um Sachen wie - BREAK-Taste - Dateienende - unbekannte Befehle kümmern und Meldungen im Y-Reg zurück- melden (bei den Geräten, die über die SIO arbeiten, meldet die SIO dann ja selbst die anderen Fehler). --- DIE TREIBER DES BETRIEBSSYSTEM Wie vorhin schon angesprochen, hat das OS selbst schon einige Treiber eingebaut. Diese haben natürlich auch Treibertabellen, deren Adressen von ATARI für spätere Versionen garantiert ist: Bildschirmeditor E: $E400 EDITRV Bildschirmtreiber S: $E410 SCRENV Tastaturtreiber K: $E420 KEYBDV Druckertreiber P: $E430 PRINTV Cassettentreiber C: $E440 CASETV Somit muß man diese(!) Treiber nicht unbedingt über die CIO aufrufen, sondern kann die Routinen auch direkt benutzen. Beispiel zur Öffnung eines Bildschirms in Graphics 24: ICAUX1=Lesen/Schreiben/Fenster ICAUX2=Graphikmode 00010 SCRENV=$E410 00020 ICAX1Z=$2A 00030 ICAX2Z=$2B 00040 ICIDNO=$2E 00050 RAMTOP=106 00060 00070 START JSR OPENGR8 00080 .1 JMP .1 00090 00100 OPENGR8 LDA RAMTOP Platz 00110 SEC schaffen 00120 SBC #$1E 00130 STA RAMTOP 00140 LDA #$8 00150 STA ICAX2Z 00160 LDA #12 read+write 00170 STA ICAX1Z 00171 LDA #$60 00172 STA ICIDNO 00180 00190 LDA SCRENV+1 00200 PHA 00210 LDA SCRENV 00220 PHA 00230 RTS 00240 Am Anfang muß man erstmal 7680 ($1E00) Bytes Platz schaffen. Nach einmaligem Aufruf der Routine würde ich immer wieder RESET drücken, da ja jedesmal Platz gemacht wird (nacher platzt's). Dann schiebt die Routine- wie die CIO- die Adresse-1 auf den Stack und führt einen RTS aus. Noch ein Beispiel: Eine Taste einlesen: 00010 KEYBDV=$E420 00020 00030 START JSR GETK 00040 CMP #27 ESC 00050 BNE START 00060 RTS 00070 00080 GETK LDA KEYBDV+4+1 00090 PHA 00100 LDA KEYBDV+4 00110 PHA 00120 RTS 00130 --- EINSATZBEISPIELE FÜR TREIBER Tja, was kann man machen, es gibt ja schon so viele? z.B. - Window-Treiber (ich kenne schon drei,einer auch für Graphics 8, allerdings einen Tick zu langsam, die anderen für Textwindows) - 80-Zeichen-Bildschirmtreiber (gibt's auch schon) - etc... - Änderung vorhandener Treiber (z.B. könnte man die PUTBYTE- Routine des Druckertreibers so ändern, daß Epson-Steuercodes in 1029-Codes gewandelt werden,oder eine Seitennumerierung hinzuge- fügt wird) Ein Beispielprogramm auf Disk gibt's diesmal nicht, da ich momentan im Clinch mit der Zeit liege (das Schul- halbjahr ist hier kürzer denn je, somit kommen pro Woche 2-3 Klausuren...). Wer mir schreiben möchte, kann dies gerne tun. (Allgemein ohne Rückporto, doch bei schweren Sachen wie Disks etc. wäre ich darüber nicht traurig.) Tim-Philipp Müller Forsthöhe 8 2100 Hamburg 92 Good Byte bis zum nächsten Mal!