Uridium/Schnelllader

Aus C64-Wiki
Zur Navigation springenZur Suche springen

<< zurück zu Uridium


Uridium/Schnelllader: Die folgenden Abschnitte stellen den disassemblierten Kassetten-Schnelllader des Spiels Uridium 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 rechts in die Speicherzelle $00A9. 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 BCC-Befehl bei AA00 jeweils auf den hierfür aktuell notwendigen Codeabschnitt.

ORG $033C
      DB $03   ; Code für "Absolut zu ladendes Programm"
      DW $02A7 ; Startadresse
      DW $0304 ; Endadresse+1
      DB $05   ; Code für "weiß"
      DB $0E   ; Code für "Groß-/Kleinbuchstaben"
      DB "Uridium.     "
      DB $9A   ; Code für "hellblau"

; IRQ-Routine des Schnellladers
P_AA: PHA          ; Akku retten
      TYA
      PHA          ; Y-Register retten
      LDA $DC05    ; Timerstand CIA1 Timer holen (High-Byte)
      LDY #$19     ; CIA1 Timer A neu laden und starten (one shot)
      STY $DC0E
      EOR #$02     ; Bit 9 des Timerstands von CIA1 Timer A invertieren
      LSR A        ; in CF übertragen (Timerstand>=512: 0-Bit, <512: 1-Bit)
      LSR A
      ROL *$A9     ; und von rechts in das empfangene Byte schieben
      LDA *$A9     ; Empfangenes Byte nach A holen
AA00: BCC AA01     ; Zentraler Sprungverteiler, falls 0-Bit herausgeschoben
      BCS AA03     ; sonst zum Ende der Interruptroutine
; 1. Einsprung: Suche nach dem ersten Synchronisationszeichen
AA01: CMP #$40     ; Synchronisationszeichen $40 empfangen?
      BNE AA03     ; zum Ende der Interruptroutine falls nicht
      LDA #AA05-AA00-$02
      STA AA00+$01 ; sonst nächstes Byte bei 2. Einsprung verarbeiten lassen
AA02: LDA #$FE     ; Bitzähler %11111110, immer 8 Bit einlesen
      STA *$A9     ; als empfangenes Byte setzen
AA03: LDA $DC0D    ; Interruptanforderung löschen
      PLA          ; Y-Register zurückholen
      TAY
      PLA          ; Akku zurückholen
AA04: RTI          ; Rückkehr aus Interrupt
; 2. Einsprung: Suche nach dem 2. Synchronisationszeichen
AA05: CMP #$40     ; Weiteres Synchronisationszeichen $40 empfangen?
      BEQ AA02     ; dann überlesen
      CMP #$5A     ; Nächstes Synchronisationszeichen $5A empfangen?
      BEQ AA06     ; dann Synchronisation erfolgreich
      LDA #AA05-AA00-$02
      STA AA00+$01 ; sonst Synchronisation neu starten
      BNE AA02     ; Unbedingter Sprung
AA06: LDA #AA07-AA00-$02
      STA AA00+$01 ; Nächstes Byte bei 3. Einsprung verarbeiten lassen
      LDA #$00     ; Prüfsumme für empfangene Bytes initialisieren
      STA *$C1
      BEQ AA02     ; Bitzähler initialisieren und Rückkehr aus Interrupt
; 3. Einsprung: Header einlesen und in Speicher schreiben
AA07: STA *$FB     ; Empfangenes Headerbyte an $FB...$FE speichern
      INC AA07+$01 ; Schreibzeiger für Headerbytes weiterzählen
      LDA AA07+$01 ; und nach A holen
      CMP #$FF     ; Schon alle Headerbytes empfangen?
      BNE AA02     ; Bitzähler initialisieren und Rückkehr aus Interrupt fals nicht
      LDA #AA08-AA00-$02
      STA AA00+$01 ; sonst nächstes Byte bei 4. Einsprung verarbeiten lassen
      BNE AA02     ; Bitzähler initialisieren und Rückkehr aus Interrupt
; 4. Einsprung: Datenblock einlesen und in Speicher schreiben
AA08: LDY #$00     ; Schreibindex für empfangene Bytes initialisieren
      STA ($FB),Y  ; Empfangenes Byte in Speicher schreiben
      EOR *$C1     ; und in Prüfsumme einarbeiten
      STA *$C1
      INC *$FB     ; Schreibzeiger erhöhen, Low-Byte
      BNE AA09     ; Sprung falls kein Überlauf
      INC *$FC     ; Schreibzeiger erhöhen, High-Byte
AA09: LDA *$FB     ; Schreibzeiger mit Endadresse vergleichen, Low-Byte
      CMP *$FD
      LDA *$FC     ; Schreibzeiger mit Endadresse vergleichen, High-Byte
      SBC *$FE
      BCC AA02     ; Sprung falls Endadresse noch nicht erreicht
      LDA #AA10-AA00-$02
      STA AA00+$01 ; sonst nächstes Byte bei 5. Einsprung verarbeiten lassen
      BNE AA02     ; Unbedingter Sprung
; 5. Einsprung: Prüfsumme merken und Flag für "Block gelesen" setzen
AA10: STA *$C2     ; Empfangenes Byte (Prüfsumme) merken
      LDA #$FF     ; Flag für "Block gelesen" setzen
      STA *$02
      LDA #AA01-AA00-$02
      STA AA00+$01 ; Nächste Resynchronisation vorbereiten
AA11: LDA #$FB     ; Schreibzeiger für nächsten Header initialisieren
      STA AA07+$01 ; AA00+$01 ; Nächste Resynchronisation vorbereiten
      BNE AA02     ; Bitzähler initialisieren und Rückkehr aus Interrupt

; Auf Blockende warten, dann Checksumme prüfen und Ladebildschirm starten
P_AB: LDA $D020    ; Rahmenfarbe
      EOR #$08     ; blinken lassen
      STA $D020
      LDA *$02     ; Flag für "Vollständigen Block empfangen"
      BEQ P_AB     ; Rücksprung falls Block noch nicht vollständig empfangen
      JSR P_BB     ; Checksumme prüfen
      LDA #$00     ; Sprung nach $E000 vorbereiten
      STA BA00+$01
      LDA #$E0
      STA BA00+$02
      JMP P_BA     ; Ladebildschirm starten

; Füllbytes ohne Funktion
      DB $20,$20,$20,$20,$20,$20


Initialisierung[Bearbeiten | Quelltext bearbeiten]

Der folgende Programmteil wird beim Laden von Uridium von Kassette gelesen. Dieser Vorgang überschreibt den Vektor 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
P_BA: SEI        ; IRQs verbieten
      LDA #$05   ; Alle ROMs ausblenden
      STA *$01
      LDA #$1F
      STA $DD0D  ; Alle NMIs von CIA2 abschalten
      STA $DC0D  ; Alle IRQs von CIA1 abschalten
      LDA $DD0D  ; Alle NMIs von CIA2 löschen
      LDA $DC0D  ; Alle IRQs von CIA1 löschen
      LDA #$68   ; Startwert von CIA1 Timer A auf $0368 (912) setzen
      STA $DC04  ; Low-Byte
      LDA #$03
      STA $DC05  ; High-Byte
      LDA #$90   ; Signal an CIA1 Pin FLAG löst IRQ aus
      STA $DC0D
      LDA #<P_AA ; IRQ-Vektor
      STA $FFFE  ; Low-Byte setzen
      LDA #>P_AA ; IRQ-Vektor
      STA $FFFF  ; High-Byte setzen
      LDA #<AA04 ; NMI-Vektor auf RTI-Befehl umbiegen
      STA $FFFA  ; Low-Byte
      LDA #>AA04
      STA $FFFB  ; High-Byte
      LDA #$00
      STA *$02   ; Flag für "Block empfangen" löschen
      CLI        ; Interrupts zulassen
BA00: JMP P_AB

P_BB: LDA #$07   ; Alle ROMs einblenden
      STA *$01
      LDA #$00
      STA *$02   ; Flag für "Block empfangen" löschen
      LDA *$C1   ; Errechnete Checksumme nach A holen
      CMP *$C2   ; und mit von Band gelesener Prüfsumme vergleichen
      BNE BB00   ; Sprung falls Prüfsummenfehler
      RTS        ; sonst Rückkehr aus Prüfroutine
BB00: JMP $FCE2  ; Reset

; Füllbytes ohne Funktion
      DB $CD,$98,$20,$B6,$C2,$A5,$5F,$85,$2D

T000: DW $E38B ; Vektor für BASIC-Warmstart
      DW P_BA  ; Vektor für Eingabe einer Zeile (umgebogen auf Initialisierungsroutine des Schnellladers)