Tales of the Arabian Nights/Schnelllader

Aus C64-Wiki
Zur Navigation springenZur Suche springen

<< 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)