Nachdem wir in der vorletzten Ausgabe der ST Computer die allgemeinen Assembler-Macros abgedruckt haben, wollen wir uns diesmal mit den Diskettenmacros beschäftigen. Dazu wollen wir zunächst einmal ein paar Erläuterungen zu den Assembler-Macros geben.
Wenn man mit ISAM & PRIMA arbeitet, kann man bis zu sechs Diskettendateien gleichzeitig eröffnen. Wem dies aber nicht genügt, dem steht die Möglichkeit offen, die Diskettendefinitionen zu erweitern. Für eine siebte Datei müßte man dazu nur die Definitionen HANDL7, RECL7, FILE7 und EOF7 editieren.
Von diesen sechs gleichzeitig offenen Dateien dürfen aber nur maximal drei Dateien als ISAM-Dateien organisiert sein. Die Erläuterungen und Erweiterungsmöglichkeiten von ISAM-Dateien werden dann noch genauer in der Dezemberausgabe der ST Computer besprochen werden.
Mit den sequentiellen Zugriffsmacros WRITE und GET können nicht nur Diskettendateien, sondern auch Bildschirm, Tastatur, die serielle RS 232-und die parallele Schnittstelle, also auch ein Drucker, angesprochen werden.
Man muß hierfür anstelle von OPEN die Handle-Nummer für das gewünschte Peripheriegerät nach HANDLx (x = Dateinummer; siehe auch bei den Diskettendefinitionen) bringen. Das Gleiche gilt auch für die Recordlänge, die in RECLx definiert wird. Die Handle-Nummern sind folgendermaßen festgelegt:
0 = Tastatur
1 = Bildschirm
2 = Serielle Schnittstelle (RS 232)
3 = Parallele Schnittstelle (z. B. Drucker)
Nach dem Ende der Verarbeitung muß man anstelle von CLOSE die Dateinummer wieder freigeben. Dies geschieht, indem man den Wert -1 als Wort (.W) nach HANDLx und eine Null als Langwort (.L) nach EOFx schreibt.
Schicken eines 1-stelligen Records an einen Drucker
Um diese besser verständlich zu machen, beschicken wir als Beispiel einen Drucker mit 1-stelligen Records:
Wenn man Diskettendateien, deren Länge unbekannt ist, also zum Beispiel irgendwelche Textdateien, lesen will, sei hier noch ein kleiner Tip gegeben.
Man kann in diesem Fall natürlich mit dem READ-Macro und der Recordlänge 1 arbeiten und warten, bis die EOF-Bedingung auftaucht. Das hat aber den Nachteil, daß es relativ langsam vonstatten geht, da viele Einzelzugriffe notwendig sind. Schneller geht es mit einer groß gewählten Recordlänge. Wie aber eine Recordlänge einer Datei festlegen, deren Größe man nicht kennt? Das folgende Beispiel zeigt hierfür eine Möglichkeit:
Festlegen einer unbekannten Recordlänge
Doch nun zu den einzelnen Macrobefehlen:
Das Format dieses Macros entspricht dem gleichen Befehl im BASIC. Dem Macro müssen vier Parameter folgen.
Der erste Parameter gibt an, ob eine Datei neu gebildet wird (I) oder eine schon bestehende eröffnet werden soll (0). Er sagt nichts über die spätere Zugriffsmethode, Lesen oder Schreiben, aus. Der zweite Parameter ist die Dateinummer, der dritte der Dateiname und der vierte die Recordlänge. Als Angabe für den dritten Parameter dürfen nur Register oder Literale benutzt werden.
Beispiele:
OPEN ”I”,1,”Dateiname”,95
OPEN ”O”,2,D 1,100
Falsch:
OPEN "T”,l,#Name,20
; #Name als Parameter nicht erlaubt
;
;
OPEN: MACRO
OP0?0: TST.W HANDL72
BMI OP1?0
MOVE.L #-100,D0 ; ALREADY OPENED
MOVE.L #0P7?0,DSKRET :RETURN-ADR.V.FEHLERROUT.
MOVE.B #?2,DSKFIL ;FAN-NR. -> DSKFIL
JMP DSKERROR
OP1?0: EQU *
IF ?1 = "O"
CLR.W -(SP)
ELSE
MOVE.W #2,-(SP)
ENDIF
IF '?3’ > 'D7'
BRA OP4?0
OP2?0: DC *?3’
OP3?0: EQU *-l
EVEN
OP4?O: MOVE.L #OP2?0+1,FILE?2
CLR.B OP370
ELSE
MOVE.L ?3,FILE?2
ENDIF
MOVE.L #?4,RECL?2
MOVE.L FILE? 2,-(SP)
IF ?1 = "0"
MOVE.W #$3C,-(SP>
ELSE
MOVE.W #$3D,-(SP)
ENDIF
TRAP #1
ADDQ.L #8, SP
TST.L D0
BPL OP5?O
MOVE.L #OP7?0,DSKRET ;RETURN-ADR.V.FEHLERROUT.
MOVE.B #?2,DSKFIL SFAN-NR. -> DSKFIL
JMP DSKERROR
OP5?0: MOVE.W D0.HANDL72
IF ?1 = "I"
MOVE.L #DTABUF,-(SP)
MOVE.W #S1A,-(SP) ;SET DTA
TRAP #1
ADDQ.L #6,SP
CLR.W -(SP) ;ATTRIBUT O
MOVE.L FILE?2,-(SP) ;ADR. FILENAME
MOVE.W #$4E,-(SP) ; FUNKTION SFIRST
TRAP #1
ADDQ.L #8,SP
TST.L D0
BPL 0P6?0
MOVE.L #0P7?0,DSKRET JRETURN-ADR.V.FEHLERROUT.
MOVE.B #?2,DSKFIL ;FAN-NR. -> DSKFIL
JMP DSKERROR
OP6?0: MOVE.L DTABUF+26,EOF?2 ;DATEIGRÖßE IN BYTES
ENDIF
OP7?0: EQU *
ENDM
Open
Format: CLOSE Dateinummer
Die Ein- bzw. Ausgabe von oder an Ein/Ausgabegeräten wird beendet, somit ist die Dateinummer wieder frei.
Beispiel: CLOSE1
CLOSE: MACRO
TST.W HANDL?1
BPL CL070
MOVE.L #-101,D0 SNOT OPEN
MOVE.L #CL2?0,DSKRET ;RETURN-ADR.V.FEHLERROUT.
MOVE.B #?1,DSKFIL ;FAN-NR. -> DSKFIL
JMP DSKERROR
CL0?0: MOVE.W HANDL?1,-(SP)
MOVE.W #$ 3E,-(SP)
TRAP #1
ADDQ.L #4,SP
TST.L D0
BPL CL1?0
MOVE.L #CL2?0,DSKRET ;RETURN-ADR.V.FEHLERROUT.
MOVE.B #?1,DSKFIL ;FAN-NR. -> DSKFIL
JMP DSKERROR
CL1?0: MOVE.W #-1,HANDL?1 ;KENNZEICHEN F. NOT OPEN
CLR.L EOF?1
CL2?0: EQU *
ENDM
— Daten an eine bestehende Datei an-hängen
Format: EXTEND Dateinummer
Bevor dieses Macro aufgerufen wird, muß zuerst ein OPEN ”1” erfolgen. Anschließend können dann Daten mit dem WRITE-Macro in die gewünschte Datei geschrieben werden.
Beispiel: EXTEND 3
EXTEND: MACRO
CLP. W -(SP)
MOVE.W HANDL?1,-(SP>
MOVE.L EOF?1,-(SP)
MOVE.W #942,-(SP) ; LSEEK
TRAP #1
ADD.L #10,SP
TST.L D0
BPL EX 1?0
MOVE.L #EX1?0, DSKRET ; RETURN-ADR.V.FEHLERROUT.
MOVE.B #?1,DSKFIL J FAN-NR. -> DSKFIL
JMP DSKERROR
EX 1?0: EQU *
ENDM
Extend
— Ermitteln der relativen Satznummer des letzten Datei-Records
Format: LOF Dateinummer
Bei diesem Macro ist zu beachten, daß bei Dateien, die mit READ oder WRI-TE bearbeitet werden, der Aufruf nur unmittelbar nach dem OPEN-Macro erfolgen darf; bei anderen Dateien dagegen immer, sofern sie irgendwann zuvor geöffnet wurden. Die letzte Recordnummer steht anschließend im Datenregister DO.
Beispiel: LOF 3
LOF: MACRO
MOVEM.L D1-D3,-(SP>
MOVE.L EOF?1,D1
MOVE.L RECL?1,D3
JSR DIVI
MOVE.L D1,D0
MOVEM.L EN DM (SP)+,D1-D3
ENDM
Format: GET Dateinummer, # Record-nummer,# Puffer
Der angegebene Datensatz wird aus einer relativen Datei gelesen und in den Puffer geschrieben. Wird das Ende der Datei erreicht, steht anschließend eine -99 im Datenregister DO. Bei Verwendung von Registern als Parameter ist darauf zu achten, daß sie als Langwörter (.L) vorliegen müssen.
Beispiele: GET 2,# 12,# Puffer GET l,Dl,D2
GET: MACRO
TST.W HANDL?1
BPL GE 1?0
MOVE.L #-101,D0 ;ndt open
MOVE.L #GE4?0,DSKRET ; RETURN-ADR.V.FEHLERROUT.
MOVE.B #?1.DSKFIL ; FAN-NR. -> DSKFIL
JMP DSKERROR
GE1?0: MOVEM.L Dl-D2,-(SP)
MOVE.L ?2, DO
MOVE.L RECL?1,D2 JRECL
MOVE.L D0,Dl
JSR MULTI :* RECORD-#
MOVE.L D1 ,D0
MOVEM.L (SP)+,D1-D2
CMP.L EOF?1,D0 JINNERHALB DATEIGRENZEN ?
BLS GE2?0 J JA
MOVE.L #-99,D0 ;OUT OF FILE-BOUNDS
BRA GE4?0
GE2?0: SUB.L RECL?1,D0
CLR.W -(SP>
MOVE.W HANDL?1,-(SP)
MDVE.L D0,-(SP)
MDVE.W #942,-(SP) SLSEEK
TRAP #1
ADD.L #10,SP
TST.L D0
BPL GE3?0
MOVE.L #GE4?0,DSKRET ;RETURN-ADR.V.FEHLERROUT.
MOVE.B #?1.DSKFIL ;FAN-NR. -> DSKFIL
JMP DSKERRDR
GE3?0: MOVE.L ?3,-(SP>
MOVE.L RECL?1,-(SP>
MOVE.W HANDL?1,-(SP)
MDVE.W #9 3F,-(SP) i READ
TRAP #1
ADD.L #12,SP
TST.L D0
BPL GE4?0
MOVE.L #GE4?0,DSKRET ;RETURN-ADR.V.FEHLERROUT.
MOVE.B #?1.DSKFIL JFAN-NR. -> DSKFIL
JMP DSKERROR
GE4?0: EQU ★
ENDM
Format: PUT Dateinummer, # Recordnummer,# Puffer
Der angegebene Datensatz wird aus dem Puffer in eine relative Datei geschrieben. Ebenfalls wie bei dem GET-Macro müssen die Parameter bei der Verwendung von Registern als Langwörter (.L) vorliegen.
Beispiele: PUT 2,# 12,# Puffer PUT 1,D1,D2
Put
— Nächsten sequentiellen Datensatz lesen
Format: READ Dateinummer,# Puffer
Wenn das Ende der Datei (EOF) erreicht wird, wird eine -99 in das Datenregister DO übergeben.
Beispiel: READ 2,D2
READ: MACRO
TST.W HANDL?1
BPL RE 170
MOVE.L #-101,D0 ;FILE NOT OPEN
MOVE.L #RE3?0,DSKRET ; RETURN-ADR.V.FEHLERROUT.
MOVE.B #71,DSKFIL ;FAN-NR. -> DSKFIL
JMP DSKERROR
RE1?0: MOVE.L RECL?1,D0
SUB.L D0,EOF?1 JEOF ?
BPL RE270 JNEIN
MOVE.L #-99,D0 JJA, EOF
BRA RE370
RE2?0: MOVE.L 72,-CSP)
MOVE.L RECL?1,D0
MOVE.L D0,-CSP)
MOVE.W HANDL?1,-CSP)
MOVE.W #S3F,-CSP) J READ
TRAP #1
ADD.L #12,SP
TST.L D0
BPL RE370
MOVE.L #RE3?0,DSKRET ; RETURN-ADR.V.FEHLERRDUT.
MOVE.B #71,DSKFIL ;FAN-NR. -> DSKFIL
JMP DSKERROR
RE370: EQU *
ENDM
Format: WRITE Dateinummer, # Puffer
Beispiel: WRITE 2,D4
WRITE: MACRO
TST.W HANDL71
BPL WR070
MOVE.L #-101,D0 JFILE NOT OPEN
MOVE.L #WR9?0,DSKRET ;RETURN-ADR.V.FEHLERROUT.
MOVE.B #71,DSKFIL 1FAN-NR. -> DSKFIL
JMP DSKERROR
WR070: MOVE.L 72,-CSP)
MOVE.L RECL?1,D0
MOVE.L D0,-CSP)
MOVE.W HANDL71,-CSP)
MOVE.W #$ 40,-C SP) ;WRITE
TRAP #1
ADD.L #12,SP
TST.L D0
BMI WR170
CMP.L RECL?1,D0
BEQ WR970
MOVE.L #-102,D0
WR170: MOVE.L #WR9?0,DSKRET ;RETURN-ADR.V.FEHLERROUT.
MOVE.B #71,DSKFIL JFAN-NR. -> DSKFIL
JMP DSKERROR
WR9?0: EQU *
ENDM
Write
— Umbenennen von Dateien
Format: RENAME ”Alt”,”Neu”
Tritt ein Fehler nach Aufruf dieser Routine auf, wird ein negativer Wert in das Datenregister DO geschrieben, ansonsten eine Null.
RENAME: MACRO
BRA RENA370
RENA1?0: DC 71
DC 0
RENA2?0: DC 72
DC 0
EVEN
RENA3?0: MOVE.L #RENA2?0,-CSP)
MOVE.L #RENA170,-CSP)
MOVE.W #0,-CSP)
MOVE.W #$56,-CSP)
TRAP #1
ADD.L #12,SP
ENDM
;
— Löschen von Dateien
Format: KILL "Dateiname”
Das Datenregister DO wird ebenso wie bei dem RENAME-Macro behandelt, also negativer Wert bei einem aufgetretenen Fehler und Null im Normalfall.
Kill
KILL: MACRO
BRA KIL270
KIL170: DC 71
DC 0
EVEN
KIL270: MOVE.L #KIL170,-CSP)
MOVE.W #$41,-CSP)
TRAP #1
ADDQ.L #6,SP
ENDM
Das letzte Kapitel des zweiten Teils von ISAM & PRIMA beinhaltet die oben genannten Definitionen und Fehler-Routinen; außerdem noch einen kleinen Hinweis auf den Autor.
Bei jedem Diskettenmacro, mit Ausnahme von RENAME und KILL, wird automatisch auf Fehler geprüft. Tritt ein solcher auf, erscheint dann ein Fehlerhinweis in Klartext auf dem Bildschirm und das Programm wartet solange, bis ein Tastendruck erfolgt. Wird eine Taste gedrückt, wird das Programm direkt hinter dem Macro fortgesetzt, in dem der Fehler auftrat und der Fehlercode in das Datenregister DO übergeben. Es besteht also die Möglichkeit, hinter jedem Diskettenmacro DO abzufragen und bei aufgetretenem Fehler anschließend nach eigenen Wünschen fortzufahren.
Eine Ausnahme bildet der Fehlercode — 99, der das Ende der Datei (EOF) anzeigt. Hier erfolgt kein automatischer Fehlerhinweis, da dies ja nicht sehr sinnvoll wäre.
Falls nun aber der Wunsch besteht, aus irgendwelchen Gründen eine automatische Fehleranzeige zu unterdrücken, kann man dies auf folgende Weise leicht lösen.
Man muß dazu nur den Vektor DSK-VEC, der in der Fehlerbehandlungs-Routine definiert ist, auf die eigene Fehlerroutine einstellen. Zuvor sollte man aber sicherheitshalber den Originalvektor in einem Datenregister sichern. Der Vektor DSKRET (.L) gibt dann die Adresse an, in der die Instruktion steht, die unmittelbar hinter dem zum Fehler führenden Macro liegt. Dies wäre dann die Adresse, die man anspringen muß, nachdem man den Fehler erfolgreich beheben konnte.
Diskettendefinitionen & Fehlerbehandlungsroutine
Damit sei für den zweiten Teil der Assemblermacros erst einmal genug. In der nächsten Ausgabe werden dann die Standardroutinen, wie zum Beispiel Eingabe-, Mathematik- und Zahlenumwandlungs-Routinen behandelt werden. (HE)