Magic Disk 64

home to index to html: MD9212-KURSE-FLOPPY-KURS_7.1.html
----------------------------------------
              Floppy-Kurs:              
      "Es rappelt in der Kiste..."      
                (Teil 7)                
----------------------------------------
Hallo und herzlich Willkommen zum  sieb-
ten  Teil  des  Floppy-Kurses. In diesem
Monat möchten wir  uns  an  die  Floppy-
Programmierung  in Assembler heranwagen.
Hierbei werden wir alle notwendigen Rou-
tinen zum I/O-Handling von Maschinenspa-
che aus kennenlernen. Allerdings sollten
Sie schon einige  Assembler-Vorerfahrung
mitbringen  und  zumindest  Kenntnis vom
Befehlssatz des 6510-Prozessors haben.  
DER EINSTIEG IN ASSEMBLER               
Wie Sie bemerkt haben, waren alle bishe-
rigen  Programmbeispiele  und Befehlser-
läuterungen in BASIC programmiert.  Dies
diente   hauptsächlich  der  Einfachheit
halber.  Wenn  Sie  nun  ein  angehender
Assemblerprogrammierer  sind,  so werden
Sie sich desöfteren schon einmal gefragt
haben, wie Sie die Floppy in  Maschinen-
sprache  ansprechen  können. Dies unter-
scheidet sich von BASIC  zwar  schon  in
einigen Punkten, da es etwas aufwendiger
ist, jedoch können wir hier komplett auf
schon  im  Betriebssystem des 64ers vor-
handene Routinen zurückgreifen, die  le-
diglich  mit  den  richtigen  Parametern
gefüttert werden müssen. Diese  Routinen
sind  dieselben,  die auch vom BASIC des
C64 benutzt werden, weshalb die  Parame-
terübergabe  der  von BASIC sehr ähnlich
ist. Kommen wir zunächst einmal zu eini-
gen grundlegenden Dingen:               
ÜFFNEN UND SCHLIESSEN VON FILES         
Jedesmal, wenn wir einen Zugriff auf die
Floppy ausführen  wollten,  mussten  wir
zuvor   immer  einen  Filekanal  öffnen.
Hierzu wurden mit Hilfe des OPEN-Befehls
einige Parameter an die  Floppy  überge-
ben,  die zur eindeutigen Definition des
Kanals notwendig waren. Diese  Parameter
waren  die  Filenummer, die Devicenummer
und die Sekundäradresse. Oft folgte  der
ganzen  Anweisung dann auch noch ein Fi-
lename, dessen Appendix ebenso die  ver-
langte Operation spezifizierte. Man kann
also sagen, daß diese Werte alles Grund-
werte sind, die zum  Datenaustausch  mit
der  Floppy  benötigt werden. Aus diesem
Grund müssen sie auch bei jeder Fileope-
ration angegeben werden. Möchten wir nun
eine  Operation von Assembler aus durch-
führen, so müssen  wir  diese  Parameter
zunächst  dem  Betriebssystem mitteilen.
Dies  geschieht  über  die  beiden  ROM-
Routinen  "SETPAR"  und "SETNAM". SETPAR
hat die Einsprungadresse $FFBA.  An  sie
werden die Filenummer, sowie Geräte- und
Sekundäradresse  übergeben.  SETNAM legt
den Filenamen (inklusive Appendix) fest.
Sie steht bei $FFBD. Beide Routinen  tun
nichts  anderes, als die gegebenen Werte
in Betriebssystem-Zwischenspeichern  der
Zeropage abzulegen.                     
Nachdem die Werte festgelegt sind,  kön-
nen wir die Betriebssystemroutine "OPEN"
aufrufen,  die  uns  den  Kanal  mit der
Floppy öffnet. Ihre Einsprungadresse ist
bei $FFC0. Zum  Schließen  benutzen  wir
die Routine "CLOSE" bei $FFC3.          
Wenn  wir ein File öffnen, so müssen wir
zunächst einmal seinen Namen  festlegen.
Diesen  legen  wir irgendwo im Speicher,
an einer bekannten Adresse, ab. Die Län-
ge  des Namens benötigen wir ebenso. Als
nächstes können wir  SETNAM  und  SETPAR
aufrufen.  SETNAM  wird  die Adresse des
Filenamens und seine Länge,  SETPAR  die
logische Filenummer, die Geräte- und die
Sekundäradesse   übergeben.   Hier  eine
Öbersicht der Registerbelegungen:       
SETPAR: Akku   = Filenummer             
        X-Reg. = Geräteadresse          
        Y-Reg. = Sekundäradresse        
SETNAM: Akku   = Länge des Filenamens   
        X-Reg.  = Low-Byte der Speicher-
                 adresse des Namens     
        Y-Reg. = High-Byte der Speicher-
                 adresse des Namens     
Ich möchte  Ihnen  hierzu  ein  Beispiel
liefern.  Angenommen,  Sie  wollten  das
sequentielle File "TEST" zum Lesen  öff-
nen.  Als  Filenummer  wollen  wir die 1
wählen, als Sekundäradresse 2. Die Gerä-
teadresse  ist  in  Bezug auf die Floppy
natürlich 8 (oder 9,10,11 wenn Sie  eine
zweite, dritte oder vierte Floppy besit-
zen). All  diese  Parameter  entsprechen
also dem BASIC-Befehl:                  
OPEN 1,8,2,"TEST,S,R"                   
Möchten wir diesen Befehl nun in Maschi-
nensprache umsetzen,  so  schreiben  wir
folgendes   Assembler-Programm.  Hierbei
gehe ich davon aus, daß wir den  Filena-
men "TEST,S,R" als ASCII-Code bei Adres-
se $0334 (dem  Kasettenpuffer)  abgelegt
haben:                                  
LDA #$01   ;Filenummer 1                
LDX #$08   ;Geräteadresse 8             
LDY #$02   ;Sekundäradresse 2           
JSR $FFBA  ;SETPAR aufrufen             
LDA #$08   ;Filename ist 8 Zeichen lang 
LDX #$34   ; und liegt bei Adresse      
LDY #$03   ; $0334                      
JSR $FFBD  ;SETNAM aufrufen             
Die Parameter für das File "TEST"  wären
damit festgelegt. Da das ",S,R" im File-
namen enthalten  ist,  weiß  die  Floppy
auch  gleich  schon, daß wir ein sequen-
tielles File lesen möchten.             
Als Nächstes müssen wir das zuvor spezi-
fizierte  File  öffnen.  Dies  geschieht
über die oben schon erwähnte Betriebssy-
stemroutine "OPEN". Sie  benötigt  keine
Parameter und wird direkt aufgerufen:   
JSR  $FFC0  ;File mit zuvor gesetzem Na-
            men und Parametern öffnen   
Nun ist das  File  "TEST"  geöffnet.  Da
aber  auch  jeder  Datenfluß  einmal ein
Ende hat, muß unser File irgendwann ein-
mal  wieder geschlossen werden. Dies ge-
schieht, wer hätte das gedacht, mit  der
ROM-Routine  "CLOSE",  die  bei  Adresse
$FFC3 angesprungen wird. Da auch mehrere
Files gleichzeitig  offen  sein  können,
muß ihr die Filenummer des zu schließen-
den Files im Akku übergeben werden:     
LDA #$01   ;File mit Filenummer 1       
JSR $FFC3  ; schließen                  
DER DATENAUSTAUSCH                      
Wie man ein File  öffnet,  sollte  Ihnen
nun klar sein. Wenn Sie jedoch auch noch
mit  ihm  komunizieren  wollen  (was sie
bestimmt tun möchten, da es anders sinn-
los  wäre ein File zu öffnen), so müssen
Sie   weiterhin   fünf   Betriebssystem-
Routinen kennen, die Ihnen dies ermögli-
chen.  Zunächst  wären  da  "CHKIN"  und
"CHKOUT".  Sie  dienen der Umleitung der
Standard-Ein/Ausgabe  auf  den  entspre-
chenden  Filekanal.  Wenn  Sie aus einem
File lesen wollen, so sollten  Sie  nach
dem  Üffnen  desselben die Routine CHKIN
aufrufen. Mit ihr  teilen  Sie  dem  Be-
triebssystem  mit,  daß  Sie,  wenn  Sie
jetzt etwas einlesen, die Daten aus die-
sem Filekanal haben möchten. Möchten Sie
in  ein  File  schreiben,  so müssen Sie
CHKOUT aufrufen um in das geöffnete File
schreiben  zu  können.  Beide   Routinen
benötigen  die  Filenummer  des entspre-
chenden Files im  X-Register.  Die  Ein-
sprungadresse  von  CHKIN ist $FFC6, die
von CHKOUT $FFC9.                       
Wenn Sie  die  Standard-Ein/Ausgabe  mit
Hilfe unserer beiden Routinen umgeleitet
haben,  so  können  Sie  die Ihnen viel-
leicht schon  bekannten  Routinen  BASIN
($FFCF) und BASOUT ($FFD2) zum Lesen und
Schreiben  von  Daten  vom, bzw. an, das
Ein/Ausgabe-Gerät  benutzen.  Rufen  Sie
diese  Routinen  bei unveränderter Stan-
dard-Ein-/Ausgabe auf, so erscheint  bei
BASIN ein Cursor auf dem Bildschirm, der
dem  Assemblerprogramm  eine Eingabe von
der  Tastatur  übermittelt,  bei  BASOUT
wird ein Zeichen an die aktuelle Cursor-
position gedruckt und der Cursor um eine
Stelle weiterbewegt  (wie  Sie  bemerken
ist das Standard-Eingabegerät die Tasta-
tur, das Standard-Ausgabegerät der Bild-
schirm).                                
Bei umgeleiteter  Eingabe  erhalten  Sie
nun  beim  Aufruf von BASIN das aktuelle
Byte  des  geöffneten  Files   im   Akku
zurück.  Bei  umgeleiteter  Ausgabe wird
jedes Byte, daß Sie in  den  Akku  laden
und  anschließend an BASOUT übergeben in
das geöffnete File hineingeschrieben.   
Haben Sie nun Ihre Fileoperationen been-
det, so ist  es  notwendig,  die  fünfte
Routine  zu  benutzen,  von der ich oben
sprach. Sie heißt "CLRCH" und wird  ver-
wendet, um die Standard-Ein/Ausgabe wie-
der zurückzusetzen  auf  'Tastatur'  und
'Bildschirm'.  Ihre Einsprungadresse ist
$FFCC. Sie wird VOR dem Aufruf von CLOSE
benutzt und benötigt keine Parameter.   
FEHLERERKENNUNG UND BEHANDLUNG          
Bevor   wir  uns  der  Praxis  zuwenden,
zunächst noch ein Wort zur  Fehlererken-
nung.  Hierüber  können wir nämlich beim
Lesen eines Files  auch  erkennen,  wann
wir sein letztes Byte gelesen haben.    
Prinzipiell gilt: tritt während der  Ar-
beit  einer  der  Floppy-Betriebssystem-
Routinen ein Fehler auf, so wird das  an
das  aufrufende  Programm  durch ein ge-
setztes  Carry-Bit  zurückgemeldet.   So
können  Sie also nach jeder der Routinen
durch  eine  einfache  "BCS"-Verzweigung
("Branch on Carry Set") auf eine Fehler-
behandlungsroutine  verzweigen.  Hierbei
steht  dann  im Akku ein Fehlercode, mit
dessen Hilfe Sie  die  Art  des  Fehlers
feststellen  können. Hier eine Liste mit
den möglichen  Fehlermeldungen  und  den
Ursachen für einen aufgetretenen Fehler.
In  eckigen  Klammern stehen jeweils die
Betriebssystem-Routinen,  die  den  ent-
sprechenden   Fehler   auslösen  können.
Steht nichts  dahinter,  so  handelt  es
sich um einen allgemeinen Fehler:       
0: "Break Error"  -  Die  RUN/STOP-Taste
   wurde gedrückt.                      
1: "too many files" - Der 64er verwaltet
   intern maximal 10 offene  Files.  Sie
   versuchten ein elftes File zu öffnen.
   Oder  aber  sie  haben schon zu viele
   Files zur Floppy hin offen (Sie erin-
   nern sich: man darf maximal 3 sequen-
   tielle, oder 1 relatives  und  1  se-
   quentielles  File  gleichzeitig offen
   halten). {OPEN}                      
2: "file  open"  -  Sie  versuchten, ein
   schon offenes File nochmal zu öffnen.
   {OPEN}                               
3: "file not open" - Sie versuchten, ein
   ungeöffnetes File anzusprechen.  {CH-
   KIN, CHKOUT, CLOSE}                  
4: "file  not found" - Das File, das Sie
   zum Lesen  öffnen  wollten  existiert
   gar nicht. {OPEN}                    
5: "device not  present"  -  Die  Floppy
   (oder  das  gewählte Gerät) ist nicht
   eingeschaltet. {OPEN}                
6: "not  an input file" - Sie versuchten
   aus einem  zum  Schreiben  geöffneten
   File zu lesen. {CHKIN}               
7: "not an output file" - Sie versuchten
   in ein zum Lesen geöffneten  File  zu
   schreiben. {CHKOUT}                  
8: "missing filename" - Sie gaben keinen
   Filenamen an. {OPEN}                 
9:  "illegal  device number" - Sie gaben
   eine  ungültige   Devicenummer    an.
   {OPEN}                               
Beachten  Sie bitte, daß nicht unbedingt
alle Fehler aus obiger  Liste  auftreten
müssen, da man die oben genannten Routi-
nen auch zum Anprechen von anderen Gerä-
ten  verwenden kann (z.B. Drucker, Data-
sette, etc.). Üffnen Sie z.B. einen  Ka-
nal  zum Drucker, so brauchen Sie keinen
Filenamen - der Fehler  8  wird  in  dem
Fall also nie auftreten.                
Als weitere Fehlererkennungshilfe stellt
uns das Betriebssystem auch eine Status-
speicherstelle zur  Verfügung.  Sie  ist
absolut identisch mit der Variablen "ST"
von BASIC. Fragt ein BASIC-Programm die-
se Variable ab,  so  greift  der  BASIC-
Interpreter auf eben diese Speicherstel-
le  zurück.  Die  Assemblerprogrammierer
finden  den  I/O-Status in der Zeropage,
nämlich  in  Speicherstelle  $90   (dez.
144).  Um feststellen zu können, ob wäh-
rend der Arbeit mit der Floppy ein  Feh-
ler  aufgetreten ist, müssen wir sie le-
diglich einlesen  und  analysieren.  Ein
Fehler  wird  hierbei  durch das gesetzt
sein eines  oder  mehrerer  Bits  dieser
Speicherstelle gemeldet. Hier eine Bele-
gung der Bits (nur für  die  Arbeit  mit
der  Floppy  gültig, bei Kasettenbetrieb
gilt eine andere Belegung):             
Bit Bedeutung                           
----------------------------------------
 0  Fehler beim Schreiben               
 1  Fehler beim Lesen                   
 6  Datei-Ende wurde erreicht (Lesen)   
 7  Gerät nicht vorhanden oder abge-    
    schaltet ("device not present")     
Sie sehen, daß Sie  hier,  wie  auch  in
BASIC,  das  Ende  eines Files durch ge-
setzt sein des 6. Bits von ST  feststel-
len können. Dann nämlich hat ST den Wert
64,  den wir bei BASIC-Abfragen auch im-
mer  verwendeten.  Sie  sehen   übrigens
auch,  warum  bei  erneutem  Lesen trotz
beendetem  File  die   Fehlernummer   66
zurückgeliefert  wird. Das File ist dann
nämlich zu Ende und es trat  ein  Fehler
beim  Lesen  auf,  weil es ja gar nichts
mehr zu lesen gibt. Damit sind die  Bits
1  und  6 gesetzt (2+64) was dem Wert 66
entspricht.                             
Wenn ST den Wert 0 enthält, so ist alles
gut gegangen. Auf diese Weise können wir
in Assembler  sehr  einfach  den  Fehler
abfragen:  Wir  lesen die Speicherstelle
$90 einfach ein und  verzweigen  mittels
BNE auf eine Fehlerbehandlungsroutine.  
ZUSAMMENFASSUNG                         
Abschließend  zu  diesen Routinen möchte
ich   Ihnen    nun    zwei    Universal-
Lese/Schreib-Routinen   vorstellen,  die
Sie zum Lesen, bzw. Schreiben eines  Fi-
les  verwenden  können. Sie finden diese
Routinen auch auf dieser  MD  unter  dem
Namen  "FK.I/O.S".  Sie  sind  im Hypra-
Ass-Format gespeichert. Um sie sich  an-
zuschauen  können Sie sie wie ein BASIC-
Programm laden und listen.              
Zunächst  einmal  möchte  ich  Ihnen die
"ReadFile"-Routine vorstellen. Sie liest
ein File an eine beliebige Adresse  ein.
Hierbei übergeben Sie Low- und High-Byte
in  X-  und  Y-Register, sowie die Länge
des Filenamens  im  Akku.  Der  Filename
selbst  soll  immer bei $0334 (dez. 820)
stehen:                                 
ReadFile:                               
       stx $fb      ;Startadresse in    
       sty $fc      ; Zeiger schreiben  
       ldx #$34     ;Namensadresse=$0334
       ldy #$03     ;in X/Y (Len in Ak.)
       jsr $ffbd    ;Und Name setzen    
       lda #01      ;Filenummer=1       
       ldx #08      ;Geräteadresse=1    
       ldy #00      ;Sek.=0 (=PRG lesen)
       jsr $ffba    ;Parameter setzen   
       jsr open     ;File öffnen        
       ldx #01      ;Ausgabe auf FNr. 1 
       jsr chkin    ; umleiten          
       ldy #00      ;Index auf 0 setzen 
loop1: jsr basin    ;Byte lesen         
       sta ($fb),y  ;und auf Zeiger-    
                     adresse speichern  
       inc $fb      ;Den Zeiger in      
       bne l1       ; $FB/$FC um 1      
       inc $fc      ; erhöhen           
l1:    lda $90      ;File-Ende erreicht?
       beq loop1    ;Nein, dann weiter! 
       jsr $ffcc    ;Ja, also Standard- 
                     Ein-/Ausgabe       
                     zurücksetzen.      
       lda #01      ;Und File mit File- 
       jmp $ffc3    ; nummer 1 schließen
Als nächstes stelle ich Ihnen die  "Wri-
teFile"-Routine vor. Sie speichert Daten
in  einem beliebigen Speicherbereich auf
Diskette und wird mit denselben Vorraus-
setzungen   aufgerufen  wie  "ReadFile":
Name bei $0334, Namenslänge im Akku  und
Startadresse  des  zu  speichernden  Be-
reichs in X-/Y-Register. Zusätzlich müs-
sen  Sie  die Endadresse dieses Bereichs
(in  Lo/Hi-Darstellung)  vorher  in  den
Speicherstellen $FD/$FE abgelegt haben: 
WriteFile:                              
       stx $fb      ;Startadresse in    
       sty $fc      ; Zeiger schreiben  
       ldx #$34     ;Namensadresse=$0334
       ldy #$03     ;in X/Y (Len in Ak.)
       jsr $ffbd    ;Und Name setzen    
       lda #01      ;Filenummer=1       
       ldx #08      ;Geräteadresse=1    
       ldy #01      ;Sek.=1 (=PRG       
                     schreiben)         
       jsr $ffba    ;Parameter setzen   
       jsr $ffc0    ;File öffnen        
       ldx #01      ;Eingabe auf FNr.1  
       jsr $ffc9    ; umleiten          
       ldy #00      ;Index auf 0 setzen 
loop2: lda ($fb),y  ;Byte aus Sp. holen 
       jsr $ffd2    ;und an Floppy sen- 
                     den                
       inc $fb      ;Den Zeiger in      
       bne l2       ; $FB/$FC um 1      
       inc $fc      ; erhöhen           
l2:    lda $fe      ;Quellzeiger $FB/$FC
       cmp $fc      ; mit Zielzeiger    
       bne loop2    ; $FD/$FE           
       lda $fd      ; vergleichen. Wenn 
       cmp $fb      ; ungleich, dann    
       bne loop2    ; weitermachen.     
       jsr $ffcc    ;Wenn gleich, dann  
                     Standard-I/O       
                     zurücksetzen.      
       lda #01      ;und File mit File- 
       jmp $ffc3    ;nummer 1 schließen 
Wie  Sie  sehen, habe ich hier den Trick
mit den Sekundäradressen  verwendet.  Da
bei  der Sekundäradresse die Werte 0 und
1 für "Programm  lesen"  bzw.  "Programm
schreiben"  stehen,  erübrigt  sich  ein
umständliches anhängen von  ",P,R"  bzw.
",P,W"  an  den  Filenamen. Dafür jedoch
können mit den  Routinen  nur  PRG-Files
gelesen und geschrieben werden.         
Bitte Teil 2 des Floppy-Kurses laden !  
Valid HTML 4.0 Transitional Valid CSS!