Magic Disk 64

home to index to html: MD9302-KURSE-FLOPPY-KURS_9.1.html
----------------------------------------
               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
Valid HTML 4.0 Transitional Valid CSS!