ndr-nkc.de ndr-nbc.de
  
Startseite
News
 
NDR-NKC
Geräte Z80
Geräte 68000
Geräte 8088
 
NKC Emulator
 
Z80 Section
Baugruppen
ROM's
Software
68000 Section
Baugruppen
ROM's
PASCAL/S
Software
CP/M 68K
8088 Section
Baugruppen
Downloads
 
Bussysteme
Stromversorgung
Input / Output
Grafikkarten
Speicherkarten
Massenspeicher
Weitere Baugruppen
 
Projekte
 
Dokumentation
Datenblätter
Glossar
Portraits
Links

Impressum

 

CP/M 68K Programmierkurs - Arbeiten mit Dateien

Wie der Name schon sagt: die Hauptaufgabe des BDOS (Basic Disc Operation System) ist der Umgang mit Disketten und den Dateien, die darauf gespeichert sind. Dieses Kapitel beschäftigt sich mit den Grundlagen der Verarbeitung von Dateien unter CP/M 68K.

Themen dieses Kapitels

  • Ermitteln des freien Platzes auf einer Diskette
  • Ermitteln der Größe einer Datei
  • Laden einer Datei in den Speicher
  • Zusammensetzen zweier Textdateien
  • Löschen und Anlegen von Dateien

Ermitteln des freien Speichers auf einem Laufwerk

Dieses Beispiel zeigt noch nicht direkt den Umgang mit Dateien, ist jedoch geeignet um die Grundlagen Zum Umgang mit dem DMA Buffer zu zeigen. Außerdem kann man das Berechnen des freien Speicherplatzes nutzen, um Fehler beim Speichern von Daten abzufangen.
****************************
* FREE.S
****************************

CURDISK   EQU 25           * BDOS Get Current Disk
SETDMA    EQU 26           * BDOS Set DMA Address
DISKSPACE EQU 46           * BDOS GET Disk Free Space
PRINTSTR  EQU 9            * BDOS Print String

TEXT                       * ------------------------

START:
    MOVE #SETDMA, D0       * BDOS Funktionsnummer
    MOVE.L #DMABUF, D1     * Puffer im BSS-Segment
    TRAP #2                * DMA Puffer setzen

    MOVE #CURDISK, D0      * BDOS Funktionsnummer
    TRAP #2                * Aktuelles Laufwerk ermitteln
    MOVE D0, D1            * in D1 merken
    ADD.B #$41, D0         * ASCII Korrektur
    MOVE.L #VAR0, A1       * Ausgabeposition
    MOVE.B D0, (A1)        * in Ausgabepuffer schreiben

    MOVE #DISKSPACE, D0    * BDOS Funktionsnummer
    TRAP #2                * Ergebnis im DMA-Puffer

    MOVE.L #DMABUF, A1     * Adresse des DMA-Puffers
    MOVE.L (A1), D0        * Anzahl freier Blöcke
    MOVE.L #VAR1, A0       * Ausgabeadresse im Puffer
    BSR PRINTD             * als Dezimalzahl

    MOVE.L (A1), D0        * Anzahl freier Blöcke
    MULU #128, D0          * zu je 128 Bytes
    MOVE.L #VAR2, A0       * Ausgabeadresse im Puffer 
    BSR PRINTD             * als Dezimalzahl

    MOVE #PRINTSTR, D0     * BDOS Funktionsnummer
    MOVE.L #BUFFER, D1     * Start des Textes
    TRAP #2                * Ausgeben

    RTS                    * Programmende

DATA                       * ------------------------

BUFFER:   DC.B 13,10
          DC.B 'Laufwerk '
VAR0:     DC.B ' :',13,10
          DC.B '- Freie Sektoren  : '
VAR1:     DC.B '        ',13,10
          DC.B '- Freier Speicher : '
VAR2:     DC.B '        ',13,10
          DC.B '$'

BSS                       * ------------------------

DMABUF:   DS.B 128        * 128 Byte Puffer für DMA

Ermitteln der Größe einer Datei

Angenommen, wir wollen den Inhalt einer Datei von der Diskette in den Arbeitsspeicher laden. In diesem Fall müssen wir wissen, wie groß die Datei ist und wie viel Arbeitsspeicher (noch) verfügbar ist. Zum Ermitteln der Dateigröße stellt das BDOS eine eigene Funktion (Nummer 35) zur Verfügung. Wir schreiben also zunächst ein Programm mit dem Namen FILESIZE, welches einen Parameter (Name der Datei deren Größe zu ermitteln ist) übernimmt und danach die Größe der angegebenen Datei anzeigt.
****************************
* FILESIZE.S
****************************

OPENFILE  EQU 15           * BDOS Open File
CLOSEFILE EQU 16           * BDOS Close File
FILESIZE  EQU 35           * BDOS Get File Size
PRINTSTR  EQU 9            * BDOS Print String

TEXT

START:
    LINK A6, #0            * Stack Frame markieren
    MOVE.L 8(A6), A1       * Adresse der Base Page holen
    TST.B $80(A1)          * Parameter angegeben?
    BEQ NOFILE             * Nein, dort weiter

    LEA $5C(A1), A2        * FCB Adresse nach A2

    MOVE #OPENFILE, D0     * BDOS Open File
    MOVE.L A2, D1          * FCB Adresse
    TRAP #2                * ausführen
    CMP #255, D0           * Fehler?
    BEQ ERROPEN            * Ausgabe und Ende

    MOVE #FILESIZE, D0     * BDOS Get File Size
    MOVE.L A2, D1          * FCB Adresse
    TRAP #2                * ausführen

    CLR.L D0               * 24 Bit Wert zusammensetzen
    MOVE.B 33(a2), D0      * MSB laden
    SWAP D0                * nach oben
    MOVE.W 34(a2), D0      * LSB laden
    MULU #128, D0          * Mal Sektorgröße

    MOVE #CLOSEFILE, D0    * BDOS Close File
    MOVE.L A2, D1          * FCB Adresse
    TRAP #2                * ausführen

    MOVE.L #VAR1, A0       * Ausgabeadresse
    BSR PRINTD             * Dezimalwert in Buffer
    MOVE.L #BUFFER, D1     * Bufferadresse laden

EXIT:
    MOVE #PRINTSTR, D0     * BDOS Print String
    TRAP #2                * Text ausgeben
    UNLK A6                * Stack Frame freigeben
    RTS                    * Programmende

NOFILE:
    MOVE.L #ERRNF, D1      * Adresse Fehlermeldung
    BRA EXIT               * Ausgeben und Ende
ERROPEN:
    MOVE.L #ERROP, D1      * Adresse Fehlermeldung
    BRA EXIT               * Ausgeben und Ende

DATA

BUFFER:   DC.B 13,10,'Laenge der Datei in Bytes : '
VAR1:     DC.B '          ',13,10
          DC.B '$'
ERRNF:    DC.B 13,10,'Kein Dateiname angegeben'13,10,'$' 
ERROP:    DC.B 13,10,'Fehler beim oeffnen der Datei'13,10,'$' 

Laden einer Datei in den Speicher

Das folgende Beispiel zeigt, wie man den Inhalt einer beliebigen Datei komplett in den Speicher lädt. Dabei werden die Daten auf der nächsten 128 Byte Grenze unmittelbar hinter das Programm geladen. Dabei werden immer ganze Blöcke zu je 128 Byte aus der Datei geladen.

****************************
* LOADFILE.S
****************************

OPENFILE  EQU 15           * BDOS Open File
CLOSEFILE EQU 16           * BDOS Close File
READFILE  EQU 20           * BDOS Read File
SETDMA    EQU 26           * BDOS Set DMA Address
PRINTSTR  EQU 9            * BDOS Print String

TEXT

START:
    LINK A6, #0            * Stack Frame markieren
    MOVE.L 8(A6), A1       * Adresse der Base Page holen
    TST.B $80(A1)          * Parameter angegeben?
    BEQ NOFILE             * Nein, dort weiter

    LEA $5C(A1), A2        * FCB Adresse nach A2

    MOVE #OPENFILE, D0     * BDOS Open File
    MOVE.L A2, D1          * FCB Adresse
    TRAP #2                * ausführen
    CMP #255, D0           * Fehler?
    BEQ ERROPEN            * Ausgabe und Ende

    MOVE.L #DATEI, D1      * Niedrigste Ladeadresse
    AND.L #$FF80, D1       * Anpassung auf naechste
    ADD.L #128, D1         * 128 Byte Grenze

    MOVE.L #VON, A0        * Startadresse
    MOVE.L D1, D0          * ausgeben
    BSR PRINT8X

LOOP:
    MOVEM.L D1, -(A7)      * Ladeadresse merken
    MOVE #SETDMA, D0       * DMA Adresse setzen
    TRAP #2
    MOVE #READFILE, D0     * Lesen aus Datei
    MOVE.L A2, D1          * FCB Adresse 
    TRAP #2                
    MOVEM.L (A7)+, D1      * Ladeadresse wiederherstellen
    ADD.L #128, D1         * nächste Adresse berechnen
    TST D0                 * Alle Blöcke gelesen?
    BEQ LOOP               * Nein, dann wiederholen

    MOVE #CLOSEFILE, D0    * BDOS Close File
    MOVE.L A2, D1          * FCB Adresse
    TRAP #2                * ausführen

    MOVE.L #OKTXT, D1      * Textausgabe OK 
EXIT:
    MOVE #PRINTSTR, D0     * BDOS Print String
    TRAP #2                * Text ausgeben
    UNLK A6                * Stack Frame freigeben
    RTS                    * Programmende

NOFILE:
    MOVE.L #ERRNF, D1      * Adresse Fehlermeldung
    BRA EXIT               * Ausgeben und Ende
ERROPEN:
    MOVE.L #ERROP, D1      * Adresse Fehlermeldung
    BRA EXIT               * Ausgeben und Ende

DATA

OKTXT:    DC.B 13,10,'Datei eingelesen von '
VON:      DC.B '-------- bis '
BIS:      DC.B ‚--------',13,10,'$'
ERRNF:    DC.B 13,10,'Kein Dateiname angegeben'13,10,'$' 
ERROP:    DC.B 13,10,'Fehler beim oeffnen der Datei'13,10,'$'

BSS

DATEI:    DS.B 1          * Niedrigste mögliche Ladeadresse

Zusammensetzen zweier Textdateien

Der folgende Code dient dazu, zwei Textdateien zu einer Datei zusammenzuführen. Das Programm erwartet als Parameter zwei Dateinamen von existierenden Textdateien. Beide Dateien werden nacheinander in den Speicher eingelesen und danach wieder auf der Diskette gespeichert. Die zusammengesetzte Textdatei ersetzt die erste Datei. Das bedeutet, dass der Inhalt der zweiten Datei an die erste Datei angehängt wird.

****************************
* JOINTEXT.S
****************************

OPENFILE  EQU 15           * BDOS Open File
CLOSEFILE EQU 16           * BDOS Close File
READFILE  EQU 20           * BDOS Read File
WRITEFILE EQU 21           * BDOS Write File
SETDMA    EQU 26           * BDOS Set DMA Address
PRINTSTR  EQU 9            * BDOS Print String

TEXT

START:
    LINK A6, #0            * Stack Frame markieren
    MOVE.L 8(A6), A1       * Adresse der Base Page holen

    LEA $5C(A1), A2        * Adresse FCB1 nach A2
    LEA $38(A1), A3        * Adresse FCB2 nach A3

    MOVE #OPENFILE, D0     * BDOS Open File
    MOVE.L A2, D1          * FCB1 Adresse
    TRAP #2                * ausführen
    CMP #255, D0           * Fehler?
    BEQ ERROPEN            * Ausgabe und Ende

    MOVE #OPENFILE, D0     * BDOS Open File
    MOVE.L A3, D1          * FCB2 Adresse
    TRAP #2                * ausführen
    CMP #255, D0           * Fehler?
    BEQ ERROPEN            * Ausgabe und Ende

    MOVE.L #DATEI, D1      * Ladeadresse Datei 1

LOOP1:
    MOVEM.L D1, -(A7)      * Ladeadresse merken
    MOVE #SETDMA, D0       * DMA Adresse setzen
    TRAP #2
    MOVE #READFILE, D0     * Lesen aus Datei
    MOVE.L A2, D1          * FCB1 
    TRAP #2                
    MOVEM.L (A7)+, D1      * Ladeadresse wiederherstellen
    ADD.L #128, D1         * nächste Adresse berechnen
    TST D0                 * Alle Blöcke gelesen?
    BEQ LOOP               * Nein, dann wiederholen

    MOVE.L #DATEI, A0      * Datei 1 nach Endekennung durchsuchen
LOOP2:
    CMP.B #$1A, (A0)+      * Endekennung $1A ?
    BNE LOOP2              * bis gefunden
    MOVE.L A0, D1          * Ende Datei 1
    SUBQ.L #1, D1          * Endekennung überschreiben
    
LOOP3:
    MOVEM.L D1, -(A7)      * Ladeadresse merken
    MOVE #SETDMA, D0       * DMA Adresse setzen
    TRAP #2
    MOVE #READFILE, D0     * Lesen aus Datei
    MOVE.L A3, D1          * FCB2 
    TRAP #2                
    MOVEM.L (A7)+, D1      * Ladeadresse wiederherstellen
    ADD.L #128, D1         * nächste Adresse berechnen
    TST D0                 * Alle Blöcke gelesen?
    BEQ LOOP               * Nein, dann wiederholen

    MOVE #CLOSEFILE, D0    * BDOS Close File
    MOVE.L A2, D1          * FCB1 
    TRAP #2 

    MOVE #CLOSEFILE, D0    * BDOS Close File
    MOVE.L A3, D1          * FCB2 
    TRAP #2 

    CLR.B 12(A2)           * FCB1 EX = 0
    CLR.B 32(A2)           * FCB1 CR = 0

    MOVE #OPENFILE, D0     * BDOS Open File
    MOVE.L A2, D1          * FCB1
    TRAP #2
    CMP #255, D0           * OK?
    BEQ ERROPEN

    MOVE.L #DATEI, D1      * Startadresse
LOOP4:
    MOVEM.L D1, -(A7)      * Adresse merken
    MOVE #SETDMA, D0       * BDOS Set DMA Address
    TRAP #2
    MOVE #WRITEFILE, D0    * BDOS Write File
    MOVE.L A2,D1           * FCB1
    TRAP #2
    MOVEM.L (A7)+, D1      * Adresse wiederherstellen
    TST D0                 * Fehler?
    BNE ERRWRITE

    MOVE.L D1, A0          * Aktuellen Block absuchen
    MOVE #127, D3          * 128 Bytes
LOOP5:
    CMP.B #$1A, (A0)+      * Endekennung enthalten?
    BEQ FERTIG
    DBRA D3, LOOP5
    ADD.L #128, D1         * Nächster Block
    BRA LOOP4

FERTIG:
    MOVE #CLOSEFILE, D0    * BDOS Close File
    MOVE.L A2, D1          * FCB1
    TRAP #2

    MOVE.L #OKTXT, D1      * Textausgabe OK 
EXIT:
    MOVE #PRINTSTR, D0     * BDOS Print String
    TRAP #2                * Text ausgeben
    UNLK A6                * Stack Frame freigeben
    RTS                    * Programmende

ERROPEN:
    MOVE.L #ERROP, D1      * Adresse Fehlermeldung
    BRA EXIT               * Ausgeben und Ende
ERRWRITE:
    MOVE.L #ERRWR, D1
    BRA EXIT

DATA

OKTXT:    DC.B 13,10,'Dateien erfolgreich zusammengesetzt',13,10,'$'
ERROP:    DC.B 13,10,'Fehler beim Laden einer Datei',13,10,'$'
ERRWR:    DC.B 13,10,'Fehler beim Schreiben der Datei',13,10,'$'

BSS

DATEI:    DS.B 1          * Niedrigste mögliche Ladeadresse

Löschen und Anlegen von Dateien

Zum Abschluss des Kapitels ein kleines Programm zum Anlegen einer neuen Textdatei auf der Diskette. Das Beispiel ist absichtlich kurz gehalten und soll nur dazu dienen, die Arbeitsweise darzustellen. Beim Ausprobieren bitte darauf achten, dass eine bereits vorhandene Datei mit dem angegebenen Dateinamen überschrieben wird.
****************************
* MAKETEXT.S
****************************

OPENFILE  EQU 15           * BDOS Open File
CLOSEFILE EQU 16           * BDOS Close File
WRITEFILE EQU 21           * BDOS Write File
MAKEFILE  EQU 22           * BDOS Make File
SETDMA    EQU 26           * BDOS Set DMA Address
PRINTSTR  EQU 9            * BDOS Print String

TEXT

START:
    LINK A6, #0            * Stack Frame markieren
    MOVE.L 8(A6), A1       * Adresse der Base Page holen
    TST.B $80(A1)          * Parameter vorhanden?
    BEQ NOFILE             * Fehlermeldung ausgeben

    LEA $5C(A1), A2        * Adresse FCB1 nach A2

    MOVE #OPENFILE, D0     * BDOS Open File
    MOVE.L A2, D1          * FCB1 Adresse
    TRAP #2                * Testen ob Datei schon vorhanden
    CMP #255, D0           * Fehler?
    BEQ CONT               * Nicht vorhanden, anlegen

    MOVE #DELETEFILE, D0   * BDOS Delete File
    MOVE.L A2, D1          * FCB1
    TRAP #2

CONT:
    MOVE.L #MAKEFILE, D0   * BDOS Make File
    MOVE.L A2, D1          * FCB1
    TRAP #2
    CMP #255, D0           * Fehler?
    BEQ ERRMAKE

    MOVE #OPENFILE, D0     * BDOS Open File
    MOVE.L A2, D1          * FCB1
    TRAP #2 

    MOVE.L #INHALT, D1     * Zu schreibende Daten

    MOVE #SETDMA, D0       * BDOS Set DMA Address
    MOVE.L #INHALT, D1     * Startadresse
    TRAP #2

    MOVE #WRITEFILE, D0    * BDOS Write File
    MOVE.L A2,D1           * FCB1
    TRAP #2
    TST D0                 * Fehler?
    BNE ERRWRITE

    MOVE #CLOSEFILE, D0    * BDOS Close File
    MOVE.L A2, D1          * FCB1
    TRAP #2

    MOVE.L #OKTXT, D1      * Textausgabe OK 
EXIT:
    MOVE #PRINTSTR, D0     * BDOS Print String
    TRAP #2                * Text ausgeben
    UNLK A6                * Stack Frame freigeben
    RTS                    * Programmende

NOFILE:
    MOVE.L #ERRNO, D1      * Adresse Fehlermeldung
    BRA EXIT               * Ausgeben und Ende
ERRMAKE:
    MOVE.L #ERRMA, D1      * Adresse Fehlermeldung
    BRA EXIT               * Ausgeben und Ende
ERRWRITE:
    MOVE.L #ERRWR, D1      * Adresse Fehlermeldung
    BRA EXIT               * Ausgeben und Ende

DATA

OKTXT:    DC.B 13,10,'Datei erfolgreich erstellt',13,10,'$'
ERRNO:    DC.B 13,10,'Fehler kein Dateiname angegeben',13,10,'$'
ERRMA:    DC.B 13,10,'Fehler beim Anlegen der Datei',13,10,'$'
ERRWR:    DC.B 13,10,'Fehler beim Schreiben der Datei',13,10,'$'

INHALT:   DC.B '*********************************',13,10
          DC.B '* NEU ANGELEGTE DATEI',13,10
          DC.B '*********************************',13,10
          DC.B $1A

Fazit

Auch wenn die Beispiele immer länger werden, so schwierig ist die Nutzung der BDOS-Funktionen nicht. Viel wichtiger ist es, sich vorher ein Konzept für ein umzusetzendes Programm zu erstellen.
Weiter zu Teil 8 der Serie: Bibliotheken

Zurück zu Teil 6 der Serie: Wichtige Datenstrukturen