---------------------------------------- Floppy-Kurs "Es rappelt in der Kiste..." (Teil 9) ----------------------------------------
Herzlich Willkommen zum neunten und letzten Teil des Floppy-Kurses. In den vorangehenden Folgen haben wir einiges über den Aufbau von Disketten und das Ansprechen der Floppy gelernt. Ich möch- te diesen Kurs nun mit einem anspruchs- vollen Programmbeispiel abschließen, das wir uns im Laufe der heutigen Folge erarbeiten wollen. Es dient als Beispiel für die Programmierung der Floppy in Assembler und gleichzeitig auch als Bei- spiel für das was möglich ist, wenn eine Diskette richtig manipuliert wird. DIE AUFGABE Sicherlich kennen Sie das Problem: Sie sind gerade dabei Ihre Diskettensammlung aufzuräumen und Ihre Programme so umzu- kopieren, daß jede Diskette optimale Platzausnutzung aufweisen soll. Am Be- sten so, daß restlos jeder Block dieser Diskette beschrieben ist. Beim Zusam- menstellen bleiben dann aber noch noch 17 Blocks übrig - Mist, kein Platz mehr für das letzte, 30 Blocks lange Pro- gramm! Was tun? Im Prinzip bleiben Ihnen nur die folgenden Möglichkeiten: 1) Sie fangen nochmal von vorne an (Gähn - Kopieren dauert lange). 2) Sie belassen alles, wie es ist (Är- gerlich - 17 Blocks verschenkt). 3) Sie packen das letzte Programm (Wie- der Gähn - dauert auch lange und aus- serdem hat das File hinterher be- stimmt genau 18 Blocks, so daß es doch nicht passt). 4) Sie benutzen das Programm "USEDIR", das wir uns in diesem Kursteil erar- beiten wollen. Nun werden Sie fragen: "Na schön, und wie will dieses Programm nun 13 weitere Blocks freibekommen, wenn die Diskette voll ist?". Ganz einfach: aus dem Direc- tory. "USEDIR" nimmt sich die Tatsache zunutze, daß der Track 18, in dem das Directory einer Diskette steht, nicht für normale Files zur Verfügung steht. Er ist lediglich für die Fileeinträge reserviert. In jedem der 18 Fileein- tragsblocks (Sektoren 1-18, 0 ist für DiskHeader und BAM reserviert) können nun 8 Einträge stehen, was einer maximal mögliche Anzahl von 144 Einträgen ent- spricht. Da eine normale Diskette aber so gut wie nie so viele Files beher- bergt, liegen eine Menge dieser Direc- toryblocks brach. Gerade bei einer rand- vollen Diskette werden sie bis in alle Ewigkeit unbenutzt bleiben, da ja keine neuen Files mehr hinzukommen können. Im günstigsten Fall, nämlich dann, wenn Sie weniger als 9 Files auf der Diskette haben, sind das 17 Blocks, die noch zusätzlich frei sind! Diese Blocks soll UseDir nun einfach als Datenblocks verwenden. Es muß lediglich einen Fileeintrag kreieren, in dem der Zeiger für den ersten Track und Sektor auf einen der unbenutzten DirBlocks zeigt. Wird dieses File dann geladen, so greift das DOS der Floppy schön brav auf diese sonst ungenutzten Blocks zu, so als gäbe es keinen Unterschied. Tatsäch- lich hat die Diskette dann jedoch 683 Blocks (maximal) anstelle von nur 664! DIE THEORIE Was muß unser Programm nun tun, um ein File auf die oben beschriebene Weise umzukopieren. Zunächst einmal wollen wir hier eine Einschränkung vereinbaren, die uns die Arbeit erleichtern soll: ein File, das auf diese Weise installiert werden soll, muß länger sein, als es freie Directoryblöcke gibt. Daraus er- gibt sich natürlich, daß die Diskette mindestens noch einen 'normalen', freien Datenblock hat. Das zu installierende File muß desweiteren natürlich kleiner, oder gleich lang der insgesamt verfügba- ren Blöcke sein und sollte vom Typ "PRG" sein. Daraus ergeben sich folgende Auf- gaben für unser Programm: 1) Das zu installierende File einlesen und benötigte Anzahl von Blöcken er- mitteln. 2) Anzahl der freien Blöcke der Zieldis- kette ermitteln. 3) Anzahl der freien Directoryblöcke der Zieldiskette ermitteln. 4) Vergleichen, ob das File den obig gegebenen Restriktionen entspricht und ob noch genügend Platz auf der Zieldiskette ist. 5) Wenn ja, dann weiter, sonst abbre- chen. 6) Nun muß berechnet werden, wieviele Bytes in den Directoryblocks Platz haben. Alles restliche wird anschlie- ßend, als normales File, mit Hilfe der WriteFile-Routine aus dem vor- letzten Kursteil auf die Diskette geschrieben. 7) Jetzt suchen wir den Fileeintrag des soeben gespeicherten Files aus den Directoryblocks heraus und Lesen die Informaton für den ersten Track und Sektor aus dem Eintrag aus. 8) Diese Information wird sogleich in die Track- und Sektornummer des er- sten freien Directoryblocks abgeän- dert. 9) Jetzt müssen wir nur noch die fehlen- den Directoryblocks schreiben und den letzten Directoryblock auf den ersten Track/Sektor des geschriebenen Files zeigen lassen - Fertig ist die In- stallation!
DIE BENÜTIGTEN PROGRAMMTEILE
Kommen wir nun also zu unserem Programm. Dabei möchte ich Ihnen zunächst einmal eine Liste der darin enthaltenen Routi- nen geben. Hierbei habe ich in zwei Ar- ten unterschieden: in Steuer- und IO- Routinen. Diese beiden Namen treffen Ihre Bedeutung zwar nicht voll und ganz, jedoch musste irgendwo eine Grenze gezo- gen werden. Die erste Art, die Steuerroutinen also, sind alles Funktionen, die entweder nichts direkt mit der Floppy zu tun ha- ben, und somit für uns uninteressant sind, oder aber Funktionen, die wir in vorangegangenen Kursteilen schon bespro- chen hatten, und somit nicht noch einer zweiten Dokumentation bedürfen. All die- se Routinen werden nur mit ihrem Namen, ihrer Funktion und ihren Parametern auf- geführt, damit Sie wissen, wozu sie da sind, und wie man sie benutzt. Die zweite Art von Routinen sind größ- tenteils Floppy-Routinen, die eine Be- schreibung benötigen und im Laufe dieses Kursteils alle nocheinmal genauer doku- mentiert sind. Desweiteren werden diverse Speicherzel- len als Zwischenspeicher für verschie- dentliche Werte benutzt. Diese haben, der besseren Öbersichlichkeit wegen, richtige Namen, und können im Prinzip überall im Speicher stehen. Dennoch will ich die von mir benutzten Speicherzellen hier einmal aufführen. Sie liegen, bis auf einige Außnahmen, im Speicherbereich von $0332-$03FF, dem Kasettenpuffer al- so, der bei Floppybenutzung ja unbe- nutzt, und deshalb verwendbar ist. Hier nun also die besprochenen Beschreibun- gen:
1) BENUTZTE SPEICHERZELLEN: * MEM0-MEM4 Die fünf Zeropageadressen von $02 bis $06. Sie werden für die Zwischenspei- cherung verschiedenster Ergebnisse herangezogen. * FILEMEM ($0F00) Dies ist die Anfangsadresse des Spei- chers, in den das zu installierende Programm geladen wird. * NUMBUFF ($0332) Hier wird der ASCII-String einer Kon- vertierten Zahl abgelegt (maximal 5 Zeichen). * NEED ($0337) Zwischenspeicher für die Länge des gelesenen Files in Blocks. * DSKFREE ($0338/$0339) Speicher für die Anzahl der freien Blocks der Zieldiskette. * ALLFREE ($033A/$033B) Anzahl der insgesamt (inkl. freie Dir- blocks) auf der Zieldiskette verfügba- ren Blocks. * DIRFREE ($033C) Anzahl der freien Directoryblocks * DIRSTRT ($033D) Sektornummer des ersten freien Direc- toryblocks. * FTRACK ($033E) Tracknummer des ersten, vom normal geschriebenen File benutzten, Daten- blocks. * FSECTOR ($033F) Sektornummer des ersten, vom normal geschriebenen File benutzten, Daten- blocks. * DSINDEX ($0340) Indexzeiger auf den aktuellen Eintrag der Dirblockliste. * COMBUFF ($0341-) Zwischenspeicher für Befehle, die an die Floppy gesandt werden sollen. * NAME Dieses Label beszeichnet die Starta- dresse, des 17 Zeichen langen Zwi- schenspeichers für Filenamen. Dieser befindet sich direkt im Sourcecode. 2) STEUERROUTINEN
* GETIN: Diese Funktion verlangt keine Parameter. Sie liest mit Hilfe der BASIN-Routine des Betriebssystems ei- nen maximal 16 Zeichen langen String von der Tastatur ein und wird zum Ein- geben des Filenamens benutzt. Dieser String liegt nach dem Rücksprung ab der Adresse NAME. Die Länge des File- namens steht in der Speicherzelle MEM0. Am Ende des Namensstring wird ein Nullbyte als Endmarkierung an- gefügt. * STROUT: Diese Routine gibt einen AS- CII-Text auf dem Bildschirm aus. Lo/- Hi-Byte der Textadresse müssen in Akku und Y-Register übergeben werden. Der Text muß mit einem Nullbyte enden. * OPENCOM: Diese Routine öffnet den Be- fehlskanal mit der logischen Filenum- mer 1. Beim Üffnen wird die Diskette automatisch initialisiert (Floppybe- fehl "I") * OPENIO: Hier wird der Befehlskanal mit der Filenummer 1 (wie OPENCOM) und ein Pufferkanal mit der Filenummer 2 (und Sekundäradresse 2) geöffet. * RFILE: Dies ist die "ReadFile"-Routine aus dem letzten Kursteil. Sie liest das File, dessen Namen bei NAME steht und dessen Namenslänge in MEM0 abge- legt ist, an die Adresse FILEMEM. Sie benutzt die Zeropageadressen $F9/$FA als Lesezeiger. Hier steht nach dem Rücksprung gleichzeitig auch die Enda- dresse des gelesenen Files. * WFILE: Schreibt das File in NAME und MEM0 auf Diskette. Die Startadresse des zu speichernden Bereichs muß dabei in den beiden Zeropageadressen $FD/$FE, die Endadresse in $F9/$FA stehen. * STATOUT: Gibt die ermittelten Werte für "Anzahl benötigte Blocks", "Freie DirBlocks", und "Freie Diskblocks" auf dem Bildschirm aus.
3) IO-ROUTINEN: * STRIEC: Wie "STROUT", nur daß diesmal
ein String auf den IEC-Bus (also an die Floppy) ausgegeben wird. * SENDCOM: Da wir zur Erfüllung unserer Aufgabe immer nur Floppybefehle benö- tigen, die aus einem festen String und einer angehängten, variablen Zahl be- stehen, wird diese Routine benutzt, um einen Befehl, dessen String an der Adresse in X- und Y-Register steht und dessen abschließende Nummer im Akku übergeben wurde, an die Floppy zu sen- den. * WDUMMY: Diese Routinelegt auf der Zieldiskette ein File mit dem Namen in NAME und MEM0 an und löscht es direkt wieder. Wozu dies notwendig ist, wer- den wir später sehen. * GETDSKF: Ermittelt die Anzahl der freien Blocks der Zieldiskette und legt sie in DSKFREE ab. * GETDIRF: Ermittelt die Anzahl der freien Directoryblocks der Zieldisket- te und legt sie in DIRFREE ab. Deswei- teren wird die Summe von DSKFREE und DIRFREE berechnet und in ALLFREE abge- legt. * GETNEED: Berechnet die benötigte An- zahl Blöcke des zuvor eingelesenen Files und legt Sie bei "NEED" ab. * CHGENT: Diese Routine sucht den File- namen in NAME aus dem Directory he- raus, liest die Nummern des ersten Tracks und Sektors dieses Files ein, und überschreibt diese beiden Informa- tionen mit den Werten für den ersten freien Directoryblock. * WBLOCKS: Diese Routine schreibt alle fehlenden Blocks des Files in die freien Directoryblocks und gibt im letzten dieser Blocks Track- und Sek- tornummer des ersten Datenblocks des 'normal' gespeicherten Files an. DIE PRAXIS Nach all der trockenen Theorie wollen wir nun endlich zur Praxis schreiten. Beginnen möchte ich mit der Steuerrouti- ne 'MAIN' unseres Programms, in der das oben aufgeführte Aufgabenschema in Pro- grammcode umgesetzt ist. Anschließend wollen wir uns mit den benutzten Unter- routinen beschäftigen. 1) MAIN Diese Routine steuert das gesamte Pro- gramm. Zunächst einmal wollen wir die Bildschirmfarben setzen, den Titeltext ausgeben und den Namen des zu installie- renden Files ermitteln. Ist dieser Name gleich dem String X", so soll das Pro- gramm mit einem RESET verlassen werden:
main lda #11 ;Bildschirm- sta 53280 ;farben sta 53281 ;setzen. lda #<(text1) ;Titeltext ldy #>(text1) ;auf Bildschirm jsr strout ;ausgeben. jsr getin ;Und Filename einlesen. cpy #1 ;Vergleichen, ob bne m3 ;der Name="X" lda #"x" ;ist. cmp name ;Wenn nein, dann bne m3 ;weitermachen. jmp 64738 ;Sonst: RESET.
Als Nächstes müssen wir das File lesen und seine Blocklänge berechnen. Hierauf- hin wird der Benutzer dazu aufgefordert, die Zieldiskette einzulegen, von der wir dann die Anzahl der freien Dir- und Diskblocks ermitteln. Gleichzeitig wird dann auch noch das Dummyfile erzeugt. Am Ende werden alle ermittelten Werte mit- tels der Routine STATOUT auf dem Bild- schirm ausgegeben:
m3 jsr rfile ;File einlesen jsr getneed ;Anzahl der benö- tigten Blocks berechnen lda #<(text2) ;"Zieldisk ein- ldy #>(text2) ;legen" jsr strout ;ausgeben und mloop1 jsr inkey ;auf Tastendruck beq mloop1 ;warten. lda #<(text3) ;"Untersuche ldy #>(text3) ;Zieldisk" jsr strout ;ausgeben. jsr wdummy ;Dummy-File anle- gen und löschen. jsr openio ;Kanäle öffnen jsr getdskf ;Freie Diskblocks ermitteln jsr getdirf ;Freie Dirblocks ermitteln. jsr closeio ;Kanäle schließen jsr statout ;Werte ausgeben.
Nachdem nun all diese Dinge getan sind, müssen wir nun erst einmal prüfen, ob das gelesene File und die Daten der Zieldiskette es uns ermöglichen, das File auf die Diskette zu schreiben. Hierbei wird abgebrochen, wenn keine Dirblocks mehr frei sind, das File kür- zer als die noch verfügbaren Dirblocks, oder länger als die gesamt verfügbaren Blocks ist:
lda dirfree ;DirFree lesen bne m1 ;wenn<>0, weiter. lda #<(errtxt1) ;Sonst "Kein Dir- ldy #>(errtxt1) ;blk mehr frei" jmp errout ;ausg. u. Ende. m1 cmp need ;DirFree mit NEED bcc m2 ;vergleichen. lda #<(errtxt2) ;Wenn >, dann ldy #>(errtxt2) ;"File zu kurz" jmp errout ;ausg. u. Ende. m2 ldy allfree+1 ;Hi-Byte ALLFREE lesen. bne ok ;Wenn <>0, dann genug Platz. lda allfree+0 ;Sonst Lo-Byte lesen cmp need ;u. m. NEED vgl. bcs ok ;Wenn >, Ok. lda #<(errtxt3) ;Sonst "File zu ldy #>(errtxt3) ;lang" aus- jmp errout ;geben
Wurden all diese Vergleiche erfolgreich bestanden, so kann das File installiert werden. Hierzu müssen zunächst einige Vorbereitungen getroffen werden: Als erstes sollten wir die Sektornummer des ersten freien Directoryblocks ermitteln. Dies ginge natürlich dadurch, indem wir die BAM einlesen würden, und uns einen unbelegten Block als Startblock heraus- suchen würden. Es geht aber noch viel einfacher: das DOS der Floppy beschreibt die Sektoren einer Diskette nämlich mei- stens in einer ganz bestimmten Reihen- folge. Das ist bei den normalen Daten- blocks nicht unbedingt gesichert, da bei einer nahezu vollen Diskette diese Rei- henfolge nicht mehr eingehalten werden kann. Beim Directorytrack 18 können wir uns jedoch mit 100%-iger Sicherheit da- rauf verlassen, daß sie immer eingehal- ten wird. So gibt es nämlich eine ganz bestimmte Reihenfolge, in der die Direc- torytracks geschrieben werden. Wir müs- sen lediglich wissen, wieviele Blocks benutzt sind, und uns die Sektornummer des nächsten Blocks aus einer Tabelle zu holen. Dies ist dann automatisch der erste leere Dirblock. Die angesprochene Tabelle ist bei dem Label "BLKTAB" abge- legt, und beinhaltet die folgenden Werte für Sektornummern:
BLKTAB .byte 0,1,4,7,10,13,16 .byte 2,5,8,11,14,17 .byte 3,6,9,12,15,18,$ff
Bitte nun Teil 2 des Floppy-Kurses laden