The Sacred Armour of Antiriad/Schnelllader
<< zurück zu The Sacred Armour of Antiriad oder Firelord
The Sacred Armour of Antiriad/Schnelllader und Firelord/Schnelllader: Die folgenden Abschnitte stellen den disassemblierten Kassetten-Schnelllader der Spiele The Sacred Armour of Antiriad und Firelord dar. Sie sind gegliedert in einzelne Codeblöcke, die gemäß ihrer Funktion während des Ladens gruppiert sind.
Dateiname und Hauptschleife des Schnellladers[Bearbeiten | Quelltext bearbeiten]
Direkt hinter dem Dateinamen findet sich im allerersten Block auf Kassette die Hauptschleife des Schnellladers sowie die Routine zum Lesen eines Byte von Band. Das Programm, das sich auf der Kassette dann an diesen Header anschließt, ist nur 93 Bytes lang und übernimmt nur die Initialisierung und die initiale Synchronisation. Ferner stellt dieses Programm die Routine zum Einlesen eines einzelnen Bits von Band bereit, die im Kassettenpuffer keinen Platz mehr gefunden hat.
ORG $033C
DB $03 ; Code für "Absolut zu ladendes Programm"
DW $02A7 ; Ladeadresse
DW $0304 ; Endadresse+1
DB "ANTIRIAD" ; bzw. "FIRELORD"
DB $00,$00,$00,$00,$00,$00,$00,$00
; Hauptschleife des Schnellladers
P_AA: SEI ; Interrupts während Ladevorgang verbieten
LDA #$07 ; CIA 2 Timer B Low-Byte ($07 bei "ANTIRIAD", $6E bei "FIRELORD")
STA $DD06
LDX #$01 ; CIA 2 Timer B High-Byte
AA00: JSR P_BC ; Ein Bit von Band nach CF holen
ROL *$F7 ; und von rechts in Byte an Adresse $F7 schieben
LDA *$F7 ; Letzte 8 gelesene Bits holen
CMP #$63 ; und mit Synchronisationskennzeichen $63 vergleichen
BNE AA00 ; Rücksprung falls nicht Synchronisationskennzeichen $63
LDY #$64 ; Y=erstes Byte der Startsequenz
AA01: JSR P_AB ; Ein Byte von Band holen
CMP #$63 ; und mit Synchronisationskennzeichen $63 vergleichen
BEQ AA01 ; Alle Synchronisationskennzeichen $63 überlesen
AA02: CPY *$F7 ; Gelesenes Byte mit Byte aus Startsequenz vergleichen
BNE AA00 ; Resynchronisation, falls nicht zur Startsequenz passend
JSR P_AB ; Ein Byte von Band holen
INY ; Startsequenz weiterzählen
BNE AA02 ; Rücksprung falls noch nicht alle Zahlen von $64 bis $FF
CMP #$00 ; Ist nächstes Byte ein Nullbyte?
BEQ P_AA ; dann Resynchronisation
AA03: JSR P_AB ; Headerbytes von Band holen
STA $002B,Y ; und in Tabelle an Adresse $002B schreiben
STA $00F9,Y ; und in Tabelle an Adresse $00F9 schreiben
INY ; Schreibindex erhöhen
CPY #$0A ; Schon 10 Bytes von Band gelesen?
BNE AA03 ; sonst Rücksprung und weiteres Byte lesen
LDY #$00 ; Schreibindex initialisieren
STY *$90 ; Statusvariable ST initialisieren
STY *$02 ; Prüfsumme für gelesene Datenbytes initialisieren
AA04: JSR P_AB ; Byte von Band lesen
STA ($F9),Y ; und an Zieladresse in Speicher schreiben
EOR *$02 ; Datenbyte in Prüfsumme einarbeiten
STA *$02 ; und zurückschreiben
INC *$F9 ; Low-Byte der Zieladresse erhöhen
BNE AA05 ; Sprung falls kein Überlauf
INC *$FA ; sonst High-Byte der Zieladresse erhöhen
AA05: LDA *$F9 ; Low-Byte der nächsten Schreibadresse holen
CMP *$2D ; und mit Low-Byte der Endadresse+1 vergleichen
LDA *$FA ; High-Byte der nächsten Schreibadresse holen
SBC *$2E ; und einschließlich Übertrag mit High-Byte der Endadresse+1 vergleichen
BCC AA04 ; Rücksprung falls Endadresse+1 noch nicht erreicht
JSR P_AB ; Prüfsumme von Band holen
INY ; Y=1
STY *$C0 ; Flag für Bandmotor setzen
CLI ; Interrupts wieder zulassen
CLC ; Evtl. Kennzeichen für "Kein Fehler"? (wirkungslos)
LDA #$00
STA $02A0 ; Interruptvektor nicht wiederherstellen
JSR $FC93 ; Rekorderbetrieb beenden
JSR $E453 ; BASIC-Vektoren laden
LDA *$F7 ; Gelesene Prüfsumme holen
EOR *$02 ; und mit errechneter Prüfsumme verknüpfen
ORA *$90 ; und mit Statusvariable ST verknüpfen
BEQ AA06 ; Sprung falls kein Prüfsummenfehler
JMP $FCE2 ; sonst Reset auslösen
AA06: LDA *$31 ; Weitere Datenblocks von Band laden?
BEQ AA07 ; Sprung falls nicht
JMP BB00 ; sonst nächsten Block laden
AA07: LDA *$32 ; Flag für Maschinensprache-/BASIC-Programm testen
BEQ AA08 ; Sprung falls BASIC-Programm
JMP ($002F) ; sonst Einsprung über Startvektor
AA08: JSR $A533 ; BASIC-Programmzeilen neu binden
LDX #$03 ; 3 Zeichen
STX *$C6 ; in Tastaturpuffer schreiben
AA09: LDA T000-1,X ; Zeichen "rU" <ENTER> nacheinander einlesen
STA $0276,X ; und in Tastaturpuffer schreiben
DEX ; Schreibzeiger vermindern
BNE AA09 ; Rücksprung falls noch nicht 3 Zeichen geschrieben
JMP P_BD ; In Direktmodus wechseln
; Ein Byte von Band holen und nach A
P_AB: LDA #$07 ; Anzahl zu lesender Bits-1
STA *$F8 ; setzen
AB00: JSR P_BC ; Ein Bit von Band holen
ROL *$F7 ; und von rechts in Byte an Adresse $F7 schieben
INC $D020 ; Bildschirmfarbe hochzählen
DEC *$F8 ; Bitzähler vermindern
BPL AB00 ; Rücksprung falls noch nicht 8 Bits gelesen
LDA *$F7 ; Gelesenes Byte nach A holen
RTS ; und zurück zur aufrufenden Routine
Initialisierung[Bearbeiten | Quelltext bearbeiten]
Der folgende Programmteil wird beim Laden von Antiriad oder Firelord von Kassette gelesen. Dieser Vorgang überschreibt den Vektor für die Eingabe einer BASIC-Zeile mit der Startadresse des Schnellladers und löst damit nach dem Ende des Ladevorgangs einen Autostart aus. Anschließend findet zunächst eine Synchronisation mit den Banddaten statt, bevor die Kontrolle an die Hauptschleife des Schnellladers im Kassettenpuffer übergeben wird.
PRG $02A7
; Stop-Taste deaktivieren
P_BA: LDA #$80
ORA *$91
JMP $F6EF
; Einsprung
P_BB: LDA #<P_BA
SEI ; Interrupts verbieten
STA $0328 ; STOP-Vektor (Low-Byte)
LDA #>P_BA
STA $0329 ; STOP-Vektor (High-Byte)
BB00: CLI ; Interrupts wieder erlauben
LDY #$00
STY *$C6 ; Tastaturpuffer löschen
STY *$C0 ; Flag für Bandmotor löschen
STY *$02 ; Prüfsumme für empfangene Bytes initialisieren
LDA $D011 ; Bildschirm abschalten
AND #$EF
STA $D011
BB01: DEX ; Ca. 333 ms Pause
BNE BB01
DEY
BNE BB01
SEI
JMP P_AA ; Weiter zur Laderoutine
; Ein Bit von Band holen und nach CF
P_BC: LDA $DC0D ; Auf Impuls vom Band warten
AND #$10
BEQ P_BC
LDA $DD0D ; Flags für abgelaufene CIA 2-Timer lesen
STX $DD07 ; CIA 2 Timer B High-Byte setzen
LSR A ; Flag für Unterlauf von Timer B nach CF holen
LSR A
LDA #$19 ; CIA 2 Timer B neu laden und im "One Shot"-Modus starten
STA $DD0F
RTS
P_BD: JSR $A68E ; Programmzeiger auf BASIC-Start
LDA #$00 ; Erstes Byte des Programms auf $00 setzen
TAY
STA ($7A),Y
JMP $A474 ; "READY." ausgeben und in Direktmodus
T000: DB $52,$D5,$0D ; "rU" <ENTER>
DB $00,$00,$00,$00,$00,$00,$00,$00,$00
DW $E38B ; Unveränderter Vektor für BASIC-Warmstart
DW P_BB ; Umgebogener Vektor für Eingabe einer Zeile
Umkopieren eines Datenblocks in das RAM unter dem I/O-Bereich[Bearbeiten | Quelltext bearbeiten]
Der erste Datenblock des Programms wird zunächst in den Adressbereich $1000-$17FF geladen, soll aber letztendlich in das RAM unter dem I/O-Bereich an Adresse $D000-$D7FF übertragen werden. Unmittelbar an den Datenblock schließt sich daher (im Adressbereich $1800-$185F) die folgende kurze Routine an, die zuerst den Datenblock verschiebt und dann mit Hilfe der Kernal-Routinen eine weitere Kopie des Schnellladers in den Speicher des C64 lädt. Dieser liest dann die restlichen Datenblöcke des Spiels vom Band in den Hauptspeicher ein.
PRG $1800
; Geladenen Datenblock von $1000..$17FF nach $D000..$D7FF umkopieren
P_CA: SEI ; Interrupts verbieten
LDA *$01 ; Aktuelle Speicherkonfiguration holen
PHA ; und retten
LDA #$00 ; Ganzen Adressraum auf RAM umschalten
STA *$01
LDA #$00 ; Lesezeiger auf $1000 initialisieren
STA *$61
LDA #$10
STA *$62
LDY #$00 ; Lese-/Schreibindex initialisieren
CA00: LDA *$62 ; High-Byte des Lesezeigers holen
PHA ; und retten
LDA ($61),Y ; Datenbyte aus Bereich $1000..$1FFF holen
PHA ; und retten
CLC ; Lesezeiger um $C000 erhöhen (als Schreibzeiger)
LDA *$62
ADC #$C0
STA *$62
PLA ; Gerettetes Datenbyte zurückholen
STA ($61),Y ; und in Bereich $D000..$DFFF schreiben
PLA ; Gerettetes High-Byte des Lesezeigers zurückholen
STA *$62 ; und wiederherstellen
INY ; Lese-/Schreibindex erhöhen
BNE CA00 ; Rücksprung falls kein Überlauf
INC *$62 ; High-Byte des Lesezeigers erhöhen
CLC ; Zugehörigen Schreibzeiger errechnen
LDA *$62
ADC #$C0
CMP #$E0 ; Schon Ende des zu schreibenden Bereichs erreicht?
BNE CA00 ; Rücksprung falls noch nicht
PLA ; Vorige Speicherkonfiguration zurückholen
STA *$01 ; und wiederherstellen
LDA #$00 ; Status ST für Ladevorgang
JSR $FF90 ; setzen (wirkungslos)
LDA #$01 ; Logische Dateinummer
LDX #$01 ; Geräteadresse
LDY #$01 ; Sekundäradresse
JSR $FFBA ; Dateiparameter für nächsten Ladevorgang setzen
LDA #$00 ; Länge des Dateinamens=0, nächste Datei von Band laden
JSR $FFBD ; Dateinamenparameter setzen
LDA #$00 ; LOAD/VERIFY-Flag auf "LOAD" setzen
JSR $FFD5 ; LOAD-Routine, Schnelllader P_AA..P_AB nochmals einlesen
JMP ($0302) ; und anspringen