Elidon/Schnelllader
<< zurück zu Elidon
Elidon/Schnelllader: Die folgenden Abschnitte stellen den disassemblierten Kassetten-Schnelllader des Spiels Elidon dar. Sie sind gegliedert in einzelne Codeblöcke, die gemäß ihrer Funktion während des Ladens gruppiert sind.
Nachladen des eigentlichen Schnellladers[Bearbeiten | Quelltext bearbeiten]
Lädt man "Elidon" von Band, so wird als erstes ein Datenblock in den Adressbereich $02E8-$0303 geladen. Dieser überschreibt den Vektor für Eingabe einer Zeile mit der Startadresse der Routine, die den eigentlichen Schnelllader nachlädt, wodurch diese unmittelbar nach dem Abschluss des Ladevorgangs automatisch gestartet wird.
ORG $02E8 ; Laderoutine für Nachladen des eigentlichen Schnellladers P_AA: LDA #$00 ; Programm-Modus setzen STA *$9D LDA #$00 ; Länge des Dateinamens=0 JSR $FFBD ; setzen LDA #$01 ; Logische Dateinummer=1 TAX ; Geräteadresse=1 TAY ; Sekundäradresse=1 JSR $FFBA ; setzen LDA #$00 ; Load/Verify-Flag auf "Load" setzen JSR $FFD5 ; Nächstes Programm von Band laden JMP P_AG ; und starten DW $E38B ; Vektor für BASIC-Warmstart DW P_AA ; Vektor für Eingabe einer Zeile, umgebogen auf Laderoutine
Unterprogramme des Schnellladers[Bearbeiten | Quelltext bearbeiten]
Der Schnelllader ist sehr klar strukturiert und enthält keinerlei Versuche, die Arbeitsweise des Programms zu verschleiern. Er ist damit ein Musterbeispiel für den Aufbau eines Datassetten-Schnellladers: Zunächst Initialisierung der I/O-Bausteine, danach erst bitweise, dann byteweise Synchronisation mit den Banddaten, gefolgt vom Einlesen der Datenblöcke in die zugehörigen Speicherbereiche. Übertragungsfehler werden schließlich anhand einer Prüfsumme erkannt, die als EXOR-Verknüpfung aller Datenbytes eines Programmblocks errechnet wird.
Ungewöhnlich ist allerdings die Reaktion auf eine fehlerhafte Prüfsumme: Anstatt — wie zahlreiche andere Datassetten-Schnellader — sofort einen Reset auszulösen oder den Rechner zu blockieren, färbt der Schnelllader von Elidon nur kurz den Bildschirm rot und setzt dann seine Arbeit fort. Für den Anwender hat dies denn Vorteil, dass das Spiel eventuell auch von einer nur geringfügig beschädigten Kassette geladen werden kann, falls der Lesefehler einen nicht genutzten Speicherabschnitt oder unkomprimierte Grafikdaten betrifft.
PRG $C003 ; Einen Programmteil von Band lesen, Startadresse an $C3/$C4, Endadresse an $C1/$C2 P_AB: SEI ; Interrupts während Laderoutine verbieten LDA #$05 ; Alle ROMs ausblenden STA *$01 JSR P_AD ; Synchronisation AB00: JSR P_AF ; Ein Datenbyte von Band lesen und nach A DEC *$01 ; I/O-Bereich auch ausblenden, ganzer Adressraum mit RAM belegt STA ($C3),Y ; Gelesenes Datenbyte in Speicher schreiben INC *$01 ; I/O-Adressraum wieder einblenden EOR *$FC ; Gelesenes Byte in Prüfsumme einarbeiten STA *$FC ; und speichern INC *$C3 ; Schreibzeiger erhöhen (Low-Byte) BNE AB01 ; Sprung falls kein Überlauf INC *$C4 ; Schreibzeiger erhöhen (High-Byte) AB01: LDA *$C3 ; Schreibzeiger (Low-Byte) CMP *$C1 ; mit Endadresse (Low-Byte) vergleichen LDA *$C4 ; Schreibzeiger (High-Byte) SBC *$C2 ; durch Subtraktion mit Endadresse (High-Byte) vergleichen BCC AB00 ; Rücksprung, falls noch nicht ganzer Programmteil gelesen JSR P_AF ; Prüfsumme von Band lesen und nach A CMP *$FC ; und mit errechneter Prüfsumme vergleichen BEQ AB03 ; Sprung, falls Prüfsummen gleich LDA #$02 ; sonst Bildschirm rot färben STA $D020 LDY #$00 ; und ca. 330 ms warten AB02: DEX BNE AB02 DEY BNE AB02 AB03: RTS ; Bildschirm abschalten P_AC: LDY #$00 ; Zähler für Warteschleife LDA $D011 ; Bildschirm abschalten AND #$EF STA $D011 AC00: DEX ; und ca. 330 ms warten BNE AC00 DEY BNE AC00 RTS ; Synchronisation P_AD: LDA #$00 ; Prüfsumme initialisieren STA *$FC JSR P_AC ; Bildschirm abschalten LDA #$07 STA $DD06 ; Low-Byte von CIA 2 Timer B auf $07 setzen LDX #$01 AD00: JSR P_AE ; Ein Datenbit von Band lesen ROL *$FB ; und von rechts in bisher gelesenes Byte schieben LDA *$FB ; Bisher gelesenes Byte nach A holen CMP #$02 ; und mit Synchronisationszeichen $02 vergleichen BNE AD00 ; Rücksprung und weitersuchen, falls ungleich LDY #$09 ; Start der Synchronisations-Sequenz AD01: JSR P_AF ; Ein Byte von Band lesen CMP #$02 ; und mit weiterem Synchroinisationszeichen $02 vergleichen BEQ AD01 ; Überlesen und Rücksprung, falls ja AD02: CPY *$FB ; Gelesenes Byte mit Synchronisations-Sequenz vergleichen BNE AD00 ; Rücksprung und erneute Synchronisation, falls ungleich JSR P_AF ; sonst nächstes Byte von Band lesen DEY ; und Synchronisations-Sequenz weiterzählen BNE AD02 ; Rücksprung, falls noch nicht Ende der Sequenz erreicht RTS ; Ein Datenbit von Band lesen und im Carry-Flag zurückliefern P_AE: LDA #$10 ; Warten auf Signal von Datassette AE00: BIT $DC0D BEQ AE00 LDA $DD0D ; Flag für "CIA 2 Timer B abgelaufen" merken und löschen STX $DD07 ; High-Byte von CIA 2 Timer B auf $01 setzen PHA ; A auf Stack retten LDA #$19 ; CIA 2 Timer B neu laden und im "One shot"-Modus starten STA $DD0F PLA ; A vom Stack zurückholen LSR A ; Gelesenes Datenbit ins Carry-Flag übertragen LSR A ; CIA 2 Timer B abgelaufen=1-Bit, nicht abgelaufen=0-Bit RTS ; Ein Datenbyte von Band lesen und in A zurückliefern P_AF: LDA #$08 ; 8 Bits STA *$FD ; als Bitzähler merken AF00: JSR P_AE ; Ein Bit von Band ins Carry-Flag holen ROL *$FB ; und von rechts in das gelesene Datenbyte schieben INC $D020 ; Bildschirm-Rahmenfarbe erhöhen DEC *$FD ; Bitzähler erniedrigen BNE AF00 ; Rücksprung falls noch nicht 8 Bits gelesen LDA *$FB ; Gelesenes Byte nach A holen RTS
Hauptprogramm des Schnelladers[Bearbeiten | Quelltext bearbeiten]
Das Hauptprogramm setzt nacheinander für die beiden Programmblöcke, aus denen sich Elidon zusammensetzt, jeweils die Anfangs- und Endadresse und ruft danach die Laderoutine für jeden der beiden Blöcke auf. Anschließend startet sie das Spiel durch einen absoluten Sprung in den zuletzt gelesenen Programmblock. Im Gegensatz zu vielen anderen Schnellladern geht den Banddaten kein Header mit Anfangs- und Endadressen voraus, sondern auf dem Band finden sich nur die eigentlichen Datenbytes.
; Hauptprogramm des Schnellladers P_AG: LDA #$C6 ; Startadresse für ersten Programmteil auf $C600 setzen STA *$C4 LDA #$00 STA *$C3 LDA #$00 ; Endadresse für ersten Programmteil auf $D000 setzen STA *$C1 LDA #$D0 STA *$C2 JSR P_AB ; Ersten Programmteil von Band lesen LDA #$08 ; Startadresse für zweiten Programmteil auf $0800 setzen STA *$C4 LDA #$00 STA *$C3 LDA #$00 ; Endadresse für zweiten Programmteil auf $A000 setzen STA *$C1 LDA #$A0 STA *$C2 JSR P_AB ; Zweiten Programmteil von Band lesen LDA #$37 ; Alle ROMs wieder einblenden STA *$01 CLI ; Interrupts wieder zulassen LDA $D011 ; Bildschirm wieder einschalten ORA #$10 STA $D011 LDX #$04 ; und ca. 5 ms warten AG00: DEY BNE AG00 DEX BNE AG00 JMP $08D0 ; Spiel starten