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