Alien Syndrome/Schnelllader
<< zurück zu Alien Syndrome
Alien Syndrome/Schnelllader: Die folgenden Abschnitte stellen den disassemblierten Floppy-Schnelllader des Spiels Alien Syndrome dar. Sie sind gegliedert in einzelne Codeblöcke, die gemäß ihrer Funktion vor dem und während des Ladens gruppiert sind.
Floppy-seitige Schnelllade-Routinen[Bearbeiten | Quelltext bearbeiten]
Die folgenden Routine P_AA
liest den nachzuladenden Programmteil Sektor für Sektor in Puffer 0 (ab Adresse $0300) ein und folgt dabei den Verkettungszeigern in den ersten beiden Bytes jedes Sektors. Aus dem Sektor werden, jeweils beginnend ab Offset 2, alle gültigen Datenbytes an den C64 gesandt. Die Übertragung eines Bytes übernimmt hierbei die Routine P_AB
.
DEVICE EQU $08 ; Geräteadresse 8 SOURCE1: P_AA: LDA #$08 ; CLOCK low STA $1800 LDA #$C8 ; Standardwert setzen STA *$64 ; für Zahl der Halbspurschritte bis Spur 0 LDA #$20 ; Rate des Jobschleifen-Interrupt erhöhen (alle 8 ms statt alle 14 ms) STA $1C07 ; VIA 2 Timer 1 High-Byte LDA *$18 ; Spur des zuletzt gelesenen Blocks LDX *$19 ; Sektor des zuletzt gelesenen Blocks STA *$06 ; als Spur von Puffer 0 merken STX *$07 ; als Sektor von Puffer 0 merken AA00: CLI ; Interrupts erlauben (Jobschleife aktivieren) LDY #$0F ; Anzahl Leseversuche AA01: LDA #$80 ; Jobcode "Lesen eines Sektors" STA *$00 ; als Job für Puffer 0 merken AA02: LDA *$00 ; Warten bis Job ausgeführt BMI AA02 CMP #$01 ; Kein Fehler? BEQ AA03 ; Sprung wenn kein Fehler DEY ; Anzahl Leseversuche erniedrigen BNE AA01 ; Sprung falls noch nicht alle Leseversuche JSR $D042 ; BAM in Puffer lesen JMP $EB22 ; Zeropage initialisieren AA03: SEI ; Interrupts verbieten (Jobschleife deaktivieren) LDA #$00 ; Alle Blöcke außer dem letzten enthalten 256 Bytes LDX $0301 ; Sektornummer des nächsten Blocks STX *$07 ; als Sektor von Puffer 0 merken LDY $0300 ; Spurnummer des nächsten Blocks STY *$06 ; als Spur von Puffer 0 merken BNE AA04 ; Sprung wenn nicht letzter Block INX ; Anzahl gültiger Bytes im letzten Block TXA ; nach A AA04: STA *$37 ; Anzahl gültiger Bytes im aktuellen Block merken LDA #$00 ; CLOCK high STA $1800 LDY #$02 ; Datenübertragung ab Position 2 beginnen AA05: LDA $0300,Y ; Nächstes Datenbyte aus Puffer holen CMP #$DF ; Wert $DF (dient als End of Block/End of File)? BNE AA06 ; Sprung wenn nicht $DF JSR P_AB ; $DF übertragen LDA #$DF ; Bytestuffing, $DF nochmals AA06: JSR P_AB ; Datenbyte übertragen INY ; Schreibzeiger erhöhen CPY *$37 ; Schon alle gültigen Bytes im Puffer übertragen? BNE AA05 ; Sprung falls nicht alle Bytes übertragen LDA $0300 ; Spur des nächsten Blocks gleich 0, also letzter Block? BEQ AA07 ; Sprung falls letzter Block LDA #$DF ; $DF leitet Endekennzeichen ein JSR P_AB ; übertragen LDA #$00 ; $00 als Blockendekennzeichen ($DF $00) JSR P_AB ; übertragen LDA #$08 ; CLOCK low STA $1800 JMP AA00 ; Nächsten Block übertragen AA07: LDA #$DF ; $DF leitet Endekennzeichen ein JSR P_AB ; übertragen LDA #$FF ; $FF als Dateiendekennzeichen ($DF $FF) JSR P_AB ; übertragen JMP $EB22 ; Zeropage initialisieren ; Byte in A auf DATA senden, Synchronisation durch Pegelwechsel auf CLOCK P_AB: STA *$14 ; Datenbyte merken LDA #$04 ; Bitmaske für CLOCK in JSR AB00 ; Bit 0 und 1 senden JSR AB00 ; Bit 2 und 3 senden JSR AB00 ; Bit 4 und 5 senden AB00: LSR *$14 ; Niederwertigstes Bit nach CF LDX #$02 ; DATA high BCC AB01 ; Sprung falls Bit in CF gelöscht LDX #$00 ; DATA low AB01: BIT $1800 ; Warten auf CLOCK high BNE AB01 STX $1800 ; Bit auf DATA senden LSR *$14 ; Nächstes Bit nach CF LDX #$02 ; DATA high BCC AB02 ; Sprung falls Bit in CF gelöscht LDX #$00 ; DATA low AB02: BIT $1800 ; Warten auf CLOCK low BEQ AB02 STX $1800 ; Bit auf DATA senden RTS
Startroutinen[Bearbeiten | Quelltext bearbeiten]
Die nachfolgende Routine P_AC
überträgt die Floppy-seitigen Schnelllade-Routinen mittels des "M-W"-Befehls ("Memory-Write") in Abschnitten zu jeweils 29 Bytes in das RAM der Floppy ab Adresse TARGET1=$0400
. Anschließend wird der Schnelllader dort mittels "M-E" ("Memory-Execute") gestartet. Da beide Floppy-Befehle mit "M-" beginnen, übernimmt die Unterroutine P_AD
das Versenden dieses Präfixes.
; Floppy-seitige Schnelllade-Routine in Floppy-Speicher schreiben und dort starten P_AC: LDY #<TARGET1 ; Low-Byte Schreibzeiger im Floppy-RAM AC00: JSR P_AD ; Befehlskanal öffnen und Präfix "M-" senden LDA #$57 ; 'W' für "M-W", "Memory-Write" JSR $EDDD ; ... auf IEC-Bus ausgeben (IECOUT) TYA ; Low-Byte Schreibzeiger im Floppy-RAM JSR $EDDD ; ... auf IEC-Bus ausgeben (IECOUT) LDA #>TARGET1 ; High-Byte Schreibzeiger im Floppy-RAM JSR $EDDD ; ... auf IEC-Bus ausgeben (IECOUT) LDA #29 ; Blockgröße TAX ; als Bytezähler nach X JSR $EDDD ; ... auf IEC-Bus ausgeben (IECOUT) AC01: LDA SOURCE1,Y ; Floppy-seitige Schnelllade-Routine byteweise lesen JSR $EDDD ; und an Floppy senden INY ; Schreibzeiger erhöhen DEX ; Bytezähler erniedrigen BNE AC01 ; Rücksprung falls noch nicht ganzer Block übertragen JSR $EDFE ; UNLISTEN senden CPY #$AE ; Schon 6*29=174 Bytes gesendet? BNE AC00 ; Rücksprung falls noch nicht alle Bytes gesendet JSR P_AD ; Befehlskanal öffnen und "M-" senden LDA #$45 ; 'E' für "M-E", "Memory-Execute" JSR $EDDD ; ... auf IEC-Bus ausgeben (IECOUT) LDA #<TARGET1 ; Low-Byte der Startadresse im Floppyspeicher JSR $EDDD ; ... auf IEC-Bus ausgeben (IECOUT) LDA #>TARGET1 ; High-Byte der Startadresse im Floppyspeicher JSR $EDDD ; ... auf IEC-Bus ausgeben (IECOUT) JSR $EDFE ; UNLISTEN senden LDA #$03 ; CLOCK und DATA AND $DD00 ORA #$04 STA $DD00 ; auf High setzen JSR $4711 ; Programmteil laden LDA #DEVICE ; Geräteadresse JMP $F291 ; CLOSE ; Befehlskanal öffnen und Präfix "M-" senden P_AD: LDA #DEVICE ; Geräteadresse #8 JSR $ED0C ; LISTEN senden LDA #$6F ; Sekundäradresse #15 (Befehlskanal) JSR $EDB9 ; Sekundäradresse nach LISTEN senden LDA #$4D ; 'M' JSR $EDDD ; ... auf IEC-Bus ausgeben (IECOUT) LDA #$2D ; '-' JMP $EDDD ; ... auf IEC-Bus ausgeben (IECOUT)
C64-seitige Schnelllade-Routinen[Bearbeiten | Quelltext bearbeiten]
Falls die Floppy bereit zum Senden ist (erkennbar an CLOCK=high), fordert die C64-seitigen Schnelllade-Routine P_AG
mit 8 aufeinanderfolgenden Pegelwechseln auf der CLOCK-Leitung jeweils die Übertragung eines Bits an. Damit die Floppy das Dateiende signalisieren oder die Übertragung anhalten kann (um den nächsten Sektor von Diskette zu lesen), hat das Datenbyte $DF eine Sonderfunktion: Der Zwei-Byte-Code $DF $FF
signalisiert das Dateiende, der Code $DF $00
hält die Übertragung an. Da beide Codes auch zufällig im Datenstrom des geladenen Programmteils vorkommen können, wird jedes Datenbyte $DF als Zwei-Byte-Code $DF $DF
übertragen (Bytestuffing).
; Ein Datenbyte von der Floppy in <A> einlesen P_AE: PHP ; Flags und Indexregister retten TXA PHA TYA PHA LDA *$90 ; Dateiende erreicht? BNE AE02 ; Sprung falls Dateiende AE00: JSR P_AF ; Ein Byte von der Floppy einlesen und in <A> sowie an Adresse $A5 speichern CMP #$DF ; Sonderzeichen $DF? BNE AE02 ; Fertig falls nicht Sonderzeichen $DF JSR P_AF ; Sonst nächstes Byte von der Floppy einlesen und in <A> sowie an Adresse $A5 speichern CMP #$DF ; Nochmals $DF? BEQ AE02 ; Ja, dann Datenbyte $DF zurückliefern (Bytestuffing) CMP #$FF ; Endekennzeichen $FF? BEQ AE01 ; Ja, dann als Status merken JSR P_AG ; Nein, Nach kurzer Verzögerung auf CLOCK high warten JMP AE00 ; Erneut ein Byte von Floppy einlesen AE01: STA *$90 AE02: PLA ; Indexregister und Flags zurückholen TAY PLA TAX PLP LDA *$A5 ; Gelesenes Datenbyte nach A holen RTS ; Ein Byte von der Floppy einlesen und in <A> sowie an Adresse $A5 speichern P_AF: LDY #$08 ; Bitzähler AF00: LDA $DD00 ; Zustand der IEC-Leitungen EOR #$50 ; CLOCK invertieren TAX LDA $DD00 ; Zustand der IEC-Leitungen STX $DD00 ; Pegelwechsel auf CLOCK ASL A ; Wert von DATA ins CF ROR *$A5 ; und als empfangenes Bit speichern DEY ; Bitzähler vermindern BNE AF00 ; Rücksprung falls noch nicht 8 Bits empfangen LDA *$A5 ; Empfangenes Byte nach A holen DEC $D020 ; Bildschirmrand kurz blinken lassen INC $D020 RTS ; Nach kurzer Verzögerung auf CLOCK high warten (als Zeichen für "Floppy bereit zum Senden"), dann CLOCK und DATA low P_AG: LDY #$2F ; Verzögerung AG00: DEY BNE AG00 AG01: LDA $DD00 ; Zustand der IEC-Leitungen AND #$40 ; CLOCK prüfen BEQ AG01 ; Rücksprung falls CLOCK low AG02: LDA #$03 AND $DD00 ORA #$C4 STA $DD00 ; CLOCK und DATA auf low LDY #$07 ; Verzögerung AG03: DEY BNE AG03 RTS