Wo bin ich – Anzeige der Spur & Sektor für die 1541

Einführung

Der Fokus liegt weniger auf dem Aufbau des Diskettenformats, sondern darauf, wie sich die Position des Schreib-/Lesekopfes relativ einfach ermitteln lässt.

Informationen zum Aufbau der Commodore 1541 Diskettenformate finden sich unter anderem hier: Visualizing Commodore 1541 Disk Contents.

Beim Formatieren der Disketten im VC1541 von Commodore wird vor jedem Datenabschnitt ein Sektorheader geschrieben. Dieser Bereich enthält genau die gewünschten Informationen, die für die Anzeige von Spur und Sektor benötigt werden.

Wie werden die Daten erfasst?

Das Abrufen der Rohdaten ist nicht schwierig. Die notwendigen Informationen werden zwischen dem GateArray (325572-01) und dem VIA (6522) ausgetauscht.

Hier wird einfach das VIA 6522 auf dem Steckplatz UC2 verwendet, um die erforderlichen Daten abzurufen.

Die folgenden Leitungen sind erforderlich:

  • PIN 2-9
    • PA0 – PA7 / D0 – D7: Die Datenleitungen D0 bis D7 von der Lese-/Schreibelektronik sind hier angeschlossen
  • PIN 13
    • PB3 / ACT: Die Leitungen, die auch die rote LED an der Vorderseite des Diskettenlaufwerks steuern, zeigen die entsprechende Aktivität an
  • PIN 17
    • PB7 / SYNC: SYNC-Signal, das auf der Datenleitung 0xFF entspricht
  • PIN 39
    • CA2 / SOE: Signal, das vom VIA zur Lese-/Schreibe-Elektronik gesendet wird. Nur dann kann das ByteReady-Signal erzeugt werden. Das VIA ist bereit für Daten.
  • PIN 40
    • CA1 / BR oder ByteReady: So signalisiert das GateArray, dass ein neues Byte auf den Datenleitungen vorhanden ist.

Die Datenleitungen beziehen sich übrigens nicht auf die Leitungen zwischen Prozessor, RAM, ROM und VIAs, sondern nur auf die 8-Bit-Verbindung zwischen VIA und GateArray (oder der diskreten Version in den alten Longboard-Varianten).

Ein Ausflug in Bits und Bytes

Wenn nun ein Logikanalysator an die genannten Leitungen angeschlossen und das Verzeichnis geladen wird, sind bereits alle erforderlichen Informationen vorhanden.

Was sofort ins Auge fällt, ist der zusammenhängende Block im unteren linken Bereich. Außerdem ist darunter ein HIGH-Signal zu sehen, das dazu passt.

Direkt darunter ist ein Signal erkennbar, das über die gesamte Bildschirmbreite auf “HIGH” bleibt. Dies ist die Aktivitäts-LED, die den Moment anzeigt, wenn der Motor eingeschaltet wird und der Kopf beginnt, Daten zu lesen. Es dauert eine Weile (die Diskette dreht sich mit 300 Umdrehungen pro Minute, also 5 pro Sekunde), bis die Drehzahl konstant ist und die SYNC-Signale erkannt werden.

Der vergrößerte zusammenhängende Block sieht dann so aus:

Was auf diesem Bild schon sehr gut zu erkennen ist, sind die kleinen Lücken zwischen den Datenleitungen (den oberen 8 Balken).

Dies sind die SYNC-Signale, die während des Formatierens geschrieben werden. Daran lässt sich erkennen, wann der nächste Datenblock kommt.

Zuerst erkennt man ein SYNC-Signal, dann einen kurzen Bereich, erneut ein SYNC und dann einen längeren Bereich.

Der kürzere Bereich ist der Sektorheader und der längere ist der Bereich, in dem sich die eigentlichen Nutzerdaten befinden.

Hier interessiert nur der Sektorheader.

Dies ist nun der komplette Sektorheader eines Sektors. Vor jedem Sektor wird dieser Header geschrieben und enthält die Informationen, um welche Spur und welchen Sektor es sich handelt, die Disketten-ID, dass es sich um einen Sektorheader handelt, und eine Prüfsumme.

Mit diesen Daten weiß das Diskettenlaufwerk immer, wo sich der Kopf befindet.

Das ByteReady-Signal zeigt an, wenn ein gültiges Byte vorhanden ist, das das VIA dann verarbeiten kann oder für die CPU bereitstellt.

Wird dieses Signal als Trigger an einer fallenden Flanke verwendet, können die Bytes vom Logikanalysator in numerischer Form angezeigt werden. Diese sind gut im hellblauen Streifen zu erkennen.

Besonders gut zu sehen ist das SYNC-Signal, das logisch aus 0xFF besteht, also sind alle Leitungen auf HIGH gezogen.

Der Bereich wurde noch einmal vergrößert.

Der Sektorheader

Wenn man sich bereits etwas eingehender mit dem Diskettenformat und dessen Aufbau beschäftigt hat, würde man als erstes eine 0x08 erwarten. Dies ist der Beginn des Sektorheaders oder eine 0x07 für die Nutzerdaten. Es folgen eine Prüfsumme, der Sektor, die Spur und die Disketten-ID. Danach kommt ein Leerraum, der nach dem Formatieren 0x0F enthält.

Betrachtet man jedoch die gerade aufgezeichneten Daten, passt es irgendwie nicht zusammen.

Es ist etwas schwer zu erkennen, aber die folgenden Bytes wurden übertragen:

0x52 0x57 0x55 0x29 0x72 0xD2 0xB5 0xD5 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55

Nun kommt der „gemeine“ Teil, denn diese Bytes wurden im sogenannten GCR-Verfahren kodiert.

Es reicht also nicht aus, die Bytes einfach vom Hexadezimalsystem ins Dezimalsystem zu übersetzen, da sonst nur Unsinn herauskommt. Diese Bytes müssen zuerst übersetzt werden.

GCR-Kodierung

Das Lesen und Schreiben basiert auf einer recht ausgeklügelten Zeitsteuerung, den SYNC-Markierungen und der Hoffnung, dass die Drehzahl wirklich immer 300 Umdrehungen pro Minute beträgt.

Das Ganze würde auch funktionieren, wenn es nicht die Nullen, also logisch LOW, gäbe. Zwei oder drei „LOW“ können noch relativ zuverlässig über das Timing abgebildet werden, aber dann wird die Erkennung schwierig.

Also wurde ein System entwickelt, bei dem nicht mehr als zweimal hintereinander LOW auftritt. Das GCR-System, auch als Group Code Recording oder Gruppen-Codierung bekannt.

Dafür werden 4 Bits in 5 Bits umgewandelt.

Als Beispiel soll direkt der eben gelesene Sektorheader dienen:

0x52 0x57 0x55 0x29 0x72 0xD2 0xB5 0xD5 0x55 0x55

Warum nur 10 Bytes oder genau 10 Bytes, wird gleich erklärt.

Zuerst müssen die hexadezimalen Werte in binäre Werte übersetzt werden.

0x52 = 01010010
0x57 = 01010111
0x55 = 01010101
0x29 = 00101001
0x72 = 01110010
0xD2 = 11010010
0xB5 = 10110101
0xD5 = 11010101
0x55 = 01010101
0x55 = 01010101


Jetzt ist es am einfachsten, alle Bits hintereinander zu schreiben.

01010010010101110101010100101001011100101101001010110101110101010101010101010101

Nun müssen Gruppen von fünf Bits gebildet werden. Deshalb auch die 10 Bytes und nicht nur die eigentlich 8 benötigten Bytes. Es wird eine Anzahl benötigt, die durch 5 teilbar ist. 5 Bytes hätten gereicht, aber es soll der ganze Sektorheader betrachtet werden.

01010 01001 01011 10101 01010 01010 01011 10010 11010 01010 11010 11101 01010 10101 01010 10101

Die Codierungstabelle

Was jetzt gebraucht wird, ist die Tabelle, die die Codierung enthält. Sozusagen die Enigma für die Diskettendaten. Und der Vergleich ist sogar weniger weit hergeholt als man denkt.

GCR-CodeNibbleNibble in Hex
0101000000x0
0101100010x1
1001000100x2
1001100110x3
0111001000x4
0111101010x5
1011001100x6
1011101110x7
0100110000x8
1100110090x9
1101010100xA
1101110110xB
0110111000xC
1110111010xD
1111011100xE
1010111110xF

Nun kommt ein wenig Fleißarbeit. Für jede Fünfergruppe gibt es einen entsprechenden 4-Bit-Wert. Diese müssen herausgesucht und notiert werden.

01010 = 0000 = 0x0
01001 = 1000 = 0x8
01011 = 0001 = 0x1
10101 = 1111 = 0xF
01010 = 0000 = 0x0
01010 = 0000 = 0x0
01011 = 0001 = 0x1
10010 = 0010 = 0x2
11010 = 1010 = 0xA
01010 = 0000 = 0x0
11010 = 1010 = 0xA
11101 = 1101 = 0xD
01010 = 0000 = 0x0
10101 = 1111 = 0xF
01010 = 0000 = 0x0
10101 = 1111 = 0xF

Jetzt die Bytes einfach wieder zusammensetzen:

081F0012A0AD0F0F = 0x08 0x1F 0x00 0x12 0xA0 0xAD 0x0F 0x0F

Die dekodierten Daten

Nun ist auch ein Sektorheader erkennbar. Er beginnt mit dem Byte 0x08. Am Ende sind die 0x0F Füllbytes zu erkennen.

Wird nun eine XOR-Operation über das 3., 4., 5. und 6. Byte ausgeführt:

00 XOR 12 XOR A0 XOR AD = 1F

Dann erhält man die Prüfsumme, die sich im 2. Byte befindet.

Der Sektor befindet sich im 3. Byte, welches hier 0x00 enthält. Ohne große Umrechnung war dies Sektor 0 der Diskette.

Im 4. Byte ist die Spur mit dem Byte 0x12, was dezimal 18 entspricht. Also befand sich der Kopf auf Spur 18 und Sektor 0, als der Logikanalysator gerade aufgezeichnet hat.

Die beiden folgenden Bytes sind die ASCII-Werte für die Disketten-ID. 0xA0 entspricht dezimal 160 und 0xAD entspricht 173.

Von diesen hohen Werten nicht überraschen lassen. Die gerade verwendete Diskette enthielt Sonderzeichen. Meistens stehen dort eher Zahlen.

Warum so kompliziert?

Der Vorteil dieser Methode ist, dass sie unabhängig vom Kernal funktioniert. Viele Anzeigen dieser Art schauen einfach in den RAM des Diskettenlaufwerks, da dort auch die aktuelle Spur und der Sektor zu finden sind.

Allerdings befinden sich diese Daten je nach Kernal an unterschiedlichen Adressen. Man könnte dies zwar aufwendig abfangen und mit entsprechenden Tabellen umrechnen, jedoch ist dies fehleranfällig und könnte sich mit einem neuen Kernal wieder ändern.

Eine Anzeige muss her

Im Grunde ist es nicht so schwer, diese Daten zu erhalten. Das Lesen der Rohdaten und das Dekodieren in die echten Werte war eigentlich recht einfach.

Leider wird dies in vielen Büchern wissenschaftlicher dargestellt, als es in der Realität ist.

Zusätzlich zu den Daten gab es noch verschiedene andere Signale. Das ACT-Signal, welches bei Aktivität immer HIGH ist. Aber Aktivität ist ein dehnbarer Begriff. Vielleicht hat jemand schon beobachtet, dass es Momente gibt, in denen die LED leuchtet, obwohl der Motor stillsteht. Daher ist dies allein kein geeigneter Indikator. Und im Fehlerfall blinkt die LED, sodass das Signal ständig wechselt.

Man könnte das Motorsignal auswerten. Aber auch dies ist nicht immer zuverlässig, da der Motor laufen könnte, ohne dass Daten gelesen oder geschrieben werden (Testprogramme sind ein Beispiel).

Interessanter ist das SYNC-Signal, da es nur ausgelöst werden kann, wenn eine formatierte Diskette unter dem Magnetkopf rotiert.

Das ByteReady-Signal zeigt an, wenn ein gültiges Byte vorliegt. Doch dies allein ist kein Indikator, da es auch ausgelöst wird, wenn die Diskette noch nicht die volle Drehzahl erreicht hat. Aufgrund der Art und Weise, wie dieses Signal erzeugt wird, ist festzustellen, dass das ByteReady-Signal auch im Leerlauf der Diskette ständig aktiviert ist.

Schließlich gibt es noch das SOE-Signal. Doch allein darauf kann man sich nicht verlassen, da es in Verbindung mit dem ByteReady-Signal steht.

Eine Kombination dieser Signale ist daher erforderlich.

Eine Abfolge spezifischer Ereignisse ist am besten geeignet.

Zwei Punkte sind sicher: Das ACT- und das SOE-Signal müssen auf HIGH sein, wenn der Kopf „arbeitet“ und vor allem brauchbare Daten ausgegeben werden sollen. Dann müssen immer wieder SYNC-Signale vorhanden sein.

Dies ist der beste Weg, um eine Art Checkliste zu durchlaufen. Nun weiß man, wie das Diskettenlaufwerk reagiert, wenn es Daten liest oder schreibt. Dies kann ähnlich wie bei einer Ampelsteuerung durchgeführt werden. Grün wird nur, wenn zuvor Rot und davor Gelb angezeigt wurde (zumindest ist dies bei Ampeln in Deutschland so).

Ampeln werden durch sogenannte Zustandsautomaten oder endliche Automaten gesteuert. Das vorherige Ereignis steuert das nächste Ereignis und der aktuelle Status kann jederzeit bestimmt werden.

Zusätzlich sind Abbruchparameter erforderlich. Wenn das ACT- und SOE-Signal HIGH sind und auch SYNC erkannt wurde, können Lesefehler dennoch zu einem Abbruch führen und keine brauchbaren Daten mehr erzeugen. In diesem Fall muss der Zustandsautomat erkennen, dass ein Fehler vorliegt, und von vorne beginnen oder in eine Fehlerbehandlungsroutine verzweigen.

Wie am besten vorgehen?

Der einfachste Weg, das Ganze zu realisieren, ist mit einem Mikrocontroller für Einsteiger, auch Arduino genannt 🙂 Man „sammelt“ ein halbes Dutzend Bibliotheken von anderen, schreibt zwei oder drei Zeilen Code und wird so zum großen Entwickler einer Spur/Sektor-Anzeige.

Dies ist natürlich der einfache Weg.

Oder man macht es auf die „harte Tour“ in Hardware. Der Aufwand ist natürlich viel höher, aber der Lerneffekt ebenso. Und man hat es wirklich selbst gemacht.

Für diesen Fall wurde ein kleines FPGA verwendet. Auch wenn manche ein FPGA mit einem Mikrocontroller verwechseln, sollte man sich an die „Programmierung“ eines solchen wagen.

Leider glauben viele dies und haben dann ihre Probleme damit. Der „Code“ hat in manchen Bereichen Ähnlichkeiten mit einer Programmiersprache. Aber letztlich beschreibt man die Hardware damit. Dieser „Code“ kann einfach in echte Chips umgewandelt werden und beispielsweise einen TTL-Baustein ersetzen. Letzteres ist sogar weniger Aufwand als ein FPGA zu nutzen.

Dafür wurde das Ganze in verschiedene Module unterteilt. Ein GCR-En-/Decoder wurde bereits für ein anderes Projekt geschrieben, bei dem Disketten formatiert und kopiert werden, ohne die CPU zu benötigen. Zwei Laufwerke werden einfach über ein FPGA und die beiden Gate-Arrays gekoppelt.

Dann der Display-Controller. Um nicht alle Leitungen für das 7-Segment-Display an das FPGA anschließen zu müssen, wurde ein MAX7221 dazwischen geschaltet. Er kümmert sich um das Multiplexing, die Helligkeitssteuerung und ist hauptsächlich für die Steuerung von LEDs ausgelegt.

Angesprochen wird er über eine SPI-Schnittstelle, für die ebenfalls eine Bibliothek geschrieben wurde.

Es ist viel mehr Arbeit als nur einen Arduino zu nehmen, den Code anderer zu kopieren und dann ein Display anzuschließen. Aber es macht mehr Spaß, man lernt wesentlich mehr und hat es selbst gemacht.

Zumal die Bibliotheken auch für andere Projekte benötigt werden.

Breadboards sind verhasst

Leider gibt es keine Alternative zum Zusammenstecken. So sah das Ergebnis aus.

Ständig gibt es lose Kontakte und seltsame Fehler und Probleme. Aber oft gibt es keine Alternative.

So sah das Ergebnis dann aus.

Unten links ist das FPGA zu sehen. Es handelt sich um das bekannte Altera Cyclone II Miniboard, das manchmal in China für knapp 5 Dollar oder in Europa für knapp 10 Euro zu bekommen ist.

Auf der Platine befindet sich ein Altera EP2C5T144C8N Chip. Also die recht kleine Version. Aber unschlagbar im Preis und es gibt noch viel Spielraum in Bezug auf die Ressourcen. Es wird mit einem 50 MHz Oszillator getaktet.

Zwischen dem FPGA und dem Display ist der Pegelwandler zu sehen. Hier wurden typische China-Module mit dem MOSFET BSS138 verwendet.

Zum Thema Geschwindigkeit. Anfangs wurde immer eine komplette Spur eingelesen. Da das FPGA so schnell ist, wird dies inzwischen nicht mehr gemacht.

Komplettes Einlesen der Spur völlig unnötig

Bei den Experimenten wurde festgestellt, dass das Einlesen einer kompletten Spur überflüssig und sogar langsamer ist. Das FPGA ist so schnell, dass das GCR-Dekodieren oder -Kodieren (in einem anderen Projekt) so schnell ist, dass es immer ausreicht, nur 5 Bytes zu verarbeiten. Selbst dann wartet das FPGA noch mehrere Taktzyklen, bis das nächste Byte ankommt.

Wenn hier von langsam gesprochen wird, ist das natürlich Jammern auf höchstem Niveau. Es geht um ein paar Taktzyklen mehr. Aber bei 50 MHz ist das wirklich unbedeutend, zumindest wenn die Basis ein mit 1 MHz getaktetes Diskettenlaufwerk ist und die Daten sogar noch viel langsamer sind (im kHz-Bereich).

So konnten die Schieberegister enorm reduziert und noch mehr Ressourcen gespart werden.

Das Ganze geht so schnell, dass die Sektor-Anzeige eigentlich nicht mehr lesbar ist. Bei 5 Umdrehungen pro Sekunde und teilweise bis zu 21 Sektoren pro Spur kann man ausrechnen, wie oft sich das Ganze ändert.

Es ist dennoch ein netter Gag.

Viel interessanter ist es, das Diskettenformat besser kennenzulernen und sich tiefer in die 1541 einzuarbeiten. Vielleicht wird eine kleine Platine aus der Spur-Anzeige gemacht. Es wird noch nach kleinen verfügbaren FPGAs auf dem Markt gesucht. Viele Signale werden nicht benötigt, da hier nur gelesen, aber nicht gesteuert werden soll.

Gibt es Interesse an so etwas? Einfach in den Kommentaren mitteilen.

0 Comments
Älteste
Neueste
Inline-Feedbacks
Alle Kommentare anzeigen
Nach oben scrollen