In dieser Reihenfolge werden die Blocks
des Track 18 IMMER belegt. Der Wert $FF
am Ende der Liste steht hier als Endmar-
kierung der Liste, die später beim Be-
schreiben der Dirblocks von Bedeutung
ist. Nun müssen wir erst einmal die Sek-
tornummer 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 Zieldis-
kette 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 schrei-
benden Files berechnen. Da die ersten
beiden Bytes eines Datenblocks immer als
Zeiger auf den nächsten Datenblock die-
nen, müssen wir also den Wert DIR-
FREE*254 zur FILEMEM-Adresse hinzuaddie-
ren, um unsere Anfangsadresse zu erhal-
ten:
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ängli-
chen Bytes in den Dirblocks unterzubrin-
gen:
jsr openio ;Kanäle öffnen
jsr chgent ;Eintrag suchen
und ändern.
jsr wblocks ;DirBlocks
schreiben.
jsr closeio ;Kanäle schließen
lda #<(text4) ;"File install-
ldy #>(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 Zei-
sty $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 unter-
scheidet 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 umge-
wandelt und an den Befehlsstring in X/Y
angehängt wird. Der gesamte Befehl wird
dabei bei COMBUFF abgelegt und dann mit-
tels 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 notwen-
dig, um sicherzustellen, daß auch die
richtige Anzahl an Dirblocks als 'be-
legt' gekennzeichnet ist. Sollten näm-
lich 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äm-
lich einen neuen Dirblock hinzufügen,
der ab dann nicht mehr zur Datenspeiche-
rung benutzt werden kann. Damit es dabei
keine Konfrontationen gibt, wird das
File also sporadisch schon einmal ange-
legt 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 zei-
gen, 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 Endmar-
kierung 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 Filena-
menspuffers. Für den Namen werden 17
Bytes reserviert, da ja maximal 16 Zei-
chen 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 subtra-
hiert, 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 ge-
braucht. 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 wer-
den, 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 Feststel-
len der freien Blocks der Diskette. Die-
ser Wert ist normalerweise nicht direkt
aus dem DiskHeaderBlock zu erfahren. Die
einzige Möglichkeit wäre, die Blockbele-
gungen 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 $02FA (Lo) und $02FC
(Hi) des Floppyspeichers abgelegt. Was
liegt also näher, als diesen Wert di-
rekt, ü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 Source-
text abgelegt werden (3 Zeichen ab
Adresse $02FA 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 Direc-
tory 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 DiskHea-
derBlocks. Wir müssen also den Block
18/0 in den Puffer lesen, und den Puf-
ferzeiger 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 ledi-
glich 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 Sourcecode-
texte 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 durch-
sucht die Directoryblocks nach unserem
Fileeintrag, liest aus ihm den
Track/Sektor des ersten 'normalen' Da-
tenblocks aus und legt ihn in den Adres-
sen FTRACK und FSEKTOR ab. Desweiteren
wird hier dann Track und Sektor des er-
sten, 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 An-
fangspositionen der einzelnen Fi-
leeinträge eines Directoryblocks abge-
legt 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ückgeschrie-
ben:
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