The Sacred Armour of Antiriad/Schnelllader

Aus C64-Wiki
Zur Navigation springenZur Suche springen

<< zurück zu The Sacred Armour of Antiriad


The Sacred Armour of Antiriad/Schnelllader: Die folgenden Abschnitte stellen den disassemblierten Kassetten-Schnelllader des Spiels The Sacred Armour of Antiriad 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",$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
      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 Blocknummer 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 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