Gridtrap/Schnelllader

Aus C64-Wiki
Zur Navigation springenZur Suche springen

<< zurück zu Gridtrap


Gridtrap/Schnelllader: Die folgenden Abschnitte stellen den disassemblierten Kassetten-Schnelllader des Spiels Gridtrap dar. Sie unterteilen sich in den Header des Programms, der bereits bei der Suche nach einem Programm in den Kassettenpuffer übertragen wird, und dem ersten Programmteil, der anschließend geladen und durch Überschreiben des Sprungvektors für die Eingabe einer Zeile automatisch gestartet wird.

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. Im 2. bis 16. Zeichen des Dateinamens wie auch in den darauffolgenden, üblicherweise nicht genutzten 171 Bytes findet sich aber ein großer Teil der Routinen für den Schnelllader.

ORG $033C

      DB $03      ; Code für "Absolut zu ladendes Programm"
      DW $02A5    ; Ladeadresse
      DW $0304    ; Endadresse+1

      DB $1F      ; Erstes Zeichen des Dateinamens: Zeichenfarbe auf "Dunkelblau" setzen

; Programmblock von Band lesen
P_BA: JSR $E1D4   ; Default-Parameter für LOAD und SAVE setzen
      JSR BA01    ; Entspricht "JSR BA00", Synchronisation und Programmblock von Band lesen
      JSR $E17A   ; Abschluss der LOAD-Routine
BA00: JSR P_BB    ; Synchronisation, bis Programm mit Blocknummer ungleich 0 gefunden
BA01: LDA *$AB    ; Nummer des Programmblocks nach A holen
      CMP #$02    ; A mit konstanter Blocknummer 2 vergleichen
      BEQ BA02    ; Sprung, falls Programmblock 2 gefunden (nicht verwendet)
      CMP #$01    ; A mit konstanter Blocknummer 1 vergleichen
      BNE BA00    ; Erneute Synchronisation, falls weder Block 1 noch Block 2 gefunden
BA02: JSR $F5D2   ; "LOADING"/"VERIFYING" ausgeben
      JSR P_BC    ; Laderoutine aufrufen
; Unerreichbarer Code
      LDA *$BD    ; Von Band gelesene Prüfsumme nach A holen
      EOR *$D7    ; mit errechneter Prüfsumme vergleichen
      ORA *$90    ; und mit Statusvariable ST ODER-verknüpfen
      BEQ BA03    ; Sprung, falls Prüfsumme korrekt und Statusvariable gleich $00
      LDA #$FF    ; Sonst Statusvariable ST auf "Fehler setzen"
      STA *$90
BA03: JMP $F5A9   ; Ladevorgang mit Status "OK" beenden

; Synchronisation, bis Programmblock mit Blocknummer ungleich 0 gefunden
P_BB: JSR P_BF    ; Synchronisation
      CMP #$00    ; Erneute Synchronisation, falls Blocknummer $00 folgt
      BEQ P_BB
      STA *$AB    ; Blocknummer merken
      JMP BD00    ; Bandbetrieb beenden

; Laderoutine
P_BC: JSR P_BF    ; Synchronisation
BC00: JSR P_AB    ; Ein Byte von Band lesen und in A zurückliefern
      CPY *$93    ; Flag für LOAD/VERIFY mit "LOAD" vergleichen
      BNE BC01    ; Sprung falls "VERIFY"
      STA ($C3),Y ; Gelesenes Byte in Speicher schreiben
BC01: INC $D020   ; Bildschirm-Rahmenfarbe hochzählen
      NOP
      STX *$90    ; Statusvariable ST auf $01 setzen
      EOR *$D7    ; Gelesenes Byte in Prüfsumme einarbeiten
      STA *$D7    ; und Prüfsumme zurückschreiben
      INC *$C3    ; Schreibzeiger erhöhen (Low-Byte)
      BNE BC02    ; Sprung falls kein Überlauf
      INC *$C4    ; Schreibzeiger erhöhen (High-Byte)
BC02: LDA *$C3    ; Schreibzeiger nach A holen (Low-Byte)
      CMP #$00    ; und mit Endadresse des Programms vergleichen (Low-Byte)
      LDA *$C4    ; Schreibzeiger nach A holen (High-Byte)
      SBC #$6F    ; und mit Endadresse des Programms vergleichen (High-Byte)
      BCC BC00    ; Weiter laden, falls Endadresse noch nicht erreicht
      JSR P_AB    ; Ein Byte von Band holen und in A zurückliefern (Prüfsumme, anschließend ignoriert)
      JMP P_BG    ; Fälschlicherweise Bandbetrieb nochmals starten (statt beenden) und Spiel starten

; Bandbetrieb beenden
P_BD: INY         ; Befehl nie ausgeführt; Einsprung über BD00
BD00: STY *$C0    ; Recordermotor ausschalten
      CLI         ; Interrupts wieder zulassen
      CLC
      LDA #$00    ; Interruptvektor während Bandbetrieb ungültig machen
      STA $02A0
      JMP $FC93   ; Recorderbetrieb beenden

; Bandbetrieb starten
P_BE: LDY #$00    ; Recordermotor einschalten
      STY *$C0
      LDA $D011   ; Bildschirm ausschalten
      AND #$EF
      STA $D011
BE00: DEX         ; Etwa 330 ms Verzögerung
      BNE BE00
      DEY
      BNE BE00
      SEI         ; Interrupts während Ladevorgang abschalten
      RTS

; Synchronisation, liefert Nummer des Programmblocks zurück
P_BF: JSR $F817   ; Warten auf Bandtaste
      JSR P_BE
      STY *$D7
      LDA #$07    ; Timer B Low-Byte
      STA $DD06   ; setzen
      LDX #$01    ; Timer B High-Byte
BF00: JSR P_AC    ; 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 BF00    ; Rücksprung falls nicht
      LDY #$09
BF01: JSR P_AB    ; Byte von Band lesen
      CMP #$02    ; Weitere Synchronisationszeichen $02 überlesen
      BEQ BF01
BF02: CPY *$BD    ; Synchronisationszeichen $09,...,$01 gelesen?
      BNE BF00    ; Erneute Synchronisation falls nicht
      JSR P_AB    ; Byte von Band lesen
      DEY         ; Synchronisationszeichen herunterzählen
      BNE BF02    ; Sprung falls noch nicht alle Synchronisationszeichen $09..$01 gelesen
      RTS         ; Rückkehr zur aufrufenden Routine

; Programm laden und dann Spiel durch Sprung an Startadresse $6E00 starten
P_BG: JSR P_BE    ; Bandbetrieb starten
      JMP $6E00   ; Spiel starten

Programmblock[Bearbeiten | Quelltext bearbeiten]

Die Programmdaten, die beim Laden der ersten Datei von den Datassettenroutinen des Kernals in den Speicher übertragen werden, enthalten in erster Linie drei weitere Routinen des Schnellladers, die im Programmheader keinen Platz mehr gefunden haben. Die Ladeadresse dieses Programms ist so gewählt, dass es zudem mit seinen letzten beiden Bytes den BASIC-Vektor für die Eingabe einer Zeile mit der Anfangsadresse des Schnellladers überschreibt, so dass dieser anschließend automatisch startet.

PRG $02A5

      DB  $00     ; Bildschirmzeile
      DB  $01     ; Flag für PAL- oder NTSC-Version (1="PAL")

; Mittels "CBM80"-Kennung Steckmodul ab Adresse $8000 vortäuschen, dann Ladevorgang starten
P_AA: LDX #$0A       ; Anzahl zu kopierender Bytes
AA00: LDA AA01-$01,X ; Vektoren und "CBM80"-Kennung lesen
      STA $7FFF,X    ; und an Adresse $8000 kopieren
      DEX            ; Schreibindex vermindern
      BNE AA00       ; Rücksprung, falls noch nicht alle Bytes kopiert
      JMP P_AD       ; Sprung zur Laderoutine

AA01: DW  P_AD                ; Reset-Vektor
      DW  P_AD                ; NMI-Vektor
      DB  $C3,$C2,$CD,$38,$30 ; "CBM80"-Kennung
      DB  $00,$40             ; Füllbytes

; Ein Byte von Band lesen und in A zurückliefern
P_AB: LDA #$08    ; Bitzähler initialisieren
      STA *$A3
AB00: JSR P_AC    ; Ein Bit von Band lesen und nach CF
      ROL *$BD    ; Gelesenes Bit von rechts in Speicherzelle $BD schieben
      NOP         ; 6 us warten
      NOP
      NOP
      DEC *$A3    ; Bitzähler vermindern
      BNE AB00    ; 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
P_AC: LDA #$10    ; Bitmaske für Interrupt durch Pin FLAG
AC00: BIT $DC0D   ; Auf Interrupt prüfen
      BEQ AC00    ; 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 in aufrufende Routine

; Initialisierung
P_AD: LDX #$00    ; LOAD/VERIFY Flag
      LDY #<$17FA ; Startadresse für Laden, Low-Byte
      LDA #>$17FA ; Startadresse für Laden, High-Byte
      STX *$0A    ; LOAD/VERIFY-Flag auf "LOAD" setzen
      STX *$93    ; LOAD/VERIFY-Flag auf "LOAD" setzen
      STX *$90    ; Statuswort ST löschen
      STY *$C3    ; Startadresse für Laden auf $17FA setzen
      STA *$C4     
      INC $D020   ; Bildschirm-Rahmenfarbe weiterzählen
      JMP P_BA    ; Zur Laderoutine im Header des Programms springen

      DW  $8000   ; Vektor für BASIC-Warmstart, ungültig
      DW  P_AA    ; Vektor für Eingabe einer Zeile, umgebogen auf Schnelllader