Eigentlich wollte ich ja nach dem fünften Teil dieses Kurses (im Novemberheft) in der Versenkung verschwinden. Doch Sie haben zu früh aufgeatmet: Der Floppykurs erfährt eine -wenn auch kurze - Fortsetzung. Häufig gestellte Leserfragen, die alle interessieren könnten, sollen einmal beantwortet werden, außerdem möchte ich noch zu dem einen oder anderen Thema einen Nachtrag bringen.
Frage 1: Kann ich die Anzahl der FATs im Bootsektor auch auf 1 abändern und so mehr Platz auf der Diskette schaffen?
In der ST-Computer 7/87 hatte ich noch spekuliert, daß dies wohl möglich sei. Mittlerweile haben Tests aber ergeben, daß GEMDOS auf andere FAT-Anzahlen als zwei nicht vorbereitet ist. Es ist und bleibt eben der Schwachpunkt im Betriebssystem des ST, das GEMDOS. An anderer Stelle in diesem Heft finden Sie im GEMDOS-Kurs von Alex Esser (sei gegrüßt!) mehr Informationen zu diesem leidigen Thema.
Frage 2: Welche Manipulationen sind mit den fiktiven Verzeichniseinträgen 7 und möglich?
Wahrscheinlich keine. Im Teil 2 des Floppykurses habe ich zwar erwähnt, daß diese beiden Einträge in jedem Unterverzeichnis automatisch gebildet werden und durch eine Verzeigerung die Orientierung im Ordnergestrüpp erleichtern können; doch hat sich auch hier herausgestellt, daß GEMDOS diese Einträge überhaupt nicht benutzt, um sich zurecht-zufmden. und sind nur beibehalten worden, um mit MSDOS-Disketten kompatibel zu bleiben (Hallo Alex!).
Frage 3: Welche Probleme gibt es beim Einsatz von HYPERFORMAT?
Nicht mehr viele. Ich hatte ja vor längerer Zeit gemutmaßt, daß eventuell verschiedene Controllerserien an recht merkwürdigen Toleranzen schuld sein könnten, die HYPERFORMAT zu schaffen machten. Mittlerweile ist HYPERFORMAT aber so sicher geworden, daß diese minimalen Schwankungen wohl nicht mehr den Ausschlag geben.
Weiterhin wichtig bleibt aber die Drehzahl Ihres Laufwerks. Sie muß im Bereich von 300 bis 302 Umdrehungen pro Minute liegen und nicht, wie früher erwähnt, im Bereich bis zu 304 Umdrehungen. Auf diese Zahl war ich verfallen, weil mir das Public-Domain-Programm SPEED .TOS immer 1.5 Umdrehungen zuviel anzeigte; das heißt, ein Laufwerk, das die Diskette 300mal pro Minute komplett herumwirbelt, hat laut SPEED .TOS 301.5 Umdrehungen. Mittlerweile habe ich mir meine eigenen Meßprogramme geschrieben, die ihren Dienst korrekt verrichten. Sollten Sie selbst SPEED.TOS verwenden, können Sie bei Drehzahlanzeigen bis 304 Umdrehungen noch ruhig bleiben; darüberhinaus wird es aber langsam brenzlig für HYPERFORMAT. Warum?
HYPERFORMAT benötigt in den jetzigen Versionen etwa 6250 Bytes auf einer Spur. Bei einer normalen Drehzahl hat man die auch, sogar etwa 50 bis 70 Bytes mehr (wenn auch der Hersteller des Floppycontrollers das nicht wahrhaben will). Dreht das Laufwerk aber zu schnell, wird der Platz enger; es kann dann passieren, daß der letzte Sektor auf der Spur nicht mehr komplett geschrieben werden kann.
Es kommt auch vor, daß sich bei zu fixen Laufwerken die Datenfelder der Sektoren etwas verbreitern und die nachfolgenden Lückenbytes überschreiben; geschieht das mehrmals, werden die Synchronisationsbytes des nachfolgenden Adreßfeldes angeknabbert, und die Katastrophe ist nicht mehr weit (Zähne fest zusammenbeißen, Hände in den Nacken, Atem anhalten und beten).
Um dies alles brauchen Sie sich aber meist keine Gedanken zu machen, weil die Laufwerke im Normalfall schon ab Werk richtig justiert sind. Nun ist aber bei ATARI eigentlich nichts normal, und deswegen gibt es immer wieder Laufwerke, die nicht genau genug eingestellt sind, was man aber selbst leicht nachholen kann. Bei der alten SF314 (Epson-Laufwerk, zu erkennen am lauten Röhren des Drehmotors und der kleinen Auswurftaste) geht man zum Beispiel folgendermaßen vor:
Im Listing 1 und der zugehörigen Dokumentation finden Sie eine Routine, die Sie in den Extended Minimon (siehe ST-Computer 9/87 und 10/87) einbinden können. Sie mißt die aktuelle Drehzahl und errechnet auch einen Durchschnittswert.
Bei anderen Laufwerkstypen (selbst von den Original-ATARI-Laufwerken gibt es mindestens vier Versionen, von den Laufwerken im 1040 oder in den MegaSTs ganz zu schweigen) mag der Regler anders heißen und auch anders zu erreichen sein, das Prinzip bleibt dasselbe. Eine ausführliche Anleitung für einige ausgewählte Laufwerkstypen finden Sie in meinem Floppybuch, das dem nächst wohlfeil im Handel zu erstehen ist. Dort finden Sie übrigens nebst anderen Überraschungen auch eine neue Über-Giga-Version von HYPERFORMAT (V3.0).
Frage 4: Mein Laufwerk schlägt schon bei Spur 80 an; kann man das irgendwie ändern?
Man kann eventuell. Zu diesem Thema hat mich sogar einmal ein Leser angerufen, der sich etwas ausgedacht hatte. Er hatte irgendwelche mechanischen Begrenzungen in seinem Laufwerk einfach abgeschleift, was natürlich ein wenig hemdsärmlig ist. Aber es funktionierte dann doch so gut, daß er - Zitat - ”den Lesekopf so weit nach innen bewegen kann, bis er aus der Halterung fällt”. Auf diese Weise kann man einige innere Spuren (80 bis 85) noch zur Datenspeicherung nutzen und - per HYPERFORMAT - über 960000 Bytes auf eine Diskette quetschen. Ich möchte Ihnen davon abraten, höhere Spuren als Spur 85 zu benutzen, weil dort Ihre Daten wirklich nicht mehr sonderlich sicher wären. Leider habe ich nichts mehr von diesem mutigen Zeitgenossen gehört; er möge sich doch, falls er diese Zeilen hier liest, noch einmal bei mir melden. Danke.
So, und nun möchte ich mich für einige meiner Fehlgriffe im Floppykurs entschuldigen. Ein paar Details sind doch nicht so korrekt gewesen, wie ich sie nach bestem Wissen und Gewissen ausgeforscht und niedergeschrieben hatte. Zum Glück handelt es sich vergleichsweise um Kleinigkeiten.
In der ST-Computer 11/87 verhinderte beispielsweise ein dummer Tippfehler, daß Sie die wahre Codierung der Steprate in Controllerbefehlen erführen. Hier die korrigierte Tabelle (Tabelle 1):
Stepratenfeld | Steprate |
---|---|
r1 r0 | |
0 0 | 6ms |
0 1 | 12ms |
1 0 | 2ms |
1 1 | 3ms |
(Tabelle 1: Das Stepratenfeld in FDC-Befehlen, diesmal hoffentlich richtig abgetippt)
Im dritten Teil habe ich die Belegung der Adresse SFF8606 (DMAModus-Register) erläutert. Dieses Register ergibt -wenn man es liest - den aktuellen DMA-Status. In Bit 0 steht dann aber nicht, wie irrtümlich abgedruckt, eine 0, wenn kein DMA-Fehler aufgetreten ist, sondern eine 1.
Mein schlimmster Schnitzer aber - und das haben auch einige erkannt und mich je nach Temperament mehr oder weniger verärgert darauf hingewiesen - war die Darstellung der FATStruktur im ersten Teil des Floppykurses. Dort hatte ich folgenden Anfang einer FAT angegeben:
F7 FF FF 03 40 00 05 FF F0
Eine solche FAT kann unter TOS gar nicht existieren, die letzten beiden Bytes müßten eigentlich vertauscht sein. Schon damals hatte ich ja einen Hilferuf an Sie, verehrte Leserin, lieber Leser, abgesetzt, da ich selbst anfangs mit der FAT so meine Schwierigkeiten hatte. In der Zwischenzeit habe ich durch eigene Experimente und nicht zuletzt durch einige nette Zuschriften viel darüber gelernt und möchte das an dieser Stelle weitergeben.
Auf der FAT ist die Belegung einer Diskette mit Dateien vermerkt. Dabei werden aber immer komplette Cluster belegt; das sind normalerweise zwei zusammenhängende Sektoren. Eine FAT könnte nun so anfangen:
F7 FF FF 03 40 00 05 F0 FF
Jedem Cluster werden in der FAT 12 Bit (!) zugewiesen, das sind drei Hexadezimalziffern. TOS und Brüderchen MS-DOS beginnen die Nummerierung ihrer Cluster erst mit 2, die fiktiven Cluster 0 und 1 sind reserviert. In der FAT stehen an ihrer Stelle, wie man oben sieht, einige mysteriöse Bytes, die in TOS keine Wirkung haben und deswegen auch Null sein können. Unter MSDOS ist das erste Byte das sogen an n te Media-Byte und entspricht seinem Pendant im Bootsektor (siehe Floppykurs Teil II). Daß hier beim ST seltsamerweise nach dem Formatieren im Desktop eine $F7 steht, ist ein Grund, warum man ST-Disketten auf MSDOS-Maschinen doch nicht so ohne weiteres lesen kann.
Prinzipiell ist die FAT einfach zu verstehen. Im Diskettenverzeichnis steht für jede Datei ein Zeiger auf den ersten Cluster, den diese Datei belegt (siehe dazu auch Floppykurs, Teil II, über das Inhaltsverzeichnis der Diskette). Diesen Zeiger verwendet TOS, um an die betreffende Stelle der Blockbelegungstabelle zu springen. Dort hat nämlich jeder Cluster auf der Diskette einen eigens für ihn reservierten Platz in der FAT: Cluster 2 bekommt Platz Nr. 2, Cluster 500 hat Platz 500.
Nehmen wir an, in der Directory steht als erster Cluster die ’2’. Im FAT-Eintrag für Cluster 2 steht eine weitere Clusternummer ’3’. Aha, denken wir uns, die Datei setzt sich also auch in Cluster 3 fort. Mit dieser Drei springen wir in den FAT-Eintrag für Cluster 3- Dort finden wir wieder einen Verweis auf eine andere Clusternummer (nicht unbedingt auf Cluster 4).
Irgendwann ist auch die längste Datei am Ende: Dies wird in der Regel durch die fiktiven Clusternummern $FF8-$FFF angezeigt. Ein Wert von $FF0 bis $FF7 in einem FAT-Eintrag bedeutet, daß der betroffene Cluster beschädigt ist, also nicht belegt werden kann. Außerdem bedeutet ein Wert 0 in einem FAT-Eintrag, daß der Cluster frei ist.
Während das noch recht einsichtig klingt, werden Sie jetzt in der Praxis Ihre Schwierigkeiten haben. Denn auch die FAT-Einträge werden im Intel-Format abgespeichert, das heißt, niedrigstwertiges Byte zuerst. Dadurch ergibt sich in einer FAT ein ziemlich undurchsichtiger Wust, nämlich in unserem Beispiel:
F7 FF FF 03 40 00 05 F0FF...
(Bytenr: 012345678...)
MS-DOS und auch TOS füllen nämlich 16-Bit-Zahlen, die auf der Diskette im INTEL-Format stehen, mit den 12-Bit-Einträgen auf. Um das zu verstehen, lassen Sie uns das Konzept der Über-Cluster einführen. Das sind ganz einfach immer drei Bytes in der FAT. Der erste Über-Cluster in unserer Beispiel-FAT wäre dann F7 FF FF und interessiert uns nicht, weil er ja nur für die fiktiven Cluster 0 und 1 benutzt wird. Der zweite Über-Cluster ist schon interessanter:
0 3 4 0 00
+ + +
Nun nehmen wir an, ein Directoryeintrag zeige auf den Clustereintrag Nummero 2, also auf den Anfang unseres zweiten Über-Clusters. Die mit ”T” gekennzeichneten Nibbles (halbe Hexzahlen sozusagen) gehören zum ersten Cluster des Über-Clusters; da wir Intel-Format vor uns haben, muß die Null aus dem zweiten Byte noch vor die ”03”, also: 003, und schon haben wir die Nummer des nächsten Folgeclusters. Diese 003 zeigt auf den Clustereintrag 3 in der FAT, und der ist im nicht markierten Bereich des obigen Über-Clusters zu finden. Mit diesen nicht gekennzeichneten Nibbles verfährt man ähnlich wie vorhin, auch hier rutscht der höherwertige Teil (”00”) nach vorne, so daß wir eine hübsche 004 erhalten.
Für diejenigen, die das Selbermachen lieben, ist noch wichtig herauszufinden, wo ein bestimmter Eintrag in der FAT steht, und wie man algorithmisch vorgeht. Dazu gibt es ein Kochrezept:
Man prüfe, ob die gesuchte Clusternummer gerade ist. Ist sie das, multipliziere man sie mit 1.5 und lese dann das Wort ab der errechneten Stelle. Also zum Beispiel für die Clusternummer 4:
4 ist gerade, mal 1.5 ergibt 6, also liest man ab Byte 6 der Bei-spiel-FAT das Wort $05F0. Das dreht man wegen des Intel-Formats um zu $F005 und ignoriert das oberste Nibble - ergibt $005.
Ungerade Clusternummern multipliziert man ebenfalls mit 1.5 und ignoriert den Nachkommaanteil. Beispiel: Clusternummer 3 mal 1.5 ergibt 4.5. Ohne Nachkommastellen also 4. Ab Byte 4 lesen wir das Wort $4000. Was kommt jetzt? Richtig, Byteschaufelei wegen Intel-Format und so (Ergebnis $0040). Von diesem Ergebnis fällt das unterste Nibble weg (entspricht einer Division durch 16 oder 4 Rechtsshifts): Macht $004.
Wenn Sie diesen Algorithmus nachvollziehen und mit dem Konzept der Über-Cluster vergleichen, -werden Sie feststellen, daß ein Über-Cluster immer an einem geraden Clustereintrag beginnt. Ist die Nummer des gesuchten Eintrags also gerade, greift man auf die mit ”+” markierten Nibbles zu, ansonsten auf die anderen. Genau dieses Verhalten bildet der Algorithmus nach.
Ich denke, damit sind Sie fürs erste genügend verwirrt. Das war jetzt aber wirklich der vorläufig letzte Teil des Floppykurses; ich möchte mich jetzt meiner Festplatte widmen. Mal sehen, ob sich da ähnlich viel herausholen läßt wie aus der Floppy und deren Controller. Keep hacking, Ihr
Listing 1:
' Minimon für den ST
' Written 1987 by Claus Brod
' Am Felsenkeller 2
' 8772 Marktheidenfeld
'
' V.2.1 mit rudimentärer Registerroutine
' V.2.2 Registerroutine korrigiert, zusätzliche Fileausgabe
' V.2.3 mit Speedtest
'
Cls
Do
Print
Print "Minimon ST - (C) 1987 by Claus Brod"
Print
Repeat
Print "Sektormonitor oder Trackmonitor oder Quit (S/T/Q)?"
A$=Upper$(Input$(1))
Until A$="S" Or A$="T" Or A$*"Q“
Exit If A$="Q"
If A$="S"
@Sektormon
Else
@Trackmon
Endif
Loop
End
'
'
Procedure Gibmirzeit
Alert 1,"Funktion noch nichtI implementiert.",1,"OK",A
Return
'
' Prozedur Trackmon
' initialisiert den Trackmonitor
' zeigt in einer Schleife das Menü an, fragt auf Tastendruck ab
' und verteilt auf die Unterroutinen
'
Procedure Trackmon
@Init_trackmon
Cls
Prn%=0
Richtung%=0
Seite%=0
Drive%=0
Steprate%=1 ! 3ms Steprate
R$=Chr$(27)+"p"
O$=Chr$(27)+"q"
@Rst ! auf Track 0 zurückfahren
Do
Print
Print "************ TRACKMON (C) ***********"
@Prntable
Print R$;"0";O$;" Track 0, ";R$;"1";O$;"Step, ";R$;"2";O$;" Step-In, ";
Print R$;"3";O$;" Step-Out, ";R$;"4";O$;"Seek, ";R$;"5";O$;" Rd Sec, ";
Print R$;"6";O$;" Wr Sec"
Print R$;"7";O$;" Rd Adr. ";R$;"8";O$;"Rd Trk, ";R$;"9";O$;" Wr Trk, ";
Print R$;"A";O$;" IRQ, ";R$;"D";O$;"ump Buf. ";R$;"S";O$;"eite (";Seite%;
Print "), ";R$;"P";O$;"rn (o":
If Prn%=1
Print "n)"
Else
If Prn%=0
Print "ff)"
Else
Print "n file)"
Endif
Endif
Print R$;"R";O$;"egister, ";R$;"G";O$;"eschwindigkeit, ":R$;"Q";O$;"uit"
M$=Upper$(Input$(1))
Exit If M$="Q"
If M$="G"
@Speed
Endif
If M$="S"
Seite%=1-Seite%
Endif
If M$= "P"
Inc Prn%
If Prn%>2
Prn%=0
Endif
If Prn%=2
Input "Filename";Fi$
Endif
Endif
If M$="D"
@Dump_buf
Endif
If M$="A"
@Irq ! FOC unterbrechen
Endif
If M$="R"
@Register
Endif
If M$<="9" And M$>="0"
On Val(M$)+1 Gosub Rst,Step,Step_in,Step_out,Seek,Rdsec,Wrsec,Rdadr
On Val(M$)-7 Gosub Rdtrk,Wrtrk
Endif
Loop
Return
'
'
Procedure Init_trackmon
Print "Einen Moment, bitte!"
Restore Locksley
@Readprog(1000)
' LOCKSLEY.S einlesen
Inter$=Prg$
Inter=Varptr(Inter$)
Opcode=Inter*3
Restore Select
@Readprog(1000) ! Reserve für Erweiterung
' SELECT.S einlesen
Sel$=Prg$
Sel=Varptr(Sel$)
Laufwerk=Sel+3
Return
'
'
Procedure Select
Poke Laufwerk,Seite%+2 ! Laufwerk A, Seite "Seite%"
Call Sel
Return
Procedure Deselect
Poke Laufwerk,0 ! deselektieren
Call Sel
Return
'
Procedure Mach_schon(O%)
@Select ! Laufwerk selektieren
Poke Opcode,O%
Call Inter ! Kommando ausführen
@Deselect ! Laufwerk abwählen
Return
'
Procedure Register
' se1+3:8 für lesen, 9 für schreiben, 10 für DMA-Status
' in sel+4 wird das Register übergeben
' in sel+8 wird der Wert übergeben
Print R$;"Register";O$
Print R$;"L";O$;"esen oder ";R$;"S";O$;"chreiben?"
Repeat
A$=Upper$(Input$(1))
Until A$="L" Or A$="S"
If A$="L"
@Get_them_al1
Else
Op%=9
Poke Se1+3,Op%
Print "(1) Kommandoregister"
Print "(2) Trackregister"
Print "(3) FDC-Sektorregister"
Print "(4) Datenregister"
Print "(5) DMA-Sektorregister"
Repeat
A=Val(Input$(1))
Until A>B And A<6
R%=(A-1)*2
If A=5
R%=16
Endif
Dpoke Sel+4,128+R%
If Op%=9
Input "Neuer Wert für das Register";W%
Dpoke Sel+8,U%
Endif
Call Sel
Print "Opcode: $";Hex$(Peek(Sel+3))
Print "Register: $";Hex$(Dpeek(Sel+4))
Print "Wert: $";Hex$(Dpeek(Sel+8) And 255)
Print
Endif
Return
'
'
Procedure Get_them_all
Poke Sel+3.8 ! Register lesen
Dpoke Sel+4,128+0
Call Sel
Print "FDC-Statusregister: $";Hex$(Dpeek(Sel+8) And 255)
Dpoke Sel+4,128+2
Call Sel
Print "Trackregister: $";Hex$(Dpeek(Sel+8) And 255)
Dpoke Sel+4,128+4
Call Sel
Print "FDC-Sektorregister: $";Hex$(Dpeek(Sel+8) And 255)
Dpoke Sel+4,128+6
Call Sel
Print "Datenregister: $";Hex$(Dpeek(Sel+8) And 255)
Dpoke Sel+4,128+16
Call Sel
Print "DMA-Sektorregister: $";Hex$(Dpeek(Sel+8) And 255)
Poke Sel+3,10 ! DMA-Status lesen
Call Sel
Print "DMA-Status: $";Hex$(Dpeek(Sel+8) And 255)
Return
'
' Prozedur Rst
' fährt den Lesekopf auf Spur 0 zurück
'
Procedure Rst
Print R$;"Restore";O$
Track%=0
Richtung%=0
@Mach_schon(0+Steprate%) ! Restore-Befehl
Return
'
' Prozedur IRQ
' unterbricht den Floppycontroller bei der Arbeit
'
Procedure Speed
Local Dr,Lp%,Avr
@Irq
Cls
Print At(5.2);"Drehzahlmessung"
Print At(5.9);" Drehzahl : "
Print At(5,11);"Durchschnitt : "
Mfp%=&HFFFA01
Genau%=10
@Select
Dpoke Sel+2,9
Dpoke Sel+4,&H80
Dpoke Sel+8,&HD4
Call Sel
Repeat ! Warte auf Index
Until (Peek(Mfp%) And 32)=0 ! Dann Start !
Repeat
Dpoke Sel+2,9
Dpoke Sel+4,&H80
Dpoke Sel+8,&HD4
T2=Timer
For T%=1 To Genau%
Call Sel
Repeat
Until (Peek(Mfp%) And 32)=0
If Inkey$<>"" Or Mousek
T%=99
Endif
Next T%
Exit If T%=100
Dr=120B0*Genau%/(Timer-T2)
Print At(22,9);Using "###.###",Dr
Add Avr,Dr
Inc Lp%
Print At(22,11);Using "###.###",Avr/Lp%
Until Inkey$<>"" Or Mousek
@Irq
@Deselect
Return
'
'
Procedure Irq
Print R$;"IRQ";O$
@Mach_schon(208) ! IRQ-Befehl
Return
'
' Prozedur Step
' fährt den Lesekopf einen Schritt in die eingeschlagene Richtung
'
Procedure Step
Print R$;"Step";O$
Track%=Track%+Richtung%
@Mach_schon(32+16+Steprate%) ! Step mit Track-Update
Return
'
' Prozedur Step_in
' fährt den Lesekopf einen Schritt nach innen
'
Procedure Step_in
Print R$;"Step-in";O$
Richtung%=l
Track%=Track%+Richtung%
@Mach_schon(64+16+Steprate%) ! Step-in mit Update
Return
'
' Prozedur Step-out
' fährt den Kopf einen Schritt nach aupen
'
Procedure Step_out
Richtung%=-1
Print R$;"Step-out";O$
Track%=Track%+Richtung%
@Mach_schon(96+16+Steprate%) ! Step-out mit Update
Return
'
' Prozedur Seek
' fährt den Lesekopf auf die gewünschte Spur
'
Procedure Seek
Print R$;"Seek";O$
Input "Zieltrack";Trk
If Trk>Track%
Richtung%=1
Else
If Trk<Track%
Richtung%=-1
Endif
Endif
Track%=Trk
Poke Inter+5,Trk ! Spurnummer abliefern
@Mach_schon(16+Steprate%) ! Seek-Befehl
Return
'
' Prozedur Rdsec
' liest Sektor(en) auf aktuellem Track ein
'
Procedure Rdsec
Print R$;"Read sector";O$
Input "Welcher Sektor";Sector%
Poke Inter+7,Sector% ! Sektornummer schreiben
Input "Wieviel Bytes";Laenge
Buf$=Space$(12*512)
Dpoke Inter+8,laenge ! Länge der Übertragung
Lpoke Inter+10,Varptr(Buf$) ! Pufferadresse
@Mach_schon(128+16) ! Read multiple sectors
Return
'
' Prozedur Rdadr
' Liest Adreßfelder auf aktuellem Track ein
'
Procedure Rdadr
Print R$;"Read Adress";O$
Input "Wieviele AdrePfelder";Laenge
Dpoke Inter+8,Laenge ! Zahl der Adrepfelder
Laenge=Laenge*6 ! 6 Byte pro AdrefSfeld
Buf$=Space$()512)
Lpoke Inter+10,Varptr(Buf$) ! Pufferadresse Buf2$=Space$(180)
Lpoke Inter+14,Varptr(Buf2$) ! Pufferadresse für Status
@Mach_schon(192) ! Rd-Address-Befehl
Return
'
' Prozedur Wrsec
' schreibt Sektor(en) auf aktuellen Track
'
Procedure Wrsec
Print R$;"Write sector";O$
Input "Welcher Sektor";Sek
Poke Inter+7,Sek ! Sektornummer
Input "Wieviel Bytes";Laenge
Dpoke Inter+8,Laenge ! Länge der Übertragung
Lpoke Inter+10,Varptr(Buf$) ! Pufferadresse
@Mach_schon(168+16) ! Write multiple sectors
Return
'
' Prozedur Rdtrk
' Aktuellen Track einiesen
'
Procedure Rdtrk
Print R$;"Read Track";O$
Buf$=Space$(8008)
Lpoke Inter+10,Varptr(Buf$) ! Pufferadresse
Input "Wieviel Bytes":Laenge
Dpoke Inter+8,Laenge ! Länge der Übertragung
@Mach_schon(192+32) ! Read Track
Return
'
' Prozedur Wrtrk
' Einen Track formatieren
'
Procedure Wrtrk
Print R$;"Write Track";O$
T$=Space$(8000)
' liest die Trackdaten ab dem Label Trackdaten ein
' Format der Datazeilen:
' zu schreibendes Byte, danach Anzahl (nie oft soll dieses Byte geschrieben werden)
' "***.***" heit Schluß
Restore Trackdaten
Cn=1
Do
Read B$,Z$
@Hextodec(B$)
B=S
@Hextodec(Z$)
Z=S
Exit If B$="***"
If Upper$(B$)="TRACK"
B=Track%
Endif
If Upper$(B$)="SIDE"
B=5eite%
Endif
For T=1 To Z
Print B
Mid$(T$,Cn,1)=Chr$(B)
Inc Cn
Next T
Loop
Print
Lpoke Inter+10,Varptr(T$) ! Pufferadresse
Input "Wieviel Bytes";Laenge
Dpoke Inter+8,Laenge ! Länge der Übertragung
@Mach_schon(15*16) ! Write Track
Return
' Prozedur Dump_buf
' Gibt ersten oder zweiten Puffer aus
' und erlaubt ihn zu edieren
Procedure Dump_buf
Repeat
Print "Ersten oder zweiten Puffer ausgeben (1/2)?"
Ch$=Input$(1)
Until Ch$="1" Or Ch$="2"
If Ch$="1"
Sec$=Buf$
@Dump(Laenge)
Else
Sec$=Buf2$
@Dump(Len(Buf2$))
Endif
Print R$;"Edit (Y/N)?";O$
A$=Upper$(Input$(1))
If A$="Y"
If Ch$="1"
Sec$=Buf$
@Edit
Buf$=Sec$
Else
Sec$=Buf2$
@Edit
Buf2$=Sec$
Endif
Endif
Return
'
' Prozedur Prntable
' Statusmeldung ausgeben
'
Procedure Prntable
Inter=Varptr(Inter$)
Opcode=Inter+3
Sel=Varptr(Sel$)
Laufwerk=Sel+3
Print "Opcode :";
Dpeek(Inter+2);Tab(48);
If Dpeek(Inter+30)=0
Print "Kein ";
Endif
Print "Timeout!"
Print "Track :";Track%;Tab(40);
Print "Sektor :";Dpeek(Inter+6)
Print "Adresse des Puffers 1 :";Lpeek(Inter+10):Tab(40);
Print "Adresse des Puffers 2 :";Lpeek(Inter+14)
Print "FDC-Status :";Peek(Inter+19);Tab(40);
Print "DMA-Status :";Peek(Inter+21)
Print "Startadresse DMA :";Lpeek(Inter+22);Tab(40);
Print "Endadresse DMA :";Lpeek(Inter+26)
Print "Gelesene/geschriebene Bytes :";Dpeek(Inter+8)
Return
'
' Prozedur Readprog
' Liest Programm aus Datazeilen ein
'
Procedure Readprog(L)
Prg$=Space$(L)
T=1
Repeat
Read A$
If A$<>"***"
Mid$(Prg$,T,1)=Chr$(Val("&h"+A$))
Endif
Inc T
Until A$="***"
Return
'
' Prozedur Hextodec
' Wandelt A$ in Dezimal um (Ziel: S)
'
Procedure Hextodec(A$)
S=0
A$=Upper$(A$)
For I=1 To Len(A$)
A=Asc(Right$(A$,I))
If A>64
A=A-7
Endif
A=A-48
S=S+A*16^(I-1)
Next I
Return
'
'
' Sektormon: Kleiner Diskmon mit Standardfähigkeiten
'
Procedure Sektormon
Cls
Prn%=8
Status%=0
Seite%=0
Track%=0
Sector%=1
Drive%=8
Sec$=Space$(512)
R$=Chr$(27)+"p"
O$=Chr$(27)+"q"
@Lesen
Do
Print
Print "**** Minimon (C) 1987 Claus Brod *** Status: ";Status%;" ****"
Print R$;"R";O$;"ead, ";R$;"W";O$;"rite, ";R$;"T";O$;"rk (";Track%;"), ";
Print R$;"S";O$;"eite (";Seite%;"), Se";R$;"k";O$;"tor (";Sector%;"), ";
Print R$;"E";O$;"dit, ";R$;"D";O$;"ump, ";R$;"P";O$;"rn (o";
If Prn%
Print "n), ";
Else
Print "ff), ";
Endif
Print "E";R$;"x";O$;"ec, ";R$;"Q";O$;"uit"
M$=Upper$(Input$(1))
If M$="X"
@Exe
Endif
If M$="P"
Prn%=1-Prn%
Endif
If M$="T"
Input "Track";Track%
Endif
If M$="S"
Input "Seite";Seite%
Endif
If M$="K"
Input "Sektor";Sector%
Endif
If M$="R"
@Lesen
Endif
If M$="W"
@Schreiben
Endif
If M$="E"
@Edit
Endif
If M$="D"
@Dump(512)
Endif
Exit If M$="Q"
Loop
Return
'
' Sektor einlesen
'
Procedure Lesen
Buffer%=Varptr(Sec$)
Status%=Xbios(8,L:Buffer%, L:0, Drive%, Sector%, Track%, Seite%, 1)
Return
'
'
' Sektor schreiben
'
Procedure Schreiben
Buffer%=Varptr(Sec$)
Status%=Xbios(9,L:Buffer%,L:B,Drive%,Sector%,Track%,Seite%,1)
Return
'
'
' Sektorpuffer ausgeben
'
Procedure Dump(L)
If Prn%=0
Open "O",#1,"con:"
Else
If Prn%=1
Open "0",#1,"prn:"
Else
Open "0",#1,Fi$
Endif
Endif
Print #1,"Track: ";Track%;" Sektor: ";Sector%;" Seite: ";Seite%
For T=1 To L Step 16
A$=Str$(T-1)
While Len(A$)<3
A$="0"+A$
Wend
D$=" "
Print #1,A$;D$;
For I=0 To 15
V$=Mid$(Sec$,T+I,1)
A$=Hex$(Asc(O$))
If V$<" " Or V$>"z"
V$=" "
Endif
Print #1,Right$("0"+A$,2)
D$=D$+V$
Next I
Print #1,D$
A$=Inkey$
If A$=" "
A=Inp(2)
Endif
Exit If A$>"" And A$<>" "
Next T
Close #1
Return
'
'
' Byte ändern
'
Procedure Edit
Input "Byte Nr.";Byte%
Print "Alter Wert ist: ";Asc(Mid$(Sec$, Byte%+1,1))
Input "Neuer Wert in dezimal oder ASCII";Wert$
Wert%=Val(Wert$)
If Wert%=0 And Left$(Wert$,1)<>"0"
Wert%=Asc(Wert$)
Endif
Mid$(Sec$,Byte%+1,1)=Chr$(Wert%)
Return
'
'
' anderes Programm ausführen
'
Procedure Exe
Fileselect "*.*","",Sel$
If Exist(Sel$)<>0
S=Fre(0)
Reserve 50000
Showm
Exec 0,Sel$,"",""
Reserve S-1000
Endif
Return
'
'
' Datawüste mit den Oaten für LOCKSLEY und
' SELECT sowie ein paar Trackdaten
'
Locksley:
Data 60,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0
Data 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
Data 0,B,0,0,0,0,48,E7,FF,FE,42,80,61,0,1,36
Data 45,FA,FF,EE,24,80,3C,3A,FF,CA,45,FA,FF,E8,34,BC
Data 0,0,45,FA,FF,DA,34,BC,0,0,50,F9,0,0,4,3E
Data 61,0,1,1E,51,F9,0,0,4,3E,45,FA,FF,C4,20, 12
Data 61,0,1,2,4C,DF,7F,FF,4E,75,32,3C,0,1E,61,A
Data 33,C7,0,FF,86,4,32,3C,0,1E,51,C9,FF,FE,4E,75
Data 2E,30,0,4,0,0,8,39,0,5,0,FF,FA,1,67,60
Data 53,87,67,40,45,FA,FF,8E,4A,52,67,EA,45,FA,FF,70
Data 15,79,0,FF,86,9,0,1,15,79,0,FF,86,B,0,2
Data 15,79,0,FF,86,D,0,3,20,3A,FF,54,B0,BA,FF,5C
Data 6D,C4,1E,3C,0,D0,61,0,0,EC,45,FA,FF,58,34,BC
Data 0,0,60,1C,61,1A,1E,3C,0,D0,61,0,0,08,45,FA
Data FF,3E,34,BC,0,1,45,FA,FF,3C,34,BC,0,0,4E,75
Data 30,39,0,FF,86,4,45,FA,FF,1A,34,80,4E,75,30,39
Data 0,FF,86,6,45,FA,FF,E,34,80,42,41,12,39,0,FF
Data 86,9,E1,89,12,39,0,FF,86,B,E1,89,12,39,0,FF
Data 86,D,45,FA,FE,F6,24,81,92,BA,FE,EC,45,FA,FE,DA
Data 34,81,4E,75,45,FA,FE,E0,24,87,13,C7,0,FF,86,D
Data E0,8F,13,C7,0,FF,86,B,E0,8F,13,C7,0,FF,86,9
Data 2E,3A,FE,C4,42,80,30,3A,FE,B0,0E,80,45,FA,FE,BC
Data 24,87,4E,75,2F,0,3F,3C,0,20,4E,41,5C,8F,4E,75
Data 3E,6,3A,6,8,6,0,7,66,10,CC,3C,0,F0,BC,3C
Data 0,10,67,0,1,64,66,0,1,50,8,6,0,6,66,A
Data 8,6,0,5,67,2A,66,0,0,F4,CC,3C,0,F0,BC,3C
Data 0,C0,67,0,1,66,BC,3C,0,E0,67,6A,BC,3C,0,F0
Data 67,0,0,9E,61,0,FE,B4,32,3C,0,FA,60,0,FE,BC
Data 2E,3A,FE,48,61,0,FF,6E,45,FA,FE,5A,34,BC,0,1
Data 33,FC,0,90,0,FF,86,6,33,FC,1,90,0,FF,86,6
Data 33,FC,0,90,0,FF,86,6,3E,3C,8,E,61,8,FE,7C
Data 33,FC,0,84,0,FF,86,6,3E,3A,FE,C,61,0,FE,6C
Data 33,FC,0,80,0,FF,86,6,3E,5,61,0,FE,5E,61,0
Data FE,70,60,0,FE,EA,2E,3A,FD,F2,61,0,FF,18,45,FA
Data FE,4,34,BC,0,1,33,FC,0,90,0,FF,86,6,33,FC
Data 1,90,0,FF,86,6,33,FC,0,90,0,FF,86,6,3E,3C
Data 0,E,61,0,FE,26,33,FC,0,80,0,FF,86,6,60,B8
Data 2E,3A,FD,B8,61,0,FE,0E,45,FA,FD,CA,34,BC,0,1
Data 33,FC,1,90,0,FF,86,6,33,FC,0,90,0,FF,86,6
Data 33,FC,1,90,0,FF,86,6,3E,3C,0,E,61,0,F0,EC
Data 33,FC,1,80,0,FF,86,6,60,0,FF,7E,2E,3A,FD,7C
Data 61,6,FE,A2,45,FA,F0,8E,34,BC,8,1,33,FC,1,90
Data 0,FF,86,6,33,FC,0,90,0,FF,86,6,33,FC,1,90
Data 0,FF,86,6,3E,3C,0,E,61,0,FD,B0,33,FC,1,84
Data 0,FF,86,6,3E,3A,FD,40,61,0,FD,A0,33,FC,1,80
Data 0,FF,86,6,60,0,FF,32,33,FC,8,80,8,FF,86,6
Data 61,0,F0,88,60,0,FD,9A,33,FC,0,86,0,FF,86,6
Data 3E,3A,FD,12,61,0,FD,74,33,FC,0,88,0,FF,86,6
Data 3E,5,61,0,F0,66,60,0,FD,78,2E,3A,FC,FE,26,7A
Data FC,FE,61,0,FE,20,33,FC,0,90,8,FF,86,6,33,FC
Data 1,90,0,FF,86,6,33,FC,0,90,0,FF,86,6,3E,3C
Data 0,1,61,0,FD,36,33,FC,0,80,0,FF,86,6,34,3A
Data FC,C8,3E,5,61,0,FD,24,61,0,FD,36,32,3A,FC,C4
Data 36,C1,51,CA,FF,EE,60,8,FD,A6,0,0
Data ***
'
Select:
Data 60,E,0,0,0,0,0,0,0,0,0,0,0,0,0,0
Data 48,E7,FF,FE,42,80,61,6A,45,FA,FF,F2,24,80,50,F9
Data 0,0,4,3E,3E,3A,FF,0C,66,14,33,FC,0,80,0,FF
Data 86,6,32,39,0,FF,86,4,8,1,0,7,66,F4,C,7
Data 0,8,6C,5C,A,7,0,7,CE,3C,0,7,40,E7,0,7C
Data 7,0,13,FC,0,E,0,FF,88,0,10,39,0,FF,88,0
Data C0,3C,0,F8,8E,0,13,C7,0,FF,88,2,51,F9,0,0
Data 4,3E,46,DF,45,FA,FF,96,20,12,61,6,4C,DF,7F,FF
Data 4E,75,2F,0,3F,3C,0,20,4E,41,5C,8F,4E,75,51,C9
Data FF,FE,4E,75,2F,A,3F,3C,0,9,4E,41,5C,8F,4E,75
Data C,7,0,8,67,14,C,7,0,9,67,20,C,7,0,A
Data 67,52,45,FA,0,68,61,DC,60,BA,33,FA,FF,48,0,FF
Data 86,6,61,1C,45,FA,FF,42,34,80,60,A8,3E,3A FF 3A
Data CE,7C,0,FF,33,FA,FF,2E,0,FF,86,6,61,14,60,94
Data 32,3C,8,1E,61,A8,30,39,0,FF,86,4,32,3C,0,1E
Data 60,9C,32,3C,0,1E,61,96,33,C7,0,FF,86,4,32,3C
Data 0,1E,60,8A,33,FC,8,90,0,FF,86,6,30,39,0,FF
Data 86,6,45,FA,FE,F4,34,80,60,0,FF,5A,52,6F,75,74
Data 69,6E,65,20,6E,6F,63,68,28,6E,69,63,68,74,20,69
Data 6D,70,6C,65,6D,65,6E,74,69,65,72,74,2E,D,A,0
Data 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
Data ***
Trackdaten:
Data 4E,2
' Trackvorspann
'
Data 00,2
' Sektorvorspann
Data F5,3,FE,1
' Syncbytes und Adreßmarke
Data Track,1,Side,1,1,1,3,1,F7,1
' Sektorvorspann und Checksumme
Data 4E,14,0,A
' Lückenbytes
Data F5,3,FB,1
' Syncbytes und Datenmarke
Data CB,400,F7,1
' Sektordaten und Checksumme
Data 4E,18
' Lückenbytes
'
Data 00,2
' Sektorvorspann
Data F5,3,FE,1
' Syncbytes und Adreßmarke
Data Track,1,Side,1,2,1,0,1,F7,1
' Sektorheader (Sektor mit 128 Bytes) und Checksumme
Data 4E,14,0,A
' Lückenbytes
Data F5,3,FB,1
' Syncs und Datenmarke
Data CB,40,F7,1
' Sektordaten (unvollständig) und Checksumme
Data 4E,10
' Lückenbytes
'
Data 00,2
' Sektorvorspann
Data F5,3,FE,1
Data Track,1,Side,1,3,1,2,1,F7,1
' normaler 512-Byte-Sektor
Data 4E,14,0,A
Data F5,3,FB,1
Data CB,200
' Sektordaten
Data F7,1,4E,10
'
Data 00,2
' Sektorvorspann
Data FS,3,FE,1
Data Track,1,Side,1,4,1,4,1,F7,1
' Sektor mit der Größenangabe '4'
Data 4E,14,0,A
Data F5,3,FB,1
Data 02,200
' Sektordaten des zweiten Sektors Nr. 3
Data F7,1,4E,10
'
Data 4E,200
' Tracknachspann
Data ***,***
In den letzten beiden Folgen haben Sie ja schon miterlebt, daß der MINIMON sich ganz gut dazu eignet, selbstgebastelte Erweiterungen anzulügen. Um die Routine in Listing 1 einzubinden, müssen Sie nur das Menü des Trackmon-Teils etwas erweitern (einen Vorschlag dazu finden Sie ebenfalls im Listing). Die Routine mißt die Drehzahl des selektierten Laufwerks und gibt sie auf dem Schirm aus. Ein Tastendruck bricht die Messung ab.
Wie funktioniert die Routine? Das Programm schickt jeweils FORCE-IRQ-Befehle (siehe Floppykurs, Teil 5) an den Controller, deren Bit 2 gesetzt ist. Dadurch wird bei jedem Indeximpuls ein Interrupt ausgelöst. Dieser Interrupt wird dem MFP68901 im ST durchgemeldet. Der legt daraufhin Bit 5 seines GPIP-Registers (SFFFAOl) auf Low-Pegel (löscht es also). Auf solche Low-Pegel wartet das Programm; nach 10 Indeximpulsen wird die Zeit gemessen. die das Laufwerk dafür gebraucht hat. Aus dieser Zeit kann man durch eine einfache Formel errechnen, wieviele Umdrehungen das Laufwerk hat.
Die Formel sollte ich vielleicht erklären. Sie lautet:
(1) Drehzahl = 12000 * Genau% / (Zeit für Genau% Umdrehungen in 200stel Sekunden)
Versuchen wir uns dieser Formel schrittweise zu nähern. Bei Solldrehzahl - 300 Umdrehungen pro Minute - braucht das Laufwerk 0.2 s für eine Umdrehung. Das entspricht 40/200 Sekunden (diese Umrechnung brauchen wir gleich noch). Die tatsächliche Drehzahl ergibt sich nun aus dem Quotienten aus dieser Solldrehzeit und der wirklich gemessenen Zeit, multipliziert mit 300:
(2) Drehzahl = 300*Solldrehzeit/(gemessene Zeit)
Die Solldrehzeit ist (0.2 Sekunden * Genau%) = (40/200 Sekunden * Genau%). Setzt man das ein, ergibt sich:
(3) Drehzahl = 300* (40/ 200)Genau%/(gemessene Zeit) = 12000Genau% / ((gemessene Zeit)*200)
Damit sind wir schon ziemlich genau bei der ersten Formel angekommen. Den Faktor 200 im Nenner können wir uns schenken, weil im GFABASIC-Programm die Zeit eh schon in 200stel Sekunden (über die TIMER Variable) gemessen wird. Damit steht genau die Formel (1) vor uns.
Die Messung ist hinreichend genau, in der abgedruckten Version liegt der Meßfehler bei maximal +/-0.7 Umdrehungen. Mit dem Parameter Genauso können Sie - falls Sie so pingelig sind - die Exaktheit verbessern. Für HYPERFORMAT-Disketten sind Umdrehungsgeschwindigkeiten von 300 bis 302 Upm optimal.
Nach dem Anlaufen der Routine sollten Sie eine Weile warten, bis sich die Drehzahl stabilisiert hat. Probieren Sie doch mal, was passiert, wenn Sie Ihr Laufwerk während des Drehzahltests drehen und schütteln (aber nicht übertreiben).
Trackmon mit eingebauter Speed-Routine
Listing
' Diese Anpassung der Routine Trackmon soll Ihnen ver-
' deutlichen, wie man die SPEED-Routine in den EX-
' TENDED MINIMON einbauen könnte.
Procedure Trackmon
@Init_trackmon
Cls
Prn%=0
Richtung%=0
Seite%=0
Drve%=0
Steprate%=1
R$=Chr$(27)+"p"
O$=Chr$(27)+"q"
@Rst ! auf Track 0 zurückfahren
Do
Print
Print "*************** TRACKMON (C) 1987 Claus Brod ****************"
@Prntable
Print R$;"0";O$;" Track 0, ";R$;"1";O$;" Step, ";R$;"2";O$;" Step-In, ";
Print R$;"3";O$;" Step-Out, ";R$;"4";O$;" Seek, ";RS; "5'* jOS;" RdSec,
Print RS;"6";OS;" Wr Sec"
Print R$;"7";OS;" Rd Adr, RS;"8";O$;" Rd Trk, **;R$;"9" ;O$f WrTrk, “j
Print R$;"A";O$;" IRQ, ";R$;"0";O$;"ump Buf, ;RS;"S";O$;"eite (";Seite%;
Print "), ";R$;"P";O$;"rn (o";
If Prn%=1
Print "n)"
Else
If Prn%=0
Print
Else
Print "n file)"
Endif
Endif
'
'
' ............. Die folgende Zeile ist neu!!!
Print R$;"R";O$;"egister, ";R$;"G";O$;‘eschwindigkeit,";R$;
Print "Q";O$;"uit"
' ...............weiter wie gewohnt
'
M$=Upper$(Input$(1))
Exit If M$="Q“
'
' Jetzt wieder etwas Neues!!!
If M$="G"
@Speed
Endif
' ab jetzt wieder kalter Kaffee
'
If M$="S"
Seite%=1-Seite%
Endif
If M$="P"
Inc Prn%
If Prn%>2
Prn%=0
Endif
If Prn%=2
Input "Filename";Fi$
Endif
Endif
If M$="D"
@Dump_buf
Endif
If M$="A"
@Irq ! FDC unterbrechen
Endif
If M$="R"
@Register
Endif
If M$<="9" And M$>="8"
On Val(M$)+1 Gosub Rst,Step,Step_in,Step_out,Seek,Rdsec,Wrsec,Rdadr
On Val(M$)-7 Gosub Rdtrk,Wrtrk
Endif
Loop
Return
'
Hier folgt jetzt die eigentliche Meßroutine SPEED.
'
' Speed-Routine; mißt die Drehzahl eines Laufwerks
Procedure Speed
Local Dr,Lp%,Avr
@Irq
' FDC in definierten Zustand
'
Cls
Print At(5,2);"Drehzahlmessung“
Print At(5.9);" Drehzahl : "
Print At(5,11);"Durchschnitt : "
Mfp%=&HFFFA01
' Hier meldet der MFP den FDC-Interrupt beim Indeximpuls
'
Genau%=10
' Genauigkeitsfaktor, je höher, desto länger wird gemessen
'
@Select
' Laufwerk selektieren
Dpoke Sel+2,9
Dpoke Sel+4,&H88
Dpoke Sel+8,&HD4
Call Sel
' INDEX-IRQ ($04) an den FDC schicken
' (erweiterte LOCKSLEY-Routine wird benötigt, siehe ST 11/87)
'
Repeat ! Warte auf Index
Until (Peek(Mfp%) And 32)=0 ! Dann Start !!
Repeat
Dpoke Sel+2,9
Dpoke Sei+4.&H80
Dpoke Sel+8,&HD4
' Parameterfeld der Select-Routine vorbereiten
'
T2=Timer
For T%=1 To Genau%
Call Sel
Repeat
Until (Peek(Mfp%) And 32)=0
If Inkey$<>"" Or Mousek
T%=99
Endif
Next T%
' Zeit für Genau% Umdrehungen messen
' Abbruch durch Taste oder Mausklick
Exit If T%=100
Dr=12080*Genau%/(Timer-T2)
' Formel für Drehzahl, siehe Artikel)
Print At(22,9);Using "###.###",Dr
Add Avr,Dr
Print At(22,11);Using "###.###",Avr/Lp%
Until Inkey$<>"" Or Mousek
@Irq
@Deselect
Return