Arac/Schnelllader

Aus C64-Wiki
Zur Navigation springenZur Suche springen

<< zurück zu Arac


Arac/Schnelllader: Die folgenden Abschnitte stellen den disassemblierten Kassetten-Schnelllader des Spiels Arac (Neuauflage von "Prism Leisure") dar. Sie sind gegliedert in einzelne Codeblöcke, die gemäß ihrer Funktion während des Ladens gruppiert sind.


Dateiname und Interruptroutine des Schnellladers[Bearbeiten | Quelltext bearbeiten]

Dicht hinter dem Dateinamen findet sich im allerersten Block auf Kassette die Interruptroutine des Schnellladers. Diese Routine behandelt die üblichen Phasen eines Ladevorgangs — bitweise Synchronisation, Prüfung auf Synchronisationsbytes und Laden des nachfolgenden Programmteils — und schaltet selbständig zwischen diesen um, wobei ein Statusbyte an Adresse $95 zur Unterscheidung dient.

Das Programm, das sich auf der Kassette dann an diesen Header anschließt, ist nur 64 Bytes lang und übernimmt lediglich die Initialisierung und die Steuerung des Ladevorgangs für die ersten beiden Programmblöcke, bevor die Kontrolle an eine nachgeladene, weitgehend identische Kopie dieser Laderoutine übergeben wird. Im Gegensatz zu vielen anderen Schnellladern geht den Programmblöcken auf Band kein Header mit Anfangs- und Endadressen voraus. Vielmehr sind diese Adressen als Konstanten im Programmcode des Schnellladers abgelegt, während sich auf dem Band nur die eigentlichen Datenbytes finden.

ORG $033C
      DB $03                ; Code für "Absolut zu ladendes Programm"
      DW $02C0              ; Ladeadresse
      DW $0304              ; Endadresse+1
      DB "ff              " ; Dateiname, aufgefüllt mit Leerzeichen

      DB "        "         ; Füllbytes

P_AA: SEI           ; Interrupts während Ladevorgang verbieten
      LDA #$05      ; Alle ROMs ausblenden
      STA *$01
      LDA #$1F      ; Alle IRQs von CIA1 deaktivieren
      STA $DC0D
      STA *$A4      ; Flag für "Ladevorgang abgeschlossen" auf FALSE setzen
      LDA $DC0D     ; Alle IRQ-Anforderungen von CIA1 löschen
      NOP
      LDA #$00
      STA *$95      ; Ladephase initialisieren ($00=Bit-Synchronisation)
      STA *$90      ; Statuswort ST löschen
      NOP
      NOP
      NOP
      LDA #$A0      ; Startwert von CIA1 Timer B=$03A0 (928)
      STA $DC06
      LDA #$03
      STA $DC07
      LDA #$90      ; CIA1 IRQ bei Impuls an Pin FLAG aktivieren
      STA $DC0D
      LDA #<P_AB    ; Interruptvektor auf Schnelllader umbiegen
      STA $FFFE
      LDA #>P_AB
      STA $FFFF
      CLI
AA00: LDA *$A4      ; Auf Abschluss des Ladevorgangs warten
      BNE AA00
      RTS

      DB $00        ; Füllbyte

; Interruptroutine des Schnellladers
P_AB: PHA           ; A auf Stack retten
      TYA           ; Y auf Stack retten
      PHA
      LDA $DC07     ; High-Byte von CIA1 Timer B holen
      LDY #$11      ; CIA1 Timer B neu laden und wieder starten
      STY $DC0F
      INC $D020     ; Bildschirm-Rahmenfarbe erhöhen
      EOR #$02      ; Bit 9 von CIA1 Timer B invertieren
      LSR A         ; und als gelesenes Bit ins Carry-Flag schieben
      LSR A
      ROR *$A9      ; Bit von links in gelesenes Byte schreiben
      BCC AB02      ; Sprung falls 8 Bits gelesen
      NOP
AB00: LDA $DC0D     ; Interruptanforderung löschen
      PLA           ; Geretteten Wert von Y zurückholen
      TAY
      PLA           ; Gerettenen Wert von A zurückholen
      RTI           ; Rückkehr aus Interrupt
; Zähler für empfangene Bits initialisierung und Rückkehr aus Interrupt
AB01: LDA #$7F      ; Bitzähler initialisieren (8 Bits)
      STA *$A9
      BNE AB00      ; Unbedingter Sprung
      NOP
; Bit-Synchronisation
AB02: LDA *$A9      ; Gelesenes Byte nach A holen
      LDY *$95      ; Ladephase nach Y holen
      BNE AB03      ; Sprung falls nicht Bit-Synchronisation
      CMP #$80      ; Synchronisationszeichen $80 gefunden?
      BNE AB00      ; Sprung falls nicht, dann weiter suchen
      STA *$95      ; sonst Ladephase wechseln ($80=Byte-Synchronisation)
      BEQ AB01      ; Unbedingter Sprung
      DB $00
; Byte-Synchronisation
AB03: BPL AB05      ; Sprung falls nicht Byte-Synchronisation
      CMP #$AA      ; Synchronisationszeichen $AA gefunden?
      BEQ AB04      ; Sprung falls ja
      LDA #$00      ; sonst wieder zu Bit-Synchronisation wechseln
      STA *$95      ; Ladephase zurücksetzen ($00=Bit-Synchronisation)
      BEQ AB00      ; Unbedingter Sprung
AB04: LDA #$01      ; Ladephase wechseln ($01=Programm laden)
      STA *$95
      BNE AB01      ; Unbedingter Sprung
      NOP
; Laden
AB05: LDY #$00      ; Index für Schreibzugriff setzen
      STA ($AC),Y   ; Gelesenes Byte in Speicher schreiben
      INC *$AC      ; Schreibzeiger erhöhen (Low-Byte)
      BNE AB06      ; Sprung falls kein Überlauf
      INC *$AD      ; Schreibzeiger erhöhen (High-Byte)
AB06: SEC           ; Schreibzeiger mit Endadresse vergleichen
      LDA *$AC      ; Low-Byte des Schreibzeigers
      SBC *$AE      ; minus Low-Byte Endadresse
      LDA *$AD      ; High-Byte des Schreibzeigers
      SBC *$AF      ; minus High-Byte der Endadresse
      BCC AB01      ; Rücksprung, falls noch nicht alle Bytes gelesen
      LDA #$00      ; Flag für "Ladevorgang abgeschlossen" auf TRUE setzen
      STA *$A4
      BEQ AB01      ; Unbedingter Rücksprung

      DB "        " ; Füllbytes

Initialisierung[Bearbeiten | Quelltext bearbeiten]

Der folgende Programmteil wird beim Laden von Arac 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. Nach einer kurzen Initialisierung von I/O-Bausteinen werden die Anfangs- und Endadressen der zu ladenden Programmteile gesetzt und dann die Kontrolle an die Interruptroutine übergeben.

PRG $02C0

; Einsprung des Schnellladers nach Autostart
P_AC: JSR $FF84     ; CIAs initialisieren
      LDA #$00      ; "Programm-Modus" setzen
      STA *$9D
      NOP
      NOP
      NOP
      NOP
      NOP
      NOP
      NOP
      NOP
      LDA $D011     ; Bildschirm abschalten
      AND #$EF
      STA $D011
; Ersten Programmteil laden
      LDA #$00      ; Anfangsadresse des ersten Programmteils auf $6000 setzen
      STA *$AC
      LDA #$60
      STA *$AD
      LDA #$00      ; Endadresse des ersten Programmteils auf $7400 setzen
      STA *$AE
      LDA #$74
      STA *$AF
      JSR P_AA      ; Programmteil laden
; Zweiten Programmteil laden
      LDA #$00      ; Anfangsadresse des zweiten Programmteils auf $1400 setzen
      STA *$AC
      LDA #$14
      STA *$AD
      LDA #$E0      ; Endadresse des zweiten Programmteils auf $23E0 setzen
      STA *$AE
      LDA #$23
      STA *$AF
      JSR P_AA      ; Programmteil laden
      JMP $1BB0     ; Sprung zum nächsten (fast identischen) Fastloader

      DW $E38B      ; Vektor für BASIC-Warmstart
      DW P_AC       ; Vektor für Eingabe einer Zeile, umgebogen auf Schnelllader