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)