Nur eine handvoll Bits

Ich hab mich in den letzten Tagen damit beschäftigt den Schreibmodus zum laufen zu bringen… mit einigen Hürden.

Da auf der Magnetscheibe einer Floppy die Daten ja im MFM Format gespeichert sind muss man die Daten die da rauf sollen vorher in MFM codieren.
Zur Decodierung hab ich einige Beispiele im Netz gefunden, das war nicht so schwierig, aber für die Encodierung findet sich sehr wenig. Irgendwann bin ich dann auf eine MFM Codierungroutine des Win Fellows Amiga Emulators gestoßen, hab diese dann auch ausprobiert und es kam nur Grütze bei raus :(

Nachdem ich mich dann doch durch mehrere Kapitel im Buch „Amiga Disk Drives: inside & Out“ von Grote Gelfland Abraham erschienen bei Abacus/Data Becker 1988 gekämpft habe (wer schon mal ein Hardware Buch von Data Becker in der Hand hatte weiß das die schwierig zu lesen waren, und dazu kam noch das hier in Englisch war) hab ich festgestellt das die Routine nicht vollständig MFM codierung implementiert hatte, sondern nur soweit das der Amiga Emulator das als MFM gefressen hat, es waren also die Clock Bits nicht korrekt berechnet. Auch bei der Checksummenberechnung stimmte auch irgendwas nicht.
Hab also das meiste über Bord geworfen und selbst geschrieben. Nach vielen Versuchen lief dann die Codierung eines Sektors.

Ein Sektor mit 512 Datenbytes wird zu 1024 MFM codierten Bytes, dazu kommen noch Informationen über die Nummer des Sektors, Track, Abstand zum Gap, zwei Checksummen und ein ungenutzter 16 Byte Bereich, am Ende sind es dann 1088 MFM Bytes. 11 Sektoren passen auch einen Track und dann kommt die Track Gap, ein Bereich einer Spur in den kein kompletter Sektor mehr passen würde, der aber gefüllt sein muss um alte Daten auf der Spur zu überschreiben.

In der Routine des Emulators wird die GAP nach den Sektoren geschrieben, das kam mit aber unlogisch vor da man ja nicht genau wissen kann wie lang die Spur wirklich ist, da ein Laufwerk ja auch gewissen Schwankungen unterliegt. Also schreibe ich zuerst eine etwas längere Gap und dann die Sektoren sodaß der letzte Sektor etwas von der Gap überschreibt und ich sicher gehen kann das keine alten Daten überleben und kein Sektor einer vorherigen beschreibung auch nur teilweise überlebt. Weil ein Sektor wird zu beginn durch eine reihe von MFM Bytes (4x 0xAA gefolgt von 2x 0x4489) gekennzeichnet die durch die Kodierung von Datenbytes niemals zustanden kommen können, somit eindeutig sind. Und wenn sowas von einer vorherigen beschreibung der Spur überlebt würde man plötzlich 12 Sektoren finden und wüsste nicht welches die richtigen 11 sind, oder müsste mehr Aufwand beim Lesen betreiben.

Bei einer späteren Analyse eines Logikanalysatormitschnitts eines Schreibzugriffes an einem echten Amiga stellte ich fest das die es genauso machen, darüber haben sich natürlich die Bücher ausgeschwiegen, aber egal, ging ja auch mit nachdenken :)

Irgendwann lief dann auch die Schreibroutine und ich konnte ADF Images auf Disketten schreiben, Eureka! Nur gab es eine Menge unslesbare Tracks, aber je nach Image mal mehr mal weniger, und wie ich feststellte immer an den selben Stellen. Komisch gelle? Ich zweifelte erstmal meine MFM codier routine an. Hab da aber nichts finden können. Später stellte ich dann fest das immer beim letzten Sektor das letzte Byte fehlerhaft war… Lange rede kurzer Sinn: Denkfehler in der Schreibroutine.

void diskWrite()
{
 if (writeActive == false) return;
 digitalWriteFast(_writedata, !(dataByte >> 7));
 dataByte = dataByte << 1;
 writeBitCnt++;
 if (writeBitCnt == 8) {
 writePtr++;
 dataByte = stream[writePtr];
 writeBitCnt = 0;
 }
 if (writePtr >= writeSize) {
 writeActive = false;
 digitalWriteFast(_writedata, HIGH);
 }
}

Hier meine Schreibroutine, wird im 2µs Takt aufgerufen und shiftet die Bits aus dem MFM Puffer an die Schreibleitung der Floppy. Ich habe den Fehler mal rot markiert… Ich hab den Schreibvorgang beendet bevor das letzte Byte rausgeshifted wurde… Narf! Es fehlten also von letzten Byte die 4 ungeraden Bits, das erklärte auch warum manche Tracks in Ordnung waren und viele nicht.

richtig lautet die Zeile:
if (writePtr > writeSize) { … usw}

Anfängerfehler :-P