Bad Cat/Schnelllader
<< zurück zu Bad Cat
Bad Cat/Schnelllader: Die folgenden Abschnitte stellen den disassemblierten Floppy-Schnelllader des Spiels Bad Cat dar. Sie sind gegliedert in einzelne Codeblöcke, die gemäß ihrer Funktion vor dem und während des Ladens gruppiert sind.
Startroutinen[Bearbeiten | Quelltext bearbeiten]
Die nachfolgende Routine P_AA überträgt die Floppy-seitigen Schnelllade-Routinen mittels des "M-W"-Befehls ("Memory-Write") in Abschnitten zu jeweils 34 Bytes in das RAM der Floppy ab Adresse TARGET1=$0400. Anschließend wird der Schnelllader dort mittels "M-E" ("Memory-Execute") gestartet, bevor der C64 die nachzuladende Datei zum Lesen öffnet und dann seine eigene Schnelllade-Routine aufruft. Da während des Transfers in das RAM der Floppy nur das High-Byte der Zieladresse überprüft wird, sendet die Routine nicht nur den 282 Byte langen Code, sondern unnötigerweise auch noch 230 Bytes der darauffolgenden Lookup-Table (insgesamt 512 Bytes).
Beim anschließenden Einlesen der Programmdaten wird für jedes Byte die Schnelllade-Routine P_AF aufgerufen und des empfangene Byte direkt an seine Ladeadresse geschrieben. Falls diese Schreibzugriffe die Page $CD erreichen, in der der Schnelllader gespeichert ist, und somit diesen zu überschreiben drohen, ist ein Wechsel zur normalen LOAD-Routine im ROM vorgesehen. Da die Hauptschleife des Schnellladers allerdings bereits bei Label AA11 an Adresse $CCF6 beginnt, brächte ein überlanges Programm den Schnelllader trotz dieses Schutzmechanismus zum Absturz.
DEVICE EQU $08 ; Geräteadresse 8
T000: DB $00,$00,$CD
T001: DB $22,$06,$00,'W-M'
T002: DB $04,$6C,'E-M'
P_AA: LDA *$B4 ; Inhalt von Adresse $B4
STA T000+$00 ; retten
LDA *$B5 ; Inhalt von Adresse $B5
STA T000+$01 ; retten
LDA $DD00 ; CIA2 Port A holen
AND #$03 ; Bits für VIC-Bank isolieren
STA AF02+$01 ; als Wert für "ATN high" speichern (Selbstmodifikation)
ORA #$08 ; Bit für ATN setzen
STA P_AF+$01 ; als Wert für "ATN low" speichern (Selbstmodifikation)
LDA #$00 ; Alle Sprites abschalten, verhindert VIC-Zugriffe per DMA
STA $D015
LDA #$00
STA *$90 ; Status zurücksetzen
STA *$B5 ; ?
LDA #$F0 ; Sekundäradresse 0
JSR P_AD ; LISTEN senden
LDA *$90 ; Status holen
BPL AA00 ; Sprung falls Gerät vorhanden
JMP $F707 ; "?DEVICE NOT PRESENT ERROR"
AA00: LDY #$00 ; Lesezeiger für Dateinamen initialisieren
AA01: LDA ($BB),Y ; Zeichen aus Dateinamen lesen
JSR $EDDD ; IECOUT
INY ; Lesezeiger erhöhen
CPY *$B7 ; mit Länge des Dateinamens vergleichen
BCC AA01 ; Rücksprung falls noch nicht ganzer Dateiname gesendet
JSR $EDFE ; UNLISTEN senden
LDA #$00
STA *$90 ; Status zurücksetzen
JSR P_AE ; TALK senden
LDA #$60 ; Sekundäradresse
JSR $EDC7 ; Sekundäradresse nach TALK ausgeben
JSR $EE13 ; IECIN ein Zeichen vom IEC-Bus holen
LDA *$90 ; Status holen
PHA ; und retten
JSR $EDEF ; UNTALK senden
PLA ; Status zurückholen
AND #$02 ; Timeout?
BEQ AA02 ; Sprung wenn kein Timeout
JMP $F704 ; "?FILE NOT FOUND ERROR"
AA02: LDA #<SOURCE1 ; Low-Byte der Quelladresse des Floppy-seitigen Schnelladers
LDY #>SOURCE1 ; High-Byte der Quelladresse des Floppy-seitigen Schnelladers
STA *$AE ; Low-Byte merken
STY *$AF ; High-Byte merken
LDY #<TARGET1 ; Low-Byte der Startadresse im Floppy-Speicher
LDA #>TARGET1 ; High-Byte der Startadresse im Floppy-Speicher
STY T001+$02 ; Low-Byte in "Memory-Write" ("M-W")-Befehl aufnehmen
STA T001+$01 ; High-Byte in "M-W"-Befehl aufnehmen
AA03: LDA #$6F ; Sekundäradresse 15 (Befehlskanal)
JSR P_AD ; LISTEN senden
LDX #$06 ; Länge des "M-W"-Befehls
AA04: LDA T001-$01,X ; Befehl zeichenweise lesen
JSR $FFA8 ; IECOUT
DEX ; Lesezeiger erniedrigen
BNE AA04 ; Rücksprung falls noch nich alle Zeichen gesendet
AA05: LDA ($AE),Y ; Floppy-seitigen Schnellader aus Speicher lesen
JSR $FFA8 ; IECOUT
INY ; Schreibzeiger erhöhen
BNE AA06 ; Sprung falls kein šbertrag
INC *$AF ; High-Byte der Leseadresse erhöhen
AA06: INC T001+$02 ; Low-Byte der Zieladresse im "M-W"-Befehl erhöhen
BNE AA07 ; Sprung falls kein šbertrag
INC T001+$01 ; High-Byte der Zieladresse im "M-W"-Befehl erhöhen
AA07: LDA T001+$01 ; High-Byte der Zieladresse holen
CMP #>TARGET1+$02 ; Schon 2*256=512 Bytes übertragen?
BEQ AA08 ; Sprung falls 512 Bytes übertragen
INX ; Lesezeiger erhöhen
CPX #34 ; Blockgröße erreicht?
BNE AA05 ; Rücksprung falls Blockgröáe nicht erreicht
JSR $EDFE ; UNLISTEN senden
JMP AA03 ; Nächsten Block übertragen
AA08: JSR $EDFE
LDA #$6F ; Sekundäradresse 15 (Befehlskanal)
JSR P_AD ; LISTEN senden
LDY #$04 ; Länge des "Memory-Execute" ("M-E")-Befehls minus 1
AA09: LDA T002,Y ; "M-E"-Befehl zeichenweise lesen
JSR $FFA8 ; IECOUT
DEY ; Lesezeiger erniedrigen
BPL AA09 ; Sprung falls noch nicht alle Zeichen gesendet
JSR $EDFE ; UNLISTEN senden
LDA *$C3 ; Low-Byte der Zieladresse
STA *$AE ; umkopieren
LDA *$C4 ; High-Byte der Zieladresse
STA *$AF ; umkopieren
SEI ; Interrupts während Schnellladeroutine verbieten
JSR P_AF ; Zeichen per Schnelllader in <A> einlesen
PHA ; und retten (Anzahl gültiger Datenbytes)
JSR P_AF ; Zeichen per Schnelllader in <A> einlesen
TAY ; und retten (Low-Byte der Ladeadresse)
JSR P_AF ; Zeichen per Schnelllader in <A> einlesen
STA *$B4 ; und merken (High-Byte der Ladeadresse)
LDX *$B9 ; Sekundäradresse für LOAD
BEQ AA10 ; Sprung falls nicht absolut
STA *$AF ; Low-Byte der Ladeadresse vom Programmanfang speichern
STY *$AE ; High-Byte der Ladeadresse vom Programmanfang speichern
AA10: PLA ; Anzahl gültiger Datenbytes zurückholen
AND #$FF ; und testen
BNE P_AC ; Sprung falls ungleich null
LDA #$FC
BNE AA12
AA11: JSR P_AF ; Zeichen per Schnelllader in <A> einlesen
AND #$FF ; untersuchen
BNE P_AC ; Sprung falls letzter Block des Programms
LDA #$FE ; Nicht letzter Block, enthält 254 Datenbytes
AA12: STA *$B5 ; Anzahl gültiger Bytes im Datenblock
LDY #$00
AA13: JSR P_AF ; Zeichen per Schnelllader in <A> einlesen
STA ($AE),Y ; und in an Ladeadresse schreiben
INY ; Schreibzeiger erhöhen
CPY *$B5 ; mit Anzahl gültiger Bytes im Datenblock vergleichen
BNE AA13 ; Rücksprung falls noch nicht alle Bytes empfangen
DEC $D020 ; Farbe des Bildschirmrahmens wechseln
PHA ; ? Datenbyte retten
EOR #$01 ; ?
INC $D020 ; Farbe des Bildschirmrands wiederherstellen
LDA *$AE ; Low-Byte der Ladeadresse
CLC
ADC *$B5 ; um Anzahl gültiger Datenbytes erhöhen
STA *$AE ; und zurückschreiben
LDA *$AF ; High-Byte der Ladeadresse
ADC #$00 ; um eventuellen Additionsübertrag erhöhen
STA *$AF ; und zurückschreiben
INC *$B4 ; High-Byte der Ladeadresse erhöhen
PLA ; ? Datenbyte zurückholen
INC $D020 ; Farbe des Bildschirmrahmens wechseln
LDA *$B4 ; High-Byte der Ladeadresse
CMP T000+$02 ; mit Highbyte der Adresse des Schnelladers vergleichen
BNE AA11 ; Rücksprung, falls noch nicht erreicht
CLI ; sonst Schnellader verlassen, da überschrieben
LDA T000+$00 ; Alten Wert von $B4
STA *$B4 ; wiederherstellen
LDA T000+$01 ; Alten Wert von B5
STA *$B5 ; wiederherstellen
JSR P_AB ; Load-Vektor wiederherstellen
LDA #$F0 ; Sekundäradresse 0
JSR P_AD ; LISTEN senden
LDA #$2A ; '*'
JSR $EDDD ; IECOUT
JSR $EDFE ; UNLISTEN senden
JSR P_AE ; TALK senden
LDA #$60 ; Sekundäradresse 0
STA *$B9 ; merken
JSR $EDC7 ; Sekundäradresse nach TALK ausgeben
JMP $F501 ; Sprung zur LOAD-Routine
; LOAD-Vektor wiederherstellen
P_AB: LDA #$A5 ; Low-Byte des Load-Vektor
STA $0330 ; wiederherstellen
LDA #$F4 ; High-Byte des Load-Vektor
STA $0331 ; wiederherstellen
RTS
P_AC: LDY *$B5 ; Anzahl gültiger Bytes im aktuellen Block holen
BNE AC00 ; Sprung falls letzter Block
SEC
SBC #$02 ; Länge des Verkettungspointers subtrahieren
AC00: STA *$B5 ; und als Zahl zu empfangender Datenbytes merken
DEC *$B5 ; Offset subtrahieren
LDY #$00 ; Schreibzeiger initialisieren
AC01: JSR P_AF ; Byte von Floppy empfangen
STA ($AE),Y ; und an Ladeadresse schreiben
INY ; Schreibzeiger erhöhen
CPY *$B5 ; Schon alle Datenbytes des aktuellen Blocks empfangen?
BNE AC01 ; Rücksprung falls noch nicht alle Datenbytes
LDA *$AE ; Low-Byte der Ladeadresse holen
CLC
ADC *$B5 ; um Anzahl der empfangenen Datenbytes erhöhen
STA *$AE ; und merken
TAX
LDA *$AF ; High-Byte der Ladeadresse holen
ADC #$00 ; um eventuellen Additionsübertrag erhöhen
STA *$AF ; und merken
TAY
LDA T000+$00 ; Inhalt von Adresse $B4
STA *$B4 ; wiederherstellen
LDA T000+$01 ; Inhalt von Adresse $B5
STA *$B5 ; wiederherstellen
LDA T001+$00
CMP #$22
BEQ AC02
JSR P_AB
AC02: CLC
CLI
RTS
; LISTEN senden
P_AD: PHA ; Sekundäradresse retten
LDA #DEVICE ; Geräteadresse
JSR $ED0C ; LISTEN senden
PLA ; Sekundäradresse zurückholen
JMP $EDB9 ; Sekundäradresse nach LISTEN senden
; TALK senden
P_AE: LDA #DEVICE ; Geräteadresse
JMP $ED09 ; TALK senden
C64-seitige Schnelllade-Routinen[Bearbeiten | Quelltext bearbeiten]
Da das nachzuladende Programm in Form von 4 Bitpaaren übertragen wird, von denen jedes nur für 8 μs auf die DATA- und CLOCK-Leitungen gelegt wird, ist eine exakte Synchronisation von C64 und Floppy wichtig. Zunächst wartet die Schnelllade-Routine daher vor jedem Datenbyte, dass die Floppy bereit zum Senden ist und dies dadurch kundtut, dass sie einen Low-Pegel auf der ATN-Leitung mit DATA=high (Label AF00) quittiert. Anschließend stellt die Routine sicher, dass das Timing nicht durch DMA-Zugriffe des VIC gestört werden kann: Falls der VIC gerade den sichtbaren Teil des Bildschirms darstellt, so wartet die Routine auf eine Rasterzeile, in der Badlines ausgeschlossen sind (Bit 2 der Rasterzeile im VIC-Register $D012 gesetzt, Label AF01).
Nun beendet die Routine mit ATN=high die Synchronisation und empfängt dann nacheinander 4 Bitpaare. Die Reihenfolge dieser Bits ist auf die Registerbelegung des Port B von VIA1 optimiert (nacheinander Bit 5+7, Bit 4+6, Bit 1+3 und Bit 0+2), so dass nur mit aufwändigen Schiebe- und Rotationsbefehlen das ursprüngliche Datenbyte rekonstruiert werden kann — oder mit der bei Bad Cat verwendeten, etwas speicherintensiveren Methode: Vier Lesezugriffe auf eine Lookup-Table, von denen jeder zwei korrekt positionierte Bits liefert, die anschließend nur noch untereinander mit einem logischen ODER verknüpft werden müssen. Während der VIC den Bildschirmrahmen anzeigt, dauert die Übertragung eines Byte mit dieser Routine 105 μs; während der Darstellung des Bildschirminhalts können pro 8 Rasterzeilen (alle 504 Systemtakte) 3 Bytes übertragen werden.
; Datenbyte von Floppy empfangen
P_AF: LDA #$0B
STA $DD00 ; Synchronisation per ATN low
AF00: LDA $DD00 ; Auf DATA high warten
BPL AF00
AF01: LDA $D012 ; Bildschirmzeile des VIC holen
CMP #$32 ; Oberste Rasterzeile?
BCC AF02 ; Sprung falls Bildschirmrahmen dargestellt
AND #$04 ; Warten, bis Badline vorbei
CMP #$04
BNE AF01 ; Rücksprung, falls Bit 2 der Rasterzeile gelöscht
AF02: LDA #$03 ; ATN high
STA $DD00
NOP ; Verzögerung
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
LDX $DD00 ; Bit 5 und 7 des Datenbyte nach Bit 7 und 6 von X
LDA T100,X ; Verschiebung an die richtigen Bitpositionen per Lookup-Table
LDX $DD00 ; Bit 4 und 6 des Datenbyte nach bit 7 und 6 von X
ORA T101,X ; Einblenden an die richtigen Bitpositionen per Lookup-Table
LDX $DD00 ; Bit 1 und 3 des Datenbyte nach Bit 7 und 6 von X
ORA T102,X ; Verschiebung an die richtigen Bitpositionen per Lookup-Table
LDX $DD00 ; Bit 0 und 2 des Datenbyte nach Bit 7 und 6 von X
ORA T103,X ; Verschiebung an die richtigen Bitpositionen per Lookup-Table
RTS
Floppy-seitige Schnelllade-Routine[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.
Das Versenden findet parallel auf der CLOCK- und DATA-Leitung statt, wobei jedes Datenbyte in 4 Bitpaare aufgeteilt wird, deren Reihenfolge so gewählt ist, dass sie jeweils nach 8 μs (und nach wenigen Schiebe- und Rotationsbefehlen) in Port B von VIA1 geschrieben werden können. Auf diese Weise wird kurzzeitig eine Datenrate von 250 kBit/s erreicht.
Die Floppy-seitige Schnelllade-Routine liest das zu ladende Programm sektor-weise. Jeder Übertragung zum C64 wird ein Headerbyte vorangestellt, das anzeigt, ob danach noch weitere Sektoren folgen werden (Headerbyte $00), oder ob es sich um den letzten Sektor eines Programms handelt (Headerbyte $02..$FF, entsprechend einer Zahl von 1..254 restlichen Datenbytes).
SOURCE1: ; Kommentare übernommen aus den Büchern: ; Rainer Ellinger/Lothar Englisch/Ralph Gelfand/Norbert Sczcepanowski: ; "Das große Floppybuch zur 1541" ; Rainer Ellinger: ; "Commodore 1571 & 1570 - Das große Floppybuch" ; Geringfügig modifizierte Kopie des Floppy-ROM ab $F4D1 P_BA: JSR $F50A ; Blockheader des Sektors suchen BA00: BVC BA00 ; auf Byte von Diskette warten CLV ; Leseelektronik wieder bereit machen LDA $1C01 ; Byte vom Kopf lesen STA $0300,Y ; und in aktuellen Puffer schreiben INY ; Pufferzeiger auf nächstes Byte setzen BNE BA00 ; Puffer schon voll? LDY #$BA ; ja, Pufferzeiger auf Zusatzpuffer BA01: BVC BA01 ; auf nächstes Byte von Diskette warten CLV ; Flag wieder bereit machen LDA $1C01 ; Byte von Lesekopf holen STA $0100,Y ; und in Zusatzpuffer schreiben INY ; Pufferzeiger auf nächstes Byte setzen BNE BA01 ; Zusatzpuffer voll LDA #$03 STA *$31 JSR $F8E0 ; ja, Sektor von GCR nach Binär wandeln JSR $F5E9 ; Prüfsumme der Daten berechnen EOR *$3A ; mit gelesenem Wert vergleichen BEQ BA02 ; neide identisch? LDA #$05 ; Fehlernummer für READ ERROR (23) BNE BA07 ; unbedingter Sprung zur Fehlerausgabe ; Schnelllade-Routine BA02: LDA $0300 ; Spur des nächsten Blocks holen STA *$08 ; und merken BEQ BA03 ; Sprung falls letzter Block LDA #$00 ; sonst $00 als Header voranstellen STA *$0C ; merken BEQ BA04 ; Unbedingter Sprung BA03: LDA $0301 ; Anzahl gültiger Bytes im letzten Blocks holen STA *$0C ; merken INC *$0C ; um Offset erhöhen BA04: JSR P_BC ; Headerbyte in A an C64 senden LDA $0301 ; Sektor des nächsten Block holen STA *$09 ; und merken LDA *$11 ; Erster Block? BEQ BA05 ; Sprung falls nicht erster Block LDA $0303 ; High-Byte der Ladeadresse STA *$10 ; merken STY *$11 ; Flag für "erster Block" löschen BA05: LDY #$02 ; Lesezeiger initialisieren BA06: LDA $0300,Y JSR P_BC ; Datenbyte in A an C64 senden INY ; Lesezeiger erhöhen CPY *$0C ; Schon alle Datenbytes gelesen? BNE BA06 ; Rücksprung falls nicht alle Datenbytes LDA *$08 ; Letzten Block versendet? BEQ BA07 ; Sprung falls letzter Block LDA #$01 ; Rückmeldung $00="Letzter Block", $01="Nicht letzter Block" BA07: JMP $F969 ; Aktuellen Job beenden, Fehlerrückmeldung bereitstellen ; Einsprung für "Memory-Execute" ("M-E")-Befehl P_BB: LDA #$C8 ; Standardwert setzen STA *$64 ; für Zahl der Halbspuren bis Spur 0 LDA #$04 STA *$5E STA *$5F LDA *$18 ; Spur des zuletzt gelesenen Sektorheaders LDX *$19 ; Sektor des zuletzt gelesenen Sektorheaders STA *$08 ; Spur merken STX *$09 ; Sektor merken LDA #$10 ; Rate des Jobscheifen-Interrupt erhöhen (alle 4 ms statt alle 14 ms) STA $1C07 STA *$11 LDA $1C00 ; CLOCK und DATA high, ATN nicht automatisch beantworten ORA #$08 STA $1C00 ; CLOCK low, ATN automatisch beantworten BB00: LDA #$E0 ; Jobcode "Programm in Jobschleife einbinden" STA *$01 ; als Job für Puffer 1 an Adresse $0400 setzen BB01: LDA *$01 ; Warten bis Job abgearbeitet BMI BB01 BEQ BB02 ; Sprung falls letzter Block CMP #$02 ; Fehler? BCS BB03 ; Sprung falls Fehler LDA #$08 ; Anzahl Leseversuche STA *$0D ; merken INC *$10 ; High-Byte der Ladeadresse erhöhen LDA *$10 ; High-Byte der momentanen Ladeadresse CMP BB06 ; mit Highbyte der Anfangsadresse des Schnelladers vergleichen BNE BB00 ; Rücksprung, falls C64-seitiger Schnelllader nicht überschrieben LDA $0300 ; sonst Spurnummer des aktuellen Blocks STA *$7E ; als Spurnummer des letzten Zugriff setzen LDA $0301 ; Sektornummer des aktuellen Blocks STA $026F ; als Nummer des letzten Sektors setzen JMP $C194 ; Beenden eines Rechnerbefehls, erzeugen der Fehlermeldung BB02: STA *$09 ; 0 als Sektor für Puffer 1 LDA #$12 ; Spur 18 STA *$08 ; als Spur für Puffer 1 LDA #$B0 ; Jobcode "Suchen eines Sektorheaders" STA *$01 ; als Job für Puffer 1 an Adresse $0400 setzen JMP $DAC0 ; Datei schlieáen BB03: TAY ; Fehlernummer nach Y retten DEC *$0D ; Anzahl Leseversuche erniedrigen BNE BB04 ; Rücksprung falls weiterer Leseversuch TYA ; Fehlernummer zurückholen LDX #$02 ; ? Puffernummer JMP $E60A ; Ausgabe der Fehlermeldung (A muá Fehler- und X die Puffernummer enthalten) BB04: LDA *$0D ; Verbleidende Anzahl Leseversuche holen CMP #$04 ; Nur noch 4 Leseversuche? BNE BB00 ; Sprung falls nicht LDA #$C0 ; Jobcode "Kopf auf Spur 0 setzen" STA *$01 ; als Job für Puffer 1 an Adresse $0400 setzen BB05: LDA *$01 ; warten, bis Job abgearbeitet BMI BB05 BPL BB00 ; Unbedingter Sprung zum nächsten Leseversuch BB06: DB $CB ; Datenbyte in A an C64 senden P_BC: TAX ; X=Datenbyte BC00: BIT $1800 ; Auf ATN low warten BPL BC00 LDA #$10 ; DATA und CLOCK high STA $1800 BC01: BIT $1800 ; Auf ATN high warten BMI BC01 TXA ; A=Datenbyte LSR A LSR A LSR A LSR A STA $1800 ; DATA=Bit 5, CLOCK=Bit 7 ASL A AND #$0F STA $1800 ; DATA=Bit 4, CLOCK=Bit 6 TXA ; A=Datenbyte AND #$0F STA $1800 ; DATA=Bit 1, CLOCK=Bit 3 ASL A AND #$0F STA $1800 ; DATA=Bit 0, CLOCK=Bit 2 LDA #$0F NOP STA $1800 ; DATA und CLOCK low RTS
Lookup-Table für das Umsortieren der Datenbits[Bearbeiten | Quelltext bearbeiten]
Die Schnelllade-Routine erzielt ihre hohe Geschwindigkeit dadurch, dass sie die einzelnen Bits jedes Datenbyte in einer an die Registerbelegung des VIA angepassten Reihenfolge überträgt. Das dadurch notwendige, C64-seitige Umsortieren der empfangenen Bits geschieht, indem die aus Port A von CIA2 gelesenen Leitungspegel als Index in die Lookup-Tabels T100 ... T103 verwendet werden. Da der Status der CLOCK- und DATA-Leitung in Bit 6 und 7 von Port A zu finden sind, zeigt dieser Index auf Positionen in der Lookup-Table, die — je nach Zustand der Leitungen — um ein Vielfaches von 64 Byte auseinanderliegen. Die dazwischenliegenden, 56 Byte langen Lücken können genutzt werden, um die vier Tabellen T100 ... T103 verschränkt abzulegen und damit Speicherplatz zu sparen.
; Umrechnungstabelle Register $DD00 zu Bitpaaren
T100: DB $A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0 ; Bit 5 (DATA) low, Bit 7 (CLOCK) low
T101: DB $50,$50,$50,$50,$50,$50,$50,$50 ; Bit 4 (DATA) low, Bit 6 (CLOCK) low
T102: DB $0A,$0A,$0A,$0A,$0A,$0A,$0A,$0A ; Bit 1 (DATA) low, Bit 3 (CLOCK) low
T103: DB $05,$05,$05,$05,$05,$05,$05,$05 ; Bit 0 (DATA) low, Bit 2 (CLOCK) low
DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Unbenutzt
DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
DB $20,$20,$20,$20,$20,$20,$20,$20 ; Bit 5 (DATA) low, Bit 7 (CLOCK) high
DB $10,$10,$10,$10,$10,$10,$10,$10 ; Bit 4 (DATA) low, Bit 6 (CLOCK) high
DB $02,$02,$02,$02,$02,$02,$02,$02 ; Bit 1 (DATA) low, Bit 3 (CLOCK) high
DB $01,$01,$01,$01,$01,$01,$01,$01 ; Bit 0 (DATA) low, Bit 2 (CLOCK) high
DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Unbenutzt
DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
DB $80,$80,$80,$80,$80,$80,$80,$80 ; Bit 5 (DATA) high, Bit 7 (CLOCK) low
DB $40,$40,$40,$40,$40,$40,$40,$40 ; Bit 4 (DATA) high, Bit 6 (CLOCK) low
DB $08,$08,$08,$08,$08,$08,$08,$08 ; Bit 1 (DATA) high, Bit 3 (CLOCK) low
DB $04,$04,$04,$04,$04,$04,$04,$04 ; Bit 0 (DATA) high, Bit 2 (CLOCK) low
DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Unbenutzt
DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
DB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
DB $00,$00,$00,$00,$00,$00,$00,$00 ; Bit 5 (DATA) high, Bit 7 (CLOCK) high
DB $00,$00,$00,$00,$00,$00,$00,$00 ; Bit 4 (DATA) high, Bit 6 (CLOCK) high
DB $00,$00,$00,$00,$00,$00,$00,$00 ; Bit 1 (DATA) high, Bit 3 (CLOCK) high
DB $00,$00,$00,$00,$00,$00,$00,$00 ; Bit 0 (DATA) high, Bit 2 (CLOCK) high
DB $00,$00,$00,$00,$00,$00,$00,$00 ; Unbenutzt
DB $00,$00,$00,$00,$00,$00,$00,$00
DB $00,$00,$00,$00,$00,$00,$00,$00
DB $00,$00,$00,$00,$00,$00,$00,$00