Bevor der Floppykurs so richtig in die Vollen geht, drehen wir noch eine theoretische Ehrenrunde. Es geht um das Drumherum des Floppycontrollers, dessen Programmierung sich bis jetzt kaum jemand zutraut. Aber vielleicht wird dank dieser Serie bald der Kopierschutz und die Datenpackerei auf der Diskette zum Volkssport - wenn Sie ein biĂchen durchhalten.
Zur UnterstĂŒtzung Ihrer eigenen Experimente gibt es eine Erweiterung fĂŒr den Diskmonitor MINIMON, den ich in der letzten ST vorgestellt habe. Sie wird aus PlatzgrĂŒnden leider erst im nĂ€chsten Heft abgedruckt. Die Schwierigkeit dabei ist, daĂ Floppyprogrammierung nur in Assembler denkbar ist - aber keine Angst, Sie mĂŒssen sich nicht monatelang mit moveq, lea und Konsorten herumschlagen. Hauptsache ist, daĂ Sie die Assemblerroutinen, die in das BASIC-Programm eingebunden werden, anwenden können. Und dazu muĂ ich wohl oder ĂŒbel auch ein wenig trockene Theorie erklĂ€ren.
"Kontrola ... wasân das?"
Das mögen sich einige Leser fragen, die bis jetzt in diesem Kurs noch nicht dabei waren oder die nicht so recht aufgepaĂt haben. Der Floppycontroller ist ein Chip, der nur fĂŒr den Datenaustausch mit dem Laufwerk zustĂ€ndig ist. Er entlastet den Prozessor, indem er ihm die lĂ€stige Arbeit abnimmt, die Diskettendaten zu ver- und entschlĂŒsseln sowie sie zu lesen und zu schreiben.
ZunĂ€chst einige Worte ĂŒber die Aufzeichnung. DaĂ eine Diskette in Spuren und Sektoren aufgeteilt ist, wissen Sie. Sehen wir uns so eine Spur an (siehe Bild 1).
Bild 1: Ein nackter RĂŒcken kann auch entzĂŒcken
Sie sehen, daĂ Sie nichts sehen. Das ist auch ganz in Ordnung so, denn schlieĂlich haben wir der Spur noch keine Informationen fĂŒr ihr kĂŒnftiges Leben mitgegeben. Nun könnten Sie sich vorstellen, die Bits wĂŒrden einfach nacheinander auf die Spur gekleistert: Magnetisierter Fleck fĂŒr â1â, nicht magnetisierter fĂŒr â0â. Nicht schlecht fĂŒr den Anfang, aber unbrauchbar. Denn so eine Spur ist rund, und jetzt erzĂ€hlen Sie mir mal, wo ein Kreis beginnt. Eine Markierung anbringen, nach jeder Umdrehung des Laufwerksmotors einen Indeximpuls erzeugen? Gute Idee, wird auch tatsĂ€chlich praktiziert, nur reicht das noch nicht. Ein Laufwerk kann mit vernĂŒnftigem technischen Aufwand nicht dazu gebracht werden, immer gleich schnell zu drehen.
TAKTLOSIGKEITEN
Irgendwie muĂ man also den Lesevorgang mit der Geschwindigkeit des Laufwerks synchronisieren. Ein Verfahren dazu heiĂt MFM, es wird beim ST und bei den meisten anderen Rechnern angewendet und codiert den Taktimpuls des Controllers mit in die Datenbits ein. Schreiben wir einmal einen solchen Track (siehe Bild 2).
Bild 2: Bit fĂŒr Bit - Schreiben in Salamitaktik
Jetzt können wir also einwandfrei Bits lesen, ohne taktlos zu werden. Geschafft? Denkste. Wie erkenne ich denn jetzt, wo ein bestimmtes Byte anfĂ€ngt? NatĂŒrlich, Indeximpuls abwar-ten, Bits lesen und dabei immer bis 8 Bits (=1 Byte) zĂ€hlen, bis man beim gewĂŒnschten Byte ankommt... Nein, das ist es immer noch nicht. Man will ja nicht immer den ganzen Track lesen, sondern vielleicht nur einen Sektor, und auĂerdem könnte es ja sein, daĂ die Synchronisation mit dem Indeximpuls nicht ganz so glatt lĂ€uft; dann fĂ€ngt der Controller beim falschen (zum Beispiel beim zweiten) Bit zu lesen und zu zĂ€hlen an. Ergebnis: Lesefehler, BombenanschlĂ€ge, intergalaktische Kollisionen.
In der Praxis schreibt man spezielle Bytes auf die Spur, die Synchronisationsbytes. Diese Bytes erkennt der Controller daran, daĂ sie ohne Taktinformationen geschrieben werden. Meistens schreibt man mehrere Sync-Bytes hintereinander, und der Controller verschlingt solange Bits, bis er mal einen gĂŒltigen Wert fĂŒr ein Sync-bytes ($A1) erkannt hat. Dann weiĂ er: Hoppla, das nĂ€chste Bit ist der Anfang eines Bytes. Hier also unser Track, wie er wirklich aussieht (das heiĂt, immer noch etwas verbogen und nicht so schön rund wie in Wirklichkeit) (siehe Bild 3 ).
Bild 3: Die Wahrheit kommt ans Licht
Die Markierungen der einzelnen Bits habe ich der Ăbersicht wegen weggelassen. âGapâ bezeichnet einen Abschnitt von LĂŒckenbytes, die der Controller braucht, um sich zwischen den Daten zu erholen und klar Schiff zu machen. Dabei ist er allerdings fixer, als Atari und sogar sein Hersteller ihm Zutrauen; darauf beruht meine Idee, die LĂŒckenbytes soweit zu kĂŒrzen, bis ein elfter Sektor auf die Spur paĂt HYPERFORMAT).
Nach den Syncbytes folgen die sogenannten AdreĂmarken, mit denen bestimmte Datenstrukturen angekĂŒndigt werden (Datenheader, also Vorspann oder Daten). Auch sie werden ohne Taktimpulse geschrieben. Nach den Daten- bzw. Vorspannblöcken folgt jeweils eine 2-Byte-Checksumme, mit der man die GĂŒltigkeit der Informationen nachprĂŒfen, aber auch jede Menge Unsinn treiben kann.
HACKORDNUNGEN ODER DER NAME DER DOSE
Die ganze Lese-/Schreibarbeit und die CodierungsvorgĂ€nge werden dem Abt des Klosters Atari ST, Prozessorus Maximus, von seinem Schreiberling Flopius Controllus abgenommen. Nun ist aber Prozessorus auch noch zu bequem, um Controllus die Daten selbst zu bringen oder sie abzuholen: Er setzt einen Boten ein, D.M.A. Controllus genannt, der speziell fĂŒr Datenschaufeleien dieser Art angeheuert wurde. Ernst beiseite: Der DMA-Controller (Direct Memory Access) bekommt beim Schreiben vom Prozessor die Instruktion, was der Floppycontroller tun soll. Hier dient er als Relaisstation; auĂerdem bekommt er eine Speicheradresse, wo die Informationen stehen, die er dem Controller HĂ€ppchen fĂŒr HĂ€ppchen selbstĂ€ndig ĂŒbermitteln soll. Der Prozessor zieht sich solange wĂŒrdevoll zurĂŒck, um das Ende der Ăbertragung abzuwarten, das er entweder im Erreichen einer bestimmten DMA-Adresse oder an einer Unterbrechungsanforderung des Controllers merkt. Das Lesen funktioniert analog.
Warum so ein Aufwand? WĂ€hrend der DMA-Chip sich um die Speicherschaufelei kĂŒmmert, kann der Prozessor sich seiner Freizeit oder wichtigeren AktivitĂ€ten widmen. Vor allem fĂŒr Multitasking-Betriebssysteme ist das ĂŒberlebenswichtig. Nur leider nĂŒtzt TOS diese Möglichkeiten nicht aus und verbrĂ€t die kostbare Prozessorzeit in Warteschleifen, solange gelesen und geschrieben wird. In RTOS dagegen kann man sogar wĂ€hrend des Formatierens noch andere Dinge erledigen! Ein Schema soll die folgenden, recht kniffligen AusfĂŒhrungen erhellen:
( siehe Bild 4 ).
Es zeigt alle Chips, die bei der Ein-/ Ausgabe auf Diskette zusammenspielen. Nicht nur Prozessor, DMA-Controller und Floppycontroller sind -wie man sieht - am Lesen/Schreiben beteiligt. Die Unterbrechungsanforderung des Floppycontrollers, mit der er vehement auf das Ende seiner Arbeit hinweist, gelangt zum MFP68901, einem Baustein im ST, der unter den Chips des ST nur âder Störenfriedâ heiĂt, weil er stĂ€ndig andere bei der Arbeit unterbricht: Er verwaltet alle Interruptanforderungen der Peripherie.
Dazu kommt noch, daĂ der Controller eigentlich nur ein Laufwerk ansprechen kann - und sogar nur eine Seite! Aber hilfsbereit, wie er ist, springt da der Soundchip ein und leiht dem Controller drei seiner Portbits und schaltet mit ihnen je nach Bedarf zwischen den Seiten und den Laufwerken (maximal zwei) um.
Wie diese Chips Zusammenwirken und wie man sie dazu bringt, sich gegenseitig zu unterstĂŒtzen, wird uns nun beschĂ€ftigen. Die Dreh- und Angelpunkte beim Diskzugriff sind Floppycontroller (auch FDC fĂŒr Floppy Disk Controller) und DMA-Controller.
GONDELFAHRT DURCH DEN SPEICHER
Die Aufgaben des DMA-Chips wurden ja schon kurz erwĂ€hnt: Er hievt Daten vom Speicher zum Floppycontroller (oder auch zum Controller der Festplatte) und von dort aus wieder in den Speicher, ohne daĂ sich der Prozessor darum kĂŒmmern muĂ. Der Prozessor gibt dem DMA-Chip seine Anweisungen, was er gerne da und dort hĂ€tte, und beschĂ€ftigt sich dann lieber damit, Invaders oder StripPoker zu spielen.
Die Anweisungen des Prozessors landen in ein paar Adressen, die ich jetzt in ihre Bits zerlegen werde. Auch die Ausgabe des DMA-Chips (Statusmeldungen und Ă€hnliches) lĂ€uft ĂŒber diese Adressen (siehe Tabelle 1).
Adresse Bedeutung Tabelle 1
|
$FF8604 | REGISTERZUGRIFF
Nur die unteren 8 Bits sind belegt. Aus dieser Adresse kann man den Inhalt von DMA-Chip- und Floppycontroller-Registern lesen oder man kann sie durch diese Adresse verÀndern. Welches Register ausgewÀhlt ist, hÀngt von der folgenden Adresse ab.
|
$FF8606 | DMA-Modus, DMA-Status
FĂŒr den Schreibzugriff gilt folgende Belegung:
Bit | Wirkung |
0 | keine erkennbare Bedeutung, rÀtselhaft
| 1,2 | Wenn Bit 4 gelöscht ist, kann man mit diesen Bits die Register des Floppycontrollers auswÀhlen, auf die man dann in SFF8604 zugreifen kann. Dabei spielt auch der Zustand des Schreib-/Lesebits (Bit 8) eine Rolle:
Bit 1,2 angesprochenes FDC-Register
0 0 beim Lesen Statusregister, sonst Kommandoregister
1 0 Spurregister
0 1 Sektorregister
1 1 Datenregister
| 3 | Datenaustausch mit dem Floppycontroller (Bit gelöscht) oder mit der Harddisk (Bit gesetzt)
| 4 | Ist das Bit gelöscht, kann man in $FF8604 die Register des FDC manipulieren, ansonsten den âSektorzĂ€hlerâ des DMA-Chips (siehe unten).
| 5 | Mysteriös
| 6 | Bit gelöscht: DMA an, Bit gesetzt: DMA macht Ferien
| 7 | dasselbe wie Bit 3, nur in grĂŒn: die Bitbedeutung ist gerade vertauscht. Der Sinn dieses Doppel-Moppels ist mir schleierhaft.
| 8 | Bit gelöscht: Controllerregister lesen, sonst: Controllerregister beschreiben.
Beim Lesen sind nur 3 Bits erkennbar belegt, die restlichen melden sich zwar des öfteren als gesetzt, was sie aber bedeuten, konnte ich noch nicht eruieren:
0 Fehler bei DMA? (Bit gesetzt bedeutet ja)
1 Zustand des SektorzĂ€hlers (Bit gesetzt bedeutet, daĂ der SektorzĂ€hler noch nicht bei 0 angekommen ist; dadurch kann man unvollstĂ€ndige DatenĂŒbertragungen erkennen)
2 âREQUESTâ-Bit. Hier telefoniert der Floppycontroller durch, ob er auf Daten vom DMA-Chip wartet oder welche loswerden will.
|
|
$FF8609 | DMA-ZĂ€hler, Highbyte. Hier liegen die obersten 8 Bit eines ZĂ€hlers, der angibt, welche Adresse vom DMA-Chip gerade bearbeitet wird. |
$FF860B | DMA-ZĂ€hler, Midbyte. Die mittleren 8 Bit. |
$FF860D | DMA-ZĂ€hler, Lowbyte. Die unteren 8 Bit. |
WIR KĂCHELN UNS EIN DATENBRĂU
Wie geht man mit diesem Wust nun um? Einzelne Register des Floppycontrollers anzusprechen, ist ja noch relativ einfach: Man schreibt zum Beispiel den Wert $80 in das Modusregister des DMA-Chips. Damit hat man das Statusregister des Floppycontrollers ausgewĂ€hlt, das man dann im Zugriffsregister $FF8604 auslesen kann. Anderes Beispiel: $184 ins Modusregister, und schon kann man in $FF8604 das Sektorregister beschreiben (halten Sie sich immer die Tabelle 1 vor Augen!). Und so weiter. Nehmen wir an, wir wollten jetzt den Speicherbereich von JETZT__GEHTS__ABERâLOS bis DA__HĂRTS__ABERâAUF auf die Diskette schreiben, beispielsweise als Sektor. Kompliziert, denken Sie? Irrtum. SEHR kompliziert. Das Kochrezept dafĂŒr.
- Startadresse der Ăbertragung (also JETZT__GEHTS__ABER__LOS) nacheinander (und in dieser Reihenfolge) in die DMA-ZĂ€hlerbytes (Low-byte, Midbyte, Highbyte) eintragen. Nun weiĂ der DMA-Chip, wo die Ăbertragung losgeht.
- Zur Sicherheit: Den Status des DMA-Chips löschen. Wie man das macht, muĂ einem allerdings gesagt werden: Dazu âklappertâ man mit der Schreib-/Leseleitung (Bit 8 des DMA-Modus-Registers), das heiĂt, man wechselt schnell hintereinander deren Zustand. Wir wollen auf die Diskette schreiben, also legen wir die Leseleitung zuerst auf 1, dann auf 0 und dann wieder mit Schritt 3 auf 1.
- Hier beschreiben wir nĂ€mlich das DMA-Modusregister mit der Instruktion, die wir brauchen. In unserem Fall wollen wir mit dem DMA-Chip Daten ĂŒbertragen. Wo er mit der Ăbertragung anfangen soll, weiĂ er bereits. Aber wann hört er auf? Das mĂŒssen wir ihm noch in sein goldenes Buch, den SektorzĂ€hler schreiben. In den SektorzĂ€hler schreibt man die Anzahl der zu ĂŒbertragenden Sektoren (ein Sektor besteht auch hier aus 512 Bytes), der DMA-Chip zĂ€hlt dieses Register dann selbstĂ€ndig wĂ€hrend der Ăbertragung herunter. Indem Sie $190 ins DMA-Modus-Register schreiben, wĂ€hlen Sie den SektorzĂ€hler des DMA-Chips zum Beschreiben aus.
- Diesem SektorzĂ€hler ĂŒbergeben wir in $FF8604 nun die Maximalzahl von Sektoren, die der DMA-Chip ĂŒbertragen soll. Bei uns wĂ€re das 1 + ( DA_HĂRTS__ABER__AUF - JETZT__GEHTS__ABER__LOS ) / 512, die 1 wird addiert, um auch die paar ĂŒberzĂ€hligen Bytes noch loszuwerden, falls die Divison nicht glĂŒcklich und ganzzahlig ausgeht (und wo gibt es schon noch ein happy end?).
- Auf Ă€hnliche Weise sagen wir dem Floppycontroller, welchen Sektor er auf der Diskette beschreiben soll. $184 ins DMA-Modusregister, und das Sektorregister des FDC liegt uns in SFF8604 fertig zum heftigen Beschreiben zu FĂŒĂen. Was wir dann auch tun.
- Und jetzt wĂ€hlt man das Kommandoregister des FDC aus ($180 ins DMA-Modus-Register) und ĂŒbergibt ihm in $FF8604 einen Read-Sector-Befehl.
NatĂŒrlich warâs das noch lange nicht. Jetzt mĂŒĂte man noch das Ende der Ăbertragung abwarten. Das macht man entweder, indem man die Unterbrechungsanforderung des Floppycon-trollers abwartet, mit der er Fehler oder das Ende seiner MĂŒhsal anzeigt, oder indem man den DMA-ZĂ€hler beĂ€ugt, abwartet, bis die Ăbertragung bei einer bestimmten Adresse angelangt ist (in unserem Fall bei DA__HĂRTS__ABER__AUF) und dann den Controller brutal abwĂŒrgt (dazu gibt es einen speziellen Strangulationsbefehl). Und wer ganz sauber arbeitet, sollte sich danach noch den Status von DMA-Chip und Floppycontroller anschauen, um eventuelle Fehler abzufangen...
Damit Sie sich schnell zurechtfinden und nicht immer in die einzelnen Bits gehen mĂŒssen, habe ich in einer Tabelle die Werte zusammengefaĂt, die man in die DMA-Modus-Adresse schreiben muĂ, um bestimmte Register auszuwĂ€hlen. Hier die Tabelle fĂŒr das Lesen von Registern:
Wert |
angesprochenes Register |
$80 |
Statusregister des Floppycontrollers |
$82 |
Spurregister des FDC (Floppycontroller) |
$84 |
Sektorregister des FDC |
$86 |
Datenregister des FDC |
$90 |
SektorzÀhler des DMA-Chips |
Und die Tabelle fĂŒr den Schreibzugriff auf Register:
$180 |
Kommandoregister des FDC |
$182 |
Spurregister des FDC |
$184 |
Sektorregister des FDC |
$186 |
Datenregister des FDC |
$190 |
SektorzÀhler des DMA-Chips |
Eine kleine humoristische Einlage des DMA-Chips sollte noch ErwĂ€hnung finden: Liest man weniger als 16 Bytes ein, tut sich gar nichts. Woran liegtâs? Der DMA-Chip puffert intern 16 Bytes, bevor er sie in den Speicher schreibt. Wenn wir also 167 Bytes zu lesen wĂŒnschen, liefert der DMA-Chip 160 (zehnmal 16) und behĂ€lt 7. Dieser Puffer wird ĂŒbrigens gelöscht, wenn Sie den Status per Schreib-/ Leseleitung-Klappern löschen...
Beim Schreiben von Datenmengen (also nicht von Registern) benimmt sich der DMA-Chip noch eigenwilliger. Man ist nicht etwa dann mit dem Schreiben eines Sektors fertig, wenn die aktuelle DMA-Adresse 512 Bytes höher ist als die Startadresse, sondern erst bei 512 + 32 Bytes! Zum GlĂŒck spinnt nur der DMA-ZĂ€hler und nicht die DatenĂŒbertragung selbst, so daĂ man diesen Fehler leicht umgehen kann: Man wartet einfach ein biĂchen lĂ€nger (eben bis laut ZĂ€hler 512 + 32 Bytes ĂŒbertragen sind).
Wenn Sie das alles auf Anhieb verstanden haben, sind Sie wahrscheinlich an der Entwicklung des DMA-Chips beteiligt gewesen. Schauen Sie sich mal im Listing 1 (LOCKSLEY.S) die Routine wrsec an, mit der man Sektoren schreibt. Dort werden Sie wiederfinden, was ich Ihnen erklÀrt habe. Noch eine Anmerkung: Bilden Sie sich nicht ein, Sie könnten diese direkte Programmierung des DMA-Chips effektiv und effizient in einer Hochsprache erledigen - wenn es eine Hochburg der Assemblerprogrammierung gibt, dann liegt sie in der Floppyprogrammierung, wo es zeitlich ziemlich knapp wird.
Aber geben Sie jetzt nicht auf, weil ihre einzigen Fremdsprachen Englisch und BASIC sind. FĂŒr Sie stelle ich im nĂ€chsten Teil des Floppykurses eine Erweiterung fĂŒr den MINIMON vor, mit dem Sie all diese Dinge von BASIC aus erledigen können. Bevor ich dazu komme, bringen wir noch schnell die Funktionen von Soundchip und MFP beim Diskzugriff hinter uns.
Bild 4: Die MaikÀfer kommen!
LUSTVOLLES STĂHNEN NACH FEIERABEND
Wenn der Controller fix und ferne mit der Welt ist, also sein Kommando abgearbeitet hat, meldet er das, indem er eine Unterbrechungsanforderung auslöst. Die meldet er dem MFP (Sie wissen schon, der ungemĂŒtliche Zeitgenosse von vorhin). Wie fragt man das ab? Ganz einfach:
btst #5,mfp
beq fertig
Dieser Assemblerbrocken testet Bit 5 des I/O-Port im MFP (Adresse $FFF-A01). Wenn das erschöpfte âFertigâ-Keuchen des Controllers durch die Chiplandschaft hallt, meldet das der MFP, indem er dieses Bit auf 0 setzt. Wie das im Programm aussieht, sehen Sie in der Routine WARTEN_AUF__GODOT von LOCKSLEY.S (siehe Listing 1).
STABILE SEITENLAGE IM LAUFWERK
Beim Soundchip sind im Grunde nur zwei Adressen interessant. Die eine heiĂt schlicht SND (zumindest in meinem Select-Programm), liegt bei $FF-8800 und ist das Auswahlregister des Chips. Das heiĂt, man schreibt die Nummer des gewĂŒnschten Soundchipregisters in diese Adresse hinein und kann dann entweder deren Inhalt aus SND lesen oder das angewĂ€hlte Register verĂ€ndern, indem man in $FF8802 (SNDWRT fĂŒr âSoundchip-Write-Eingangâ) einen Wert schreibt. Das Register des Soundchips, das uns interessiert, ist das vierzehnte. Darin liegt der Port A des Chips:
Belegung von Port A des Soundchips
Bit |
Bedeutung |
0 |
Seitenauswahl bei der Floppy |
1 |
Auswahlsignal fĂŒr Laufwerk A |
2 |
Auswahlsignal fĂŒr Laufwerk B |
Die restlichen Bits interessieren uns nicht. Bevor wir also den Floppycontroller selbst ansprechen (bzw. den DMA-Controller), mĂŒssen wir erst im Soundchip Seite und Laufwerk einstellen. Auch das finden Sie in einem Programm des Floppykurses, in SELECT.S.
So, jetzt reichtâs aber wirklich mit Adressen und Bits und Kommandos und derlei Verwirrendem mehr. Im Grunde habe ich das alles nur fĂŒr diejenigen Verwegenen herausgearbeitet, die sich selbst an die Programmierung machen wollen, obwohl ich doch in dieser Ausgabe der ST eine Sammlung von Routinen vorstelle, die jeder abkupfern und zum Vorbild nehmen kann. NatĂŒrlich können Sie sich auch noch selbst bemĂŒhen; dazu gibt es im nĂ€chsten Teil des Floppykurses relativ komplette Informationen ĂŒber den Floppycontroller (die hĂ€tten diesmal alle Heftgrenzen gesprengt).
FRAGEN ĂBER FRAGEN
Seit der ersten Folge des Floppykurses rennt man mir telefonisch und brieflich die Bude ein. Das ist auch ganz in Ordnung so, denn dabei kann ich ja auch noch lernen. Nur hÀufen sich gewisse Fragen, und ich nehme an, daà sie von allgemeinem Interesse sind:
Frage 1: Kann man mit HYPERFORMAT auch Festplatten formatieren? Die Antwort: Nein, nein, nein. Erstens nimmt HYPERFORMAT den Floppycontroller in die Mangel und nicht den Festplattencontroller. Zudem ist der bei den verschiedenen Festplatten, die fĂŒr den ST angeboten werden, auch noch unterschiedlich. Und drittens wĂ€re mir auf der Festplatte Datensicherheit wirklich wichtiger als 20 oder 30 Prozent mehr KapazitĂ€t, finden Sie nicht?
Frage 2: Gibt es neue Versionen von HYPERFORMAT und wo bekomme ich sie? Ich arbeite immer noch recht hĂ€ufig an HYPERFORMAT, weil mir immer wieder etwas dazu einfĂ€llt. Die aktuelle Version ist jetzt (Ende Juni) 2.2 mit Tendenz zur 2.3. Sie hat eine zusĂ€tzliche Verifyoption und ein paar kleinere Verbesserungen mitbekommen. Zu bekommen ist die jeweils neueste Version mit einigen Extras gegen frankierten RĂŒckumschlag und Diskette sowie 10 DM unter meiner Adresse, die Sie in den Fistings finden.
Frage 3: Wie kompatibel sind HYPERFORMAT-Disketten zu anderen Rechnern? Knifflig. Ich könnte mir gut vorstellen, daĂ Sie HYPERFORMAT auf vielen anderen Laufwerken physikalisch lesen können. Das hĂ€ngt sehr stark vom Floppycontroller ab, aber da die meisten nach dem MFM-Standard arbeiten, habe ich da eine gewisse Hoffnung. Das logische Format ist natĂŒrlich je nach Rechner völlig verschieden. Am Ă€hnlichsten sind Disketten, die unter MS-DOS formatiert wurden. Insofern besteht Hoffnung, falls Atari doch einmal in ferner Zukunft den MS-DOS-Emulator bringt. Vielleicht vertiefe ich mich dann auch noch einmal in die Materie und produziere ein HYPERFORMAT fĂŒr MS-DOS-Rechner... Wo wir gerade bei KompatibilitĂ€ten sind: FĂŒr das Blitter-TOS werde ich eine neue Version von HYPERFORMAT herausbringen. Wie sich HYPERFORMAT mit dem AMIGA vertrĂ€gt, konnten Sie ja schon in der letzten Folge erfahren.
Frage 4: HYPERFORMAT produziert bei mir Disketten, auf die ich nicht mehr schreiben kann. Tja, das kann viele Ursachen haben. Erstens sollten Sie lieber zweimal nachprĂŒfen, ob Sie auch eine lauffĂ€hige Version haben, das heiĂt, ob Sie nicht vielleicht doch einem Tippfehler erlegen sind oder etwas beim Kopieren schiefgegangen ist. Dann sollten Sie sicher sein, daĂ Sie HYPERFORMAT auch richtig bedienen (siehe ST 6/87). Und lĂ€uft es dann noch nicht, gibt es immer noch mehrere Möglichkeiten: Verwenden Sie schlechte Disketten? PrĂŒfen Sie mal nach, ob mit hochwertigen Disketten nicht was zu machen ist. Dreht Ihr Laufwerk zu schnell? Normal ist eine Umdrehungszahl zwischen 300 und 304 Umdrehungen pro Minute (herauszufinden mit dem Public-domain-Programm SPEED.TOS oder auch mit dem neuen COPYSTAR).
Trifft das alles nicht zu, dann gehören Sie wahrscheinlich zu den vom Schicksal benachteiligten ST-Besitzern, deren Controller HYPERFORMAT (noch) nicht vertrĂ€gt. Aber selbst dann ist noch nicht aller Tage Abend. Oft hilft es, wenn Sie nicht alle Tracks formatieren, die Sie erreichen können, sondern nur bis Spur 80. Wenn Sie ein Sourcelisting haben, vorzugsweise das der Version 2.1, versuchen Sie die LĂŒckenbytes zu Ă€ndern (in der Version 2.1 ganz am Anfang des Listings als gap1 bis gap4 durchparametriert), das Programm zu assemblieren und damit zu formatieren. Wenn Sie das nicht können, fragen Sie einen Freund oder schreiben Sie mir. Wenn Sie selbst Probleme mit HYPERFORMAT hatten und sie irgendwie gelöst haben, lassen Sie es doch die Welt wissen: Schreiben Sie mir oder der âST-Computerâ ĂŒber Ihre Erfahrungen - geben Sie dabei bitte genau Ihre Systemkonfiguration an (und auch bitte das Kaufdatum Ihres ST, ich vermute, daĂ es verschiedene Baureihen gibt). Leider kann ich nicht ausschlieĂen, daĂ trotz aller BemĂŒhungen einige ST-Besitzer auf HYPERFORMAT verzichten mĂŒssen - das Programm geht nun mal bis an physikalische Grenzen heran.
Frage 5: Was kommt als nĂ€chstes? WĂ€hrend des Kurses kommen mir immer mehr Ideen zum Thema. Darunter ist aas bereits angekĂŒndigte Kopierprogramm fĂŒr HYPERFORMAT-Disketten, ein wirklich superschnelles Formatierprogramm fĂŒr ânormaleâ 9- und 10-Sektordisketten, eine ganz besondere RAM-Disk, der BrĂŒckenschlag zwischen .AMIGA und ST und und und...
Bleiben Sie also dran. In der nĂ€chsten Folge werden wir uns noch einmal dem Controller und dessen Programmierung widmen. Der MINIMON wird wohl noch ein wenig wachsen (irgendwann werden wir ihn umtaufen mĂŒssen), und schlieĂlich gibt es noch ein paar Anwendungen fĂŒr den Trackmonitor. Und den Rest behalte ich vorerst fĂŒr mich. Bis bald!
FREIHEIT FĂR DEN LESEKOPF!
Die Floppyroutinen finden Sie in Listing 1 und 2. Listing 1, LOCKSLEY.S, ist ein Assemblerprogramm, dem der Befehlscode des Controllerbefehls und einige Parameter in einem Feld ĂŒbergeben werden und das daraufhin selbsttĂ€tig die richtige Routine auswĂ€hlt und sich mit DMA, MFP und FDC herumschlĂ€gt. Listing 2, SELECT.S, dient bislang nur dazu, das richtige Laufwerk und die richtige Seite anzuwĂ€hlen, wird aber noch erweitert werden.
Ein paar Anregungen: Lesen Sie mal Spuren von verschiedenen Disketten ein (normal formatierte und HYPER-FORMATierte). Sehen Sie den Unterschied? Bei HYPERFORMAT liegen die Sektoren viel dichter beieinander. Versuchen Sie doch mal, ein eigenes Trackformat zu erzeugen. Wie wÀre es mit 16 Sektoren zu 256 Bytes (damit ist das erzeugte Format kompatibel zu bestimmten HP-Rechnern)? Oder mit 1024-Byte-Sektoren?
Schauen Sie sich auch mal - sofern Sie so etwas besitzen - eine kopiergeschĂŒtzte Diskette an und versuchen Sie herauszufinden, worin der Schutz besteht (1024-Byte-Sektoren, wild durcheinandergewĂŒrfelte SektorgröĂen, Checksummen- und andere Fehler...); das sollte ĂŒbrigens keine Aufforderung zum Raubkopieren sein, deswegen halte ich mich mit konkreten Tips zu bestimmten Programmen auch lieber zurĂŒck. Lesen Sie zur Analyse nicht nur den Track - der Read-Track-Befehl des Controllers ist nicht besonders zuverlĂ€ssig. Verwenden Sie auch Read-Address. Gehen Sie am besten so vor: Ermitteln Sie mit Read-Address, wieviele Sektoren ĂŒberhaupt vorhanden sind und wie groĂ diese sind. Dann lesen Sie die ganze Spur ein und vergleichen die Ergebnisse (dazu kann man in MINIMON den Drucker verwenden). Und zuguterletzt schauen Sie sich die einzelnen Sektoren an. Danach mĂŒĂten Sie ziemlich genau wissen, wie die Spur aussieht, auch wenn der Read-Track-Befehl nicht so funktioniert, wie er das anstĂ€ndigerweise tun mĂŒĂte.
LOCKSLEY, DER BEFREIER DES LESEKOPFES
Wie sein Namensgeber (Robin of Locksley, im Volksmund Robin Hood) kĂ€mpft LOCKSLEY. S fĂŒr die Freiheit von UnterdrĂŒckten, in diesem Fall von repressiv programmierten Leseköpfen unzĂ€hliger Laufwerke (Schrittmotoren aller LĂ€nder, vereinigt Euch!). LOCKSLEY.S ist einerseits eine Sammlung von Routinen, die Sie immer wieder brauchen werden, wenn Sie sich mit der direkten Floppyprogrammierung, entschlackt von der Last des Betriebssystems, befassen, und andererseits ein Modul, das wie SELECT.S vollstĂ€ndig relokatibel ist. SELECT.S wie LOCKSLEY.S sind mit dem AS68 assembliert worden. Wie man das macht? Dazu ruft man den AS68 so auf: âAS68 â 1 -u filename.sâ. Der Linker produziert dann nach 'linker filename.prg = filename.oâ ein lauffĂ€higes Programm.
Auch bei LOCKSLEY.S finden Sie am Anfang des Programms eine Tabelle von Ein-/Ausgabeparametern, die sich auch bei eventuellen Erweiterungen des Programms nicht verschieben wird. Wenn Sie LOCKSLEY.S benutzen, erwartet das Programm mindestens den Opcode desjenigen Befehls, den der Controller ausfĂŒhren soll, im Parameter 'opcode'. LOCKSLEY analysiert diesen Opcode und springt dann die richtige Routine fĂŒr jeden Befehl an. Zu den einzelnen Befehlen können noch weitere Parameter benötigt werden. Eine Ăbersicht der möglichen Befehle des Controllers und der Ein/ Ausgabeparameter finden Sie in der Tabelle auf der nĂ€chsten Seite. Was die einzelnen Befehle tun, finden Sie kurz in der Anleitung zum EXTEN -DED MINIMON erlĂ€utert (genaues in der nĂ€chsten Folge).
ENE MENE MISTE - DIE QUAL DER WAHL
SELECT.S ist ein Programm, das sich (bis jetzt) ausschlieĂlich damit beschĂ€ftigt, die richtige Seite und das richtige Laufwerk auszuwĂ€hlen. Man ruft es auf, bevor man einen Controllerbefehl abschickt, damit man sicher ist, daĂ der Formatierbefehl, den man im Sinne hat, auch tatsĂ€chlich die freie Disk in Laufwerk B in die Mangel nimmt und nicht die Systemdiskette in Laufwerk A. VersĂ€umt man das, erzeugt das graue Haare, aber wem unter ihnen erzĂ€hle ich damit etwas Neues...
Im Quelltext erkennen Sie, daĂ ganz am Anfang des Programms bestimmte Speicherstellen fĂŒr die ParameterĂŒbergabe durch BASIC (oder andere Sprachen) vorgesehen sind. In âlaufwerkâ schreibt man die Bitkombination fĂŒr aktuelle Seite und gewĂŒnschtes Laufwerk (dazu schauen Sie sich am besten die Belegung des Port A im Soundchip an, die im Artikel erwĂ€hnt ist). Laufwerk A, Vorderseite wĂ€hlt man an, indem man â2â in âlaufwerkâ schreibt und dann in die Routine springt.
Wenn Sie sich den Quelltext anschauen, werden Sie sich wundern, daĂ wĂ€hrend des Programms alle Interrupts ausgeschaltet werden. Das hat einen einfachen Grund. In einer Interruptroutine prĂŒft das Betriebssystem stĂ€ndig, ob auf einem Laufwerk eine Diskette gewechselt wurde. Dazu muĂ es die Laufwerke natĂŒrlich selektieren und benutzt dazu den Port A. Damit es da keine Kollisionen gibt, habe ich den Interrupt fĂŒr diese kurze Zeit einfach verboten.
Ein Wort noch zu einer weiteren Besonderheit. Nach einem Befehl deselektiert man sinnvollerweise das Laufwerk, indem man â0â in âlaufwerkâ schreibt und SELECT aufruft. Allerdings kam es dabei vor, daĂ man das Laufwerk abwĂ€hlte und trotzdem (oder gerade deswegen) der Laufwerksmotor sich wie das Auto einer groĂen Marke benahm: Er lief und lief und lief...
Woran das liegt, weiĂ ich noch nicht genau, ich hoffe da auf die UnterstĂŒtzung eines kundigen Lesers. Was ich weiĂ: Wenn man abwartet, bis das Laufwerk seinen Motor von alleine abschaltet, und dann erst die Floppy de-selektiert, funktioniert es. Dabei muĂ man aber in Kauf nehmen, daĂ nach jedem Befehl eine Sekunde fĂŒr das Auslaufen des Motors verlorengeht. Diese Warteschleife finden Sie im Programm ab dem Label âmotorâ.
In der nĂ€chsten Ausgabe werde ich SELECT so erweitern, daĂ man mit diesem Programm auch die Register des Floppycontrollers direkt von BASIC aus lesen und beschreiben kann. Deswegen sind in das Listing einige Definitionen und âopen endsâ eingebaut, ĂŒber die Sie sich vielleicht wundern mögen.
(C.B.)
Die Liste der Routinen:
main Initialisierung
motor Warteschleife, bis der Motor ausgelaufen ist
mach_mal Laufwerk und Seite selektieren
super Supervisor-/Usermodus einschalten
time Warteschleife
Befehl
|
Parameter
|
irq
|
Eingabe: nur Opcode in âopcodeâ Ausgabe: keine!
|
Read
Sektor
|
Eingabe: Opcode in âopcodeâ, Pufferadresse in âbufferlâ, Sektor in âsectorâ, Anzahl der zu lesenden Bytes in âcountâ
Ausgabe: gelesene Bytes in âcountâ, Status des Floppycontrollers in âfstâ, DMA-Status in âdstâ, Ende der DMA-Ăbertragung in âendâ, Timeoutflag in âtimeoutâ
|
Read
Track
|
Eingabe: Opcode in âopcodeâ, Pufferadresse in âbufferlâ, Zahl der zu lesenden Bytes in âcountâ Ausgabe: wie Read Sector
|
Write
Track
|
Eingabe: Opcode in âopcodeâ, Adresse der Trackdaten in âbufferlâ, Zahl der zu schreibenden Bytes in âcountâ
Ausgabe: geschriebene Bytes in âcountâ, sonst wie bei Read Sector
|
Write
Sector
|
Eingabe: Opcode in âopcodeâ, Adresse der Sektordaten in âbufferlâ, Zahl der zu schreibenden Bytes in âcountâ, Sektornummer in âsectorâ
Ausgabe: wie bei Write Track
|
Step,
Step-in
Step-out,
Restore
|
Eingabe: Opcode in âopcodeâ Ausgabe: Controllerstatus in âfstâ
|
Seek
|
Eingabe: Opcode in âopcodeâ, Zielspur in âtrackâ Ausgabe: wie bei Step etc.
|
Read
Address
|
Eingabe: Opcode in âopcodeâ, Zahl der zu lesenden AdreĂfelder in âcountâ, Pufferadresse fĂŒr die AdreĂfelder in âbufferlâ, Pufferadresse fĂŒr die Statusmeldungen in âbuffer2â
Ausgabe: wie bei Read Sector
|
Die Liste der Routinen:
main Initialisiert, verzweigt und macht SchluĂ
wrfdc Ein Byte in $ff8604 schreiben (Zugriff auf FDC- oder DMA-Register )âą as_time_goes_by Warteschleife
warten_auf_godot Wartet auf Ende des FDC-Kommandos
poll Testet auf Unterbrechungsanforderung
game_over ZeitĂŒberlauf passiert
fix_und_fertig DMA-Ăbertragung am Ende
Status Status des DMA-Chips lesen dma Startadresse fĂŒr DMĂ setzen super Supervisor/Usermodus umschalten analyze Analysiert den Opcode und verzweigt irq Routine fĂŒr den FORCE-IRQ-Befehl rdsec Routine fĂŒr den Read-Sector-Befehl
exe Einsprung fĂŒr den Zyklus âKommando schreibenâ-âwartenâ-âStatus lesenâ
rdtrk Routine fĂŒr den Read-Track-Befehl
wrtrk Routine fĂŒr den Write-Track-Befehl
wrsec Routine fĂŒr den Write-Sector-Befehl
step_dance Routine fĂŒr Step, Step-In, Step-Out und Restore
such_hasso Routine fĂŒr den Seek-Befehl
rdadr Routine fĂŒr den Read-Address-Befehl nochnid Schleifenmarke fĂŒr 'noch âne ED lesenâ
|
LOCKSLEY.S (C) 1907 Claus Brod
*********************************************
* LOCKSLEY - Der Befreier des Lesekopfes *
* Direkter Zugriff auf den Floppycontrol1er *
* --- Test auf eigene Gefahr ---- *
* Mit Schnittstelle nach auĂen fĂŒr den *
* AnschluĂ an MINIMON *
* Written 1987 by *
* Claus Brod *
* Am Felsenkeller 2 *
* 8772 Marktheidenfeld *
* *
* Version 1.0 *
* 6.6.87 (starting all over again) *
* 7.6.87 (main work) *
* 8.-11.6.87 (debugging) *
* 12.6.87 (adding some sub's) *
* 13.6.87 (fiddling with #@!?* Read Adr.) *
* 14.-16.6.87 (cleaning up) *
* Assembliert mit AS68 *
*********************************************
*************************
* Ein paar Definitionen fĂŒr den langen Weg
*************************
mfp - Sfffa01 * Adresse des MFP68901 fĂŒrs Polling
daccess= $ff8604 * DMA-Contro1ler, FDC-Zugriff oder SektorzÀhler
dmodus = $ff8606 * DMA-Contro1ler, Modus einstellen
dlow = $ff860d * DMA-Contro1ler, Ăbertragungsstart Lowbyte
dmid = $ff860b * DMA-Contro1ler, ĂŒbertragungsstart Midbyte
dhigh = $ff8609 * DMA-Contro1ler, ĂŒbertragungsstart Highbyte
time = $40000 * Timeout-Konstante
*************************
* Der Sprung ins Ungewisse
*************************
bra main * Sprung zum Programmanfang
*************************
* Ein/Ausgabefeld zur ParameterĂŒbergabe
*************************
opcode: .dc.w 0 * Hier kommt der Opcode
* des Controllerbefehls hinein
track: .dc.w 0 * Tracknummer
*
sector: .dc.w 0 * Sektornummer
*
count: .dc.w 0 * in:zu ĂŒbertragende Bytes/ID-fields etc.
* out:ĂŒbertragene Bytes
buffer1: .dc.l 0 * Adresse des ersten Puffers fĂŒr
* Track-, Sektor-, ID-Daten
buffer2: .dc.l 0 * Adresse des Reservepuffers
*
fst: .dc.w 0 * Status des Controllers
*
dst: .dc.w 0 * Status der DMA
*
dstart: .dc.l 0 * Start der DMAâĂbertragung
*
dend: .dc.l 0 * Ende der DMAâĂbertragung
*
timeout: .dc.w 0 * Timeoutflag
*
stk: .dc.l 0 * Puffer fĂŒr Stackpointer
*
dflag: .dc.w 0 * DMA-Flag
*
***************************
* Hauptverteilerroutine
***************************
main:
movem.l d0-d7/a0-a6,-(sp) * Register verschwinden lassen
clr.l d0 * Userstack wird Supervisorstack
bsr super * Supervisormodus an
lea stk(pc),a2 * Adresse des Puffers fĂŒr den Stackpointer
move.l d0,(a2) * Stackpointer retten
move.w opcode(pc),d6 * FDC-Befehl holen
lea dflag(pc),a2 * Adresse des DMA-Flags
move.w #0,(a2) * DMA-Flag initialisieren
lea timeout(pc),a2 * Adresse des Timeoutflags
move.w #0,(a2) * TimeoutâFlag initialisieren
st $43e * Floppy-VerticalâB1ankâInterrupt sperren
bsr analyze * Befehl analysieren und ausfĂŒhren
sf $43e * Floppy-VBL wieder erlauben
lea stk(pc),a2 * Adresse des Stackpointerpuffers
move.l (a2),d0 * Stackpointer holen
bsr super * Supervisormodus aus (schaaade...)
movem.l (sp)+,d0âd7/a0âa6 * Register wieder holen
rts * und raus (ade!)
******************************
* wrfdc: Byte in d7 an den Controller
* schicken
******************************
wrfdc:
move.w #30,d1 * ZĂ€hler auf 30
bsr as_time_goes_by * Warteschleife
move.w d7,daccess * d7 ins Access-Register des DMA-Chips
move.w #30,d1 * ZĂ€hler auf 30
******************************
* as_time_goes_by: Warteschleife
* mit d1 DurchlÀufen
******************************
as_time_goes_by:
dbf d1,as_time_goes_by * Looping (huiii...)
rts * back to the future
******************************
* warten_auf_godot : Wartet auf das IRQ-Signal
* des FDC
******************************
warten_auf_godot:
move.l #time,d7 * Konstante fĂŒr Timeout
poll:
btst #5,mfp * IRQ am MFP7
beq fix_und_fertig * jawoll, Kommando ist ausgefĂŒhrt
subq.l #1,d7 * TimeoutzÀhler magert ab
beq game_over * Sorry, zu lange gefackelt
lea dflag(pc),a2 * Adresse des DMA-Flags
tst.w (a2) * DMA aktiv?
beq poll * nein, zum Polling
lea buffer2(pc),a2 * Adresse der Adresse (!) des Reservepuffer!
move.b dhigh,1(a2) * Highbyte der DMA-Adresse
move.b dmid,2(a2) * Midbyte der DMA-Adresse
move.b dlow,3(a2) * Lowbyte der DMA-Adresse
move.l buffer2(pc),d0 * DMA-Adresse nach dO
cmp.l dend(pc),d0 * Mit Endadresse vergleichen
blt poll * Noch nicht erreicht, weiter testen
move.b #$d0,d7 * Force IRQ
bsr irq * FDC unterbrechen
lea dflag(pc),a2 * Adresse des DMA-Flags
move.w #0,(a2) * DMA beendet
bra fix_und_fertig * Feierabend
***************************
* Timeout-Konstante ist abgelaufen
***************************
game_over:
bsr fix_und_fertig * Status lesen und in fst ablegen
move.b #$d0,d7 * Force IRQ
bsr irq * FDC unterbrechen
lea timeout(pc),a2 * Adresse des Timeout-F1ags
move.w #1,(a2) * Timeout passiert
lea dflag(pc).a2 * Adresse des DMA-Flags
move.w #0,(a2) * DMA völlig am Ende
rts * und fertig
***************************
* DMA-Ubertragung oder FDC fertig
***************************
fix_und_fertig:
move.w daccess,d0 * Status lesen
lea fst(pc),a2 * Adresse des FDC-Status-Flags
move.w d0,(a2) * Status ablegen
rts * und raus
***************************
* status: Status und Bytezahl lesen
***************************
status:
move.w dmodus,d0 * Status lesen
lea dst(pc),a2 * Adresse des DMA-Status-Flags
move.w d0,(a2) * Status schreiben
clr.w d1 * d1 löschen
move.b dhigh,d1 * DMA-High
lsl.l #8,d1 * um ein Byte schieben
move.b dmid,d1 * DMA-Mid
lsl.l #8,d1 * um ein Byte schieben
move.b dlow,d1 * DMA-Low
lea dend(pc),a2 * Adresse der Endadresse
move.l d1,(a2) * Endadresse
sub.l dstart(pc),d1 * minus Start
lea count(pc),a2 * Adresse des BytezÀhlers
****************************
* dma: dma setzen (Spiegelbild zu status)
****************************
dma:
lea dstart(pc),a2 * Adresse der Startadresse
move.l d7,(a2) * Startadresse ablegen
move.b d7,dlow * Lowbyte
lsr.l #8,d7 * um ein Byte schieben
move.b d7,dmid * Midbyte
lsr.l #8,d7 * um ein Byte schieben
move.b d7,dhigh * Highbyte
move.l dstart(pc),d7 * Startadresse holen
clr.l d0 * d0 löschen
move.w count(pc),d0 * Bytecounter nach dO
add.l d0,d7 * Addieren
lea dend(pc),a2 * Adresse der Endadresse
move.l d7,(a2) * Endadresse ablegen
rts
*****************************
* super: Schaltet vom Usermode
* in der Supervisormode und umgekehrt
* Ăbergabe des Stackpointers in d0
*****************************
super:
move.l d0,-(sp) * Stackpointer auf Stack
move.w #$20.-(sp) * SUPER
trap #1 * im GEMDOS
addq.l #6,sp * Stack korrigieren
rts
*****************************
* analyze: Analysiert grob, welche Art von
* Befehl vorliegt
* und verteilt entsprechend
* in: d6.w Opcode
*****************************
analyze:
move.w d6,d7 * Opcode retten
move.w d6,d5 * gleich nochmal
btst #7,d6 * Bit 7 testen
bne typii * kein Typ-I-Befehl
and.b #$f0,d6 * obere 4 Bits ausmaskieren
cmp.b #16,d6 * SEEK-Befehl?
beq such_hasso * jawoll
bne step_dance * kein Seek. aber Typ-I
typii:
btst #6,d6 * Bit 6 testen
bne typiii * kein Typ-II-Befehl
btst #5,d6 * Bit 5 testen
beq rdsector * gelöscht, also Read-Sector-Befehl
bne wrsector * Write-Sector-Befehl
typiii :
and.b #$f0,d6 * obere 4 Bits ausmaskieren
cmp.b #$c0,d6 * Read Adress?
beq rdadr * jawoll
cmp.b #$e0,d6 * Read Track?
beq rdtrk * jawoll
* * alles andere ist Force Interrupt
**************************
* irq: Unterbricht den Controller
**************************
irq:
bsr wrfdc * d7 an den Controller
move.w #250,d1 * 250 SchleifendurchlÀufe
bra as_time_goes_by * kurz warten
*****************************
* rdsector: Liest einen Sektor oder
* gleich einen ganzen Haufen davon
*****************************
rdsector:
move.l buffer1(pc),d7 * Pufferadresse
bsr dma * als DMA-Adresse
lea dflag(pc),a2 * Adresse des DMA-Flags
move.w #1,(a2) * DMA-Flag setzen
move.w #$90,dmodus * mit der Sehreib/Leseleitung
move.w #$190,dmodus * kippeln, löscht den DMA-Status
move.w #$90,dmodus * Sektorzahler des DMA-Chips
move.w #14,d7 * maximal 14 Sektoren (utopisch)
bsr wrfdc * d7 an FDC
move.w #$84,dmodus * Sektorregister
move.w sector(pc),d7 * Sektornummer
bsr wrfdc * d7 an FDC
move.w #$80,dmodus * Kommandoregister
exe:
move.w d5,d7 * Kommando von d5 nach d7
bsr wrfdc * d7 an FDC
bsr warten_auf_godot * Ende des Kommandos abwarten
bra status * Status lesen
*****************************
* rdtrk: Track lesen
*****************************
rdtrk:
move.l buffer1(pc),d7 * Adresse des Spurpuffers
bsr dma * DMA initialisieren
lea dflag(pc),a2 * Adresse des DMA-Flags
move.w #1,(a2) * DMA in Arbeit!
move.w #$90,dmodus * Schreib/Leseleitung
move.w #$190,dmodus * umschalten, siehe oben
move.w #$90,dmodus * SektorzÀhler des DMA-Chips
move.w #14.d7 * 14 Sektoren
bsr wrfdc * d7 an FDC
move.w #$80,dmodus * Kommandoregister
bra exe * Kommando schreiben und beenden
*****************************
* wrtrk: Track schreiben
*****************************
wrtrk:
move.l buffer1(pc),d7 * Spurpufferadresse nach d7
bsr dma * DMA initialisieren
lea dflag(pc),a2 * Adresse des DMA-Flags
move.w #1,(a2) * DMA in Arbeit!
move.w #$190,dmodus * Schreib/Leseleitung umschalten
move.w #$90,dmodus * (bewirkt was? Raten Sie mal!)
bsr wrfdc * d7 an FDC
move.w #$100,dmodus * Kommandoregister wÀhlen
bra exe * Kommando schicken und beenden
*****************************
* wrsector: Sektor schreiben
***************************.1*
wrsector:
move.l buffer1(pc),d7 * Adresse des Puffers
bsr dma * DMA initialisieren
lea dflag(pc).a2 * Adresse des DMA-Flags
move.w #1,(a2) * DMA in Arbeit
move.w #$190.dmodus * mit der Schreib/Leseleitung
move.w #$90,dmodus * klappern
move.w #$190,dmodus * SektorzÀhler des DMA-Chips
move.w #14,d7 * Maximal 14 Sektoren (utopisch)
bsr wrfdc * d7 an FDC
move.w #$184,dmodus * Sektorregister des FDC
move.w sector(pc),d7 * Startsektor holen
bsr wrfdc * d7 an FDC
move.w #$180,dmodus * Kommandoregister des FDC
bra exe * Kommando schicken und beenden
*****************************
* step_dance: einheitliche Routine fĂŒr Step,
* step-in, step-out, restore
*****************************
step_dance:
move.w #$80,dmodus * Command-Register auswÀhlen
bsr wrfdc * Byte in d7 an FDC
bra warten_auf_godot * Auf FDC warten...
*****************************
* such_hasso: Seek-Befehl
*****************************
such_hasso:
move.w #$86,dmodus * Datenregister auswÀhlen
move.w track(pc).d7 * Tracknummer holen
bsr wrfdc * Byte in d7 an FDC
move.w #$80,dmodus * Commandregister
move.w d5,d7 * Kommando
bsr wrfdc * Byte an FDC
bra warten_auf_godot * Auf FDC warten
*****************************
* rdadr: AdreĂfeld lesen
*****************************
rdadr:
move.l buffer1(pc),d7 * Adresse des Puffers holen
move.l buffer2(pc),a3 * Adresse des Reservepuffers
bsr dma * DMA initialisieren
move.w #$90,dmodus * Schreib/Leseleitung
move.w #$190.dmodus * umschalten
move.w #$90,dmodus * und auf SektorzÀhler
move.w #1.d7 * Maximal 1 Sektor
bsr wrfdc * d7 an FDC (DMA)
move.w #$80,dmodus * Kommandoregister
move.w count(pc),d2 * Wieviele ID-Felder?
nochnid:
move.w d5,d7 * Kommando holen
bsr wrfdc * und schreiben
bsr warten_auf_godot * auf FDC warten
move.w fst(pc),d1 * FDC-Status holen
move.w d1,(a3)+ * Status in den zweiten Puffer
dbra d2,nochnid * Noch eine ID
bra status * und zum Status
SELECT.S
****************************
* SELECT.S
* Selektiert Seite und Laufwerk
* Mit Schnittstelle fĂŒr BASIC
* (C) 1987 and for all eternity by
* Claus Brod
* Am Felsenkeller 2
* 8772 Marktheidenfeld
* Version 1.0
* Last update 16.6.87
* Assembliert mit AS68
*****************************
*****************************
* Definitionen
*****************************
snd = $ff8800 * Adresse des Soundchips
sndwrt = $ff8802 * Ein/Ausgabe des Soundchips
dmodus = $ff8606 * DMA-Modus-Register
daccess = $ff8604 * DMA-Access
*****************************
* Sprung ins Hauptprogramm
*****************************
bra main
*****************************
* Eingabefeld fĂŒr BASIC
*****************************
laufwerk: .dc.w 0 * Eingabeparameter Laufwerk und Seite
parm: .dc.l 0 * Reserveein/ausgabefeld fĂŒr Erweiterungen
temp: .dc.l 0 * Reservefeld
stk: .dc.l 0 * Puffer fĂŒr Stackpointer
*****************************
* Und jetzt das Hauptprogramm
*****************************
main:
movem.l d0âd7/a0âa6,â(sp) * Register retten
clr.l d0 * Userstack wird Supervisorstack
bsr super * Supervisormode an
lea stk(pc),a2 * Stackpointer
move.l d0,(a2) * retten
st $43e * FloppyâVBL sperren
move.w laufwerk(pc),d7 * Laufwerksnummer holen
bne mach_mal * Wenn nicht gerade 0, dann mach los
move.w #$80,dmodus * Statusregister
motor:
move.w daccess,d1 * auslesen
btst #7,d1 * Motor noch an?
bne motor * jawoll
mach_ma1:
cmpi.b #8,d7 * Laufwerkscode gröĂer als 7?
bge extend * ja, extended mode
eor.b #7,d7 * Bits invertieren
and.b #7,d7 * und ausmaskieren
move.w sr,-(sp) * Status retten
or.w #$700,sr * Interrupts aus
move.b #14,snd * Port A wÀhlen
move.b snd,d0 * Port A lesen
and.b #$f8,d0 * ausmaskieren
or.b d0,d7 * neue Seite/neues Laufwerk setzen
move.b d7,sndwrt * in Port A
sf $43e * Floppy-VBL erlauben
move.w (sp)+,sr * Status wieder holen
raushier:
lea stk(pc),a2 * Stackpointer
move.l (a2),d0 * zurĂŒckholen
bsr super * wieder in den Usermode
movem.l (sp)+,d0-d7/a0-a6 * Register zurĂŒckholen
rts * und raus
*************************
* super: Schaltet vom Usermode
* in den Supervisormode und umgekehrt
* in: d0 Stackpointer
*************************
super:
move.l d0,-(sp) * Stackpointer auf Stack
move.w #$20,-(sp) * SUPER
trap #1 * im GEMDOS
addq.l #6,sp * Stack reparieren
rts * und raus
**************************
* time: Warteschleife
**************************
time:
dbra d1,time * ZĂ€hler magert ab
rts * und raus
**************************
* msg: Gibt String ab a2 aus
**************************
msg:
move.l a2,-(sp) * Adresse des Strings auf den Stack
move.w #9,-(sp) * PRINT LINE
trap #1 * im GEMDOS
addq.l #6,sp * Stack korrigieren
rts * und raus
**************************
* extend: Wird in der nÀchsten ST ergÀnzt
**************************
extend:
lea nochnit(pc),a2 * extend noch nicht
bsr msg * implementiert
bra raushier * und raus
nochnit:
.dc.b 'Routine noch nicht implementiert.',13,10,0