Aquanaut (Interceptor)/Schnelllader
<< zurück zu Aquanaut (Interceptor)
Aquanaut_(Interceptor)/Schnelllader: Die folgenden Abschnitte stellen den disassemblierten Kassetten-Schnelllader des Spiels Aquanaut (Interceptor) dar. Sie sind gegliedert in einzelne Codeblöcke, die gemäß ihrer Funktion während und nach dem Laden gruppiert sind.
Erster Programmblock (Autostart)[Bearbeiten | Quelltext bearbeiten]
Das folgende, kurze Programm ist auf der Kassette unter dem Namen "AQUANAUT" gespeichert, wobei dem Dateinamen noch das Steuerzeichen CHR$(147) (Bildschirm löschen) und viermal der Code CHR$(17) (Cursor abwärts) vorangestellt sind. Das Programm bewirkt einen Autostart sowie das Nachladen und Aktivieren des eigentlichen Schnellladers.
ORG $02A7 ; Nachladen des eigentlichen Schnellladers P_AA: LDA #$00 LDX #$01 STX *$B9 ; Sekundäradresse=1 STX *$BA ; Geräteadresse=1 STX *$B8 ; Logische Dateinummer=1 DEX STX *$B7 ; Länge des Dateinamens=0 LDA #$00 ; (überflüssig, bereits A=$00) STA *$9D ; Modus=Programm JSR $F4A5 ; Einsprung in LOAD-Befehl JMP AB01 ; Hauptschleife der Laderoutine P_AB: LDX #$00 ; Kennzeichen für "LOAD" DB $2C ; BIT abs (nächsten 2-Byte-Befehl überspringen) AB00: LDX #$01 ; Kennzeichen für "VERIFY" (nie verwendet) LDY *$2B ; Anfang BASIC-Programm (Low-Byte) LDA *$2C ; Anfang BASIC-Programm (High-Byte) STX *$0A ; LOAD/VERIFY-Flag STX *$93 ; LOAD/VERIFY-Flag STY *$C3 ; Endadresse Ladevorgang (Low-Byte) STA *$C4 ; Endadresse ladevorgang (High-Byte) JSR $E1D4 ; Parameter für LOAD und SAVE holen JSR P_BC ; Programmteil per Schnelllader laden JSR $E17A ; Ergebnis von LOAD ausgeben AB01: LDA #$E1 STA $0328 ; STOP-Vektor ungültig machen NOP NOP NOP LDX T000 ; Zähler für zu ladende Programmteile DEX ; vermindern NOP NOP STX T000 ; und zurückschreiben CPX #$00 ; Alle Programmteile nachgeladen? (überflüssiger Vergleich) BEQ AB02 ; Sprung falls ja JMP P_AB ; sonst nächsten Programmteil nachladen AB02: LDA #$83 ; Vektor für Eingabe einer Zeile wiederherstellen STA $0302 ; Low-Byte LDA #$A4 STA $0303 ; High-Byte JMP P_BB ; Zum Abschluss des Ladevorgangs und Start des Spiels DB $00,$00 ; Füllbytes T000: DB $03 ; Zähler für nachzuladende Programmteile T001: DW $E302 ; Vektor für BASIC-Warmstart (ungültig) DW P_AA ; Vektor für Eingabe einer Zeile (umgebogen auf Laderoutine)
Zweiter Programmblock (Schnelllader)[Bearbeiten | Quelltext bearbeiten]
Die folgenden Routinen werden als Programm unter dem Namen "P1" mit Hilfe der Datassetten-Routinen des Kernal nachgeladen. Durch Aufruf der Routine P_BC
wird jeweils ein Programmblock (Header und Daten) von Band gelesen und in den Speicher geschrieben. Aus der Hauptschleife der Laderoutine heraus wird P_BC nacheinander zwei Mal aufgerufen.
PRG $0400 ; Bandbetrieb vorbereiten P_BA: LDY #$00 ; Flag für Bandmotor löschen STY *$C0 LDA $D011 ; Bildschirm abschalten AND #$EF STA $D011 BA00: DEX ; Etwa 330 ms warten BNE BA00 DEY BNE BA00 SEI ; Interrupts verbieten RTS DB $00,$00,$00 ; Abschluss der Laderoutine und Start des Spiels P_BB: LDA #$2D ; Korrekturen am Programmcode STA $86FE ; vornehmen LDA #$20 STA $A2DA LDA #$95 ; Zeichenfarbe "Braun" JSR $FFD2 ; BSOUT Ausgabe eines Zeichens JMP $6182 ; Spiel starten NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP ; Header eines Programmblocks einlesen und verarbeiten, dann Programmblock laden P_BC: JSR P_BD ; Header in Kassettenpuffer einlesen LDA *$AB ; Letztes Byte der Synchronisationssequenz CMP #$02 ; mit gültigem Wert vergleichen BEQ BC00 ; Sprung falls gleich CMP #$01 ; mit weiterem gültigem Wert vergleichen BNE P_BC ; Rücksprung falls nicht NOP NOP NOP NOP BC00: LDA $033C ; Startadresse (Low-Byte) STA *$C3 ; als Schreibzeiger umkopieren (Low-Byte) LDA $033D ; Startadresse (High-Byte) STA *$C4 ; als Schreibzeiger umkopieren (High-Byte) JSR $F750 ; "FOUND " und Dateiname ausgeben NOP NOP NOP NOP NOP JSR $A82C ; STOP-Taste abfragen LDY *$B7 ; Länge des Dateinamens BEQ BC02 ; Sprung falls kein Dateiname BC01: DEY ; Lesezeiger vermindern LDA ($BB),Y ; Angegebenen Dateinamen zeichenweise lesen CMP $0341,Y ; und mit gefundenem Dateinamen vergleichen BNE P_BC ; Nächsten Header suchen und laden falls ungleich TYA ; Alle Zeichen verglichen? BNE BC01 ; Rücksprung falls nicht BC02: STY *$90 ; Status ST auf "OK" initialisieren JSR $F5D2 ; "LOADING" ausgeben LDA $033E ; Bisherige Endadresse des Programms lesen (Low-Byte) SEC SBC $033C ; und bisherige Anfangsadresse subtrahieren (Low-Byte) PHP CLC ADC *$C3 ; und Differenz zur Startadresse addieren (Low-Byte) STA *$AE ; und als Endadresse speichern (Low-Byte) LDA $033F ; Bisherige Endadresse des Programms lesen (High-Byte) ADC *$C4 ; zur Startadresse addieren (High-Byte) PLP SBC $033D ; und bisherige Anfangsadresse subtrahieren (High-Byte) STA *$AF ; und als Endadresse speichern (High-Byte) JSR P_BE ; Programmblock laden LDA *$BD ; Letztes gelesenes Byte (Prüfsumme) holen EOR *$D7 ; durch XOR mit errechneter Prüfsumme vergleichen ORA *$90 ; und mit Status ST verknüpfen BEQ BC03 ; Sprung falls alles fehlerfrei LDA #$FF ; sonst Status ST STA *$90 ; auf "ungültig" setzen BC03: JMP $F5A9 ; Endadresse nach X/Y holen ; Header in Kassettenpuffer einlesen P_BD: JSR P_BF ; Ladevorgangs starten, Synchronisation CMP #$00 ; Synchronisation gescheitert? BEQ P_BD ; Rücksprung zur erneuten Synchronisation falls ja STA *$AB ; sonst letztes Byte der Synchronisationssequenz merken BD00: JSR P_BG ; Ein Byte von Band lesen STA ($B2),Y ; und in Kassettenpuffer schreiben INY ; Schreibindex erhöhen CPY #$C0 ; Schon ganzen Header in Kassettenpuffer eingelesen? BNE BD00 ; Rücksprung falls noch nicht BEQ BE04 ; Unbedingter Sprung zum Ende des Bandbetriebs ; Programmblock laden oder vergleichen P_BE: JSR P_BF ; Ladevorgang starten, Synchronisation BE00: JSR P_BG ; Ein Byte von Band lesen CPY *$93 ; LOAD- oder VERIFY-Phase? BNE BE01 ; Sprung falls VERIFY STA ($C3),Y ; Gelesenes Datenbyte in Speicher schreiben BE01: CMP ($C3),Y ; Gelesenes Datenbyte mit Speicher vergleichen BEQ BE02 ; Sprung falls gleich STX *$90 ; sonst Status ST auf "..." setzen BE02: EOR *$D7 ; Datenbyte in Prüfsumme einarbeiten STA *$D7 ; und Prüfsumme zurückschreiben INC *$C3 ; Schreibzeiger erhöhen (Low-Byte) BNE BE03 ; Sprung falls kein Übertrag INC *$C4 ; Schreibzeiger erhöhen (High-Byte) BE03: LDA *$C3 ; Schreibzeiger holen (Low-Byte) CMP *$AE ; und mit Endadresse vergleichen (Low-Byte) LDA *$C4 ; Schreibzeiger holen (High-Byte) SBC *$AF ; und mit Endadresse vergleichen (High-Byte) BCC BE00 ; Rücksprung falls Endadresse noch nicht erreicht JSR P_BG ; Weiteres Byte von Band lesen und ignorieren JSR P_BA ; Bandmotor starten, Bildschirm abschalten INY BE04: STY *$C0 CLI ; Interrupts wieder zulassen CLC ; Zeichen für "kein Fehler" LDA #$00 STA $02A0 JMP $FC93 ; Bandbetrieb beenden ; Start des Ladevorgangs und Synchronisation P_BF: JSR $F817 ; Bandbetrieb beginnen JSR P_BA ; Bandmotor starten, Bildschirm abschalten STY *$D7 ; Prüfsumme mit Y=0 initialisieren LDA #$07 ; Low-Byte CIA2 Timer B auf 7 setzen STA $DD06 LDX #$01 ; High-Byte CIA2 Timer B BF00: JSR P_BH ; Ein Bit von Band lesen ROL *$BD ; und von rechts in Speicher an Adresse $BD schieben LDA *$BD ; Bisher gelesenes Byte holen CMP #$02 ; und mit Synchronisationsbyte $02 vergleichen BNE BF00 ; Rücksprung falls nicht LDY #$09 ; Länge der Synchronisations-Sequenz BF01: JSR P_BG ; Ein Byte von Band lesen CMP #$02 ; Weiteres Synchronisationsbyte $02? BEQ BF01 ; Überlesen falls ja BF02: CPY *$BD ; Ansonsten gelesene Bytes mit Sequenz $09...$01 vergleichen BNE BF00 ; Synchronisation neu starten falls ungleich JSR P_BG ; Nächstes Byte von Band lesen DEY ; Zähler für Synchronisationssequenz vermindern BNE BF02 ; Rücksprung, falls Sequenz noch nicht zu Ende RTS ; Ein Byte von Band lesen P_BG: LDA #$08 ; Bitzähler initialisieren (8 Bits) STA *$A3 BG00: JSR P_BH ; Ein Bit von Band lesen ROL *$BD ; und von rechts in Speicher an Adresse $00BD schieben NOP NOP NOP DEC *$A3 ; Bitzähler vermindern BNE BG00 ; Rücksprung falls noch nicht 8 Bits von Band gelesen LDA *$BD ; Gelesenes Byte in A zurückliefern RTS ; Ein Bit von Band lesen P_BH: LDA #$10 ; Auf Impuls an Pin FLAG warten BH00: BIT $DC0D BEQ BH00 LDA $DD0D ; Interruptregister CIA2 holen STX $DD07 ; High-Byte von CIA2 Timer B auf X=1 setzen PHA ; Interruptregister CIA2 retten LDA #$19 ; CIA2 Timer B neu laden und starten (one shot) STA $DD0F PLA ; Interruptregister CIA2 zurückholen LSR A ; CF setzen, falls CIA2 Timer B abgelaufen LSR A RTS