Directory auf Knopfdruck
Häufig steht man vor dem Problem, Programme direkt, also ohne SYS-Aufrufe, über einen Tastencode zu aktivieren. Wir zeigen Ihnen, wie man ein Directory auf dem Bildschirm ausgibt, ohne ein vorhandenes Basic-Programm zu zerstören.
Das Programm »Directory auf Knopfdruck« (siehe Listing 1) kann, nachdem es mit Hypra-Assassembliert wurde, mit dem Befehl SYS 49152 aktiviert werden.
Den erzeugten Maschinencode zeigt Listing 2, das auch direkt mit dem MSE eingegeben werden kann. Solange kein Reset ausgelöst oder die RUN/STOP-Taste gedrückt wird, erscheint bei der Tastenkombination »CTRL-D« das Directory auf dem Bildschirm, ohne ein eventuell im RAM stehendes Basic-Programm zu zerstören.
Der hier vorgestellte Lösungsweg, ein beliebiges Programm auf Tastendruck aufzurufen, hat den Vorteil, daß er allgemeingültig ist und nicht nur auf die Ausgabe des Directorys beschränkt ist.
Im allgemeinen müßte das Betriebssystem geändert werden, um eine zusätzliche Tastaturabfrage einzubinden. Aber wir haben Glück, denn einige Routinen im Betriebssystem werden über einen sogenannten Sprungvektor aufgerufen. Alle zugänglichen Sprungvektoren, die sich ändern lassen, befinden sich in der dritten Page, also im Bereich von $311 bis $333, jeweils im Low-/High-Byte-Format. Der zum Einbinden einer Tastaturabfrage geeignetste Vektor ist der Interruptvektor, denn diese sogenannte Interrupt-Routine wird 60mal pro Sekunde angesprungen. Ein Sprungvektor, der in diese Routine verzweigt, befindet sich in den Speicherzellen $314/$315. Die Speicherzellen enthalten im Normalzustand den Wert $31/$EA. Das bedeutet, daß immer, wenn ein Interrupt ausgelöst wird, zu einer Routine verzweigt wird, die bei $EA31 liegt. Schreibt man nun in die Speicherzellen $314/ $315 einen anderen Wert, wird bei einem Interrupt nicht mehr zur Adresse $EA31, sondern zu der Adresse verzweigt, die in den Speicherzellen $314/315 steht, wobei die Adresse $314das Low- und die Speicherzelle $315 das High-Byte der anzuspringenden, neuen Interrupt-Routine enthält. Damit sich der Vektor aber verändern läßt, muß zuerst der normale Interrupt gesperrt werden, denn sonst könnte folgendes passieren: Angenommen, es wird ein Interrupt ausgelöst, nachdem erst das Low-Byte in die Adresse $314 geschrieben wurde, dann nimmt der Computer an, daß die neue Interrupt-Routine bei $EAOO plus dem in Adresse $314 stehendem Low-Byte liegt, verzweigt an diese Adresse und stürzt ab.
Mit dem Maschinenbefehl »SEI« für SEt Interruptflag läßt sich nun der prozessorinterne Interrupt ausschalten. Dies wird in der Zeile 230 im Listing 1 realisiert. Die Zeilen 240 bis 270 sorgen dafür, daß die Startadresse der neuen Interrupt-Routine in die entsprechenden Adressen kommt. Eine Bemerkung noch zu den Zeilen 240 und 270. Durch das »kleiner«- beziehungsweise »größer«-Zeichen läßt sich eine 16-Bit-Adresse (in diesem Fall »INTER«) in zwei 8-Bit-Zahlen splitten. Durch das »kleiner«-Zeichen erhält man das Low- und entsprechend für das »größer«-Zeichen das High-Byte.
Der folgende »CLI«-Befehl (CLear Interruptflag) läßt nun den normalen Interrupt wieder zu. Nur wird jetzt, wenn ein Interruptstattfindet, nicht mehr zur Adresse $EA31, sondern zur Routine »INTER« verzweigt. Die Aufgabe des Teilprogramms »INTER« ist es, die »CTRL«- und »D«-Taste abzufragen. Sind beide Tasten gleichzeitig gedrückt, wird nach »DIR« verzweigt, ansonsten in der Zeile 420 zum normalen Interrupt nach $EA31. Die Zeilen 370 und 380 beziehungsweise 400 und 410 sperren auch den Interrupt, aber auf eine etwas andere Art.
Sie werden sich vielleicht fragen, warum der Interrupt überhaupt gesperrt werden muß. Die Antwort auf diese Frage ist leicht zu geben. Die Bearbeitung der Routine »DIR« dauert länger als 1/60 Sekunde. Dadurch würde bereits ein neuer Interrupt ausgelöst, bevorderalteabgearbeitetwäre. Die Art, wie der Interrupt abgeschaltet wird, wurde mit Absicht so gewählt, da einige Routinen im Betriebssystem den Interrupt durch den CLI-Befehl wieder zulassen, so auch die Routine »CHROUT«, die ein Zeichen auf einem Gerät, hier dem Bildschirm, ausgibt. Durch die Befehle »LDA #TIMERAUS« und »STA ICR« wird eigentlich nicht der Interrupt abgeschaltet, sondern der Timer gestoppt, der den Interrupt auslöst. Doch nun zum eigentlichen »DIR«-Programm.
Die Zeilen 450 bis 550 entsprechen dem Basic-Befehl »OPEN 1,8,0,"$"«. Dabei liegt das Augenmerk auf der Sekundäradresse »0« und dem Dollarzeichen. Das Dollarzeichen als Filename bewirkt, daß das Directory eingelesen wird und zwar einschließlich Track 18 Sektor 0. Durch die »0« als Sekundäradresse wird das Directory schon soweit aufbereitet, daß nur noch die Zeichen, die sich nach einem »LOAD"$",8« tatsächlich im RAM befinden, zum Computer gesendet werden, inklusive Filetyp, Steuerzeichen, Leerzeichen und Anzahl der Blöcke pro File. Leider enthält ein vom Floppy-Laufwerk gesendeter Directory-Eintrag auch noch Platzhalter für die Zeilenlinkadressen, die wir natürlich nicht brauchen und folglich ausblenden beziehungsweise überlesen müssen. Eine vom Floppy-Laufwerk gesendete Directory-Zeile hat folgendes Format:
LI LI AB SP "filename SP" SP FT
LI = Linkbyte; AB = Anzahl der Blöcke pro File im Low/ High-Byte-Format; SP = Leerzeichen; FT = Filetyp im Klartext.
Das einzige, was zu tun bleibt, ist die Ausgabe »RETURN« am Ende jeder Directory-Zeile (Zeile 811/812). Außerdem muß die Information, die die Anzahl der Blöcke pro File enthält, in dezimale Schreibweise umgerechnet und auf dem Bildschirm ausgegeben werden. Das ist aber kein Problem, denn das Betriebssystem stellt eine solche Routine »INTOUT=$BDCD« zur Verfügung. Wenn sie aufgerufen wird, muß der Akku das High- und das X-Register das Low-Byte der auszugebenden Zahl enthalten. Das Low-Byte wird in Zeile 590 an das X-Register übergeben. Das High-Byte dagegen wird in Zeile 630 durch das Unterprogramm »CHRIN« eingelesen und steht automatisch im Akku.
Zum Programmablauf
Die Zeilen 570 bis 620 überlesen 4 Byte beim ersten Durchlauf. Bei allen weiteren Durchläufen werden immer nur die ersten 2 Byte überlesen, die die Zeilenlinkadresse enthalten. Beim ersten Durchlauf wird neben der Zeilenlinkadresse auch die Startadresse ($0801) gesendet, die ebenfalls ausgeblendet werden muß, darum 4 Byte. Bei einem Sprung auf das Label »ROWOUT« enthält das Y-Register die Anzahl der Byte, die überlesen werden sollen plus 1. Wird die Schleife in Zeile 620 verlassen, enthält das X-Register das Low-Byte der Zahl, die die Anzahl der Blöcke pro File kennzeichnet. Das High-Byte wird in Zeile 630 eingelesen und an den Akku übergeben. Die nächste Schleife, die bei dem Label »NEXTCHR« beginnt, gibt den Rest eines Directory-Eintrags auf dem Bildschirm aus. Der »CMP«-Befehl in Zeile 730 überprüft, ob eine »0«, die das Ende des Eintrags kennzeichnet, gesendet wurde oder nicht. Bei einer »0« wird nach »LASTCHR« verzweigt, ein »RETURN« ausgegeben und zum Label »ROWOUT« gesprungen.
(ah)10 -.EQ IRQVEKLO = $314 20 -.EQ IRQVEKHI = $315 30 -.EQ SHIFTFLAG = $28D 40 -.EQ TIMERAUS = $80 50 -.EQ TIMEREIN = 129 60 -.EQ ICR = $DC0E 70 -.EQ INTERRUPTALT = $EA31 80 -.EQ SETNAM = $FFBD 90 -.EQ SETLFS = $FFBA 100 -.EQ OPEN = $FFC0 110 -.EQ CHKIN = $FFC6 120 -.EQ CHRIN = $FFCF 130 -.EQ INTOUT = $BDCD 140 -.EQ CHROUT = $FFD2 150 -.EQ CLOSE = $FFC3 151 -.EQ CLRCHN = $FFCC 160 -.EQ STATUS = $90 170 -.EQ RETTEN = $FB 180 -.EQ TASTENCODE = $C5 190 -; 200 -; 210 -.BA $C000 220 -; 221 -;******************************** 222 -;* INTERRUPTVEKTOR NEU SETZEN * 223 -;******************************** 224 -; 230 - SEI 240 - LDA #<(INTER) 250 - STA IRQVEKLO 260 - LDA #>(INTER) 270 - STA IRQVEKHI 280 - CLI 290 - RTS 300 -; 301 -;******************************** 302 -;* NEUE INTERRUPTROUTINE * 303 -;******************************** 304 -; 310 -INTER LDA TASTENCODE 320 - CMP #18 ;IST DIE TASTE >>D<< GEDRUECKT? 330 - BNE INTERE ;WENN NEIN DANN ZUM NORMALEN INTERRUPT 340 - LDA SHIFTFLAG 350 - CMP #4 ;IST >>CTRL<< GEDRUECKT? 360 - BNE INTERE ;WENN NEIN DANN ZUM NORMALEN INTERRUPT 370 - LDA #TIMERAUS ;TIMER AUSSCHALTEN/INTERRUPT SPERREN 380 - STA ICR 390 - JSR DIR ;UND ZUM UNTERPROGRAMM DIR 400 - LDA #TIMEREIN ;TIMER EINSCHALTEN/INTERRUPT ZULASSEN 410 - STA ICR 420 -INTERE JMP INTERRUPTALT 430 -; 440 -; 441 -;******************************** 442 -;* DIRECTORY * 443 -;* AUSGEBEN * 444 -;******************************** 445 -; 450 -DIR LDA #1 ;LAENGE DES FILENAMENS 460 - LDY #>(NAME) 470 - LDX #<(NAME) 480 - JSR SETNAM ;FILENAMENPARAMETERSETZEN 490 - LDA #1 ;LOGISCHE FILENUMMER = 1 500 - LDX #8 ;GERAETEADRESSE = 8 510 - LDY #0 ;SEKUNDAERADRESSE = 0 520 - JSR SETLFS ;LOGISCHE FILENUMMER UND SEKUNDAERADR. SETZEN 530 - JSR OPEN 540 - LDX #1 ;LOGISCHE FILENUMMER 550 - JSR CHKIN ;EINGABEGERAET SETZEN 560 - LDY #5 ;DIE ERSTEN 5 ZEICHEN UEBERLESEN 570 -ROWOUT STY RETTEN 580 - JSR CHRIN ;EINGABE EINES ZEICHENS 590 - TAX ;LO-BYTE BLOCKANZAHL INS X-REGISTER 600 - LDY RETTEN 610 - DEY 620 - BNE ROWOUT 630 - JSR CHRIN ;HI-BYTE BLOCKANZAHL IN DEN AKKU 640 - LDY STATUS ;IST FILEENDE SCHON ERREICHT? 650 - BNE ENDE ;WENN JA DANN FERTIG 670 - JSR INTOUT ;ANZAHL DER BLOECKE AUSGEBEN (X/AKKU) 690 - LDA #" " ;BLANK AUSGEBEN 700 - JSR CHROUT 710 -NEXTCHR JSR CHRIN ;NAECHSTES ZEICHEN HOLEN 720 - STA RETTEN ;UND RETTEN 730 - CMP #0 ;IST FILEEINTRAG AUSGEGEBEN? 740 - BEQ LASTCHR ;WENN JA DANN RETURN AUSGEBEN 790 - LDA RETTEN ;ANSONSTEN MUSS NOCH DAS LETZTE ZEICHEN 800 - JSR CHROUT ;AUSGEGEBEN WERDEN 810 - JMP NEXTCHR 811 -LASTCHR LDA #13 ;>>RETURN<< AUSGEBEN 812 - JSR CHROUT 813 - LDY #$3 ;3 ZEICHEN UEBERLESEN 814 - JMP ROWOUT 820 -ENDE JSR CLRCHN ;EIN- UND AUSGABEKANAELE 830 - LDA #1 ;UND LOGISCHES FILE SCHLIESSEN 840 - JSR CLOSE 850 - RTS 860 -; 870 -NAME .TX "$"
PROGRAMM : DIREKTORY.OBJ C000 C087 ----------------------------------- C000 : 78 A9 0D 8D 14 03 A9 C0 C3 C008 : 8D 15 03 58 60 A5 C5 C9 CA C010 : 12 D0 14 AD 8D 02 C9 04 5D C018 : D0 0D A9 80 8D 0E DC 20 E6 C020 : 2A C0 A9 81 8D 0E DC 4C 9A C028 : 31 EA A9 01 A0 C0 A2 84 FC C030 : 20 BD FF A9 01 A2 08 A0 EA C038 : 00 20 BA FF 20 C0 FF A2 44 C040 : 01 20 C6 FF A0 05 84 FB 3F C048 : 20 CF FF AA A4 FB 88 D0 93 C050 : F5 20 CF FF A4 90 D0 23 A1 C058 : 20 CD BD A9 20 20 D2 FF 52 C060 : 20 CF FF 85 FB C9 00 F0 08 C068 : 08 A5 FB 20 D2 FF 4C 60 65 C070 : C0 A9 0D 20 D2 FF A0 03 02 C078 : 4C 46 C0 20 CC FF A9 01 91 C080 : 20 C3 FF 60 24 D8 1F 0A