C 64/VC 20
Disketten kopieren
4/84, S. 92-95

Disk Copy

Wer hat sich als stolzer Besitzer eines Commodore 64 und einer 1541-Floppy noch nicht beim Kopieren von Programmen geärgert? Solange es sich um reine Basic-Programme handelt, geht es noch: Originaldiskette einlegen, Programm laden, Diskette wechseln, Programm »saven«, Diskette wechseln, Programm laden...

Schlimmer wird es, wenn sich um Maschinenprogramme oder gar um sequentielle Files handelt. Das Anlegen einer Sicherheitskopie wird zur zeitraubenden, umständlichen Prozedur und unterbleibt deshalb, bis man eines Tages feststellt, daß das Original aus irgendwelchen Gründen nicht mehr läuft. Mir ist das mit einer Datei passiert, die aus über 400 Einträgen bestand und die ich eines Tages einfach nicht mehr einladen konnte. Seitdem gibt es bei mir von allen wichtigen Disketten Sicherheitskopien, bei deren Erstellung mir das folgende Programm gute Dienste leistet.

Das Besondere an diesem Programm ist, daß alle Arten von Files mit Ausnahme relativer Dateien kopiert werden können und das recht komfortabel und schnell. Der Trick besteht darin, daß die Files, die man kopieren möchte, der Reihe nach in den Speicher gelesen werden bis dieser voll ist. Da das Programm auch die »versteckten« RAM-Bereiche mitbenutzt, die man normalerweise gar nicht ansprechen kann, weil Basic-Interpreter und Betriebssystem an derselben Speicheradresse liegen, kommt man in einem Durchgang auf stattliche 226 Blöcke (zirka 56 KByte). Sollte das noch nicht ausreichen, startet das Programm einen zweiten oder auch dritten Durchgang. Dann ist spätestens die gesamte Diskette kopiert (bei ganz ungünstigen Verhältnissen wird noch ein vierter Durchgang gebraucht). Damit ergeben sich Zeiten von unter 20 Minuten für eine Komplettkopie.

Wie funktioniert's?

Sehen wir uns zuerst das Basicprogramm an (Bild 1): Ich habe es absichtlich in mehrere Teile zerlegt, um es übersichtlicher zu machen. Die REM-Zeilen können beim Eintippen natürlich ebenso wegfallen wie die Zeilen, in denen nur ein Doppelpunkt steht.

Zeile 100 bis 140

setzt zuerst die Speicherobergrenze für Basic herunter (Speicherstelle 56) und berechnet, wieviel Speicher zum Kopieren zur Verfügung steht (RB). Um spätere Erweiterungen einbauen zu können (zum Beispiel Backup für relative Dateien), arbeite ich hier nicht mit festen Zahlen, sondern mit Variablen, die das Programm selbst berechnet. Das gilt ebenso für die Startadressen der Maschinenroutinen. Diese befinden sich direkt hinter dem Basic-Teil und brauchen deshalb nicht erst über DATA-Zeilen bei jedem Programmlauf »eingepoked« werden. Das spart nicht nur Zeit, sondern vor allem auch Speicherplatz (zirka 700 Bytes). Dafür müssen Sie beim Abschreiben zwei Teile zusammenfügen. Im Initialisierungsteil werden auch alle Variablen und Arrays eingerichtet (siehe Variablentabelle).

Zeile 160 bis 240

enthält das Menü. Sie können hier jederzeit weitere Funktionen einfügen.

Wird der Programmteil »Formatieren« gewählt, springt das Programm in die Zeilen 700 bis 750. Interessant ist hier die Möglichkeit, bei der Frage nach der Disk – ID keine Eingabe zu machen, sondern »RETURN« zu drücken. Dies ist bei Disketten sinnvoll, die bereits formatiert sind, aber gelöscht werden sollen. Das DOS der 1541 löscht dann nur die BAM und die erste Seite des Directory, was viel schneller geht als vollständiges Neuformatieren. Das Programm schließt diesen Teil mit Ausgabe der Fehlermeldung ab und springt wieder ins Menü.

Der Programmteil »Directory« ermöglicht ein schnelles Einlesen des Directorys, natürlich ohne Programmverlust. Man kann sich so einen kurzen Überblick über Original- und Zieldiskette verschaffen, ohne die Kopierroutine aufrufen zu müssen. Hier wird ein Maschinenteilprogramm benutzt, um Speicherplatz und Zeit zu sparen.

Zeile 270 bis 650

Kommen wir nun zum Kern der Sache, dem eigentlichen Kopierteil, Dieser befindet sich in den Zeilen 270 bis 650. Im ersten Teil (Zeile 270 bis 350) werden alle Files, die auf der Diskette sind, in ein Stringarray (NF$(I)) eingelesen, die zugehörigen Blocklängen in ein Variablenarray (BL%(I)). Das dauert etwas länger, weil der Speicherplatz begrenzt ist und der Basic-Interpreter mitunter eine Garbage-Collection (Müll-Sammlung) durchführt, um Platz zu schaffen. Die Anzahl der Files wird in der Variablen AN festgehalten. Ist die Diskette leer, weil man zum Beispiel noch die gerade formatierte Zieldiskette im Laufwerk hatte, springt das Programm ins Menü zurück.

In Zeile 370 bis 440 erfolgt die Auswahl, welche Files kopiert werden sollen. Das Programm schreibt dazu die einzelnen Namen mit der zugehörigen Blocklänge auf den Bildschirm und Sie können mit »J« oder »N« aussuchen. Die Entscheidung merkt sich das Programm wieder in einem Variablenarray (CF%(I)): Ist CF%=-1, wird kopiert, sonst nicht. Gleichzeitig wird in der Variablen BL aufaddiert, wieviele Blöcke zu kopieren sind, damit das Programm herausbekommt, ob ein Durchgang ausreicht oder nicht. Wenn Sie alle Files mit »N« kennzeichnen, springt das Programm wieder ins Menü.

Nachdem nun endlich alle Entscheidungen und Vorbereitungen abgeschlossen sind, geht es ans Kopieren (Zeile 460 bis 650). Der Reihe nach werden alle gekennzeichneten Files in den Speicher eingelesen. Dazu wird das Laufwerk mit »OPEN«-Befehlen angesprochen, weil so alle Arten von Files geladen und auch abgespeichert werden können. (Mit »LOAD« könnten nur Programmfiles geladen werden.) Erfreulicherweise enthält die Variable NF$ nicht nur den Namen des jeweiligen Files, sondern auch den Typ, also PRG, SEQ oder USR. Deshalb können alle Filetypen mit ein und derselben Routine verarbeitet werden.

Der Unterschied zwischen Lesen und Schreiben liegt lediglich darin, daß dem »OPEN«-Befehl im ersten Falle ein R (für Read), im zweiten ein W (für Write) angehängt wird. Die Datenübertragung selbst erledigt das Maschinenprogramm, dem wir uns gleich zuwenden werden. Um Variablen an diese Routinen übergeben zu können, benutzen wir die Zeropage-Speicherstellen 252 bis 255 ($FC bis $FF).

Werfen wir nun noch einen Blick auf die Maschinensprach-Teile (Bild 3 bis 5). Dabei soll vor allem erläutert werden, wie man den vollen RAM-Speicher des C 64 nutzen kann.

Dazu ist ein kurzer Blick auf die Speicheraufteilung des C 64 erforderlich, insbesondere den Teil ab $A000 bis $FFFF (dez. 40960 - 65535). Hier liegt normalerweise der Basic-Interpreter, der 8 KByte Adreßraum benötigt ($A000 - $C000). Darüber liegen in 4 KByte die Ein-Ausgabe-Einheiten ($D000 - $E000). Ganz oben im Speicher befindet sich das Betriebssystem, das genau wie der Basic-Interpreter 8 KByte belegt ($E000 - $FFFF). Zusätzlich ist aber der gesamte Bereich auch noch mit RAM bestückt. Woher weiß der Prozessor nun, was er benutzen soll? Lediglich 3 Bits in Speicherstelle 1 sind für die Auswahl zuständig: Bit 0 schaltet den Basic-Interpreter ein und aus, Bit 1 gleichzeitig Basic-Interpreter und Betriebssystem, Bit 2 ist für uns schon uninteressant. Werden beide, Bit 0 und Bit 1, auf 0 gesetzt, ist zusätzlich auch noch der Ein-Ausgabebereich abgeschaltet. Eigentlich doch ganz einfach. Der Teufel steckt wie fast immer im Detail: Wenn der Basic-Interpreter abgeschaltet ist, wie soll dann ein Basic-Programm laufen? Mehr noch, ohne sein Betriebssystem ist der Prozessor hilfloser als ein Blinder im Nebel.

Die Lösung liegt einfach darin, zu verhindern, daß der Prozessor überhaupt auf die Idee kommt, in sein Betriebssystem oder ins Basic hineinzuspringen. Letzteres ist nicht schwierig, denn wir befinden uns ja in einem Maschinenprogramm, wenn wir das Basic abschalten. Und bei der Bearbeitung eines solchen Programms kann nur dann etwas passieren, wenn der Prozessor das Programm verläßt. Das tut er allerdings jede 1/50 Sekunde, zum Beispiel um die interne Uhr weiterzustellen und nachzusehen, ob eine Taste gedrückt wurde etc. Das ist die sogenannte Interrupt-Routine. Wenn wir ihm die sperren, kann eigentlich gar nichts mehr schiefgehen. Und es funktioniert tatsächlich:

Im Leseteil des Maschinenprogramms wird zuerst der mit »OPEN« eröffnete Kanal als Eingabekanal gesetzt (FFC6). Dann wird ein Byte über diesen Kanal geholt. Jetzt sperrt der SEI (Set Interrupt) die Interruptroutine und wir können in aller Ruhe schalten und walten. Wir schieben das Byte ins X-Register, legen die beiden unteren Bits der Speicherstelle 1 auf 0, holen unser Byte aus dem X-Register und legen es im RAM ab. Jetzt setzen wir die Bits wieder auf 1, löschen die Interrupt-Sperre, und alles ist wieder in Ordnung. Nachdem unser Byte im RAM sicher untergebracht ist, fragen wir nun ab, ob vielleicht ein Fehler aufgetreten ist (FFB7) oder das Ende unseres Files erreicht ist. Wenn ja, springen wir ins Basic zurück und brechen im Fehlerfalle das Programm mit einer entsprechenden Meldung ab. Wenn nein, wenden wir uns dem nächsten Byte zu, das übertragen werden soll und behandeln es mit der gleichen Sorgfalt. Ganz zum Schluß müssen wir noch wieder die Kanäle zurücksetzen (Tastatur als Eingabe, Bildschirm als Ausgabe (FFCC)). Das alles klingt zwar umständlich und langwierig, geht aber in Wirklichkeit unglaublich schnell.

Das Schreiben auf Diskette bringt nichts grundsätzlich Neues, der ganze Vorgang läuft hier einfach andersherum ab. Unser Kanal 1 ist jetzt Ausgabekanal ($FFC9), und anstatt ein Byte von der Diskette zu holen, geben wir es aus ($FFD2).

Auch die Directory-Ausgabe folgt diesem Muster:

Kanal 3 als Eingabe setzen ($FFC6), Zeichen für Zeichen holen ($FFCF) und – jetzt auf dem Bildschirm – ausgeben ($FFD2).

Wichtige Bedienungshinweise

So, nun steht dem Eintippen des Programms nichts mehr im Wege. Noch ein paar wichtige Hinweise: Die beiden Teile des Programms müssen beim ersten Mal zusammengefügt werden. Dazu gehen wir folgendermaßen vor:

  1. Tippen Sie das Programm »Disk Copy« ab und speichern Sie es auf Diskette.
  2. Starten Sie das Programm mit »RUN« und drücken Sie die »RUN/STOP«-Taste, wenn das Menü erscheint.
  3. Geben sie ein: »PRINT PR« und schreiben Sie sich die angezeigte Zahl auf.
  4. Tippen Sie das Programm »Basic-Data-Lader« ein und starten Sie es. Auf die Frage nach der Anfangsadresse geben Sie Ihre aufgeschriebene Zahl ein.
  5. Folgen Sie genau den Anweisungen des Programs und geben Sie die beiden »POKE«-Befehle ein.
  6. Speichern Sie das vollständige Programm auf Diskette ab.

Jetzt haben Sie das Programm gebrauchsfähig auf Diskette. Sie können auch beliebige Änderungen am Programm durchführen, der Maschinensprach-Teil wird sich immer automatisch mitverschieben.

Anpassung auf VC 20:

Das Programm läuft auch auf dem VC 20, für den ich es ursprünglich geschrieben hatte. Nur Zeile 110 muß geändert werden:

110 POKE56,PEEK(46)+14:CLR:RB=PEEK(644)-PEEK (56):...

Wenn Sie mit einer 1541-Floppy arbeiten, sollten Sie noch einfügen:

118 OPEN1,8,15,'"UI-":CLOSE1.

Und nun viel Spaß beim Kopieren.

(Dietrich Weineck)
100 rem *** initialisierung ***
110 poke56,peek(46)+14:clr:rb=255-peek(56):pa=1:an=0:bl=0:nf$=""
120 pe=peek(45)+256*peek(46):mr=pe-135:mw=pe-79:md=pe-24
130 dimnf$(140),cf%(140),bl%(140),p%(10),al%(90),ah%(90)
140 p%(0)=0:al%(0)=0:ah%(0)=peek(56)-1
150 :
160 rem *** menue ***
170 print"{clr}{down}"tab(9)"***** disk copy *****":printtab(10)"von d.weineck 2/84"
180 print"{down}{down}{down}{down}{rght}{rght}1.  directory
190 print"{down}{rght}{rght}2.  kopieren
200 print"{down}{rght}{rght}3.  formatieren
210 print"{down}{rght}{rght}4.  ende
220 printspc(212)"{rvon}bitte waehlen sie
230 getdc$:dc=val(dc$):ifdc<1ordc>4then230
240 ondcgoto910,270,700,670
250 :
260 rem *** kopieren ***
270 print"{clr}{down}{rvon}originaldiskette einlegen"
280 gosub990
290 rem *** files einlesen ***
300 open1,8,0,"$0"
310 gosub760:ifnf$<>""then340
320 ifst=0then310
330 goto350
340 bl%(an)=asc(bl$+chr$(0)):nf$(an)=nf$:ifst=0thenan=an+1:nf$="":goto310
350 close1:an=an-1:ifan=0thenprint"{down}{down}{rvon}leere diskette{rvof}":gosub990:run
360 rem *** kopierauswahl ***
370 print"{clr}{down}antworten sie mit j/n{down}"
380 fori=1toan:printbl%(i);tab(5)nf$(i)" ? ";:poke198,0
390 wait198,1:geta$:ifa$="j"thencf%(i)=-1:bl=bl+bl%(i):printtab(30)"{rvon} ja {rvof}":goto420
400 cf%(i)=0:ifa$<>"n"then390
410 printtab(30)"nein"
420 ifbl>rbthenp%(pa)=i-1:pa=pa+1:bl=bl%(i)
430 nexti:p%(pa)=an
440 ifbl=0then640
450 rem *** kopie ***
460 print"{clr}{rvon}kopie in arbeit{down}"
470 fori=1topa
480 forrw=0to1:nr=0:ifrw=1thenprint"{rvon}{down}zieldisk einlegen":gosub990
490 forj=p%(i-1)+1top%(i)
500 ifnotcf%(j)thennextj:goto540
510 nf$=nf$(j):printbl%(j);tab(5)nf$:gosub570:ifst=0orst=64then530
520 gosub880:run
530 nextj
540 nextrw:ifi=pathen640
550 print"{rvon}{down}originaldisk einlegen":gosub990
560 nexti:run
570 ifrw=1then610
580 open1,8,5,nf$+",r":poke252,0:poke253,ah%(nr)+1
590 sysmr:nr=nr+1:al%(nr)=peek(254):ah%(nr)=peek(255)
600 close1:return
610 open1,8,5,nf$+",w":poke252,0:poke253,ah%(nr)+1
620 poke254,al%(nr+1):poke255,ah%(nr+1):sysmw
630 nr=nr+1:close1:return
640 print"{down}{down}{down}{rvon}kopie fertig !
650 gosub990:run
660 rem *** ende ***
670 poke56,160:end
680 :
690 rem *** formatieren ***
700 input"{clr}{down}{down}{down}diskname";fo$:id$="":input"{down}disk-id";id$:ifid$<>""thenid$=","+id$
710 fo$=fo$+id$
720 print"{down}{rvon}bitte zieldiskette einlegen"
730 gosub990
740 open1,8,15,"n:"+fo$:close1
750 gosub880:goto170
760 rem directory einlesen
770 get#1,a$,b$
780 get#1,bl$,b$
790 get#1,a$
800 get#1,b$:ifst<>0thenreturn
810 ifb$<>chr$(34)then800
820 get#1,b$:ifb$<>chr$(34)thennf$=nf$+b$:goto820
830 get#1,b$:ifb$=chr$(32)then830
840 nf$=nf$+","+b$:fori=0to1:get#1,b$:nf$=nf$+b$:next
850 get#1,b$:ifb$<>""then850
860 return
870 rem *** fehler-ausgabe ***
880 open15,8,15:input#15,a,b$,c,d:printa;b$;c;d:close15:gosub990:return
890 :
900 rem *** directory ***
910 print"{clr}"
920 open3,8,0,"$0":get#3,a$,a$
930 get#3,a$,a$,bl$,bh$
940 ifa$=""thenclose3:goto980
950 bl$=bl$+chr$(0):bh$=bh$+chr$(0)
960 print256*asc(bh$)+asc(bl$);
970 sysmd:goto930
980 gosub 990:goto170
990 printspc(69)"{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}":printspc(29)"{rvon}*taste*{rvof}"
1000 poke198,0:wait198,1:geta$:return
Bild 1. Basicprogramm »Disk Copy«
100 rem *** initialisierung ***
110 poke56,peek(46)+14:clr:rb=peek(644)-peek(56):pa=1:an=0:bl=0:nf$=""
120 pe=peek(45)+256*peek(46):mr=pe-135:mw=pe-79:md=pe-24
130 dimnf$(140),cf%(140),bl%(140),p%(10),al%(90),ah%(90)
140 p%(0)=0:al%(0)=0:ah%(0)=peek(56)-1
150 :
160 rem *** menue ***
170 print"{clr}{down}"tab(9)"***** disk copy *****":printtab(10)"von d.weineck 2/84"
180 print"{down}{down}{down}{down}{rght}{rght}1.  directory
190 print"{down}{rght}{rght}2.  kopieren
200 print"{down}{rght}{rght}3.  formatieren
210 print"{down}{rght}{rght}4.  ende
220 printspc(212)"{rvon}bitte waehlen sie
230 getdc$:dc=val(dc$):ifdc<1ordc>4then230
240 ondcgoto910,270,700,670
250 :
260 rem *** kopieren ***
270 print"{clr}{down}{rvon}originaldiskette einlegen"
280 gosub990
290 rem *** files einlesen ***
300 open1,8,0,"$0"
310 gosub760:ifnf$<>""then340
320 ifst=0then310
330 goto350
340 bl%(an)=asc(bl$+chr$(0)):nf$(an)=nf$:ifst=0thenan=an+1:nf$="":goto310
350 close1:an=an-1:ifan=0thenprint"{down}{down}{rvon}leere diskette{rvof}":gosub990:run
360 rem *** kopierauswahl ***
370 print"{clr}{down}antworten sie mit j/n{down}"
380 fori=1toan:printbl%(i);tab(5)nf$(i)" ? ";:poke198,0
390 wait198,1:geta$:ifa$="j"thencf%(i)=-1:bl=bl+bl%(i):printtab(30)"{rvon} ja {rvof}":goto420
400 cf%(i)=0:ifa$<>"n"then390
410 printtab(30)"nein"
420 ifbl>rbthenp%(pa)=i-1:pa=pa+1:bl=bl%(i)
430 nexti:p%(pa)=an
440 ifbl=0then640
450 rem *** kopie ***
460 print"{clr}{rvon}kopie in arbeit{down}"
470 fori=1topa
480 forrw=0to1:nr=0:ifrw=1thenprint"{rvon}{down}zieldisk einlegen":gosub990
490 forj=p%(i-1)+1top%(i)
500 ifnotcf%(j)thennextj:goto540
510 nf$=nf$(j):printbl%(j);tab(5)nf$:gosub570:ifst=0orst=64then530
520 gosub880:run
530 nextj
540 nextrw:ifi=pathen640
550 print"{rvon}{down}originaldisk einlegen":gosub990
560 nexti:run
570 ifrw=1then610
580 open1,8,5,nf$+",r":poke252,0:poke253,ah%(nr)+1
590 sysmr:nr=nr+1:al%(nr)=peek(254):ah%(nr)=peek(255)
600 close1:return
610 open1,8,5,nf$+",w":poke252,0:poke253,ah%(nr)+1
620 poke254,al%(nr+1):poke255,ah%(nr+1):sysmw
630 nr=nr+1:close1:return
640 print"{down}{down}{down}{rvon}kopie fertig !
650 gosub990:run
660 rem *** ende ***
670 poke56,160:end
680 :
690 rem *** formatieren ***
700 input"{clr}{down}{down}{down}diskname";fo$:id$="":input"{down}disk-id";id$:ifid$<>""thenid$=","+id$
710 fo$=fo$+id$
720 print"{down}{rvon}bitte zieldiskette einlegen"
730 gosub990
740 open1,8,15,"n:"+fo$:close1
750 gosub880:goto170
760 rem directory einlesen
770 get#1,a$,b$
780 get#1,bl$,b$
790 get#1,a$
800 get#1,b$:ifst<>0thenreturn
810 ifb$<>chr$(34)then800
820 get#1,b$:ifb$<>chr$(34)thennf$=nf$+b$:goto820
830 get#1,b$:ifb$=chr$(32)then830
840 nf$=nf$+","+b$:fori=0to1:get#1,b$:nf$=nf$+b$:next
850 get#1,b$:ifb$<>""then850
860 return
870 rem *** fehler-ausgabe ***
880 open15,8,15:input#15,a,b$,c,d:printa;b$;c;d:close15:gosub990:return
890 :
900 rem *** directory ***
910 print"{clr}"
920 open3,8,0,"$0":get#3,a$,a$
930 get#3,a$,a$,bl$,bh$
940 ifa$=""thenclose3:goto980
950 bl$=bl$+chr$(0):bh$=bh$+chr$(0)
960 print256*asc(bh$)+asc(bl$);
970 sysmd:goto930
980 gosub 990:goto170
990 printspc(69)"{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}{CBM-@}":printspc(29)"{rvon}*taste*{rvof}"
1000 poke198,0:wait198,1:geta$:return
100 print"{clr}{down}{down}{rght}{rght}basic - data - lader fuer 'disk copy
110 input"{down}{down}anfangsadresse";ad:ed=ad+135
120 fori=adtoed-1
130 readz:pokei,z:next
140 hb=int(ed/256):lb=edand255
150 print"{down}{down}{down}laden sie nun das programm 'disk copy'.
160 print"{down}geben sie nach dem laden ein:":print"{down}{down}{rght}{rght}poke 45,"lb":poke 46,"hb"
170 print"{down}{down}das programm befindet sich jetzt voll-
180 print"{down}staendig im speicher und kann ge'saved' {down}werden.
190 data162,1,32,198,255,160,0,32,207,255,120,170,165,1,41,252,133,1,138,145
200 data252,165,1,9,3,133,1,88,32,183,255,201,64,240,11,201,0,208,7,200,208
210 data221,230,253,208,217,32,204,255,132,254,165,253,133,255,96,162,1,32
220 data201,255,160,0,120,165,1,41,252,133,1,177,252,170,165,1,9,3,133,1,88
230 data138,32,210,255,32,183,255,201,0,208,17,200,208,2,230,253,165,255,197
240 data253,208,217,196,254,144,213,240,211,76,204,255,162,3,32,198,255,32
250 data207,255,32,210,255,208,248,169,13,32,210,255,76,204,255,0,0,0
Bild 2. Basic Lader für »Disk Copy«
LESEN VON DISKETTE
,114D  A2 01     LDX #01
,114F  20 C6 FF  JSR FFC6
,1152  A0 00     LDY #00
,1154  20 CF FF  JSR FFCF
,1157  78        SEI
,1158  AA        TAX
,1159  A5 01     LDA   01
,115B  29 FC     AND #FC
,115D  85 01     STA   01
,115F  8A        TXA
,1160  91 FC     STA (FC),Y
,1162  A5 01     LDA   01
,1164  09 03     ORA #03
,1166  85 01     STA   01
,1168  58        CLI
,1169  20 B7 FF  JSR FFB7
,116C  C9 40     CMP #40
,116E  F0 0B     BEQ 117B
,1170  C9 00     CMP #00
,1172  D0 07     BNE 117B
,1174  C8        INY
,1175  D0 DD     BNE 1154
,1177  E6 FD     INC   FD
,1179  D0 D9     BNE 1154
,117B  20 CC FF  JSR FFCC
,117E  84 FE     STY   FE
,1180  A5 FD     LDA   FD
,1182  85 FF     STA   FF
,1184  60 RTS
			
Bild 3. Für Interessierte: Maschinenroutine: »Lesen von Disk«
SCHREIBEN AUF DISKETTE
,1185  A2 01     LDX #01
,1187  20 C9 FF  JSR FFC9
,118A  A0 00     LDY #00
,118C  78        SEI
,118D  A5 01     LDA   01
,118F  29 FC     AND #FC
,1191  85 01     STA   01
,1199  B1 FC     LDA (FC),Y
,1195  AA        TAX
,1196  A5 01     LDA   01
,1198  09 03     ORA #03
,119A  85 01     STA   01
,119C  58        CLI
,119D  8A        TXA
,119E  20 D2 FF  JSR FFD2
,11A1  20 B7 FF  JSR FFB7
,11A4  C9 00     CMP #00
,11A6  D0 11     BNE 11B9
,11A8  C8        INY
,11A8  D0 02     BNE 11AD
,11AB  E6 FD     INC   FD
,11AD  A5 FF     LDA   FF
,11AF  C5 FD     CMP   FD
,11B1  D0 D9     BNE 118C
,11B9  C4 FE     CPY   FE
,11B5  90 D5     BCC 118C
,11B7  F0 D3     BEQ 118C
,11B9  4C CC FF  JMP FFCC
			
Bild 4. In Assembler: Schreiben auf Diskette
DIRECTORY HOLEN
,11BC  A2 03     LDX #03
,11BE  20 C6 FF  JSR FFC6
,11C1  20 CF FF  JSR FFCF
,11C4  20 D2 FF  JSR FFD2
,11C7  D0 F8     BNE 11C1
,11C9  A9 0D     LDA #0D
,11CB  20 D2 FF  JSR FFD2
,11CE  4C CC FF  JMP FFCC
			
Bild 5. Laden des Directorys
RB Anzahl dar zur Verfügung stehenden RAM-Blöcke
PA Anzahl der Durchgänge beim Kopieren
AN Anzahl der Files auf der Diskette
BL Anzahl der zu kopierenden Blöcke
NF$ Name und Typ des Files
PE Programmende
MR Adresse der Maschinenroutine zum Lesen
MW Adresse der Maschinenroutine zum Schreiben
MD Adresse der Maschinenroutine für Directory-Ausgabe
NF$(I) Feld für Filenamen
CF%(I) Feld für Kopierflags
BL%(I) Blocklänge der einzelnen Flles
P%(I) Anzahl der Files in einzelnen Durchgaengen
AL%(I) Endadresse der einzelnen Flles im Speicher (Low-Byte)
AH%(I) Endadresse der einzelnen Files im Speicher (Hlgh-Byte)
RW Flag für Lesen oder Schreiben
I,J Schleifenvariable
Variablen-Liste
PDF Diesen Artikel als PDF herunterladen
Mastodon Diesen Artikel auf Mastodon teilen
← Vorheriger ArtikelNächster Artikel →