← ST-Computer 09 / 1987

Floppy-Spielereien Teil 3: Durch dunkle KanÀle

Kurs

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
$FF8604REGISTERZUGRIFF
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.
$FF8606DMA-Modus, DMA-Status
FĂŒr den Schreibzugriff gilt folgende Belegung:
BitWirkung
0keine erkennbare Bedeutung, rÀtselhaft
1,2Wenn 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
3Datenaustausch mit dem Floppycontroller (Bit gelöscht) oder mit der Harddisk (Bit gesetzt)
4Ist das Bit gelöscht, kann man in $FF8604 die Register des FDC manipulieren, ansonsten den „SektorzĂ€hler“ des DMA-Chips (siehe unten).
5Mysteriös
6Bit gelöscht: DMA an, Bit gesetzt: DMA macht Ferien
7dasselbe wie Bit 3, nur in grĂŒn: die Bitbedeutung ist gerade vertauscht. Der Sinn dieses Doppel-Moppels ist mir schleierhaft.
8Bit 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.

$FF8609DMA-ZĂ€hler, Highbyte. Hier liegen die obersten 8 Bit eines ZĂ€hlers, der angibt, welche Adresse vom DMA-Chip gerade bearbeitet wird.
$FF860BDMA-ZĂ€hler, Midbyte. Die mittleren 8 Bit.
$FF860DDMA-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.

  1. 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.
  2. 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.
  3. 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.
  4. 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?).
  5. 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.
  6. 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