Tales of the Arabian Nights/Schnelllader
<< zurück zu Tales of the Arabian Nights
Tales of the Arabian Nights/Schnelllader: Die folgenden Abschnitte stellen den disassemblierten Kassetten-Schnelllader des Spiels "Tales of the Arabian Nights" 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]
Direkt hinter dem Dateinamen findet sich im allerersten Block auf Kassette die Interruptroutine des Schnellladers. Diese liest ein einzelnes Bit von Kassette und schiebt dieses von links in die Speicherzelle $00BD. Falls es Zeit ist, den Inhalt dieser Speicherzelle zu verarbeiten (während der Synchronisation nach jedem Bit, später nach jedem 8. Bit), so zeigt der BEQ-Befehl bei AA00 jeweils auf den hierfür aktuell notwendigen Codeabschnitt.
; IRQ-Routine des Schnellladers
ORG $033C
DB $03 ; Code für "Absolut zu ladendes Programm"
DW $02A7 ; Ladeadresse
DW $0304 ; Endadresse+1
DB $93 ; Code für "Bildschirm löschen"
DB $08 ; Code für "Umschaltung Groß-/Kleinschreibung verriegeln"
DB $05 ; Code für "Zeichenfarbe weiß"
DB $8E ; Code für "Umschaltung auf Großbuchstaben"
DB "arabian"
DB $1F ; Code für "Zeichenfarbe dunkelblau"
DB " "
; IRQ-Routine des Schnellladers
P_AA: DEC $C76D ; Quadrat im Ladebildschirm flackern lassen
PHA ; Akku auf Stack retten
LDA #$91 ; CIA 2 Timer 1 neu laden und starten
STA $DD0E
LDA $DD0D ; Interruptanforderungen CIA 2 lesen und löschen
LSR A ; Gelesenes Bit (Unterlauf CIA 2 Timer 1) ins CF
LDA $DC0D ; IRQ-Anforderungen CIA 1 löschen
ROR *$BD ; Gelesenes Bit von links in Speicherzelle $BD schieben
LDA *$BD ; Bisher gelesene Bits in Akku holen
DEY ; Bitzähler vermindern
AA00: BEQ P_AB ; Sprungverteiler: Sprung falls genügend Bits empfangen
AA01: PLA ; sonst Akku vom Stack zurückholen
RTI ; und Rückkehr aus Interruptroutine
; 1. Einsprung: Bitweise Synchronisation
P_AB: CMP #$A0 ; Synchronisationszeichen $A0 gelesen?
BNE AC01 ; Sprung falls nicht, dann weiter bitweise synchronisieren
LDA #P_AC-AA01 ; sonst Übergang zu byteweiser Synchronisation
STA AA00+$01 ; Sprungverteiler auf 2. Einsprung richten
BNE AD00 ; Bitzähler auf 8 setzen und Rückkehr aus Interrupt
; 2. Einsprung: Byteweise Synchronisation
P_AC: CMP #$A0 ; Synchronisationszeichen $A0 gelesen?
BEQ AD00 ; Dann weiter byteweise synchronisieren
CMP #$0A ; Synchronisationszeichen $0A gelesen?
BEQ AC02 ; Dann Übergang zum Countdown
AC00: LDA #P_AB-AA01 ; Sonst wieder zurück zur bitweisen Synchronisation
STA AA00+$01 ; Sprungverteiler auf 1. Einsprung richten
AC01: INY ; Bitzähler auf 1 setzen
PLA ; Akku vom Stack zurückholen
RTI ; und Rückkehr aus Interruptroutine
AC02: LDA #P_AD-AA01 ; Übergang zur 3. Phase
STA AA00+$01
LDA #$09 ; Startwert für Countdown auf 9 setzen
STA P_AD+$01
BNE AD00 ; Bitzähler auf 8 setzen und Rückkehr aus Interruptroutine
; 3. Einsprung: Countdown
P_AD: CMP #$00 ; Korrektes Byte für Countdown gelesen
BNE AC00 ; Zurück zur bitweisen Synchronisation falls nicht
DEC P_AD+$01 ; sonst Countdown weiterzählen
BNE AD00 ; Sprung falls Countdown noch nicht zu Ende
LDA #P_AE-AA01 ; Sprungverteiler auf 4. Einsprung richten
STA AA00+$01
LDA #$FC ; Schreibzeiger für Headerbytes setzen
STA P_AE+$01
AD00: LDY #$08 ; Bitzähler auf 8 setzen
PLA ; Akku vom Stack zurückholen
RTI ; Rückkehr aus Interruptroutine
; 4. Einsprung: 4 Headerbytes des Programmblocks einlesen
P_AE: STA *$00 ; 4 Headerbytes nach $00FC..$00FF einlesen
INC P_AE+$01 ; Schreibzeiger für Headerbytes weiterbewegen
BNE AD00 ; Sprung falls noch nicht 4 Headerbytes
LDA #P_AF-AA01 ; Sprungverteiler auf 5. Einsprung richten
STA AA00+$01
STY *$AB ; Prüfsumme löschen
LDY #$08 ; Bitzähler auf 8 setzen
PLA ; Akku vom Stack zurückholen
RTI ; Rückkehr aus Interruptroutine
; 5. Einsprung: Programm byteweise in den Speicher einlesen
P_AF: STA ($FC),Y ; Gelesenes Datenbyte in Speicher schreiben
EOR *$AB ; und in Prüfsumme einarbeiten
STA *$AB
INC *$FC ; Schreibzeiger erhöhen (Low-Byte)
BNE AF00 ; Sprung falls kein Überlauf
INC *$FD ; sonst Schreibzeiger erhöhen (High-Byte)
DEC *$FB ; ohne Funktion (Page-Counter vermindern)
AF00: INC *$FE ; Bytezähler erhöhen (Low-Byte)
BNE AF01 ; Sprung falls kein Überlauf
INC *$FF ; sonst Bytezähler erhöhen (High-Byte)
BNE AF01 ; Sprung falls noch nicht ganzer Block geladen
LDA #P_AG-AA01 ; sonst Sprungverteiler auf 6. Einsprung richten
STA AA00+$01
AF01: LDY #$08 ; Bitzähler auf 8 setzen
PLA ; Akku vom Stack zurückholen
RTI ; Rückkehr aus Interruptroutine
; 6. Einsprung: Prüfsumme einlesen und vergleichen
P_AG: EOR *$AB ; Gelesene und errechnete Prüfsumme vergleichen
BEQ AG00 ; Sprung falls übereinstimmend
LDA #$37 ; sonst alle ROMs wieder einblenden
STA *$01
JMP $FCF2 ; und Kaltstart auslösen
AG00: LDA #$01 ; Quadrat im Ladebildschirm weiß färben
STA $C76D
DEC *$FA ; Zähler für Programmteile vermindern
BNE AC00 ; Erneute Synchronisation falls noch nicht alle Programmteile gelesen
LDA #$37 ; Alle ROMs wieder einblenden
STA *$01
JSR $FF84 ; CIAs initialisieren
JMP $C8B0 ; und geladenes Programm ausführen
; Füllbytes ohne Funktion
DB $00,$00,$00,$00,$00
Initialisierung[Bearbeiten | Quelltext bearbeiten]
Der folgende Programmteil wird beim Laden von "Tales of the Arabian Nights" von Kassette gelesen. Dieser Vorgang überschreibt die Vektoren für den BASIC-Warmstart und für die Eingabe einer BASIC-Zeile mit der Startadresse des Schnellladers und löst damit nach dem Ende des Ladevorgangs einen Autostart aus.
PRG $02A7
; Initialisierung des Schnellladers
P_BA: SEI ; Interrupts verbieten
LDA #$7F ; Ausstehende Interruptanforderungen löschen
STA $DC0D ; für CIA 1
STA $DD0D ; und CIA 2
LDY #$00 ; Ausstehende Interruptanforderungen löschen
STY $D01A ; für VIC
STY $D020 ; Farbe des Bildschirmrands auf "schwarz" setzen
STY $DD0E
LDA #$4D ; Startwert von Timer A in CIA 2 auf $014D setzen
STA $DD04 ; Low-Byte
LDA #$01
STA $DD05 ; High-Byte
LDA #$90 ; CIA 1 löst IRQ bei Impuls an Pin FLAG aus
STA $DC0D
LDA #<P_AA ; Interruptvektor auf Schnelllader umbiegen
STA $FFFE
LDA #>P_AA
STA $FFFF
LDA #$05 ; Alle ROMs ausblenden
STA *$01
LDA #$FF
STA *$FB ; ohne Funktion (Page-Zähler initialisieren)
STA *$05 ; ohne Funktion
LDA #$07 ; Zähler für Anzahl der zu ladenden Programmteile setzen
STA *$FA
BA00: NOP ; 486 ms Pause
DEX
BNE BA00
DEY
BNE BA00
INY ; Bitzähler auf 1 setzen
CLI ; Interrupts wieder zulassen
CMP *$FA ; Warten, bis erster Programmteil geladen
BEQ $02EB ;
JMP $C800 ; dann Programmteil ausführen (Initialisierung des VIC für Ladebildschirm)
; Füllbytes ohne Funktion
DB $07,$BC,$81,$08,$C0,$20,$D0,$1C,$AC,$52,$08,$B9,$49,$21
T000: DW P_BA ; Vektor für BASIC-Warmstart (umgebogen auf Initialisierungsroutine des Schnellladers)
DW P_BA ; Vektor für Eingabe einer Zeile (umgebogen auf Initialisierungsroutine des Schnellladers)