Novaload
Dieser Artikel befindet sich im Aufbau und ist vorläufig als Entwurf einzustufen. |
Novaload | |
---|---|
Firma | Novaload Ltd. |
Release | 1984 |
Plattform(en) | C64 |
Genre | Schnelllader |
Steuerung | |
Medien | , |
Sprache(n) |
Novaload ist ein Kassettenschnellladeprogramm für den Commodore 64 mit Datasette.
Im Vergleich zu dem weitaus bekannteren und etablierteren Turbo Tape bietet Novaload neben der verbesserten Datendichte und der dadurch schnelleren Ladezeit noch weitere Vorteile. Beispielsweise wird der Bildschirm nicht datasettentypisch abgeschaltet, man kann also einen Ladescreen anzeigen. Dieser kann auch mit Musik unterlegt werden.
Es wurde gerne von englischen und amerikanischen Softwarehäusern und Publishern wie Ocean oder U.S. Gold zum Laden von C64-Spielen von Datassette verwendet. Das erste C64-Spiel, das Novaload nutzte, war Forbidden Forest von Cosmi.
Funktionsweise[Bearbeiten | Quelltext bearbeiten]
Den Kern von Novaload bilden zwei sehr ähnliche Versionen einer Interruptroutine, die sich selbständig mit den Banddaten synchronisiert und die nachzuladenden Programmteile dann in den Hauptspeicher des C64 einliest. Beide Versionen der Routine verwenden das gleiche Aufzeichnungsformat: Ein 0-Bit wird durch einen kurzen Impuls von 288 Systemtakten Dauer codiert, ein 1-Bit durch einen langen Impuls mit einer Länge von 688 Takten. Beim Einlesen wird ein Impuls, der mindestens 500 Takte Abstand zu seinem Vorgänger hat, als 1-Bit interpretiert, ansonsten als 0-Bit. Dieses Timing ist so großzügig bemessen, dass es auch nicht durch Badlines gestört wird, die beim Laden mit eingeschaltetem Bildschirm auftreten.
Aktiviert werden diese Interruptroutinen aus nachgeladenen Programmteilen heraus. Anschließend können dieser Programmteile wahlweise einfach auf das Ende des Ladevorgangs warten (erkennbar durch periodische Kontrolle des Schreibzeigers), oder dem Anwender die Wartezeit beispielsweise durch das Abspielen von Musik verkürzen.
Beide Versionen der Interruptroutine implementieren für die Verarbeitung der Banddaten einen endlichen Automaten, dessen aktueller Zustand in der Sprungdistanz eines Branch-Befehls (eines relativen Sprungs) codiert ist. Über diesen Sprungbefehl steuert die Routine den jeweils aktuellen Verarbeitungsschritt an, der nach seinem Abschluss die Sprungdistanz aktualisiert und den Sprung damit auf den Einsprungpunkt des nächsten Programmschritts richtet (selbstmodifizierender Code). Während des Ladens sind alle ROMs ausgeblendet; mit Ausnahme des I/O-Bereichs an $D000-$DFFF ist also der gesamte Adressraum mit RAM belegt.
Erste Interruptroutine[Bearbeiten | Quelltext bearbeiten]
Die erste Version der Interruptroutine ist auf der Kassette im Dateiheader des ersten Programmteils gespeichert, direkt hinter dem aus 16 Zeichen (einschließlich Füllbytes) bestehenden Dateinamen. Sie wird also in den Kassettenpuffer ab Adresse $0351 übertragen, sobald beim Lesen der Kassette das erste Programm gefunden wird. Aktiviert wird diese Routine durch das Hauptprogramm, typischerweise den ersten, noch mit Kernal-Routinen von der Datassette geladenen Programmteil.
Die Routine liest seitenweise (also in Blöcken zu je 256 Bytes, die jeweils auf einer 256 Byte-Grenze zu liegen kommen) Programmteile in den Hauptspeicher ein, wobei diese im ganzen Adressraum verstreut sein dürfen. Nach einem einleitenden 1-Bit und einem aus den beiden Bytes $AA, $55
bestehenden Header folgen beliebig viele Datenblöcke mit der folgende Struktur:
Länge | Inhalt | Funktion |
---|---|---|
1 | Seitennummer | High-Byte der Ladeadresse; das Low-Byte wird automatisch auf 0 gesetzt |
256 | Nutzdaten | 256 Bytes Programmdaten |
1 | Prüfsumme | Summe aus Seitennummer und allen Datenbytes modulo 256 |
Die Routine kann so konfiguriert werden, dass sie ab einer bestimmten Blocknummer damit beginnt, einen dreistelligen Zähler herunter zu zählen. Dies setzt natürlich voraus, dass der Bildschirm zuvor entsprechend vorbereitet wurde. Bei der Kassettenversion des Spiels Buggy Boy, die dieser Analyse zugrunde liegt, werden beispielsweise nacheinander Programmblöcke in die Pages $E0 … $E6, $EF … $F0, $FE … $FF, $04, $0C … $0F und $20 … $43 eingelesen. Beim Erreichen der Page $F0 beginnt ein Zähler, dessen Startwert ein nachgeladener Programmteil zuvor auf dem Bildschirm dargestellt hat, vom Wert 043 an abwärts zu zählen.
Die genaue Funktionsweise der Routine ist aus dem kommentierten Assemblerlisting ersichtlich.
Zweite Interruptroutine[Bearbeiten | Quelltext bearbeiten]
Die zweite Version der Interruptroutine dient dazu, Programmteile auf Kassette anhand ihres Dateinamens auszuwählen und sequentiell in den Speicher zu laden. Sie wird von einem nachgeladenen Programmteil in den Kassettenpuffer ab Adresse $0334 umkopiert und ersetzt dort ihre Vorgängerversion.
Nach einem einleitenden 1-Bit und einem nur aus dem Byte $AA
bestehenden Header erwartet die Routine die folgende Datenstruktur:
Länge | Inhalt | Funktion |
---|---|---|
1 | Namenslänge | Länge n des Dateinamens (0-255 Zeichen) |
0…255 | Dateinamen | Name der Datei auf Band ohne nachfolgende Füll- oder Terminierungszeichen |
2 | Startadresse | Ladeadresse des Programms im Little Endian-Format (low/high) |
2 | Endadresse | Adresse der auf das letzte Programmbyte folgenden Speicherzelle im Little Endian-Format (low/high), von Interruptroutine nicht verwendet |
2 | Länge | Länge des Programms im Little Endian-Format (low/high) |
1 | Prüfsumme | Summe aus den vorausgegangenen Header-Bytes modulo 256 |
256 / 1…256 | Nutzdaten | 256 Bytes Programmdaten (wiederholt) / 1…256 Bytes Programmdaten im letzten Block |
1 | Prüfsumme | Summe der Datenbytes im vorausgegangenen Block modulo 256 (wiederholt) |
Die genaue Funktionsweise dieser Routine ist aus dem kommentierten Assemblerlisting ersichtlich, dem wieder die Laderoutine aus der Kassettenversion des Spiels Buggy Boy zugrunde liegt. Bei diesem Spiel lädt die zweite Interruptroutine nacheinander drei namenlose Dateien von 12944, 37120 und 14816 Bytes Länge nach.