Magic Disk 64

home to index to text: MD9302-KURSE-FLOPPY-KURS_9.2.txt

In dieser Reihenfolge werden die Blocks des Track 18 IMMER belegt. Der Wert $ FF am Ende der Liste steht hier als Endmarkierung der Liste, die später beim Beschreiben der Dirblocks von Bedeutung ist. Nun müssen wir erst einmal die Sektornummer des ersten freien Dirblocks ermitteln:

ok     lda #19         ;Von der Gesamt- 
                        sektorzahl (19) 
                        für Track 18    
       sec             ;die Anzahl der  
       sbc dirfree     ;freien Dirblocks
                        subtrahieren    
                        (=Anzahl belegte
                        Blocks) und als 
       tay             ;Index in Y-Reg. 
       lda blktab,y    ;Sektornr. lesen 
       sta dirstrt     ;und speichern.  
       sty dsindex     ;Index speichern 

Nun wollen wir das File auf der Zieldiskette anlegen. Hierzu schreiben wir es zunächst ganz normal mittels der WFILE-Routine. Hierbei sollen jedoch nur die Bytes geschrieben werden, die nicht mehr in die Dirblocks passen. Wir müssen nun also die Anfangsadresse des zu schreibenden Files berechnen. Da die ersten beiden Bytes eines Datenblocks immer als Zeiger auf den nächsten Datenblock dienen, müssen wir also den Wert DIR-FREE*254 zur FILEMEM-Adresse hinzuaddieren, um unsere Anfangsadresse zu erhalten:

       ldx dirfree     ;DIRFREE in X    
                        laden (=HiByte  
                        Startadr.).     
       txa             ;u. in Akku holen
       dex             ;HiByte-1        
       asl             ;Akku*2          
       eor #$ff        ;und invertieren 
       clc             ;mit             
       adc #1          ;Öbertrag.       
       adc #<(filemem) ;LoByte von      
       bcc m5          ;FILEMEM         
       inx             ;addieren.       
m5     sta $fd         ;unde ablegen    
       txa             ;HiByte holen    
       clc             ;und mit HiByte  
       adc #>(filemem) ;FILEMEM add.    
       sta $fe         ;u. ablegen      
       jsr wfile       ;File schreiben  

Nachdem die Anfangsadresse berechnet und in $ FD/$ FE abgelegt wurde, wird die WFI-LE- Routine aufgerufen. Die Endadresse muß in $ F9/$ FA stehen, wo sie noch von der RFILE-Routine enthalten ist ( wird von ihr als Lesezeiger verwedet) .
Ist das File nun geschrieben, so müssen wir nur noch seinen Fileeintrag aus dem Directory heraussuchen, Track und Sektor des ersten freien Dirblocks eintragen und die fehlenden DIRFREE*254 anfänglichen Bytes in den Dirblocks unterzubringen:

       jsr openio      ;Kanäle öffnen   
       jsr chgent      ;Eintrag suchen  
                        und ändern.     
       jsr wblocks     ;DirBlocks       
                        schreiben.      
       jsr closeio     ;Kanäle schließen

lda #<( text4) ;" File installldy #>( text4) ; liert"

errout jsr strout      ;ausgeben.       
eo1    jsr inkey       ;Auf Tastendruck 
       beq eo1         ;warten.         
       jmp main        ;Und neu starten 

Soviel also zu unserer Steuerroutine.
Kommen wir nun zu den Unterfunktionen:
2) STRIEC Diese Routine gibt einen Zeichenstring, dessen Adresse in Akku und Y-Register steht, an den Befehlskanal aus. Der String muß mit einem Nullbyte beendet sein:
striec sta $ fb ; Adresse in Zeisty $ fc ; ger ablegen.

         lda #8        ;Floppy auf      
         jsr listen    ;Befehlskanal    
         lda #$6f      ;empfangsbereit  
         jsr seclst    ;machen.         
         ldy #0        ;String lesen    
siloop1  lda ($fb),y   ;und senden.     
         bne si1                        
         lda #8        ;Floppy zurück-  
         jmp unlist    ;setzen u. Ende. 
si1      jsr iecout    ;Zeichen senden  
         iny           ;und Zeiger+1    
         bne siloop1                    
         inc $fc                        
         jmp siloop1                    

3) SENDCOM Diese Routine wird dazu verwandt, einen Floppybefehl zu senden. Hierbei unterscheidet sie sich jedoch von der Routine STRIEC. Es wird nämlich nicht nur der Zeiger des Befehls übergeben ( in X und Y-Register), sondern auch ein Wert im Akku, der vor dem Senden in ASCII umgewandelt und an den Befehlsstring in X/ Y angehängt wird. Der gesamte Befehl wird dabei bei COMBUFF abgelegt und dann mittels STRIEC an die Floppy gesandt:
sendcom pha ; Akku retten stx scloop1+1 ; Stringzeiger sty scloop1+2 ; setzen

        ldy #0         ;Und String      
scloop1 lda $c000,y    ;nach COMBUFF    
        beq sc1        ;umkopieren.     
        sta combuff,y                   
        iny                             
        jmp scloop1                     
sc1     sty mem0       ;Zeiger retten,  
        pla            ;Akku holen,     
        jsr i2a        ;konvertieren.   
        ldy mem0       ;Zeiger zurückh. 
        ldx #0         ;und in ASCII    
scloop2 lda numbuff,x  ;konvertierte    
        beq sc2        ;Zahl an COMBUFF 
        sta combuff,y  ;anhängen.       
        inx                             
        iny                             
        jmp scloop2                     
sc2     lda #13        ;CR anhängen     
        sta combuff,y                   
        iny                             
        lda #0         ;Endmarkierung   
        sta combuff,y  ;anhängen        

lda #<( combuff) ; und Inhalt von ldy #>( combuff) ; COMBUFF an jmp striec ; Floppy senden.
4) WDUMMY Kommen wir nun zur Routine " WDUMMY" . Wir sollten zunächst einmal klären, wozu sie benötigt wird. Wie Sie oben sahen, wird sie aufgerufen, noch BEVOR irgendendet- was anderes getan wird. Hierbei tut sie eigentlich nichts anderes, als ein File mit dem Namen in NAME und MEM0 auf der Zieldiskette anzulegen und gleich darauf wieder zu löschen. Das deshalb notwendig, um sicherzustellen, daß auch die richtige Anzahl an Dirblocks als ' belegt' gekennzeichnet ist. Sollten nämlich genau 8( oder 16,24, etc.) Files auf der Zieldiskette vorhanden sein, so kann es zu Problemen kommen. Beim Schreiben eines neuen Files muß das DOS dann nämlich einen neuen Dirblock hinzufügen, der ab dann nicht mehr zur Datenspeicherung benutzt werden kann. Damit es dabei keine Konfrontationen gibt, wird das File also sporadisch schon einmal angelegt und direkt danach wieder gelöscht.
Der neue DirBlock wird dann nicht wieder freigegeben. Der Eintrag bleibt nämlich erhalten, es wird lediglich der Filetyp ' DEL' an das Programm vergeben. Hier nun also die Routine:

wdummy   lda mem0      ;Filename        
         ldx #<(name)  ;in NAME         
         ldy #>(name)  ;und MEM0        
         jsr setnam    ;setzen.         
         lda #1        ;Fileparameter   
         ldx #8        ;"1,8,1" für     
         ldy #1        ;("PRG saven")   
         jsr setpar    ;setzen.         
         jsr open      ;File öffnen.    
         ldx #1        ;Kanal 1 als     
         jsr ckout     ;Ausgabefile     
         jsr bsout     ;Byte ausgeben.  
         jsr clrch     ;Standardkanäle  
                        zurücksetzen.   
         lda #1        ;File wieder     
         jsr close     ;schließen.      
         jsr opencom   ;Befehlskanal    
                        öffnen          
         lda #<(name-2);Name-2 als      
         ldy #>(name-2);Adresszeiger    
         jsr striec    ;senden.         
         lda #1        ;Befehlskanal    
         jmp close     ;schließen.      

Nun kann ich Ihnen auch den Grund zeigen, warum der Filename im Sourcecode abgelegt wird. Hier ist nämlich vor dem eigentlichen Namen auch noch der Text " S:" abgelegt. Wenn wir nun NAME-2 an STRIEC übergeben, so enspricht das einem Scratchbefehl für den Filenamen (" S: NA-ME") . Da STRIEC ein Nullbyte als Endmarkierung verlangt, wurde die GETIN-Routine so ausgelegt, daß sie nach dem letzten eingelesenen Zeichen ein solches Byte in den NAME-Puffer schreibt. Hier nun die Source-Definition des Filenamenspuffers. Für den Namen werden 17 Bytes reserviert, da ja maximal 16 Zeichen plus die Endmarkierung 0 vonnöten sind:
. text " s:" name . byte 0,0,0,0,0,0,0,0 . byte 0,0,0,0,0,0,0,0,0

5) GETNEED                              
Diese  Routine  wird benutzt, um die An-

zahl der vom Quellfile benötigten Blocks zu ermitteln. Hierbei wird zunächst die Startadresse des Filespeichers subtrahiert, um die effektive Länge in Bytes zu ermitteln. Hiernach wird das High-Byte mit zwei multipliziert. Dies ist nämlich die Anzahl Bytes, die Aufgrund des Wegfalls der ersten beiden Bytes eines Datenblocks zu der Anzahl Lo-Bytes addiert werden muß. Ist dieser Wert größer als 256, so wird ein Block mehr gebraucht. Jetzt wird noch die Anzahl der Low-Bytes hinzuaddiert. Gibt es auch hier einen Öberlauf, so muß wieder ein Block hinzuaddiert werden. Letztendlich muß wieder ein Block hinzugefügt werden, da die letzten Bytes, selbst wenn es weniger als 254 sind, dennoch einen ganzen Block belegen:

getneed ldx #0         ;NEED            
        stx need       ;löschen.        
        lda $f9        ;Endadr. d.      
                        Quellfiles (von 
        ldx $fa        ;RFILE noch da)  
                        lesen.          
        sec            ;und Startadresse
        sbc #<(filemem);subtrahieren.   
        bcs rf1        ;Ergebnis wird in
        dex            ;MEM1 (LoByte)   
rf1     sta mem1       ;und             
        txa            ;MEM2 (HiByte)   
        sec            ;abgelegt.       
        sbc #>(filemem)                 
        sta mem2                        
        rol            ;HiByte*2        
        bcc cn1        ;Wenn<256, weiter
        inc need       ;Sonst Blocks+1  
cn1     clc            ;LoByte addieren 
        adc mem1                        
        beq cn2                         
        bcc cn2                         
        inc need       ;Bei Öberlauf    
                        Blocks+1        
cn2     inc need       ;Und nochmal     
                        Blocks+1        
        lda mem2       ;Und Hi-Byte     
        clc            ;addieren.       
        adc need       ;und in NEED     
cn3     sta need       ;ablegen.        
        rts                             

6) GETDISKF Kommen wir nun zur Routine zum Feststellen der freien Blocks der Diskette. Dieser Wert ist normalerweise nicht direkt aus dem DiskHeaderBlock zu erfahren. Die einzige Möglichkeit wäre, die Blockbelegungen der einzelnen Tracks aus der BAM zu lesen und aufzusummieren. Aber auch hier wollen wir uns eines kleinen Tricks bedienen. Wird eine Diskette nämlich initialisiert ( was wir beim Üffnen des Befehlskanals schon tun), so liest die Floppy die BAM der Diskette automatisch ein und berechnet die Anzahl der freien Blocks von selbst. Diese Anzahl wird dann in den Bytes $02 FA ( Lo) und $02 FC ( Hi) des Floppyspeichers abgelegt. Was liegt also näher, als diesen Wert direkt, über den Memory-Read- Befehl der Floppy auszulesen. Und nichts anderes tut GETDISKF:

getdskf  lda #<(com5)  ;Memory-Read     
         ldy #>(com5)  ;Befehl          
         jsr striec    ;senden.         
         lda #8        ;Floppy sende-   
         jsr talk      ;bereit auf      
         lda #$6f      ;Befehlskanal    
         jsr sectlk    ;machen.         
         jsr iecin     ;Lo-Byte lesen   
         sta dskfree+0 ;und sichern.    
         jsr iecin     ;Byte überlesen. 
         jsr iecin     ;Hi-Byte lesen   
         sta dskfree+1 ;und sichern.    
         lda #8        ;Floppy zurück-  
         jmp untalk    ;setzen.         

Zusätzlich hierzu muß noch das entspre- chende Memory-Read- Kommando im Sourcetext abgelegt werden (3 Zeichen ab Adresse $02 FA lesen) :

com5     .text "m-r"                    
         .byte 250,2,3,13,0             

7) GETDIRF Nun kommen wir zur Routine zum Ermitteln der freien Directoryblocks. Hier können wir keinen Umweg gehen, sondern müssen die BAM direkt auslesen. Da das Directory ausschließlich in Block 18 steht, genügt es, das erste Byte des BAM-Eintrags für Track 18 auszulesen. Dieses Byte steht an Position 72 des DiskHeaderBlocks. Wir müssen also den Block 18/0 in den Puffer lesen, und den Pufferzeiger auf 72 setzen um an die gewünschte Information zu kommen.
Gleichzeitig berechnet diese Routine die Anzahl der insgesamt verfügbaren Blocks auf Diskette. Hierzu müssen wir lediglich den Inhalt von DSKFREE und DIRFREE addieren und in ALLFREE ablegen.

getdirf  lda #<(com6)  ;"Block 18/0     
         ldy #>(com6)  ;lesen"          
         jsr striec    ;senden.         
         lda #<(com7)  ;"Pufferzeiger   
         ldy #>(com7)  ;auf Byte 72"    
         jsr striec    ;senden.         
         lda #8        ;Floppy sende-   
         jsr talk      ;bereit auf      
         lda #$62      ;Pufferkanal     
         jsr sectlk    ;machen          
         jsr iecin     ;Wert lesen      
         sta dirfree   ;und sichern.    
         ldx dskfree+1 ;Hi-Byte lesen   
         clc           ;Lo-Byte zu      
         adc dskfree+0 ;DIRFREE         
         bcc gf1       ;addieren.       
         inx                            
gf1      sta allfree+0 ;und in ALLFREE  

stx allfree+1 ; ablegen.

         lda #8        ;und Floppy      
         jmp untalk    ;zurücksetzen.   

Auch hier benötigen wir zwei Sourcecodetexte für die Diskkommandos:

com6     .text "u1 2 0 18 0" ;Sekt. 18/0
         .byte 13,0          ;lesen     
com7     .text "b-p 2 72"    ;Pufferzgr.
         .byte 13,0          ;auf 72.   

8) CHGENT Kommen wir nun zu einer der wichtigsten Routinen unseres Programms. Sie durchsucht die Directoryblocks nach unserem Fileeintrag, liest aus ihm den Track/ Sektor des ersten ' normalen' Datenblocks aus und legt ihn in den Adressen FTRACK und FSEKTOR ab. Desweiteren wird hier dann Track und Sektor des ersten, freien Directoryblocks eingetragen und der Block wieder auf die Diskette zurückgeschrieben. Auch diese Routine benutzt die Sektorentabelle BLKTAB, um die Reihenfolge der Directroyblocks zu ermitteln. Desweiteren benötigt sie noch eine weitere Tabelle, in der die Anfangspositionen der einzelnen Fileeinträge eines Directoryblocks abgelegt sind. Diese Tabelle heißt ENTTAB und sieht folgendermaßen aus:

enttab   .byte 2,34,66,98,130,162       
         .byte 194,226                  

Kommen wir nun jedoch zur eigentlichen Routine. Sie besteht im Prinzip aus zwei ineinander verschachtelten Schleifen, die nacheinander die einzelnen Dirblocks einlesen und jeden einzelnen Eintrag mit dem Namen in NAME vergleichen. Wird der Name gefunden, so werden die Schleifen verlassen. Dann wird nochmals auf diesen Eintrag positioniert, und zwar so, daß der Bufferpointer direkt auf die zwei Bytes für Starttrack und - sektor zeigt und dort die Werte für den ersten freien Dirblock eingertragen ( Track 18, Sektor in DIRSTRT) . Abschließend wird dieser Directoryblock inklusive der Änderung wieder auf die Diskette zurückgeschrieben:

chgent   lda #<(text6) ;"Suche          
         ldy #>(text6) ;Eintrag"        
         jsr strout    ;ausgeben        
         lda #1        ;Blockzähler     
         sta mem1      ;initialisieren  
celoop1  lda #8        ;Floppy zurück-  
         jsr untalk    ;setzen.         
         ldy mem1      ;Blkzähler holen 
         lda blktab,y  ;Sekt.nr. lesen, 
         sta mem3      ;ablegen,        
         ldx #<(com1)  ;und Sektor lesen
         ldy #>(com1)                   
         jsr sendcom                    
         inc mem1      ;Blkzähler+1     
         lda #0        ;Eintragszähler  
         sta mem2      ;initialisieren  
celoop2  ldy mem2      ;Eintr.z. holen  
         cpy #8        ;Mit 8 vgl.      
         beq celoop1   ;Ja, also näch-  
                        sten Block lesen
         lda enttab,y  ;Nein, also Pos. 
                        lesen,          
         sta mem4      ;ablegen,        
         ldx #<(com2)  ;und Pufferzeiger
         ldy #>(com2)  ;positionieren.  
         jsr sendcom                    
         inc mem2      ;Eintr.z+1       
         lda #8        ;Floppy zum      
         jsr talk      ;Senden auf      
         lda #$62      ;Pufferkanal     
         jsr sectlk    ;bewegen.        
         jsr iecin     ;Filetyp holen.  
         cmp #$82      ;u.m. "PRG" vgl. 
         bne celoop2   ;Wenn <>, dann   
                        direkt weiter.  
         jsr iecin     ;Sonst Track     
         sta ftrack    ;und Sektor      
         jsr iecin     ;holen und ab-   
         sta fsector   ;legen.          

Bitte nun Teil 3 des Floppy-Kurses laden

Valid HTML 4.0 Transitional Valid CSS!