← ST-Computer 06 / 1987

Floppyspielereien Teil 1: Mut zur Lücke

Kurs

Wie der ST seine Disketten verwaltet, und wie man ihm dabei gehörig auf die Sprünge helfen kann, soll hier am Beispiel eines Programmes gezeigt werden, das Träume erfüllt: Der HYPERFORMATTER bläst Disketten bis auf schwindelerregende 927000 Bytes auf und beschleunigt dazu noch den Zugriff um bis zu 30 %

927000 Bytes?! Wie macht man das? Um das zu erklären, muß ich weiter ausholen, weil mein Programm viele Finessen verwendet, die erst mal erklärt werden wollen. Ich möchte Ihnen dazu in einem Blitzkurs in zwei Folgen Grundlegendes und Raffiniertes über Disketten und Laufwerke erzählen. Sie sollten auch schon mal eine Diskette in der Hand gehabt haben — das sid diese kleinen viereckigen Dinger, die immer dem Bürostuhl unter die Rolle kommen (knirsch) — und Bits von Bytes unterscheiden können, sonst wird dieser Kurs Ihnen wohl nicht so viel bringen. Aber zumindest können Sie die Programmbeispiele abtippen und sich an den Ergebnissen delektieren.

Spuren, Sektoren und Lücken

Beginnen wir zur Abwechslung mal am Anfang: TOS, das Betriebssystem des ST (also nicht dieser Grafikaufsatz namens GEM), hält sich in der Diskettenverwaltung recht sklavisch an Vorgaben des großen Bruders MS-DOS. Grundsätzlich: Eine Disk teilt sich ein in Spuren (Tracks) und Sektoren. Bei der SF354 sind es 80 Tracks, bei der SF314 sogar 2 x 80 Tracks, weil da die Disketten beidseitig beschrieben werden. Jeder Track besteht wiederum aus 9 Sektoren:

(Bild 1: So sieht der Lesekopf eine typische ST-Diskette)

Spur 79 liegt innen, Spur 0 außen. Zwischen den Sektoren gibt es kleine Lücken, auf die ich noch zu sprechen komme. In den Sektoren werden die eigentlichen Daten abgespeichert, beim ST 12 Bytes pro Sektor.

Information durch Rotation

Über der rotierenden Diskette schwebt ein Schreib-Lesekopf. Beim Schreiben fließt Strom durch den Schreibkopf und erzeugt eine magnetische Fährte auf der Diskette. Beim Lesen ist es umgekehrt: Die magnetisierten Partikel auf der Disk induzieren einen Stromfluß im Lesekopf, den er als logisch T oder ’0‘ versteht. Aber keine Angst: So tief in die Physik brauchen wir nicht einzusteigen, der ST verfügt über einen Baustein (nämlich einen Diskcontroller), der sich um diese Dinge kümmert. Dieser Baustein im ST ist auch der Grund, warum die Programme dieses Kurses auch auf Fremdlaufwerken laufen: Die Floppystationen am ST sind nicht wie die anderen Rechner (C64) intelligent, sondern bestehen fast nur aus Mechanik.

Das bedeutet, die Ansteuerung hängt nur vom Controller ab, und der ist ja bei allen ST-Rechnern gleich.

Platz da!

Nun sieht man schon auf der Zeichnung, daß nach dem neunten Sektor noch viiiiel Platz ist, so viel Platz, daß viele Formatierprogramme (zum Beispiel) auch FAT-DISK aus der ST/86) dort einen zehnten Sektor unterbringen und so die Kapazität erhöhen. Das macht pr Spur immerhin 312 Bytes aus, bei 80 Spuren und 2 Seiten sind das 80 Kilobyte!

Bei vielen Laufwerken kann man auch den Schreib-Lesekopf bis über Track 79 hinaus bewegen. Einer eigenen Blitzumfrage bei Händlern und ST-Besitzern zufolge gibt es allerdings bei etwa der Hälfte aller Laufwerke Probleme ab Track 82, weil der Lesekopf anschlägt. Um herauszufinden, ob Ihr Laufwerk auch Track 82 noch mitmacht, sollten Sie mal eine freie Disk mit FATDISK formatieren. Legen Sie das Ohr aufs Laufwerk (ja, ich weiß, es klingt lächerlich, aber es lohnt sich) — wenn es bei Track 82 (FATDISK zeigt den aktuellen Track an) anders klingt als bei den vorherigen Trackwechseln (es hört sich etwa so an, als ob ein kleines Männchen in der Floppy den Lesekopf mit einem Hämmerchen bearbeitet), haben Sie Pech: Tyrannisieren Sie irgendjemanden, der Ihnen Ihre Floppy einstellen kann. Vielleicht kann der ja noch was machen. Andererseits können einige Leute aber auch ihren Kopf (quatsch, den ihrer Floppystation) bis Spur 85 bewegen!

Ein wenig Arithmetik: 83 Spuren (also Spur 0 bis Spur 82) mal 10 Sektoren mal 2 Seiten macht 1660 Sektoren = 849920 Bytes. Von dieser Summe geht aber noch einiges für Bürokratie weg, bei FATDISK bleiben nur 828416 Bytes übrig.

Verwaltungskram auf Disketten

Da ist zum ersten der geheimnisumwitterte Bootsektor (Track 0, Sektor 1, Seite 0), der 512 Bytes frißt. Nach dem Einschalten prüft der ST den Bootsektor der Diskette in Laufwerk A. Wenn dieser Bootsektor ausführbar ist, versucht der ST von dieser Diskette ein TOS zu laden. Außerdem stehen noch viele andere Informationen im Bootsektor, die ich genauer in der zweiten Folge behandeln werde.

Ab dem zweiten Sektor steht die sogenannte FAT (File Alloction Table). Auf ihr ist die Belegung der Diskette mit Dateien vermekrt. Das Format ist allerdings a bisserl kompliziert. Vorweg: TOS verwaltet seine Disketten nicht in logischen Sektoren, sondern in Clustern. Das sind jeweils 2 aufeinanderfolgende Sektoren. Eine neue Datei belegt mindestens einen ganzen Cluster — selbst bei einer Datei mit nur einem Byte! Diese Verschwendungssucht schmiert aber den Verwaltungsmechanismus und beschleunigt die Bürokratie (Parallelen mit der ,wirklichen“ Welt sind rein zufällig). Eine typische FAT fängt nun so an:

Jeder Cluster erhält in der FAT 12 Bit (!) zugewiesen, das sind drei Flexadezimalzt/ fern. Die ersten 5 Nullen sind Flags, deren Bedeutung ich noch nicht vollständig entschlüsselt habe. Bei MS-DOS, dem großen Bruder, steht im ersten Byte ein Format-kennzeichen, im zweiten ist die Kapazität der Floppy eingetragen. Seltsamerweise beeindrucken Änderungen der ersten beiden Bytes TOS nicht sonderlich.

Vielleicht hat sich ja schon ein Leser damit befaßt und scheibt mir oder der ST. Das :bere Nibble des 3.Bytes bedeutet offenbar auch nichts Besonderes (wie gesagt, ich bin für Tips zugänglich). Aber dann folgt cer Eintrag des Clusters mit der Nummer 2 (TOS speichert Daten erst ab Cluster 2 ab). Hier sehen wir ’003‘, das heißt: Die Datei, die im Cluster 2 beginnt, wird im Cluster 3 fortgesetzt. Im Eintrag für Cluster 3 steht ’400‘, also ein umgedrehtes ’004‘ (warum auch immer), die Datei setzt sich folglich bei Cluster 4 fort undsoweiter.

Am Schluß der Datei steht ein Endekennzeichen (FFO). In MS-DOS zumindest gibt es noch die Kennzeichen FF7 (Sektor beschädigt) und FF8—FFF (Dateiende). Für jeden Cluster sind 12 Bit reserviert, macht (bei normalen Format) 8640 Bit = 1080 Byte, also knapp 3 Sektoren. Trotzdem reserviert ATARI großzügig 5 Sektoren für die FAT.

Tanz auf dem Vulkan

Direkt auf die erste FAT folgt eine identische Kopie der FAT, aus Sicherheitsgründen. Nett gedacht, nur: beide FATs liegen in der Regel auf der gleichen Spur, und da viele Programme gleich eine ganze Spur schreiben, segelt bei einem Fehlgriff auch die Kopie ins Nirwana. Traurig, traurig, denn nur mit diesem roten Faden (oder besser: FATen) kann man feststellen, welche Bereiche eine Datei belegt. Gerade bei zerstörten Dateien ist das sehr wichtig — und ohne FAT gleicht der Versuch, die Datei wieder zusammenzuklauben, einer stecknadelsuche im Vesuv.

Ein Tip für diejenigen, die es trotzdem versuchen wollen (oder müssen, mein Beileid): TOS versucht grundsätzlich, aufeinanderfolgende Sektoren für neue Dateien zu verwenden. Erst wenn es auf einen breits belegten Sektor stößt, weicht das Betriebssystem aus. Auf einer einigermaßen leeren Diskette hat man also noch relativ gute Chancen, seine Dateisektoren wiederzufinden.

Nach den FATs steht in 7 Sektoren die Directory, beim normalen Format ab dem 12. Sektor, vom Anfang der Diskette an gezählt (dabei zählt man zuerst die Sektoren der Vorderseite, dsann die der Rückseite, so vorhanden, und geht dann weiter zum nächsten Track). Jeweils 32 Bytes pro Datei beinhalten deren Namen und Kenndaten unter anderem auch einen Verweis auf den ersten Dateicluster. Damit gerüstet, schaut TOS an der betreffenden stelle der FAT nach und kann den Verlauf einer Datei verfolgen. Genaueres zur Directory im Teil 2 der Reise durchs wilde Floppy-stan (in der nächsten ST).

Kurze Überschlagsrechnung: Für die Verwaltung einer Diskette gehen summa summarum 18 Sektoren für Bootsektor, FATs und Direcotry hops, also 9216 Bytes.

Nochmal in der Zusammenfassung der Anfang einer ST-Diskette:

1. Sektor: Bootsektor (Track 0, Seite 0, Sektor 1)

2. Sektor: FAT1 (Track 0, Seite 0, Sektor 2)

7. Sektor: FAT2 (Track 0, Seite 0, Sektor 7)

12. Sektor: Directory (bei SF314: Track 0, Seite 1, Sektor 3? bei SF 354: Track 1, Seite 0, Sektor 3)

Danach: Daten und Programme

Manche Formatierprogramme kürzen die beiden FATs noch auf jeweils 3 Sektoren (was völlig ausreicht) und die Directory auf 64 Einträge (also 4 Sektoren) und gewinnen so 7 Sektoren = 2584 Bytes.

Der Clou: HYPERFORMAT

Trotzdem, das alles kann noch nicht das Wahre sein: der AMIGA hat doch auch diseiben Laufwerke und formatiert auf 880K. Warum kann das der ST nicht, fragt man sich. Er kann. Aber dazu mußte ich erst mal einiges umbiegen.

Glücklicher AMIGA, du hast es leichter. Das Betriebssystem des AMIGA formatiert nämlich eine Diskette mit 11 Sektoren pro Spur! Macht zusammen — bei 80 Spuren — über 900000 Bytes! Et voilà, dachte ich mir, ds müßte der ST doch auch können, setzte mich fröhlich pfeifend an meinen ATARI-Ferrari, um die Sache auszuprobieren, und verlor schon nach kurzer Zeit die Lust: Ein schnell zusammengehacktes Formatierprogramm für 11 Sektoren formatierte zwar, doch überschrieb der elfte Sektor immer den ersten: Zuwenig Platz auf der Spur. Was tun? Irgendwo im Betriebssystem entdeckte ich schließlich die Formatierroute des XBIOS, die man auch über den internen XBIOS-Aufruf 10 erreicht. Wenn man analysiert, was TOS da so auf die Diskette schreibt, kommt man schließlich auf folgendes Track-Format: (siehe Tabelle 1)

Der lange Weg zum Glück

Das Problem: Es paßt zuwenig auf eine Spur, um einen elften Sektor schreiben zu können. Die Beobachtung: Zwischen den einzelnen Informationen auf der Spur liegen immer wieder Lückenbytes (Gapbytes). Schlußfolgerung: Wenn man die Lücken auf ein Minimum kürzt, bringt das vielleicht so viel Platz auf der Spur, daß noch ein elfter Sektor draufpaßt.

Vorspann (Index, Trackheader; "PoST Index Mark") (*) Lückenbytes (Pre Adress Mark) Synchronisationsbytes Adressmarke + Sektorinfo Checksumme Lückenbytes (PoST Adress Mark) Synchronisationsbytes Datenmarke + DATEN Checksumme Lückenbytes (PoST Data Mark) zurück zu (*). bis alle Sektoren geschrieben sind, danach: Lückenbytes bis zum Trackende.

(Tabelle 1: Einer Spur auf der Spur)

Und in der Tat: Man kann die Lückenbytes kürzen (durch Änderungen in der Formatierroutine des TOS), wenn man sich nur daran hält, daß mindestens 30 Lückenbytes zwischen Adreßmarke und Daten geschrieben werden. Das erste HYPERFORMAT modifiziert also zuerst mein RAM-TOS so, daß 11 Sektoren auf eine Spur passten, rief dann ganz normal das XBIOS auf, um zu formatieren, und gab dabei an, 11 Sektoren formatieren zu wollen.

Hexerei bringt Geschwindigkeit

HYPERFORMATiert man eine Diskette nach diesem Verfahren, gibt es allerdings bald lange Gesichter:

1. Nicht jedes Laufwerk vertrug offenbar die Roßkur fürs XBIOS. Auf Laufwerken von Freunden ließen sich HYPERFORMATierte Disketten zunächst nicht lesen, später zwar lesen, aber nicht HYPER-FORMATieren. Nach kniefieslingster Probiererei mit den Lückengrößen scheinen auch andere Laufwerke mein HYPERFORMAT zu verstehen, so daß ich damit an die Öffentlichkeit treten kann, ohne sofortige Enthauptung zu fürchten. Sollte es doch nicht laufen, liegt das an physikalischen Toleranzen der Laufwerke.

2. Die Schreib-Lesegeschwindigkeit zwar zunächst ein Graus (3mal langsamer, als die sowieso nicht sehr schnelle SF314 sonst liest). Ein Freund kam auf die rettende Idee — Stichwort Interleave (dafür bekam er auch eine Widmung im Programm).

Normalerweise werden die Sektoren so auf die Spur geschrieben wie in Bild 1 angegeben, also erst Sektor 1, dann Sektor 2 und sofort. Beim normalen Format liest die Floppy zuerst den Sektor 1, der Floppycontroller (das ist der Baustein, der die Ansteüerung des Laufwerks übernimmt) werkelt jetzt ein bißchen, und wenn er wieder bereit ist, hat sich die Lücke zwischen den Sektoren gerade unterm Lesekopf vorbeigedreht, so daß gleich der nächste Sektor gelesen werden kann. Bei den gekürzten Lücken stimmt nun dieses Timing nicht mehr, und der Controller muß immer wieder Pausen einlegen und warten, bis der passende Sektor wieder unter dem Lesekopf vorbeirotiert. Nun kann man eine Spur aber auch so formatieren:

(Bild 2: Mehr Speed durch noch mehr Mut zur Lücke)

Damit hat der Controller zwischen zwei aufeinanderfolgenden Sektoren (etwa zwischen Sl und S2) immer genug Zeit! Diese Taktik nennt man Interleaving, der Interleavefaktor ist in diesem Falle — und auch per Voreinstellung in meinem Programm — sechs (weil auf die aktuelle Sektornummer immer sechs addiert wird; wenn das Ergebnis größer als die Anzahl der Sektoren pro Spur ist, wird diese Anzahl abgezogen). So modifiziert, bringt HYPERFORMAT eine Diskette auf beachtliche Geschwindigkeit: Im Durchschnitt ist sie im gemischten Schreib-Lesezugriff 20 bis 35 % schneller als normal formatierte Disketten, in Einzelfällen liegt dieser Wert sogar noch weit besser.

Dieser Geschwindigkeitsvorteil rührt auch daher, daß man beim Diskzugriff nicht mehr so oft den Track wechseln muß, weil mehr Daten auf eine Spur passen. Und der Trackwechsel ist auch eine zeitaufwendige Sace (normalerweise werden jeweils 3ms dafür verbraten).

3. In der bisherigen Version lief HYPERFORMAT nur auf RAM-TOS, da ja Passagen aus dem TOS geändert, gepatcht werden mußten. In der jetzigen Version ist auch das gelöst.

HYPERFORMAT prüft nach, ob ein ROM-TOS vorliegt, wenn nein, erwartet es ein RAM-TOS in der Version vom 6.2.86 im Speicher (es müßte auch mit der Version vom 18.7.85 laufen), wenn ja, benutzt es eine modifizierte ROM-Routine mit Einsprüngen ins ROM. Eine wichtige Anmerkung: Booten Sie ein FASTLOAD mit, wenn Sie den Geschwindigkeitsvorteil von HYPERFORMAT-Disketten nutzen wollen. Beim Umschreiben des Programmes auf ROM-Rechner habe ich bemerkt, daß das Timing beim Lesen und Schreiben nur mit FASTLOAD optimal ist. Deswegen installiert HYPERFORMAT bei gebootetem RAM-TOS gleich FASTLOAD und FASTFORMAT mit.

ROM-Beisitzer haben zwei Möglichkeiten: Ein FASTLOAD-Programm booten (in den AUTO-Ordner kopieren), das auch auf ROM-Rechnem läuft, oder die ROMs in Eproms kopieren und dabei auf den FASTLOAD-Modus umbrennen. Dazu ändert man im Eprom U7 den Inhalt der Eprom-Adresse $0DC7 von $14 auf $10 (modifizierte EPROMS gibt es auch für 30 Mark zu kaufen). Eine von diesen Möglichkeiten sollten Sie nutzen, um alle Vorteile von HYPERFORMAT genießen zu können. Die FASTLOAD-Modifikation läuft übrigens schon seit einem Jahr bei mir und bei vielen Bekannten ohne Kompliaktionen, also keine falsche Vorsicht.

Und ein kleines Trostpflaster für ST-Besitzer ohne FASTLOAD: Das Formatieren läuft bei HYPERFORMAT auch bei ROM-Rechnern mit derselben Geschwindigkeit, als wäre ein FASTLOAD mitgebootet worden! Und wenn Sie den Interleavefaktor auf 3 einstellen, ergibt sich sogar doch noch ein kleiner Geschwindigkeitsvorteil gegenüber normalen Disketten.

Allerdings werden Disketten mit Interleavefaktor 3 wieder langsam, wenn man sie mit FASTLOAD liest. Deswegen empfehle ich dringend (um auch vom Speed her die Kompatibilität zu wahren), den Interleave nicht zu verstellen, sondern ein FASTLOAD ins TOS zu integrieren.

Die Anleitung zu HYPERFORMAT

Das Programm ist vollständig in Assembler geschrieben und relokatibel; es wurde mit dem AS68 aus dem Entwicklungspaket assembliert. Andere Assembler brauchen eventuell andere Pseudo-Ops; bitte halten Sie sich an die Anleitung Ihres Assemblers. Das Programm an sich ist recht lang zum Abtippen, seien Sie vorsichtig. Die Kommentare müssen Sie ja nicht treudoof runterhacken, aber lesen Sie die Hinweise, man kann dabei sicher was für die eigene Programmierung lernen. Nicht zuletzt deswegen ist HYPERFORMAT heavily documented, wie der Angelsachse so schön sagt.

Wenn Sie das Programm fertig eingetippt ich beneide Sie nicht), assembliert (fluch!) und gelingt (bibber!) haben, dann starten und keine Bomben oder ATARI-Gardinen entdecken, haben Sie es geschafft, Sie sind im Menü angekommen.

Im Menü können Sie einige Parameter einstellen, zum Beispiel, wieviel Spuren Sie formatieren wollen (wichtig für Leute mit dem Knackatakatak bei der 82. Spur), wieviel Seiten Ihr Laufwerk hat (auf der einseitigen Floppy hat man dank HYPERFORMAT 459000 Bytes frei), wieviel Directoryeinträge Sie zulassen wollen, und welcher Interleavefaktor gewählt wird.

Voreingestellt sind 2 Seiten, 83 Tracks (also Spur 0 bis Spur 82 einschließlich), 64 Directoryeinträge und ein Interleavefaktor 6, und damit ergeben sich mehr als 927000 freie Bytes auf Ihrer Diskette (AMIGA go home!). HYPERFORMAT kürzt die FATs dabei auf völlig ausreichende drei Sektoren. CTRL-C im Menü bricht das Programm ab, RETURN startet das Formatieren, ’B‘ überspringt das Formatieren und schreibt nur Bootsektor, FAT und Directory neu. ROM-Besitzer ohne FASTLOAD können den Interleave auf 3 einstellen (siehe oben).

Zusätzlich sind im Listing noch folgende Parameter änderbar:

virgin (Daten, mit denen die Sektoren beim Formatieren initalisiert werden) spt (Sektoren pro Track) res (Reservierte Sektoren) fat (Anzahl der FATs) secsperfat (Länge der FAT)

Von allen anderen Parametern im Listing sollten Sie zunächst mal die Finger lassen.

Sollte Ihr Laufwerk doch mal bocken und Lesefehler melden, können Sie in den Routinen change_tos und rom_fmt die gekennzeichneten „Lücken“ von 3 auf 4 vergrößern, das hilft meistens.

Diesmal haben Sie erfahren, wie eine Diskette aufgebaut ist, wie die Aufzeichnung funktioniert, was FATs, Cluster und Diskcontroller sind, wie man mit kleinen Tricks den Verwaltungsaufwand reduzeirt und mehr Platz gewinnt, und Sie haben jetzt mit HYPERFORMAT die ultimate Waffe gegen den Knetefraß durch Diskettenkauf. In der nächsten ST lesen Sie, wie man auf den Diskettencontroller des ST zugreift, was der für Finessen beherrscht, wie man BIOS, XBIOS und GEMDOS für die Arbeit mit der Floppy nutzen kann, wie gängige Kopierschutzmechanismen funktionieren und einiges mehr.

(Tabelle 2: Hier noch eine Liste der Routinen von HYPERFORMAT:

maln Hauptschleife

change_tos modifiziert RAM-TOS und inSTa11iert FASTLOAD+FASTFORMAT repair_tos macht Änderungen am RAM-TOS rückgängig, nicht aber FASTLOAD und FASTFORMAT formatdisk ganze Diskette formatieren formattrack eine Spur formatieren

rom Vorbereitungen für die romfmt-Routine romfmt Modifzierte Formatierroutine aus dem ROM

writeboot Bootsektor und FATs initialisieren

writesector einen Sektor schreiben

printmsg STring ausgeben

waitforkey Auf TaSTe warten

mallocerror,freeerror,fatal-error Fehlermeldungen

Parameters Eingabeschleife fürs Menü

op_exe Exe-Flag ändern

op_tracks Anzahl der Tracks ändern

op_side Anzahl der Seiten einSTellen

op_dir Wieviele Directoryeinträge?

op_inter Interleavefaktor ändern

calc_secs Zahl der Sektoren auf der Disk ausrechnen

********************************************************* * HYPERFORMATTER * * Written 1987 by Claus Brod * * Am Felaenkeller 2 * * 8772 Marktheidenfeld * * (C) 1987 and for all eternity by Claus Brod * * * * 1. Formatiert Diskette in Laufwerk A * * auf über 905K (>927000 Bytes frei) * * 2. Beschleunigt Diskzugriff bei Laden * * und Speichern um 20-35% * * * * Version für RAM- und ROM-TOS * * Revision 2.0, Last update 4.4.87 * * Assembliert mit AS68 aus dem Entwicklungspaket * ********************************************************* virgin .equ $cbcb * Virgin data spt .equ 11 * Sektoren pro Track laufwerk .equ 0 * Laufwerk A secsperfat .equ 3 * Sektoren pro FAT spc .equ 2 * Sectors per Cluster res .equ 1 * Reservierte Sektoren fat .equ 2 * Anzahl der FATs bufflength .equ 10000 * Länge des Trackpuffers ****************** * Routine zum Reservieren von Speicherplatz ****************** move.l a7,a5 * Stackpointer retten move.l 4(a5),a5 * Basepage—Start vom Stack nach a5 move.l $c(a5),d0 * Länge von .text add.l $14(a5),d0 * Länge von .data addieren add.l $1c(a5),d0 * Länge von .bss addieren add.l #$500,d0 * Platz für den Stack muß auch sein move.l d0,d1 * Ergebnis nach d1 add.l a5,d1 * Ergebnis + Adresse der Basepage and.l #-2,d1 * Adresse gerade machen move.l d1,a7 * Stackpointer = errechnete Adresse move.l d0,-(sp) * Größe des Bereiches move.l a5,-(sp) * Startadresse. ab der reserviert wir clr.w -(sp) * Dummy (reserviert) move.w #$4a,-(sp) * SETBLOCK trap #1 * im GEMDOS add.l #12,sp clr.l -(sp) * Userstack wird Supervisorstack move.w #$20,-(sp) * SUPER trap #1 * im GEMDOS add.l #6,sp * ab jetzt alles im Supervisormode lea save_ssp(pc),a2 move.l d0,(a2) * Supervisorstackpointer retten cmpi.l #$00FC0000,$4F2 * von ROM gebootet? beq rom_ist_da * ja. weiter bsr change_tos * RAM-TOS patchen lea romflag(pc),a2 move.b #-1,(a2) * Flag für 'kein ROM' setzen rom_ist_da: bsr main * Ab ins Hauptprogramm exitus: lea romflag(pc),a2 cmpi.b #-1,(a2) * ROM drin? bne rom_sweet_rom * jawoll, weiter bsr repair_tos * Heileheilegänschen fürs RAM-TOS rom_sweet_rom: move.l save_ssp(pc),-(sp) * zurück move.w #$20,-(sp) * in den Usermode trap #1 add.l #6,sp clr.w -(sp) * Raus in die boese Welt trap #1 ************************** * main: Holt Parameter, formatiert * und gibt Gelegenheit zur Wiederholung ************************** main: lea msg1(pc),a5 * Intromeldung bsr printmsg * ausgeben bsr parameters * Parameter einsteilen lea diskmsg(pc),a5 bsr printmsg * 'Diskette einlegen' bsr waitforkey * auf Taste warten bsr calc_secs * Sektoren ausrechnen lea fmtflag(pc),a2 cmpi.b #13,(a2) * Formatieren oder nur Bootsektor? bne nurboot bsr formatdisk * eigentliche Formatierroutine nurboot: lea againmsg(pc),a5 * Noch'ne Message bsr printmsg bsr writeboot * Bootsektor etc. schreiben bsr getkey * auf Taste warten cmpi.b #'y',d0 * nochmal? beg main * 'y' für ja, zurück cmpi.b #'Y',d0 beq main * 'Y' für ja, zurück rts ************************** * change_tos: ändert TOS ab ************************** change_tos: lea $000075c2,a5 * a5 auf Anfang der fmt-Routine move.b #3,$81(a5) * Post Index Mark, evt. auf 4 move.b #3,$8f(a5) * Pre Adress Mark. evt auf 4 move.b #21,$bf(a5) * Post Adress Mark 1 move.b #11,$cb(a5) * Post Adress Mark 2 C2) move.b #3,$f9(a5) * Post Data Mark, evt auf move.w #600,$118(a5) * Nachspann move.l #$6000034c,$58fa5) * FASTFORMAT suba.1 a5,a5 * a5 löschen move.b #$10,$7a1d(a5) * FASTLOAD rts ********************** * repairtos: siehe oben, nur retour ********************** repair_tos: lea $000075c2,a5 move.b #$3b,$81(a5) move.b #$b,$8f(a5) move.b #$15,$bf(a5) move.b *$b,$cb(a5) move.b #$27,$f9(a5) move.w #$578,$118(a5) rts *********************** * formatdisk: von Track 0-endtrack formatieren *********************** formatdisk: move.l #bufflength,-(sp) * bufflength Bytes move.w #$48,-(sp) * per MALLOC trap #1 * (GEMDOS) addq.l #6,sp * reservieren tst.l d0 * Fehler? bmi mallocerror * Rumpel... move.l d0,a6 * Trackpufferadresse nach a6 move.w #0,d4 * ab Track 0 formatieren floop: move.w #0,d5 * Seite 0 formatieren bsr formattrack lea side(pc),a2 cmpi.b #2,(a2) * 1 oder 2 Seiten? bne nureine * eine Seite, nächster Track move.w #1,d5 * Seite 1 formatieren bsr formattrack nureine: addq.w #1,d4 * Nächster Track cmp.b endtrack(pc),d4 * alle Tracks formatiert? bls floop * Nein, weiter move.l a6,-(sp) * Reservierten Bereich per move.w #$49,-(sp) * MFREE im GEMDOS trap #1 * wieder freigeben addq.l #6,sp tst.l d0 * Fehler? bne freeerror * Da soll doch... rts ************************ * formattrack: Einen Track formatieren * d5:Seite, dd:Track, a6:Puffer *********************** formattrack: move.w #virgin,-(sp) * Virgin move.l #$87654321(sp) * Magic Number move.w ileave(pc),-(sp) * Interleave move.w d5,-(sp) * Seite move.w d4,-(sp) * Track move.w #spt,-(sp) * Sektoren pro Track move.w #1aufwerk,-(sp) * Laufwerk (A) clr.l -(sp) move.l a6,-(sp) * Pufferadresse lea romflag(pc),a2 move.b (a2),d0 cmp.w #-1,d0 * ROMs eingebaut? bne rom * ja, in ROM-Routine move.w #10,-(sp) * Und ab ins XBIOS: flopfmt trap #14 add.l #2,sp redo_stk: add.l #24,sp tst d0 * Fehler passiert? bmi fatalerror * Oje oje rts rom: move.l $4a2,a1 movem.l d3-d7/a3-a7,-(a1) * Register retten move.l a1,$4a2 clr.l a5 * a5 löschen lea $FC0000,a0 * Offset-Register für ROM-Calls bsr romfmt move.l $4a2,al movem.l (a1)+,d3-d7/a3-a7 * Register holen move.l a1,$4a2 bra redo_stk ************************** * romfmt-, modifzierte Formatierroutine des ROM ************************** romfmt: jsr $1CBE(a0) * Disketten gewechselt? moveq.l #$FF,d0 jsr $1A34(a0) * Parameter setzen lea $fc0000,a0 jsr $1014(a0) * select drive and side move.w $E(a7),$9D4(a5) * Sektoren pro Track move.w $14(a7),$9D6(a5) * Interleave move.w $1A(a7),$9D8(a5) * Virgin moveq.l #2,d0 lea $fc0000,a0 jsr $1CF6(a0) * Diskette gewechselt lea $fc0000.a0 jsr $1B28(a0) * Track anfahren bne fatalerror * Fehler beim Tracksuchen move.w $9C4(a5),$0(a1) * aktueller Track move.w #$FFFF.$9E0(a5) bsr machhin * Track formatieren bne fatalerror * Fehler passiert move.w $9D4(a5),$9CA(a5) * Sektoren/Track als Zähler move.w #1,$9C6(a5) * mit Sektor X anfangen lea $fc0000,a0 jmp $lada(a0) * flopok (verify überspringen) machhin: move.w #$FFF6.$9DE(a5) move.w #1,d3 * mit Sektor X anfangen move.l $9cc(a5),a2 * Adresse des Puffers move.w #3,d1 * 4 Lückenbytes (evt. auf move.b #$4E,d0 * move.w #4,d1 ändern) bsr wmult * in Puffer schreiben nsect2: move.w d3,d4 * Sektornummer retten nsect: move.w #3,d1 * 4 Lückenbytes (evt. auf clr.b d0 * move.w #4,d1 ändern) bsr wmult move.w #2,d1 * 3 Syncbytes (nicht ändern!) move.b #$F5,d0 * $F5 schreiben bsr wmult move.b #$FE,(a2)+ * $FE, Adreßmarke schreiben move.b $9C5,(a2)+ * Tracknr. schreiben move.b $9C9,(a2)+ * Seite move.b d4,(a2)+ * Sektor move.b #2,(a2)+ * Bytes pro Sektor. Hibyte move.b #$F7,(a2)+ * Checksumme schreiben move.w #$15,d1 * 22 Lückenbytes (nicht ändern!) move.b #$4E,d0 * $4E schreiben bsr wmult move.w #$b,d1 * 12 Lückenbytes (nicht ändern!) clr.b d0 * 0 schreiben bsr wmult move.w #2,d1 * 3 Syncbytes (nicht ändern!) move.b #$F5,d0 * $F5 schreiben bsr wmult move.b #$FB,(a2)+ * $FB- Datenblockmarke move.w #$FF,d1 * 256 Worte wrvirgin: move.b $9D0(a5),(a2)+ * Virgin data move.b $9D9{a5),(a2)+ dbra d1,wrvirgin move.b #$F7,(a2)+ * Checksum schreiben move.w #3,d1 * 4 Lückenbytes (evt. auf move.b #$4E,d0 * move.w #4,d1 ändern) bsr wmult ************************** * writeboot: Bootsektor etc. schreiben ************************** writeboot: lea bootsector(pc),a5 * Bootsektor-Adresse move.w executable(pc),-(sp) * Ausfuhrbarkeitsflag move.w #-1,-(sp) * Disktyp nicht andern move.l #$11000000,-(sp) * Serial number zufällig erzeugen move 1 a5,-(3p) * Adresse des Puffers übergeben move.w #18,-(sp) * PROTOBT trap #14 * im XBIOS add.l #14,sp move.w #0,d5 * Track 0 move.w #1,d6 * Sektor 1 move.w #0,d4 * Seite 0 bsr writesector * Bootsektor schreiben move.w #2,d6 * Ab Sektor 2 move.w #0,d4 * Beite 0 move.w #0,d5 * Track 0 lea cleansector(pc),a5 * cleansector schreiben cnochma1: bsr writesector addq.w #1,d6 cmp.w #12,d6 bne cnochma1 rts ******************* * writesector: Einen Sektor schreiben * Seite in d4, Track in d5, Sektor in d6, Pufferadresse in a5 ******************* writesector: move.w #1,-(sp) * Count move.w d4,-(sp) * Seite move.w d5,-(sp) * Track move.w d6,-(sp) * Sektor move.w #laufwerk,-(sp) * Laufwerk clr.l -(sp) * Füllsel move.l a5,-(sp) * Pufferadresse move.w #9,-(sp) * FLOPWR trap #14 * Xbios add.l #20,sp rts ******************** * printmsg: String ausgeben * Adresse in a5 ******************** printmsg: move.l a5,-(sp) * Message ausgeben move.w #9,-(sp) trap #1 * GEMDOS addq.l #6,sp rts add.w $9D6(ab),d4 * Interleave draufzählen cmp.w $9D4(a5),d4 * mit größter Sektornummer^v ble nsect * vergleichen addq.w #1,d3 * Startsektor plus eins cmp.w $9d6(a5),d3 * Interleave ble nsect2 move.w #600,d1 * 601 Lückenbytes (Änderung move.b #$4E,d0 * zwecklos) bsr wmult move.b $9CF(a5),$FFFF860D * DMA—Lowbyte move.b $9CE(a5),SFFFF860B * DMA-Midbyte move.b $9CD(a5),SFFFF8609 * DMA-Highbyte move.w #$190,(a6) * DMA-Status säubern move.w #$90,(a6) move.w #$190,(a6) * Datenrichtung move.w #$1F,d7 lea $fc0000,a0 jsr $1C90(a0) * d7 an Controller schicken move.w #$180,(a6) move.w #$F0,d7 * format_track-Befehl lea $fc0000.a0 jsr $1C90(a0) * d7 an Controller move.l #$40000,d7 * timeout-Zähler mfploop: btst #5,$fffffa01 * Controller fertig? beq dmastatus * ja. weiter subq.l #1,d7 * nein, warten bne mfploop lea $fc0000,a0 jsr $1BFA(a0) * abbrechen kaputt: moveq.l #1.d7 * Fehler rts dmastatus: move.w #$190,(a6) * DMA-Status move.w (a6),d0 * lesen btst #0,d0 * Fehler? beq kaputt * ja, Fehler move.w #$180,(a6) lea $fc0000,a0 jsr $1CA4(a0) * Register lesen lea $fc0000,a0 jsr $165A(a0) * Fehlernummer and.b #$44,d0 rts wmult: * Bytes in Puffer schreiben move.b d0,(a2)+ dbra d1,wmu1t rts ********************** * waitforkey: 'Taste drücken' ausgeben * und auf Taste warten *********************** waitforkey: lea keymsg(pc).a5 * ‘Taste drücken' bsr printmsg getkey: * Einsprungpunkt ohne Message move.w #7,-(sp) * Auf Taste warten trap #1 * GEMDOS Conin without echo addq.l #2,sp rts ************************* * Error-Routine mit Einsprungpunkten für verschiedene * Fehlermeldungen. Gibt Fehler aus und verabschiedet sich ************************* mallocerror: lea ma1locmsg(pc),a5 * Fehler beim Reservieren von Speicher bra error freeerror: lea freemsg(pc),a5 * Fehler bei der Freigabe von Speicher bra error fata1error: lea errormsg(pc),a5 * Fehler beim Formatieren error: bsr printmsg * Error-Routine. Textadresse in a5 bsr waitforkey * Gibt Message aus, wartet auf Taste bra exitus * und terminiert ************************* * Parameters: Gibt Menue aus * und erlaubt Änderungen ************************* parameters: lea msg_parms(pc),a5 bsr printmsg * Menue ausgeben bsr getkey * Auf Taste warten cmpi.b #3,d0 * ^C? beq exitus * ja, raus cmpi.b #13,d0 * RETURN? beq end_parms * ja, fertig cmpi.b #'b',d0 * 'b' für boot beq end_parms cmpi.b #'B',d0 beq end_parms cmpi.b #'d',d0 * 'd' gedrückt beq op_dir * Dir—Einträge ändern cmpi.b #'D',d0 beq op_dir cmpi.b #'s’,d0 * 's' gedrückt beq op_side * Seitenzahl ändern cmpi.b #'S',d0 beq op_side cmpi.b #'t',d0 * 't' gedrückt beq op_tracks * letzten Track andern cmpi.b #'T',d0 beq op_tracks cmpi.b #'e',d0 * 'e' gedrückt beq op_exe * Ausführbarkeit andern cmpi.b #'E',d0 beq op_exe cmpi.b #'i',d0 * 'i' gedrückt beq op_inter * Interleave ändern cmpi.b #'I',d0 beq op_inter bra parameters end_parms: lea fmtflag(pc),a2 * fmt oder nur boot move.b d0,(a2) rts op_exe: * Ausführbarkeitsflag ändern lea s_exe(pc),a2 * Stringadresse lea executable(pc),a3 * Adresse der Variablen move.w (a3),d0 move.b #’Y',d1 * Yes als Default eor.w #1,d0 * Flag invertieren bne wr_exe * nicht ausführbar? move.b #'n',d1 * auf 'No' ändern wr_exe : move.b d1,(a2) * String und move.w d0,(a3) * Flag ändern bra parameters op_tracks: * Tracks ändern lea s_tracks(pc),a2 * Stringadresse lea endtrack(pc),a3 * Adresse der Variablen move.b $1(a2),d0 * Low-Nibble des Strings move.b (a3),d1 * Wert addq.b #1,d1 * um eins erhöhen addq.b #1,d0 cmpi.b #'7',d0 * mehr als 86 Tracks läuft nicht bne wr_tracks move.b #'0',d0 move.b #79,d1 * letzter Track 79 wr_tracks: move.b d0,$1(a2) * String und move.b d1,(a3) * Flag ändern bra parameters op_side: * Seiten ändern lea s_sides(pc),a2 * Stringadresse lea side(pc),a3 * Adresse im Bootsektor move.b (a3),d0 * Seitenzahl nach d0 holen move.b $1(a2),d1 eor.b #3,d0 * Seitenzahl ändern eor.b #3,d1 move.b d0,(a3) * in Bootsektor schreiben move.b d1,$1(a2) * für String aufbereiten bra parameters op_dir: lea s_dir(pc),a2 * Stringadresse lea entries(pc),a3 * Adresse der Einträge move.b (a3),d0 move.b (a2),d1 addq.b #1,d1 add.b #16,d0 * 16 aufaddieren cmpi.b #143,d0 * schon mehr als erlaubt? bne wr_dir * nein, fertig move.b #15,d0 * wieder von vorne move.b #'1',d1 wr_dir: move.b d0,(a3) * Bootsektor aktualisieren move.b d1,(a2) * String aktualisieren bra parameters op_inter: lea s_inter(pc),a2 * Stringadresse lea ileave(pc),a3 * Inter1eave-Adresse move.w (a3),d0 * Wert holen move.b 1(a2),d1 * String holen addq.b #1,d1 addq.b #1,d0 cmpi.b #10,d0 * schon 10? bne wr_inter move.w #1,d0 move.b #'1',d1 wr_inter: move.b d1,1(a2) move.w d0,(a3) bra parameters *************************** * calc_secs: Anzahl der Sektoren ausrechnen * Formel: (endtrack+1)*11*side **************************** calc_secs: clr.l d1 clr.l d0 lea sectors(pc),a3 move.b endtrack(pc),d0 * Letzter Track addq.b #1,d0 * plus eins mulu #11,d0 * mal 11 move.b side(pc),d1 mulu d1,d0 * mal side move.b d0,(a3) * Lowbyte schreiben asr.l #8,d0 * Highbyte holen move.b d0,$1(a3) * und schreiben rts ************************ * Der Text ************************ .even msg1: .dc.b 27,'E',27,'P ',13,10 .dc.b 'THE HYPER FORMATTER V2.0',13,10 .dc.b '========================',13,10 .dc.b ' Written 1987 by Claus Brod ',13,10 .dc.b ' (Thanks to CD and Anton) ',27,'q',13, .dc.b ' 927000 Bytes free & 30% faster',0 msg_parms: .dc.b 27,'Y',32+7,32+0 .dc.b 27,'pT’,27,'q Tracks ' s_tracks: .dc.b '83',13,10 .dc.b 27,'pE',27,'q Ausführbar (executable):' s_exe: .dc.b 'n',13,10 .dc.b 27,'pD',27,'q Directoryeinträge :$' s_dir: .dc.b '40',13,10 .dc.b 27,'pS',27,'q Seiten (sides) :' s_sides: .dc.b '02',13,10 .dc.b 27,'pl',27,'q interleave :' s_inter: .dc.b '06',13,10 .dc.b 13,10,27,'pCR',27,'q HYPERFORMAT ',13,10 .dc.b 27,'p^C',27,'q Quit',13,10 .dc.b 27,'pB ',27,'q Bootsektor etc. schreiben',13,10,0 .even againmsg: .dc.b 13,10,13,10,'Again (Y/N)? ',0 diskmsg: .dc.b 13,10,'Bitte Disk in Laufwerk ',65+laufwerk,' einlegen.',13,10,0 keymsg: .dc.b 'Taste drücken.',13,10,0 errormsg: .dc.b 13,10,'Fehler beim Formatieren!',13,10,0 mallocmsg: .dc.b 13,10,'MALLOC Error!',13,10,0 freemsg: .dc.b 13,10,'MFREE Error!',13,10,0 .even bootsector: .dc.b 96,56,76,111,97,100,101,114 .dc.b 203,31,238,0,2,spc,res,0,fat entries: .dc.b 63,0 sectors: .dc.b 34,7,249,secsperfat,0,spt,0 side: .dc.b 2,0,0,0,0,0,0,0,0,0,0,0,0,4 .dc.b 0,0,0,0,128,0,84,79 .dc.b 83,32,32,32,32,32,73,77 .dc.b 71,0,51,250,255,226,0,0 .dc.b 4,130,63,57,0,0,4,70 .dc.b 63,60,0,7,78,77,88,79 .dc.b 74,128,103,0,0,246,42,64 .dc.b 65,250,255,208,74,144,102,6 .dc.b 32,185,0,0,4,50,48,45 .dc.b 0,8,225,72,208,128,56,64 .dc.b 217,250,255,184,48,58,255,170 .dc.b 103,16,60,58,255,166,56,58 .dc.b 255,164,38,122,255,162,96,0 .dc.b 0,180,60,45,0,10,56,45 .dc.b 0,8,216,109,0,6,38,122 .dc.b 255,146,97,0,0,178,102,0 .dc.b 0,170,32,76,48,45,0,6 .dc.b 225,72,227,72,65,240,0,0 .dc.b 67,250,255,124,144,252,0,32 .dc.b 177,204,109,0,0,142,112,10 .dc.b 18,48,0,0,178,49,0,0 .dc.b 102,234,81,200,255,244,126,0 .dc.b 30,40,0,27,225,79,30,40 .dc.b 0,26,44,122,255,78,38,122 .dc.b 255,70,66,132,190,124,15,240 .dc.b 108,82,54,7,85,67,198,237 .dc.b 0,2,214,109,0,12,184,124 .dc.b 0,64,108,8,74,68,103,14 .dc.b 182,69,103,16,97,72,102,66 .dc.b 225,140,227,140,215,196,60,3 .dc.b 58,3,66,132,216,109,0,2 .dc.b 218,109,0,2,52,7,226,74 .dc.b 212,71,18,54,32,1,225,73 .dc.b 18,54,32,0,8,7,0,0 .dc.b 103,2,232,73,194,124,15,255 .dc.b 62,1,96,368,74,68,103,4 .dc.b 97,12,102,6,47,58,254,224 .dc.b 78,117,66,128,78,117,63,57 .dc.b 0,0,4,70,63,6,63,4 .dc.b 47,11,66,103,63,60,0,4 .dc.b 78,77,222,252,0,14,74,64 .dc.b 78,117,78,101,117,116,101,114 .dc.b 32,66,111,111,116,101,114,13 .dc.b 10,40,67,41,49,57,56,53 .dc.b 32,65,116,97,114,105,32,67 .dc.b 111,114,112,46,13,10,0,0 .dc.l 0,0,0,0,0,0,0,0 .dc.l 0,0,0,0,0,0,0,0 .dc.l 0,0,0,0,0,0,0,0,0,0,0,0 cleansector: .dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 * Je 16 Nuller .dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .dc.l 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ileave: .dc.w 6 endtrack: .dc.b 82 executable: .dc.w 0 fmtflag: .dc.b 0 romflag: .dc.b 0 .even save_ssp: .dc.l 0 .end