Bozo's Night Out/Schnelllader
<< zurück zu Bozo's Night Out
Bozo's Night Out/Schnelllader: Die folgenden Abschnitte stellen den disassemblierten Kassetten-Schnelllader des Spiels Bozo's Night Out dar. Sie sind gegliedert in einzelne Codeblöcke, die gemäß ihrer Funktion während und nach dem Laden gruppiert sind.
Startblock der Datassetten-Datei[Bearbeiten | Quelltext bearbeiten]
Der folgende Abschnitt 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 bereits ein großer Teil des Code für den Schnelllader.
ORG $033C
DB $03 ; Code für "Absolut zu ladende Datassetten-Datei"
DW P_BA ; Anfangsadresse
DW $032A ; Endadresse+1
DB 'B' ; Dateiname
DB $94 ; Code für "Insert"
DB " "
; Ein Bit von Band lesen
P_AA: LDA #$10
AA00: BIT $DC0D ; Auf Bit von Band warten
BEQ AA00
INC $D020 ; Bildschirmfarbe hochzählen
LDA #$99 ; CIA2 Timer A neu laden und starten (one-shot)
STA $DD0E
LSR $DD0D ; Flag für "Timer A abgelaufen" löschen
AA01: LSR $DD0D ; Auf Ablauf von Timer A warten
BCC AA01
LDA $DC0D ; Prüfen, ob in der Zwischenzeit ein weiteres Bit von Band gelesen wurde
AND #$10
BNE AA02 ; Sprung falls ja (dann CF=1 lassen), 1-Bit empfangen
CLC ; sonst CF=0 setzen, 0-Bit empfangen
AA02: RTS ; Rückkehr
; Initialisierung und Hauptschleife des Schnellladers
P_AB: SEI
LDA #$C1 ; NMI-Vektor auf "RTI" umbiegen
STA $0318 ; Low-Byte
LDA #$FE
STA $0319 ; High-Byte
LDA #$8B ; Bildschirm abschalten
STA $D011
LDA #$00
STA *$9E ; Prüfsumme initialisieren
STA $DD05 ; Startwert CIA2 Timer 1 auf 120 setzen: High-Byte=0
LDA #$78
STA $DD04 ; Startwert CIA2 Timer 1 auf 120 setzen: Low-Byte=120
LDA #$81
STA $DD0E ; CIA2 Timer A starten (fortlaufend)
LDA #$01 ; Startwert CIA2 Timer 1 auf 330 setzen
STA $DD05 ; High-Byte
LDA #$4A
STA $DD04 ; Low-Byte
AB00: LDA #$64 ; Zähler für Synchronisation (100 0-Bits) initialisieren
STA *$92
AB01: JSR P_AA ; Ein Bit von Band lesen
BCS AB00 ; Warten auf 0-Bit
DEC *$92 ; Anzahl 0-Bits herunterzählen
BNE AB01 ; Rücksprung falls noch nicht 100 0-Bits
AB02: JSR P_AA ; Ein Bit von Band lesen
BCC AB02 ; Weitere 0-Bits überlesen
JSR P_BA ; Ein Byte von Band lesen
STA *$C3 ; und als Startadresse im Schreibzeiger speichern (Low-Byte)
JSR P_BA ; Ein Byte von Band lesen
STA *$C4 ; und als Startadresse im Schreibzeiger speichern (High-Byte)
JSR P_BA ; Ein Byte von Band lesen
STA *$AE ; und als Endadresse+1 speichern (Low-Byte)
JSR P_BA ; Ein Byte von Band lesen
STA *$AF ; und als Endadresse+1 speichern (High-Byte)
AB03: LDX *$C4 ; Aktuellen Schreibzeiger nach X holen (High-Byte)
CPX *$AF ; und mit Endadresse+1 vergleichen (High-Byte)
BNE AB04 ; Weiter laden falls ungleich
LDX *$C3 ; Aktuellen Schreibzeiger nach X holen (Low-Byte)
CPX *$AE ; und mit Endadresse+1 vergleichen (Low-Byte)
BEQ AB05 ; Zum Abschluss der Laderoutine springen falls gleich
AB04: JSR P_BA ; Ein Byte von Band lesen
TAX ; und nach X retten
SEC ; Gelesenes Byte zur Prüfsumme addieren
ADC *$9E
STA *$9E
TXA ; Gelesenes Byte zurückholen
LDY #$00 ; Schreibindex initialisieren
STA ($C3),Y ; und gelesenes Byte in Speicher schreiben
INC *$C3 ; Schreibzeiger erhöhen (Low-Byte)
BNE AB03 ; Rücksprung falls kein Übertrag
INC *$C4 ; Schreibzeiger erhöhen (High-Byte)
JMP AB03 ; Weiter laden
AB05: JSR P_BA ; Ein Byte von Band lesen (Prüfsumme)
CMP *$9E ; und mit errechneter Prüfsumme vergleichen
BNE AB07 ; Sprung falls Prüfsummenfehler
AB06: JMP $0400 ; Nachgeladene Erweiterung des Schnellladers starten
AB07: JMP $FCE2 ; Bei Prüfsummenfehler Reset auslösen
; Alle ROMs einblenden und Schnelllader starten
P_AC: LDA #$07 ; Alle ROMs einblenden
STA *$01
JMP P_AB ; Sprung zum Start des Schnellladers
; Füllbytes ohne Funktion
DB $00,$00,$20
Ausgelagerter Code und Autostart[Bearbeiten | Quelltext bearbeiten]
Der Programmblock, der beim Laden von Bozo's Night Out nachgeladen wird, überschreibt zum einen den OUTPUT-Vektor des Kernals mit der Startadresse des Schnellladers und bewirkt damit, dass dieser unmittelbar nach dem Laden gestartet wird. Zum anderen enthält dieser Programmblock eine ausgelagerte Routine für das Lesen eines Bytes von Band, die offensichtlich im ersten Datenblock auf der Kassette keinen Platz mehr gefunden hat.
PRG $031B
; Ein Byte von Band lesen und nach A und Y
P_BA: LDY #$01 ; Bitzähler initialisieren
BA00: JSR P_AA ; Ein Bit von Band lesen
TYA ; Bitzähler nach A holen
ROL A ; und gelesenes Bit von rechts hineinschieben
TAY ; Bitzähler zurück nach Y
BCC BA00 ; Rücksprung, falls noch nicht 8 Bit von Band gelesen
RTS ; Rückkehr mit gelesenem Byte in A und Y
DW P_AC ; OUTPUT-Vektor, umgeboten auf Start des Schnellladers
DW $F6ED ; STOP-Vektor
Einbindung des Schnellloaders in LOAD-Routine des Kernals[Bearbeiten | Quelltext bearbeiten]
Der Schnelllader liest zunächst nur das folgenden Codesegment von Band und führt dieses dann aus. In diesem Codeabschnitt werden dann alle zuvor überschriebenen Sprungvektoren wiederhergestellt, bevor sich der Schnelllader in die Laderoutine des Kernals einklinkt. Auf diese Weise kann er die BASIC-Routinen nutzen, um Bozo's Night Out zu starten: Löschen des Hauptspeichers mittels NEW, und anschließendes Laden und Starten des Spiels mit Hilfe eines im Tastaturpuffer abgelegten Tastendrucks auf "LOAD+RUN" (PETSCII $83).
PRG $0400
P_CA: LDY #$0D ; 13+1=14 Bytes umkopieren
CA00: LDA $FD37,Y ; Hardware- und I/O-Vektoren
STA $031B,Y ; wiederherstellen
DEY ; Schreibindex vermindern
BPL CA00 ; Rücksprung falls noch nicht alle Bytes umkopiert
LDY #$2D ; 45+1=46 Bytes umkopieren
CA01: LDA T001,Y ; Neue Schnellade-Routinen byteweise lesen
STA $02A7,Y ; und umkopieren
DEY ; Schreibindex vermindern
BPL CA01 ; Rücksprung falls noch nicht alle Bytes umkopiert
LDA #>P_AC ; LOAD-Vektor auf Schnelllader umbiegen
STA $0331 ; High-Byte
LDA #<P_AC
STA $0330 ; Low-Byte
LDX #$05 ; 5+1=6 Unterprogrammaufrufe patchen
CA02: LDY T000,X ; Aufruf "Ein Byte von Band lesen" auf P_CC patchen
LDA #<P_CC ; Low-Byte
STA $0300,Y
LDA #>P_CC ; High-Byte
STA $0301,Y
DEX ; Schreibindex vermindern
BPL CA02 ; Rücksprung falls noch nicht alle Bytes umkopiert
LDX #$F1 ; STOP-Vektor verbiegen und unwirksam machen
LDA #$B1
STX $0329 ; High-Byte
STA $0328 ; Low-Byte
LDA #<P_CB ; Sprung zum simulierten Abschluss des ladevorgangs vorbereiten
STA AB06+$01 ; Low-Byte
LDA #>P_CB
STA AB06+$02 ; High-Byte
LDA #$02 ; 2 Tasten im Tastaturpuffer
STA *$C6
LDA #$93 ; PETSCII-Code für "Clear"
STA $0277 ; als erstes Zeichen im Tastaturpuffer
LDA #$83 ; PETSCII-Code für "LOAD+RUN"
STA $0278 ; als zweites Zeichen im Tastaturpuffer
JMP $A644 ; BASIC-Befehl NEW
; Patch-Tabelle (Adressen der Aufrufe von "Ein Byte von Band lesen" relativ zu $0300)
T000: DB $AF,$B4,$B9,$BE,$CF,$E6
T001:
PRG $02A7
; Abschluss des Ladevorgangs für Kernal simulieren
P_CB: LDA *$01 ; Datassettenmotor ausschalten
ORA #$20
STA *$01
LDA #$07 ; Flag für Bandmotor setzen
STA *$C0
LDA $D011 ; Bildschirm einschalten
ORA #$10
STA $D011
LDY #$00 ; CIA2 Timer A stoppen
STY $DD0E
CLI ; Interrupts wieder zulassen
CLC ; Zeichen für "Kein Fehler"
LDX *$AE ; Endadresse+1 des Programms, Low-Byte
LDY *$AF ; Endadresse+1 des Programms, High-Byte
RTS ; Rückkehr aus Laderoutine
; Ein Byte von Band lesen und nach A und Y
P_CC: LDY #$01 ; Bitzähler initialisieren
CC00: JSR P_AA ; Ein Bit von Band lesen
TYA ; Bitzähler nach A holen
ROL A ; und gelesenes Bit von rechts hineinschieben
TAY ; Bitzähler zurück nach Y
BCC CC00 ; Rücksprung, falls noch nicht 8 Bit von Band gelesen
STA $D020 ; Gelesenes Byte als Bildschirmfarbe setzen
RTS ; Rückkehr mit gelesenem Byte in A und Y