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