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