{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreiawvv7c6rb6zawwg5haixaxqqqmiv6nnddixft3adch5l5g5nc2j4",
"uri": "at://did:plc:nkxz2ojdvmieg2nhphvputvp/app.bsky.feed.post/3mmgiels7ldm2"
},
"coverImage": {
"$type": "blob",
"ref": {
"$link": "bafkreihglqtkktota33waifte5whe37yfneynfygkx7mwvh6tpotv5je3u"
},
"mimeType": "image/jpeg",
"size": 1966429
},
"description": "In meinem Keller stehen Kisten voller alter 5,25-Zoll-Disketten. Commodore-Software aus den späten 80ern, Spiele, Tools, selbstgeschriebener Kram. Das Problem mit Floppy-Disks: die Magnetisierung lässt mit der Zeit nach. Alle paar Jahre sollte man die Daten einmal komplett lesen und zurückschreiben, sonst wird das Medium irgendwann unlesbar. Mein letztes Auffrischen ist eine Weile her, also war es mal wieder Zeit. Zugegeben, ich arbeite nur noch extrem selten mit meinem Commodore; aber […]",
"path": "/2026/03/25/commodore-floppy-disk-preservation-xum1541-firmware-bug-opencbm/",
"publishedAt": "2026-05-22T08:11:39.000Z",
"site": "https://www.kernel-error.de",
"tags": [
"Commodore",
"Firmware",
"Linux",
"OpenSource",
"retro",
"USB",
"OpenCBM",
"Pull Request",
"seit 2021 offenes Issue im nibtools-Repository",
"Commodore – PC Projekt",
"VC-64 Turbo Tape (1986)",
"Einfach melden."
],
"textContent": "In meinem Keller stehen Kisten voller alter 5,25-Zoll-Disketten. Commodore-Software aus den späten 80ern, Spiele, Tools, selbstgeschriebener Kram. Das Problem mit Floppy-Disks: die Magnetisierung lässt mit der Zeit nach. Alle paar Jahre sollte man die Daten einmal komplett lesen und zurückschreiben, sonst wird das Medium irgendwann unlesbar. Mein letztes Auffrischen ist eine Weile her, also war es mal wieder Zeit. Zugegeben, ich arbeite nur noch extrem selten mit meinem Commodore; aber wenn ich es mache, ist es immer eine kleine Zeitreise voller Nostalgie für mich. Die Geräusche, der Geruch, die Wartezeit. Hin und wieder tut es mir einfach gut, noch mal die alten Spiele zu spielen, mit den Tools zu arbeiten oder auch meine ersten eigenen Programme noch mal zu starten, in den Code zu schauen *kopfschütteln*…. Ich habe sogar noch alte Hausaufgaben auf Disketten 😀\n\nWas als routinemäßige Sicherungsaktion geplant war, wurde dann allerdings eine mehrtägige Debugging-Session. Inklusive eines Firmware-Bugs, der seit sechs Jahren im Code schlummerte.\n\n### Die Ausgangslage\n\nMein Setup: Zwei Commodore 1571 Laufwerke, angeschlossen über einen xum1541 USB-Adapter an einem Linux-Rechner. Der xum1541 sitzt auf einem TEENSY2-Board (ATmega32U4) und spricht über USB mit OpenCBM, einer Open-Source-Treibersammlung für Commodore-Laufwerke. Die Software-Seite hatte ich in einer vorherigen Session bereits verifiziert. Beide Laufwerke laufen bei fast perfekten 300,5 RPM, lesen und schreiben fehlerfrei auf beiden Seiten und liefern sogar bit-identische Images im Crosscheck.\n\nDer Plan war simpel: Alle Disketten systematisch als 1:1-Image sichern, die physischen Medien durch Zurückschreiben auffrischen und nebenbei prüfen, ob die Inhalte bereits in Online-Archiven wie CSDB, Gamebase64 oder dem Internet Archive vorhanden sind.\n\nDer xum1541 im gelben Gehäuse. Links das USB-Kabel zum Linux-Rechner, rechts das IEC-Kabel zur 1571:\n\nUnd ein Blick auf die Platine mit dem Teensy2-Board (ATmega32U4), in dem der Firmware-Bug steckte:\n\n### Disk 001: Pirates! und das Kopierschutz-Problem\n\nDie erste Disk war eine Pirates!-Kopie (Microprose, 1987), „imported by The Critters Inc 1221“. Mit `d64copy` ausgelesen, 683 Blocks, keine Fehler. Dann zurückgeschrieben und zur Verifikation nochmal gelesen. Checksummen stimmten nicht überein.\n\nDie Analyse ergab: Das Original-D64 enthält drei Sektoren mit Error Code 5 (Data Block Checksum Error) auf Track 23 und 24. Das ist klassischer C64-Kopierschutz. Microprose nutzte absichtliche Lesefehler, um Raubkopien zu erkennen. Das Spiel prüft beim Start ob diese Fehler vorhanden sind, fehlen sie, verweigert es den Dienst.\n\n`d64copy` arbeitet auf Sektor-Ebene und kann solche GCR-Level-Fehler nicht reproduzieren. Die Error-Info wird zwar im D64 gespeichert (Emulatoren wie VICE werten sie aus), aber auf der physischen Disk gehen die absichtlichen Fehler beim Zurückschreiben verloren. Für eine echte 1:1-Kopie inklusive Kopierschutz braucht man `nibtools`. Das arbeitet direkt auf GCR/Nibble-Ebene und liest die Rohdaten vom Laufwerk, inklusive aller Timing-Patterns und absichtlichen Fehler.\n\n### nibtools bauen und der erste Crash\n\n`nibtools` liegt als Quellcode im OpenCBM-Quellbaum, muss aber separat gebaut werden. Ich habe den markusC64-v637 Branch von GitHub genommen. Build mit dem cc65 Cross-Compiler für den 6502-Floppy-Code und gcc für die Host-Tools ging glatt. Erster Versuch:\n\n\n nibread -D8 image.nib\n\nErgebnis: `LIBUSB_ERROR_PIPE`. Der USB-Transfer bricht sofort ab, nachdem der Drive-Code hochgeladen ist. nibtools erkennt die 1571 korrekt und versucht SRQ-Burst-Transfers zu nutzen, ein schnelles serielles Protokoll das die CIA-UART der 1571 verwendet. Aber der Transfer scheitert schon beim Communication-Test.\n\n### Drei Schichten tief: der Firmware-Bug\n\n**Schicht 1: Bekannter SRQ-Bug in Firmware v7.** Die xum1541-Firmware v7 hatte einen dokumentierten Bug: `IEC_SRQ` war als `0x80` definiert (Bit 7), aber die Lookup-Tabelle `iec2hw_table` hatte nur 16 Einträge (4 Bits). SRQ-Operationen griffen ins Leere. In v8 gefixt: `IEC_SRQ` auf `0x10` geändert, Tabelle auf 32 Einträge erweitert. Commit `3ef4fc0d` von Spiro Trikaliotis, 2021.\n\nProblem: Es gab kein fertiges v8-Hex für das TEENSY2-Board. Nur für ZOOMFLOPPY und PROMICRO. Die Boards haben unterschiedliche Mikrocontroller-Pin-Belegungen, also kann man die Firmware nicht einfach zwischen Boards tauschen. Lösung: AVR-Toolchain installiert (`gcc-avr`, `avr-libc`), v8 für TEENSY2 selbst gebaut und über den HalfKay-Bootloader geflasht.\n\n\n teensy_loader_cli --mcu=atmega32u4 -w -v firmware.hex\n\nRisikofrei, da der Bootloader in einem geschützten Flash-Bereich sitzt. Knopf am Teensy drücken, flashen, fertig.\n\n**Schicht 2: v8 geflasht, gleiches Problem.** Auch mit v8 kommt `LIBUSB_ERROR_PIPE`. Die OpenCBM-Library musste ebenfalls neu gebaut werden, sie prüft die Firmware-Version und war noch auf v7 kompiliert. Neu gebaut, installiert. Immer noch Crash.\n\n**Schicht 3: Der eigentliche Bug.** Also tiefer in den Quellcode. In `board-teensy2.h`, Funktion `iec_srq_write()`:\n\n\n // BUGGY — seit Commit 57bb6726 (April 2020)\n PORTD = (((data >> 4) & IO_DATA) ^ IO_DATA) | IO_SRQ;\n\nDas wurde 1:1 von der ZoomFloppy-Implementierung kopiert. Aber die Pin-Belegung ist bei den Boards unterschiedlich:\n\n * ZoomFloppy hat `IO_DATA` auf Port D, Bit 4 (PD4)\n * TEENSY2 hat `IO_DATA` auf Port F, Bit 0 (PF0)\n\n\n\nDer Code schrieb auf den komplett falschen Port mit dem falschen Bit-Shift. Das erklärt warum der Communication-Test sofort fehlschlug. Die SRQ-Daten kamen nie auf den richtigen Pins an.\n\nDer Fix, analog zur korrekten PROMICRO-Implementierung:\n\n\n // FIXED\n uint8_t port_base_data = (DDRF & IO_ATN) | IO_SRQ;\n // ...\n DDRF = (((data >> 7) & IO_DATA) ^ IO_DATA) | port_base_data;\n\nDie Änderungen im Detail: `PORTD` wird zu `DDRF` (richtiger Port für die IEC-Leitungen beim TEENSY2), der Shift von `data >> 4` auf `data >> 7` (Bit 7 des Datenbytes auf Bit 0 des Ports, wo `IO_DATA` liegt), und der ATN-Zustand wird über `port_base_data` erhalten, was vorher nicht berücksichtigt war. Timing von 0,935 µs auf 0,80 µs angepasst, passend zur PROMICRO-Implementierung.\n\nFirmware neu gebaut (8260 Bytes, 32 mehr als vorher), geflasht. `nibread` läuft sofort fehlerfrei durch alle 41 Tracks. Der Bug steckte seit April 2020 im Code. Jeder mit einem TEENSY2-basierten xum1541 hatte dieses Problem bei SRQ-Transfers.\n\nDen Fix habe ich als Pull Request eingereicht, der am 26. März vom OpenCBM-Maintainer Spiro Trikaliotis gemerged wurde. Damit ist auch ein seit 2021 offenes Issue im nibtools-Repository endlich geschlossen. Dort hatten andere User auf macOS und Fedora mit Teensy-basierten Adaptern exakt die gleichen LIBUSB-Fehler gemeldet, ohne dass die Ursache gefunden wurde.\n\n### Die bittere Lektion mit Disk 001\n\nDie erste Pirates!-Disk, der Import von The Critters Inc, war zu diesem Zeitpunkt bereits zerstört. Ich hatte sie vor dem Fix mit `d64copy` zurückgeschrieben. Das hat die GCR-Level-Kopierschutzmuster überschrieben. Das anschließend mit `nibread` erstellte NIB-Image zeigt nur noch die „reparierten“ Sektoren, nicht den originalen Kopierschutz. Disk und Images entsorgt.\n\nDie Lektion ist simpel und ärgerlich zugleich: Nie zurückschreiben, bevor das NIB-Image existiert.\n\n### Der Workflow ab Disk 002\n\nAb der zweiten Disk lief der Prozess dann sauber:\n\n 1. `nibread -D8` — GCR-Rohdaten lesen, inklusive Kopierschutz\n 2. `d64copy` — Sektor-Level-Image für Emulatoren\n 3. `nibwrite` — 1:1 zurückschreiben aus dem NIB (erhält Kopierschutz)\n 4. `d64copy` nochmal lesen + MD5-Vergleich zur Verifikation\n\n\n\n### Ergebnisse\n\nDisk| Inhalt| Status\n---|---|---\n001| Pirates! (The Critters Inc)| Verloren — Kopierschutz vor dem Fix zerstört\n002| Ace of Aces, Light Force, Hacker + Trainers| Gesichert + aufgefrischt, Killer Track auf Track 1 erhalten\n003| Commando, The Last V8, Robin of the Wood| Verloren — Medium physisch zu schwer beschädigt\n004| Warplay, Worldcup 86, Hyper Olympics| Gesichert, Original-Disk defekt (T18/S15)\n005| Pirates! (The Red Lions Import, 2-Disk)| Gesichert + aufgefrischt + verifiziert\n\n### Technische Eckdaten\n\nFür die Leute die es genau wissen wollen:\n\n * **Hardware:** 2× Commodore 1571, xum1541 (TEENSY2, ATmega32U4), Linux-Host\n * **Software:** OpenCBM (from source), nibtools (markusC64-v637), VICE 3.7.1\n * **RPM:** Konstant 300,5 RPM (Nominal: 300). Die 1571 ist elektronisch geregelt, kein Trimmpoti\n * **Kopierschutz-Typen:** Error Code 5 (Checksum Errors) auf Pirates!, Killer Track (Track komplett mit Sync-Bytes) auf der Crocodile Soft Compilation\n * **NIB-Format:** ~336 KB pro Disk (41 Tracks × 8192 Bytes GCR-Rohdaten)\n * **D64-Format:** ~175 KB pro Disk (683 Sektoren × 256 Bytes + optional 683 Bytes Error-Info)\n\n\n\n### Fazit\n\nWas als „schnell mal Disketten auffrischen“ geplant war, endete in einer Reise durch sechs Jahre alten Firmware-Code. Der Bug in `iec_srq_write()` war ein klassischer Copy-Paste-Fehler, der nie aufgefallen ist, weil kaum jemand nibtools mit einem TEENSY2-Board benutzt. SRQ-Burst-Transfers braucht man nur für nibtools, und die meisten Leute nutzen ohnehin einen ZoomFloppy-Adapter, wo der Code korrekt ist.\n\nDer Verlust von Disk 001 ärgert mich immer noch. Aber die Lektion sitzt: Erst NIB, dann zurückschreiben. Und wenn ein Tool beim ersten Mal nicht funktioniert, lohnt es sich manchmal die Firmware aufzuschrauben, statt das Tool wegzulegen.\n\nDer Blick ins Regal, wo das alles steht. Ja, es ist voll da unten:\n\nSiehe auch: Commodore – PC Projekt (mein erster Versuch mit cbm4linux und einem XM1541-Kabel, anno 2009) und VC-64 Turbo Tape (1986).\n\nFragen? Einfach melden.",
"title": "Commodore Floppy Disk Preservation: Firmware-Bug im xum1541 gefunden und gefixt"
}