Im ersten Teil habe ich gezeigt, wie der Sinclair ZX Spectrum Daten auf Kassette gespeichert hat. Dieser zweite Teil erklärt, was gespeichert wird und was einen Bandladefehler (Tape loading error) verursacht.
Das ZX Spectrum BASIC bietet einen SAVE-Befehl zum Speichern aller Arten von Daten. Er kann verwendet werden, um ein BASIC-Programm, Variablen-Arrays, aber auch beliebige Teile des Speichers zu sichern. Diese Dateien werden immer in zwei separaten Blöcken gespeichert. Der erste Block wird Header (Kopfdaten) genannt. Er enthält den Dateinamen, den Datentyp und andere Meta-Informationen. Der zweite Block folgt etwa eine Sekunde später und enthält die eigentlichen Daten.
Die interne Struktur jedes Blocks ist identisch. Das erste Byte unterscheidet zwischen Header ($00) und Datenblöcken ($FF). Das letzte Byte ist eine Paritäts-Prüfsumme. Alles zwischen diesen beiden Bytes sind die Nutzdaten (Payload).
Ein Header-Block enthält immer eine Nutzdatenmenge von 17 Bytes. Das erste Byte identifiziert den Dateityp, gefolgt vom Dateinamen (10 Zeichen), gefolgt von der Länge des Datenblocks, und abgeschlossen durch zwei optionale Parameter, die je nach Dateityp unterschiedliche Bedeutungen haben. Die Länge und die beiden Parameter belegen jeweils zwei Bytes, wobei das niederwertige Byte zuerst kommt, da die Z80-CPU Little Endian ist.
Dies ist ein beispielhafter Header-Block eines Screenshots:
00 | $00 = Header | |
| 00 | 03 | $03 = Binärdatei (Code oder SCREEN$) |
| 01 | 53 | S |
| 02 | 68 | h |
| 03 | 72 | r |
| 04 | 65 | e |
| 05 | 64 | d |
| 06 | 2E | . |
| 07 | 7A | z |
| 08 | 6F | o |
| 09 | 6E | n |
| 10 | 65 | e |
| 11 | 001B | Länge: 6912 Bytes ($1B00) |
| 13 | 0040 | Parameter 1, hier: Startadresse ($4000) |
| 15 | 0000 | Parameter 2, hier: ungenutzt |
20 | Parität |
Ein Screenshot ist eigentlich nur ein Speicherabzug, der an der Adresse $4000 beginnt (was die Startadresse des Bildschirmspeichers ist) und exakt 6912 Bytes lang ist (der ZX Spectrum hat eine Auflösung von 256×192 monochromen Pixeln plus 32×24 Bytes Farbattribute, was eine Bildschirmspeichergröße von 6912 Bytes ergibt).
Bei anderen Dateitypen haben die beiden optionalen Parameter andere Bedeutungen. Zum Beispiel speichert eine BASIC-Programmdatei die Zeilennummer, bei der nach dem Laden gestartet werden soll.
Das letzte Byte ist die Parität. Sie wird zur Fehlererkennung verwendet und einfach berechnet, indem alle gelesenen Bytes per XOR verknüpft werden. Das Ergebnis muss $00 sein, andernfalls wird ein “R Tape loading error” gemeldet.
Diese Art der Fehlererkennung ist ziemlich schwach. Aufgrund der Natur der XOR-Operation ergeben zwei Fehler wieder etwas Richtiges. Das bedeutet, dass eine gerade Anzahl an fehlerhaften Bits an der gleichen Position im Block unentdeckt bleibt. Es ist auch nicht möglich, Lesefehler zu korrigieren, da die XOR-Operation nur erlaubt, die Position des fehlerhaften Bits zu identifizieren, aber nicht das tatsächliche Byte, das den Fehler enthielt. Ausgefeiltere Fehlerkorrekturalgorithmen hätten den Ladevorgang jedoch verlangsamt.
Die Parität wird als letzter Schritt überprüft, nachdem alle Bytes aus dem Block auf dem Band gelesen wurden. Aus diesem Grund kann der Lader erst am Ende der Aufnahme entscheiden, ob der Ladevorgang erfolgreich war oder nicht.
Aber warum taucht der Tape Loading Error dann manchmal auf, während der Block noch geladen wird? Nun, im ersten Teil habe ich dir erklärt, dass die Laderoutine einfach eine unbekannte Anzahl von Bytes liest. Sie endet, wenn das Warten auf eine Impulsänderung zu lange gedauert hat. Wenn es nun eine Audiolücke auf dem Band gibt, scheint das Signal einfach mitten im Block zu enden. Es ist dann sehr wahrscheinlich, dass die Paritäts-Prüfsumme falsch ist, weil noch Bytes fehlen.
Einige einfache Kopierschutzmechanismen machten sich die Art und Weise zunutze, wie der Spectrum Daten vom Band lädt. Eine sehr übliche Methode waren “headerlose” Dateien, bei denen der Header-Block weggelassen und nur der Datenblock auf Band aufgenommen wurde. Der BASIC-LOAD-Befehl war aufgrund des fehlenden Headers nicht in der Lage, diese Dateien zu lesen.