Uridium/Schnelllader
<< 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)