Benutzer:Sirrus/Spielwiese

Aus C64-Wiki
Zur Navigation springenZur Suche springen

Spielwiese[Bearbeiten | Quelltext bearbeiten]

Das ist meine Spielwiese, hier entwerfe ich Seiten für das Wiki und stelle sie erst ein,wenn alles wunschgemäß funktioniert. Darum hier bitte nichts ändern! Außerdem brauche ich hier keine Kommentare, denn mir ist bekannt, das das was hier steht noch nicht komplett ist.

Mnemonic-Tabellen[Bearbeiten | Quelltext bearbeiten]

Eine Darstellung der Mnemonics in einer Tabelle ist zunächst einmal sinnvoll, wenn man einen Disassembler schreiben möchte. Ohne eine solche Tabelle müsste man für Mnemonics, Adressierungsarten, Datenlänge und Prozessortakte jeweils einen Block von 256 Bytes Belegen, um darin die entsprechenden Werte abzulegen. Durch die Tabelle kann man Gemeinsamkeiten von Mnemonic-Gruppen erkennen und so die Mnemonics durch logische Verknüpfungen filtern.

Tabelle im Format 16x16[Bearbeiten | Quelltext bearbeiten]

x0
x1
x2
x3
x4
x5
x6
x7
x8
x9
xA
xB
xC
xD
xE
xF
0x
$00 7
BRK
1
$01 6
ORA
(LL,X) 2
$05 3
ORA
LL 2
$06 5
ASL
LL 2
$08 3
PHP
1
$09 2
ORA
#NN 2
$0A 2
ASL
1
$0D 4
ORA
HHLL 3
$0E 6
ASL
HHLL 3
1x
$10 2+
BPL
⇒NN 2
$11 5
ORA
(LL),Y 2
$15 4
ORA
LL,X 2
$16 6
ASL
LL,X 2
$18 2
CLC
1
$19 4
ORA
HHLL,Y 3
$1D 4
ORA
HHLL,X 3
$1E 7
ASL
HHLL,X 3
2x
$20 6
JSR
HHLL 3
$21 6
AND
(LL,X) 2
$24 3
BIT
LL 2
$25 3
AND
LL 2
$26 5
ROL
LL 2
$28 4
PLP
1
$29 2
AND
#NN 2
$2A 2
ROL
1
$2C 4
BIT
HHLL 3
$2D 4
AND
HHLL 3
$2E 6
ROL
HHLL 3
3x
$30 2+
BMI
⇒NN 2
$31 5
AND
(LL),Y 2
$35 4
AND
LL,X 2
$36 6
ROL
LL,X 2
$38 2
SEC
1
$39 4
AND
HHLL,Y 3
$3D 4
AND
HHLL,X 3
$3E 7
ROL
HHLL,X 3
4x
$40 6
RTI
1
$41 6
EOR
(LL,X) 2
$45 3
EOR
LL 2
$46 5
LSR
LL 2
$48 3
PHA
1
$49 2
EOR
#NN 2
$4A 2
LSR
1
$4C 3
JMP
HHLL 3
$4D 4
EOR
HHLL 3
$4E 6
LSR
HHLL 3
5x
$50 2+
BVC
⇒NN 2
$51 5
EOR
(LL),Y 2
$55 4
EOR
LL,X 2
$56 6
LSR
LL,X 2
$58 2
CLI
1
$59 4
EOR
HHLL,Y 3
$5D 4
EOR
HHLL,X 3
$5E 7
LSR
HHLL,X 3
6x
$60 6
RTS
1
$61 6
ADC
(LL,X) 2
$65 3
ADC
LL 2
$66 5
ROR
LL 2
$68 4
PLA
1
$69 2
ADC
#NN 2
$6A 2
ROR
1
$6C 5
JMP
(HHLL) 3
$6D 4
ADC
HHLL 3
$6E 6
ROR
HHLL 3
7x
$70 2+
BVS
⇒NN 2
$71 5
ADC
(LL),Y 2
$75 4
ADC
LL,X 2
$76 6
ROR
LL,X 2
$78 2
SEI
1
$79 4
ADC
HHLL,Y 3
$7D 4
ADC
HHLL,X 3
$7E 7
ROR
HHLL,X 3
8x
$81 6
STA
(LL,X) 2
$84 3
STY
LL 2
$85 3
STA
LL 2
$86 3
STX
LL 2
$88 2
DEY
1
$8A 2
TXA
1
$8C 4
STY
HHLL 3
$8D 4
STA
HHLL 3
$8E 4
STX
HHLL 3
9x
$90 2+
BCC
⇒NN 2
$91 6
STA
(LL),Y 2
$94 4
STY
LL,X 2
$95 4
STA
LL,X 2
$96 4
STX
LL,Y 2
$98 2
TYA
1
$99 5
STA
HHLL,Y 3
$9A 2
TXS
1
$9D 5
STA
HHLL,X 3
Ax
$A0 2
LDY
#NN 2
$A1 6
LDA
(LL,X) 2
$A2 2
LDX
#NN 2
$A4 3
LDY
LL 2
$A5 3
LDA
LL 2
$A6 3
LDX
LL 2
$A8 2
TAY
1
$A9 2
LDA
#NN 2
$AA 2
TAX
1
$AC 4
LDY
HHLL 3
$AD 4
LDA
HHLL 3
$AE 4
LDX
HHLL 3
Bx
$B0 2+
BCS
⇒NN 2
$B1 5
LDA
(LL),Y 2
$B4 4
LDY
LL,X 2
$B5 4
LDA
LL,X 2
$B6 4
LDX
LL,Y 2
$B8 2
CLV
1
$B9 4
LDA
HHLL,Y 3
$BA 2
TSX
1
$BC 4
LDY
HHLL,X 3
$BD 4
LDA
HHLL,X 3
$BE 4
LDX
HHLL,Y 3
Cx
$C0 2
CPY
#NN 2
$C1 6
CMP
(LL,X) 2
$C4 3
CPY
LL 2
$C5 3
CMP
LL 2
$C6 5
DEC
LL 2
$C8 2
INY
1
$C9 2
CMP
#NN 2
$CA 2
DEX
1
$CC 4
CPY
HHLL 3
$CD 4
CMP
HHLL 3
$CE 6
DEC
HHLL 3
Dx
$D0 2+
BNE
⇒NN 2
$D1 5
CMP
(LL),Y 2
$D5 4
CMP
LL,X 2
$D6 6
DEC
LL,X 2
$D8 2
CLD
1
$D9 4
CMP
HHLL,Y 3
$DD 4
CMP
HHLL,X 3
$DE 7
DEC
HHLL,X 3
Ex
$E0 2
CPX
#NN 2
$E1 6
SBC
(LL,X) 2
$E4 3
CPX
LL 2
$E5 3
SBC
LL 2
$E6 5
INC
LL 2
$E8 2
INX
1
$E9 2
SBC
#NN 2
$EA 2
NOP
1
$EC 4
CPX
HHLL 3
$ED 4
SBC
HHLL 3
$EE 6
INC
HHLL 3
Fx
$F0 2+
BEQ
⇒NN 2
$F1 5
SBC
(LL),Y 2
$F5 4
SBC
LL,X 2
$F6 6
INC
LL,X 2
$F8 2
SED
1
$F9 4
SBC
HHLL,Y 3
$FD 4
SBC
HHLL,X 3
$FE 7
INC
HHLL,X 3

In dieser ersten Tabelle im Format 16x16 fällt bereits auf, das die Spalten x3,x7,xB und xF nicht mit Mnemonics belegt sind, also alle Mnemonics, in denen die Bits 0+1 =11 sind. Durch nur 2 Assemblerbefehle (AND #03 und CMP #03) könnte man also schon 64 illegale Codes ausfiltern. Diese Auffälligkeit bringt mich auf die Idee, 3 weitere Tabellen zu erstellen, wo je Tabelle auch die Bits 0+1 gleich sind:

Tabelle 8x8 für Mnemonics %yyyxxx00[Bearbeiten | Quelltext bearbeiten]

x0
x4
x8
xC
x0
x4
x8
xC
0x/1x
$00 7
BRK
1
$08 3
PHP
1
$10 2+
BPL
⇒NN 2
$18 2
CLC
1
2x/3x
$20 6
JSR
HHLL 3
$24 3
BIT
LL 2
$28 4
PLP
1
$2C 4
BIT
HHLL 3
$30 2+
BMI
⇒NN 2
$38 2
SEC
1
4x/5x
$40 6
RTI
1
$48 3
PHA
1
$4C 3
JMP
HHLL 3
$50 2+
BVC
⇒NN 2
$58 2
CLI
1
6x/7x
$60 6
RTS
1
$68 4
PLA
1
$6C 5
JMP
(HHLL) 3
$70 2+
BVS
⇒NN 2
$78 2
SEI
1
8x/9x
$84 3
STY
LL 2
$88 2
DEY
1
$8C 4
STY
HHLL 3
$90 2+
BCC
⇒NN 2
$94 4
STY
LL,X 2
$98 2
TYA
1
Ax/Bx
$A0 2
LDY
#NN 2
$A4 3
LDY
LL 2
$A8 2
TAY
1
$AC 4
LDY
HHLL 3
$B0 2+
BCS
⇒NN 2
$B4 4
LDY
LL,X 2
$B8 2
CLV
1
$BC 4
LDY
HHLL,X 3
Cx/Dx
$C0 2
CPY
#NN 2
$C4 3
CPY
LL 2
$C8 2
INY
1
$CC 4
CPY
HHLL 3
$D0 2+
BNE
⇒NN 2
$D8 2
CLD
1
Ex/Fx
$E0 2
CPX
#NN 2
$E4 3
CPX
LL 2
$E8 2
INX
1
$EC 4
CPX
HHLL 3
$F0 2+
BEQ
⇒NN 2
$F8 2
SED
1

Als erstes fällt hier auf, das sich alle Branch-Befehle in einer Spalte versammelt haben, diese können mit AND #1F und CMP #10 ausgefiltert werden. Dann kann man auch gleich mit AND #0F und CMP #08 zusammen 16 (2x8) der 1-Byte-Befehle ausfiltern. Danach verbleibt in der unteren Hälfte pro Zeille nur noch 1 Mnemonic (STY, LDY, CPY, CPX), wobei sich spaltenweise immer die gleiche Adressierungsart versammelt hat. Oben hingegen haben sich alle Befehle versammelt, die Einfluß auf den Programmcounter oder den Stack haben.

Tabelle 8x8 für Mnemonics %yyyxxx01[Bearbeiten | Quelltext bearbeiten]

x1
x5
x9
xD
x1
x5
x9
xD
0x/1x
$01 6
ORA
(LL,X) 2
$05 3
ORA
LL 2
$09 2
ORA
#NN 2
$0D 4
ORA
HHLL 3
$11 5
ORA
(LL),Y 2
$15 4
ORA
LL,X 2
$19 4
ORA
HHLL,Y 3
$1D 4
ORA
HHLL,X 3
2x/3x
$21 6
AND
(LL,X) 2
$25 3
AND
LL 2
$29 2
AND
#NN 2
$2D 4
AND
HHLL 3
$31 5
AND
(LL),Y 2
$35 4
AND
LL,X 2
$39 4
AND
HHLL,Y 3
$3D 4
AND
HHLL,X 3
4x/5x
$41 6
EOR
(LL,X) 2
$45 3
EOR
LL 2
$49 2
EOR
#NN 2
$4D 4
EOR
HHLL 3
$51 5
EOR
(LL),Y 2
$55 4
EOR
LL,X 2
$59 4
EOR
HHLL,Y 3
$5D 4
EOR
HHLL,X 3
6x/7x
$61 6
ADC
(LL,X) 2
$65 3
ADC
LL 2
$69 2
ADC
#NN 2
$6D 4
ADC
HHLL 3
$71 5
ADC
(LL),Y 2
$75 4
ADC
LL,X 2
$79 4
ADC
HHLL,Y 3
$7D 4
ADC
HHLL,X 3
8x/9x
$81 6
STA
(LL,X) 2
$85 3
STA
LL 2
$8D 4
STA
HHLL 3
$91 6
STA
(LL),Y 2
$95 4
STA
LL,X 2
$99 5
STA
HHLL,Y 3
$9D 5
STA
HHLL,X 3
Ax/Bx
$A1 6
LDA
(LL,X) 2
$A5 3
LDA
LL 2
$A9 2
LDA
#NN 2
$AD 4
LDA
HHLL 3
$B1 5
LDA
(LL),Y 2
$B5 4
LDA
LL,X 2
$B9 4
LDA
HHLL,Y 3
$BD 4
LDA
HHLL,X 3
Cx/Dx
$C1 6
CMP
(LL,X) 2
$C5 3
CMP
LL 2
$C9 2
CMP
#NN 2
$CD 4
CMP
HHLL 3
$D1 5
CMP
(LL),Y 2
$D5 4
CMP
LL,X 2
$D9 4
CMP
HHLL,Y 3
$DD 4
CMP
HHLL,X 3
Ex/Fx
$E1 6
SBC
(LL,X) 2
$E5 3
SBC
LL 2
$E9 2
SBC
#NN 2
$ED 4
SBC
HHLL 3
$F1 5
SBC
(LL),Y 2
$F5 4
SBC
LL,X 2
$F9 4
SBC
HHLL,Y 3
$FD 4
SBC
HHLL,X 3

Diese Gruppe zeigt (mit einer Ausnahme) eine Regelmäßigkeit, für die alleine sich schon der Aufwand mit den Tabellen gelohnt hat. Nur Befehle, die ausschließlich den Accumulator betreffen haben sich hier versammelt. Außerdem liegt in jeder Zeile ausschließlich ein Befehl und in jeder Spalte ausschließlich eine Adressierungsart
Mit 3 Ausnahmen ($91, $99 und $9D) sind auch die Prozessortakte der Befehle in den Spalten immer gleich.

Tabelle 8x8 für Mnemonics %yyyxxx10[Bearbeiten | Quelltext bearbeiten]

x2
x6
xA
xE
x2
x6
xA
xE
0x/1x
$06 2
ASL
LL 2
$0A 1
ASL
1
$0E 3
ASL
HHLL 3
$16 2
ASL
LL,X 2
$1E 3
ASL
HHLL,X 3
2x/3x
$26 2
ROL
LL 2
$2A 1
ROL
1
$2E 3
ROL
HHLL 3
$36 2
ROL
LL,X 2
$3E 3
ROL
HHLL,X 3
4x/5x
$46 2
LSR
LL 2
$4A 1
LSR
1
$4E 3
LSR
HHLL 3
$56 2
LSR
LL,X 2
$5E 3
LSR
HHLL,X 3
6x/7x
$66 2
ROR
LL 2
$6A 1
ROR
1
$6E 3
ROR
HHLL 3
$76 2
ROR
LL,X 2
$7E 3
ROR
HHLL,X 3
8x/9x
$86 2
STX
LL 2
$8A 1
TXA
1
$8E 3
STX
HHLL 3
$96 2
STX
LL,Y 2
$9A 1
TXS
1
Ax/Bx
$A2 2
LDX
#NN 2
$A6 2
LDX
LL 2
$AA 1
TAX
1
$AE 3
LDX
HHLL 3
$B6 2
LDX
LL,Y 2
$BA 1
TSX
1
$BE 3
LDX
HHLL,Y 3
Cx/Dx
$C6 2
DEC
LL 2
$CA 1
DEX
1
$CE 3
DEC
HHLL 3
$D6 2
DEC
LL,X 2
$DE 3
DEC
HHLL,X 3
Ex/Fx
$E6 2
INC
LL 2
$EA 1
NOP
1
$EE 3
INC
HHLL 3
$F6 2
INC
LL,X 2
$FE 3
INC
HHLL,X 3

In den Spalten 0A und 1A haben sich die restlichen 1-Byte-Befehle versammelt. Wenn diese ausgefiltert sind, enthält wieder jede Zeile einen Befehl und jede Spalte eine Adressierungsart.

Tabelle 8x8 für Mnemonics %yyyxxx11[Bearbeiten | Quelltext bearbeiten]

Die vierte Tabelle braucht nicht mehr erstellt zu werden, da sie keine gültigen Befehle mehr enthält.

Entwurf eines Disassemblers[Bearbeiten | Quelltext bearbeiten]

Ein Disassembler muss zunächst Mnemonic von illegalen Codes trennen und dann die Adressierungsarten richtig zuordnen. Das Trennen der Mnemonics von illegalen Codes macht man am besten gruppenweise, was durch die erstellten Tabellen vereinfacht wird. Wenn man die Gruppen immer mit AND auf einen Wert bringt, um sie mit CMP auszufiltern, kann man später Tabellen für die AND- und CMP-Werte erstellen und daraus die Werte mit indirekter Adressierungauslesen. Doch für die Tabelle brauche ich noch einen weiteren Wert, um festzulegen, wie ein erkannter Code weiter verarbeitet werden soll.

;X soll als Zeiger für die Tabellen dienen, da Y gebraucht wird um den Code indirect-y-indiziert zu holen
           LDX #Tab1Len
NotFound   DEX
           BEQ Ende            ;oder ein anderes RTS anspringen
           LDA (ptrDisass),y
           AND Tab_AND-1,X
           CMP Tab_CMP-1,X
           BNE NotFound

X enthält jetzt einen Wert, mit dem man bestimmen kann, wie jetzt weiter verfahren wird. Eine Möglichkeit wäre, einen Einsprungpunkt so auf den Stack zu legen, als wäre es eine Rücksprungadresse von JSR. Mit RTS würde man auf dem Weg einen "JMP Absolut,X simulieren.

           LDA Hi_Einsprung-1,X   ;Einen manipulierten "JMP" mit RTS vorbereiten
           PHA
           LDA Lo_Einsprung-1,X
           PHA
Ende       RTS

Eine andere Möglichkeit wäre, den X-Wert weiter zu verarbeiten um anhand einer neuen Tabelle zu entscheiden, was weiter geschehen soll:

           TXA
           LDX #Tab2Len
           CMP Entscheidung,X

Ziel des Filterns[Bearbeiten | Quelltext bearbeiten]

Das Disassemblieren soll soll über das Ausfiltern 2 Werte ermitteln, für die 2 Speicheradressen benötigt werden. Ich benenne diese einmal provisorisch mit CodeMne und CodeAdr. Über die genau verwendeten Adressen kann man sich später Gedanken machen. Da CodeMne maximal 55=$37 enthalten kann, weil es nur 56 verschiedene Mnemonics gibt (0-55 während -1=$FF kennzeichnet das kein Mnemonic erkannt wurde), kann man relativ einfach den Wert mit 3 multiplizieren, um die 3 Buchstaben des Mnemonics zu holen.

;Diese Routine soll nur aufgerufen werde, wenn CodeMne nicht $FF enthält
           LDA CodeMne
           ROL            ;*2 (dadurch wird auch Carry gelöscht)
           ADC CodeMne
           TAX
           LDA MneListe,X
           JSR Ausgeben
           LDA MneListe+1,X
           JSR Ausgeben
           LDA MneListe+2,X
           JSR Ausgeben
           LDA #20            ;Space
           JMP Ausgeben

Diese Routine ist geringfügig (4 Byte CodeMne in ZP, sonst 5 Byte) länger, als wenn man mit 3 Listen arbeitet, die jeweils einen der 3 Buchstaben enthalten (TabChar1, TabChar2, TabChar3)

           LDX CodeMne
           LDA TabChar1,X
           JSR Ausgeben
           LDA TabChar2,X
           JSR Ausgeben
           LDA TabChar3,X
           JSR Ausgeben
           LDA #20          ;Space
           JMP Ausgeben

Wenn keine Adresse für CodeMne verwendet wird, sondern der MneCode in X übergeben wird, ist diese Variante auch kürzer (10 Byte) als folgender Code:

           TXA
           PHA
           TSX
           INX
           ROL
           ADC 0100,X
           TXS
           TAX
           LDA MneListe,X
           JSR Ausgeben
           LDA MneListe+1,X
           JSR Ausgeben
           LDA MneListe+2,X
           JSR Ausgeben
           LDA #20            ;Space
           JMP Ausgeben

Ausfiltern[Bearbeiten | Quelltext bearbeiten]

Man fängt am besten damit an, die Werte auszufiltern, die der Regelmäßigkeit einer anderen Gruppe wiedersprechen. Als Beispiel nehme ich einmal die beiden BIT- und die beiden JMP-Befehle, die als einzige Befehle wiedersprechen, dass mit AND #87 / CMP #04 nur illegale Codes ausgefiltert werden:

  • AND #F7 und CMP #24 filtert BIT aus
  • AND #DF und CMP #4C filtert JMP aus

Jetzt sind alle verbliebenen Befehle mit dem Bitmuster 0xxxx100 illegal (AND #87 / CMP #04). Weiter gehts ...

  • AND #9F und CMP #0A filtert die impliziten Adressierungen von ASL, ROL, LSR und ROR aus

Jetzt sind alle verbliebenen Befehle mit dem Bitmuster 0xxxx010 illegal (AND #87 / CMP #02).