P.C. Fuzz/Schnelllader
<< 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.