P.C. Fuzz/Schnelllader

Aus C64-Wiki
Zur Navigation springenZur Suche springen

<< zurück zu P.C. Fuzz


P.C. Fuzz/Schnelllader: Die folgenden Abschnitte stellen den disassemblierten Kassetten-Schnelllader des Spiels "P.C. Fuzz" dar. Sie sind gegliedert in einzelne Codeblöcke, die gemäß ihrer Position auf dem Magnetband gruppiert sind.

Header-Block[Bearbeiten | Quelltext bearbeiten]

Das folgende Datensegment ist der erste Block auf der Kassette, sollte also nur den Dateityp, die Anfangs- und Endadresse sowie den Namen des Spiels enthalten. In den darauffolgenden, üblicherweise nicht genutzten 171 Bytes findet sich aber in verschlüsselter Form der erste Teil des Schnellladers und ein Copyright-Vermerk.

ORG $033C
      DB $03       ; Code für "Absolut zu ladendes Programm"
      DW $0300     ; Ladeadresse
      DW $0370     ; Endadresse+1
      DB $08,".. P.C. FUZZ .." ; $08: Zeichensatz-Umschaltung sperren

      DB "(C) TEQUILA BELGIUM - ANIROG UK"

; Verschlüsselter Schnelllader, Adressbereich $0370-$03E7
      DB $50,$00,$42,$60,$54,$85,$C6,$88,$E8,$65,$68,$7E
      DB $C4,$68,$7D,$3C,$54,$83,$C6,$83,$6E,$D1,$00,$90,$2B,$01,$93,$5E
      DB $D2,$DE,$E4,$81,$68,$7A,$D0,$04,$90,$23,$01,$E4,$81,$78,$7C,$E2
      DB $5E,$E8,$74,$10,$23,$01,$C4,$68,$7B,$64,$80,$78,$63,$D4,$B3,$46
      DB $A6,$81,$90,$23,$01,$C2,$E0,$90,$23,$01,$C2,$E1,$10,$23,$01,$C2
      DB $96,$90,$23,$01,$C2,$97,$10,$23,$01,$C8,$E0,$F3,$60,$E8,$01,$73
      DB $61,$52,$E0,$E2,$96,$D2,$E1,$72,$97,$68,$75,$90,$23,$01,$A4,$10
      DB $23,$01,$A4,$46,$50,$01,$52,$DB,$C6,$90,$68,$30

T000: DB "MASTER DATE:26/09/84"

Programmblock (Autostart und Decodier-Routine)[Bearbeiten | Quelltext bearbeiten]

Die Programmdaten, die beim Laden der Datei ".. P.C. FUZZ .." von den Datassettenroutinen des Kernals in den Speicher übertragen werden, biegen zum einen zahlreiche Sprungvektoren des Kernal auf den Schnelllader um und lösen damit nach dem Laden einen Autostart aus, zum anderen findet sich hier die zweite Hälfte des Maschinencode für den Schnelllader sowie die Routine zu seiner Decodierung.

PRG $0300

      DW P_BB  ; Vektor für BASIC-Wrmstart, umgebogen auf Schnelllader
      DW P_BB  ; Vektor für Eingabe einer Zeile, umgebogen auf Schnelllader
      DW P_BB  ; Vektor für Umwandlung in Interpretercode, umgebogen auf Schnelllader
      DW P_BB  ; Vektor für Umwandlung in Klartext, umgebogen auf Schnelllader
      DW P_BB  ; Vektor für BASIC-Befehlsadresse holen, umgebogen auf Schnelllader
      DW P_BB  ; Vektor für Ausdruck auswerten, umgebogen auf Schnelllader
      DB $00   ; Akku für SYS-Befehl
      DB $00   ; X-REG für SYS-Befehl
      DB $00   ; Y-REG für SYS-Befehl
      DB $00   ; Status-Register für SYS-Befehl

      DB $00,$00,$00,$00

      DW $EA31 ; IRQ-Vektor
      DW $FEC1 ; BRK-Vektor, umgebogen auf RTI-Befehl
      DW $FEC1 ; NMI-Vektor, umgebogen auf RTI-Befehl
      DW P_BB  ; OPEN-Vektor, umgebogen auf Schnelllader
      DW P_BB  ; CLOSE-Vektor, umgebogen auf Schnelllader
      DW P_BB  ; CHKIN-Vektor, umgebogen auf Schnelllader
      DW P_BB  ; CKOUT-Vektor, umgebogen auf Schnelllader
      DW P_BB  ; CLRCH-Vektor, umgebogen auf Schnelllader
      DW P_BB  ; INPUT-Vektor, umgebogen auf Schnelllader
      DW P_BB  ; OUTPUT-Vektor, umgebogen auf Schnelllader
      DW $E68E ; STOP-Vektor, inaktiviert
      DW P_BB  ; GET-Vektor, umgebogen auf Schnelllader
      DW P_BB  ; CLALL-Vektor, umgebogen auf Schnelllader
      DW P_BB  ; Warmstart-Vektor, umgebogen auf Schnelllader
      DW P_BB  ; LOAD-Vektor, umgebogen auf Schnelllader
      DW P_BB  ; SAVE-Vektor, umgebogen auf Schnelllader

; Übergang zum Schnelllader
P_BA: NOP
BA00: LDA $D020    ; Rahmenfarbe nach A holen
      STA *$B7     ; und zwischenspeichern
      BNE P_BE     ; Unbedingter Sprung zum Schnelllader

; Decodier-Routine
P_BB: CLC          ; Decodieren durch Linksshift, mit 0-Bit beginnen
BB00: ROL T000-$01 ; Code des Schnellladers vom Ende her rotieren/decodieren
      DEC BB00+$01 ; Zeiger auf nächste zu rotierende/decodierende Speicherzelle richten (Modifikation des vorausgehenden Befehls!) 
      BNE BB00     ; Rücksprung; dieser Sprungoffset wird schließlich durch Linksshift auf BA00 umgebogen
      BRK

Auf die Auflistung des codierten Schnellladers in Form von zweistelligen Hexadezimalzahlen wurde hier verzichtet. Stattdessen zeigt der folgende Abschnitt den bereits von der Programmschleife an P_BB decodierten Maschinencode.

Entschlüsselter Schnelllader, Adressbereich $0345-$036F (Programmblock)[Bearbeiten | Quelltext bearbeiten]

; Ein Byte von Band lesen und in A zurückliefern
P_BC: LDA #$08  ; Bitzähler
      STA *$A3  ; initialisieren
BC00: JSR P_BD  ; Ein Bit von Band lesen und nach CF
BC01: ROL *$BD  ; und von rechts in Speicherzelle $BD schieben
      DEC *$A3  ; Bitzähler vermindern
      BNE BC00  ; Rücksprung falls noch nicht 8 Bit gelesen
      LDA *$BD  ; Gelesenes Byte nach A holen
      RTS       ; Rücksprung zur aufrufenden Routine

; Ein Bit von Band lesen und in CF zurückliefern
P_BD: LDA #$10  ; Bitmaske für Interrupt an Pin FLAG
BD00: BIT $DC0D ; Auf Interrupt prüfen
      BEQ BD00  ; Rücksprung falls kein Impuls von Band
      LDA $DD0D ; Interruptanforderungen CIA2 holen und löschen
      STX $DD07 ; CIA2 Timer B High-Byte auf 1 setzen
      PHA       ; A retten
      LDA #$19  ; CIA2 Timer B neu laden und starten (one shot)
      STA $DD0F
      INC $D020 ; Rahmenfarbe erhöhen
      PLA       ; A zurückholen
      LSR A     ; Bit für "Unterlauf Timer B" nach CF
      LSR A
      RTS       ; Rückkehr zur aufrufenden Routine

Entschlüsselter Schnelllader, Adressbereich $0370-$03E7 (Header-Block)[Bearbeiten | Quelltext bearbeiten]

P_BE: LDY #$00    ; Recordermotor einschalten
      STY *$C0
      LDA #$0B    ; Bildschirm ausschalten
      STA $D011
BE00: DEX         ; Etwa 330 ms Verzögerung
      BNE BE00
      DEY
      BNE BE00
      SEI         ; Interrupts während Ladevorgang ausschalten
      LDA #$07    ; Timer B Low-Byte
      STA $DD06   ; setzen
      LDX #$01    ; Timer B High-Byte
BE01: JSR P_BD    ; Ein Bit von Band nach CF holen
      ROL *$BD    ; und von rechts in Adresse $BD schieben
      LDA *$BD
      CMP #$02    ; Synchronisationszeichen $02 gelesen?
      BNE BE01    ; Rücksprung falls nicht
      LDY #$09
BE02: JSR P_BC    ; Byte von Band lesen
      CMP #$02    ; Weitere Synchronisationszeichen $02 überlesen
      BEQ BE02
BE03: CPY *$BD    ; Synchronisationszeichen $09,...,$01 gelesen?
      BNE BE01    ; Erneute Synchronisation falls nicht
      JSR P_BC    ; Byte von Band lesen
      DEY         ; Synchronisationszeichen herunterzählen
      BNE BE03    ; Sprung falls noch nicht alle Synchronisationszeichen $09..$01 gelesen
      CMP #$00    ; Nullbyte gelesen?
      BEQ P_BE    ; Erneute Synchronisation falls ja
      LDA #$66    ; Opcode für "ROR zeropage"
      STA BC01    ; Schieberichtung umkehren
      JSR P_BC    ; Byte von Band lesen
      STA *$C1    ; als Schreibzeiger (Low-Byte)
      JSR P_BC    ; Byte von Band lesen
      STA *$C2    ; als Schreibzeiger (High-Byte)
      JSR P_BC    ; Byte von Band lesen
      STA *$2D    ; als Endadresse+1 (Low-Byte)
      JSR P_BC    ; Byte von Band lesen
      STA *$2E    ; als Endadresse+1 (High-Byte)
BE04: JSR P_BC    ; Datenbyte von Band lesen
      STA ($C1),Y ; und in Speicher schreiben
      INC *$C1    ; Schreibzeiger erhöhen (Low-Byte)
      BNE BE05    ; Sprung falls kein Überlauf
      INC *$C2    ; Schreibzeiger erhöhen (High-Byte)
BE05: LDA *$C1    ; Schreibzeiger holen (Low-Byte)
      CMP *$2D    ; und mit Endadresse+1 vergleichen (Low-Byte)
      LDA *$C2    ; Schreibzeiger holen (High-Byte)
      SBC *$2E    ; und mit Endadresse+1 vergleichen (High-Byte)
      BNE BE04    ; Rücksprung falls noch nicht alle Datenbytes gelesen
      JSR P_BC    ; Byte von Band lesen
      PHA         ; als Rücksprungadresse-1 (High-Byte) auf Stack speichern
      JSR P_BC    ; Byte von Band lesen
      PHA         ; als Rücksprungadresse-1 (Low-Byte) auf Stack schreiben
      STY $02A0   ; Zwischengespeicherten IRQ-Vektor löschen
      LDA *$B7    ; Gerettete Bildschirm-Rahmenfarbe
      STA $D020   ; wiederherstellen
      RTS         ; Übergang von Schnelllader zu geladenem Programm

Nach dem Laden des eigentlichen Programmcode in den Adressbereich $2800—$C9FF folgt zunächst noch (angesprungen über den abschließenden RTS-Befehl des obigen Codeabschnitts) das aufwändige Decodieren und Umkopieren dieses Speicherblocks nach $0800—$A9FF, bevor das Spiel endlich beginnt.