Loco/Schnelllader

Aus C64-Wiki
Zur Navigation springenZur Suche springen

<< zurück zu Loco


Loco/Schnelllader: Die folgenden Abschnitte stellen den disassemblierten Kassetten-Schnelllader des Spiels Loco dar. Sie sind gegliedert in einzelne Codeblöcke, die gemäß ihrer Funktion während und nach dem Laden gruppiert sind.

Startblock der Datassetten-Datei[Bearbeiten | Quelltext bearbeiten]

Das folgende Datensegment ist der erste Block auf der Kassette, sollte also nur den Dateityp, die Anfangs- und Endadresse sowie den Namen des Spiels enthalten. In den darauffolgenden, üblicherweise nicht genutzten 171 Bytes findet sich aber der Code des ebenso kompakten wie leistungsfähigen Schnellladers.

ORG $033C

      DB $03      ; Kennzeichen für "Absolut zu ladende Datassetten-Datei"
      DW $0300    ; Anfangsadresse
      DW $0334    ; Endadresse+1
      DB 'LOCO BY A.R.C.',$00,$00 ; Antony 'Ratt' Crowther

; Programmblock von Band lesen und starten
P_AA: JSR P_AB    ; Byte von Band lesen
      CMP #$00    ; Füllbytes $00 überlesen
      BEQ P_AA
      JSR P_AC    ; Byte von Band lesen
      STA *$C1    ; und als Startadresse (Low-Byte) speichern
      JSR P_AC    ; Byte von Band lesen
      STA *$C2    ; und als Startadresse (High-Byte) speichern
      JSR P_AC    ; Byte von Band lesen
      STA *$2D    ; und als Endadresse+1 (Low-Byte) speichern
      JSR P_AC    ; Byte von Band lesen
      STA *$2E    ; und als Endadresse+1 (High-Byte) speichern
AA00: JSR P_AC    ; Programmbyte von Band lesen
      STA ($C1),Y ; und in Speicher schreiben
      INC *$C1    ; Schreibzeiger erhöhen (Low-Byte)
      BNE AA01    ; Sprung falls kein Übertrag
      INC *$C2    ; Schreibzeiger erhöhen (High-Byte)
AA01: LDA *$C1    ; Schreibzeiger holen (Low-Byte)
      CMP *$2D    ; und mit Endadresse+1 vergleichen (Low-Byte)
      LDA *$C2    ; Schreibzeiger holen (High-Byte)
      SBC *$2E    ; und mit Endadresse+1 vergleichen (High-Byte)
      BCC AA00    ; Rücksprung falls Endadresse noch nicht erreicht
      STY $02A0   ; Y=0 in IRQ-Vektor während Bandbetrieb schreiben (?)
      JSR $FC93   ; Recorderbetrieb beenden
      JSR $FD15   ; Hardware und I/O-Vektoren setzen
      STY *$C0    ; Flag für Bandmotor auf $FF setzen
      CLI         ; Interrupts wieder zulassen
      JSR $E453   ; BASIC-Vektoren laden
      LDA #$FE    ; STOP-Vektor verbiegen
      STA $0328   ; und damit Stop-Taste deaktivieren
      JSR $A660   ; BASIC-Befehl CLR
      JSR $A68E   ; Programmzeiger auf BASIC-Start
      JMP $A7AE   ; Interpreterschleife

; Initialisierung und Synchronisation
P_AB: LDY #$00  ; Recordermotor einschalten
      STY *$C0
      LDA #$0B  ; Bildschirm ausschalten
      STA $D011
AB00: DEX       ; Etwa 0.33 s Verzögerung
      BNE AB00
      DEY
      BNE AB00
      SEI       ; Interrupts während Ladevorgang abschalten
      LDA #$07  ; Timer B Low-Byte
      STA $DD06 ; setzen
      LDX #$01  ; Timer B High-Byte
AB01: JSR P_AD  ; setzen und ein Bit von Band holen
      ROL *$BD  ; Gelesenes Bit von rechts in Speicherzelle $BD schieben
      LDA *$BD
      CMP #$02  ; Synchronisationszeichen $02 gelesen?
      BNE AB01  ; Rücksprung falls nicht
      LDY #$09
AB02: JSR P_AC  ; Byte von Band lesen
      CMP #$02  ; Weitere Synchronisationszeichen $02 überlesen
      BEQ AB02
AB03: CPY *$BD  ; Synchronisationszeichen $09,...$01 gelesen?
      BNE AB01  ; Erneute Synchronisation falls nicht
      JSR P_AC  ; Byte von Band lesen
      DEY       ; Synchronisationszeichen herunterzählen
      BNE AB03  ; Sprung falls noch nicht alle Synchronsationszeichen $09..$01 gelesen
      RTS       ; Rückkehr zur aufrufenden Routine

; Ein Byte von Band lesen und nach A
P_AC: LDA #$08  ; Bitzähler
      STA *$A3  ; initialisieren
AC00: JSR P_AD  ; Ein Bit von Band lesen und nach CF
      ROL *$BD  ; Gelesenes Bit von rechts in Speicherzelle $BD schieben
      DEC *$A3  ; Bitzähler vermindern
      BNE AC00  ; Rücksprung falls noch nicht 8 Bit gelesen
      LDA *$BD  ; Gelesenes Byte nach A holen
      RTS       ; Rückkehr zur aufrufenden Routine

; Ein Bit von Band lesen und nach CF
P_AD: LDA #$10  ; Bitmaske für Interrupt durch Pin FLAG
AD00: BIT $DC0D ; Auf Interrupt prüfen
      BEQ AD00  ; Rücksprung falls kein Impuls vom Band
      LDA $DD0D ; Interruptanforderungen CIA2 holen und löschen
      STX $DD07 ; CIA2 Timer B High-Byte auf 1 setzen
      PHA       ; A retten
      LDA #$19  ; CIA2 Timer B neu laden und starten (one shot)
      STA $DD0F
      PLA       ; A zurückholen
      LSR A     ; Bit für "Unterlauf Timer B" nach CF
      LSR A
      RTS       ; Rückkehr zur aufrufenden Routine
      NOP

Programmblock[Bearbeiten | Quelltext bearbeiten]

Die Programmdaten, die beim Laden der Datei "LOCO BY A.R.C." von den Datassettenroutinen des Kernals in den Speicher übertragen werden, enthalten keinen ausführbaren Code, sondern überschreiben lediglich die meisten der BASIC-Vektoren mit der Startadresse des Schnellladers und erzwingen damit einen Autostart.

PRG $0300

      DW P_AA  ; Vektor für BASIC-Warmstart
      DW P_AA  ; Vektor für Eingabe einer Zeile
      DW P_AA  ; Vektor für Umwandlung in Interpretercode
      DW P_AA  ; Vektor für Umwandlung in Klartext (LIST)
      DW P_AA  ; Vektor für BASIC-Befehlsadresse holen
      DW P_AA  ; Vektor für Ausdruck auswerten
      DB $00   ; Akku für SYS-Befehl
      DB $00   ; X-Reg für SYS-Befehl
      DB $00   ; Y-Reg für SYS-Befehl
      DB $00   ; Status-Register für SYS-Befehl
      DB $00   ; eigentlich JMP-Befehl für USR-Funktion
      DW $0000 ; eigentlich USR-Vektor
      DB $00
      DW $EA31 ; IRQ-Vektor
      DW $FEC1 ; BRK-Vektor
      DW $FEC1 ; NMI-Vektor
      DW P_AA  ; OPEN-Vektor
      DW P_AA  ; CLOSE-Vektor
      DW P_AA  ; CHKIN-Vektor
      DW P_AA  ; CKOUT-Vektor
      DW P_AA  ; CLRCH-Vektor
      DW P_AA  ; INPUT-Vektor
      DW P_AA  ; OUTPUT-Vektor
      DW $E68E ; STOP-Vektor
      DW P_AA  ; GET-Vektor
      DW P_AA  ; CLALL-Vektor
      DW P_AA  ; Warmstart-Vektor
      DW P_AA  ; LOAD-Vektor
      DW P_AA  ; SAVE-Vektor