Eine eigene virtuelle Machine

Übersicht BlitzBasic FAQ und Tutorials

Neue Antwort erstellen

Vertex

Betreff: Eine eigene virtuelle Machine

BeitragMo, Feb 23, 2004 19:45
Antworten mit Zitat
Benutzer-Profile anzeigen
Folgendes soll mal kurz vortsellen, wie man ein Emulator einen Assembler
und ein Disassembler für eine virtuelle (also nur von mir ausgedachte)
Machine schreibt.

Wie sieht eigentlich eine Exe aus, die von Blitz erstellt wird?
Zuerst hat jede Exe unter Windows einen sogenannten Header.
In ihm ist eine Signatur wieder zu finden, die Windows sagt, das diese
Datei eine ausführbare Exe (Execute = Ausführen) ist. Dann wird in ihr
ebenfalls beschrieben, wo Datateil und der Codeteil der Exe zu finden ist.
Man gibt soetwas in Offsets (das sind Position in Byte innerhalb der Exedatei) an.
Dieser Header
wird von Blitz einfach erzeugt, wer sich dafür interessiert:
http://www.wotsit.org/download.asp?f=exe-win

Im Datateil sind all die Variablen wieder zu finden, die zuvor einen konstanten
Wert bekommen haben. Dabei wird je nach Assemblerdialekt z.B.
ganze so angegeben:
IntVar dd 1234567
ShortVar dw 12345
ByteVar db 123
StringVar db "Hello world"
bei dd steht das letzte für "double" und das double ist in Bezug auf
double word zu sehen. 2 mal word = 2 mal short = 4 Byte groß
dw steht dann für word das ist in Blitz eben short also 2 Byte groß.
db steht für byte wie in blitz und hat 8 bit.
Dynamische Speicherblöcke wie z.B. Banks die zur Laufzeit erstellt werden,
werden über betriebsystemeigene Funktionen erstellt via Melloc z.B. unter
Windows. Hierbei kümmert sich Windows selber um die Speicherverwaltung.

Im Codeteil kann man die ganzen Befehle des Prozessors wieder finden.
Ab Intel 8086 hat man sich auf einen Standart geeinigt.
Das sieht z.B. so aus
MOV MeineVar,30
dabei wird der Wert 30 in eine Variable kopiert (nicht verschoben)
Es gibt sehr viele Befehler davon, eine Liste aller Prozessor Befehle fidnet
man im Internet.

Wie wird so ein Assemblerbefehl in einer Exedatei eingebunden?
Jeder Prozessorbefehl hat einen sogenannten OPCode. Dabei kann z.B. ein
MOV mehrere OPCodes haben, da darauf geachtet werden muss, ob man
nun einer Integer-, Sort- oder Bytevariable einen Wert zuweist und oder
man mit sogenannten Registern arbeitet (dazu später). Nehmen wir mal
an, unsere Variable ist 32 Bit groß (also Integer) und der dazugehörige
OPCode für MOV ist 25. Die Variable wurde vorher schon in eine Speicheradesse
sagen wir mal 1000 umgewandelt, dann sehe das ganze Codetechnisch
so aus:
Stream = WriteFile("MeinProgramm.exe")
; Header rein schreiben
; ...
WriteByte Stream,25 ; 25 = MOV für eine 32 Bit Variable
WriteInt Stream,1000 ; Die schon umgewandelte Adresse der Variable
WriteInt Stream,30 ; Der Wert 30 der der Variable zugewiesen werden soll
; ...
; Datasegement eintragen
; ...
CloseFile Stream

Was sind Regsiter?
Register sind kleine Spiecherbereich im Prozessor (also nicht der externe
WorkRAM = Arbeitspeicher / RAM = Random Acces Memory)
Ein 32 Intelpentiumprozessor hat z.B. 4 Workregister. Das heißt sie sind
überall einsetzbar.
Diese 4 register sind 32 Bit groß (was auch zum Namen 32 Bit Prozessor
führt (es hat auch noch was mit der Speicheradressenverarbeitung zu tun))
Man nennt sie A, B, C und D. Sie werden alle nochmal unterteilt z.B. Register A
AL und AH (ALow AHigh beider sind 8 Bit groß)
AX bestehend aus AL und AH (ist 16 Bit groß)
EAX bestehend aus AX und den anderen 16 Bit (somit ist er 32 Bit groß)
Dann existiert noch ein sogenannter PC. PC steht für Programmcounter.
Er wird immer erhöht, sobald ein Prozessorbefehl ausgeführt wird.
Da Register direkt im prozessor intekriert sind, sind sie auch viel schneller
zu beschreiben und auszulesen.

Was ist ein Stack?
Ein Stack ist ein Stapelspeicher. Intelprozessoren arbeiten mit einen
sogenannten FIFO Prinzip. FIFO = First in first out.
d.H. der Prozessor kann auf diesen Stapel Werte ablegen. Muss er ihn abarbeiten,
so wird der oberste Eintrag ausgelesen und weggekickt. Erst dann kann er
der vorletzten Wert auslesen.
Der Stack wird für Sprungadressen verwendet änlich dem Goto.
z.B.
Befehl1 ; CP = 1
Befehl2 ; CP = 2
Befehl3 ; CP = 3
Jump MeinLabel ; CP = 4
Befehl7 ; CP = 8
Befehl8 ; CP = 9
Befehl9 ; CP = 10
.MeinLabel
Befehl4 ; CP = 5
Befehl5 ; CP = 6
Befehl6 ; CP = 7
Return ;
Bei einem Sprung zu einem Label, muss sich der Prozessor merken,
an welcher Adresse er zurücksprignen soll (durch Return ausgelöst), und
somit muss er diese Adresse auf den Stack legen. Nach Return holt sich
der Prozessor diesen Wert wieder, ubnd springt zurück zum Befehl7.

Interups:
Interups werden durch den Prozssorbefehl Int aufgerufen. Dabei wird
die Interupt nummer übergeben.
z.B.:
MOV AH,0
MOV AL,13h ; Modus 13h = 640 * 480 * 256 Farben
Int 10h ; BIOS-Interupt auslösen.
(das h steht für hex, 13h und 10h sind somit hexzahlen)
Als erstes wir im Register AH eine 0 eingetragen, und dann im Register
AL eine 19 (oder eben 13h). Das BIOS holt sich nach dem Interupt 10h
diese beiden Werte, und stellt auf diesen Bildschirmodus um.
Durch BIOS Interups werden auch Tastenereigniss, Mauskoordinaten,
Festplatten Einträge etc. ausgelesen.
Wer sich dafür interessiert:
http://www.datasource.de/programmierung/index.html

Wie schreibt man nun sich eine eigene virtuelle Machine?
Man muss sich vorher gedanken machen, was sie alles können soll.
Meine die ich z.Z. schreibe orientiert sich stark am GameBoyAdavance.

Dann erstellt man sich eine Liste mit allen Prozessorbefehlen die man so
brauchen könnte, und überlegt sich auch, welche Interups also eine
Art Systeminterne funktionen man zu verfügung stellt. Nun überlegt man sich
welche Register es geben wird, wie groß sie sind, und wie man sie benennt.
Beim GBA gibt es z.B. 16 Register namens R0-15
Dann weist man diesen Befehlen einen OPCode also eine Funktionsnummer
zu.
man muss eben dabei auf Byte, Short und Integer sowie die ganzen ausgedachten
Register achten.
Jetzt kann man sich ein Assemblerdialekt ausdenken. Meiner sieht inetwa
so aus:
Code: [AUSKLAPPEN]

DESCRIPTION:
   Autor: Max Musterman
   Language: English
   Any thing is possible or not :)
INCLUDES:
   Functions.asm
DEFINES:
   blubregister R0
CODE:
   MOV blubregister,R1
   .MyLabel
   ; Comment1
   JMP MyLabal ; Comment2
DATA:
   df MyVar 25.5
   db GGG 20
   db Bla[] @incbin("bla.bmp",0,0)

Man muss also alles durch parsen. Auf Syntaxfehler brauchen man dabei nur
wenig zu achten, nur z.B. das MOV nicht plötzlich vom User 6 Parameter
überweisen bekommen hat, obwohl es nur 2 hat.
Spätenstens jetzt muss man sich überlegen, wie seine ROM bzw. Exe
strukturmäßig aussehen soll.
ROM steht übrigens für Read Only Memory. Meine sind so aufgebaut:
Zitat:

Header:
Offset Beschreibung
0 - 2 "EXT" (Signature) - Steht für "Exist" so heißt meine Machine
2 - 6 Version (Float) - Assemblerversionsnummer
7 - 11 Descriptionoffset (Integer) - wo steht die Beschreibung der ROM?
12 - 16 Descriptionlength in Byte (Integer) - und wie lang ist sie?
17 - 21 Codeoffset (Integer) - Wo steht der ausführbare Code in der ROM?
22 - 26 Codelength in Byte (Integer) - und wie groß ist er?
27 - 31 Dataoffset (Integer) - wo findet man das Datasegment?
32 - 36 Datalength in Byte (Integer) - und wie lang ist es?
Nun kommt das Description- und danach das Codesegment.
Die Descrioption ist ein einfacher Text, der vom Emulator angezeigt wird.

Jetzt werst alle Includes eingebunden die Labels, Variablen und Defines
enthalten können. Nun werden alle Variabalen in Speicheradressen, Labels
in Offsets innerhalb der ROM ausgetauscht, und Defines durch ihren Wert
bzw. ihrer Zeichenkette, und auch incbin durch den inhalt der angegebenen
Datei ersetzt. (die beidne letzten Parameter benutze ich als Start und Endoffset,
was alles von der Datei mit eingebunden wird.

. All dies wird in eine *.obj Datei gespeichert.
Die *.asm Datei wird gekickt, und die *.obj datei geöffnet. Nun wird
eine *.bin bzw. *.exe Datei angelegt. Auch eine Bank mit dem Header,
dessen Werte vorläufig auf 0 gesetzt werden:
Header = CreateBank(37)
PokeByte Header,00,Asc("E") ; |
PokeByte Header,00,Asc("X") ; > EXT
PokeByte Header,00,Asc("T") ; |
; Der Rest des headers ist sowiso auf 0, da CreateBank alles mit 0 füllt in der Bank

Da als erstes in der *.obj (und auch *.asm) eine Description steht, wird
diese durchgeparst, in die Datei geschrieben, und das Descriptionoffset
auf 37 gestellt (da die Description direkt an dem Header kommt, der 37
Byte groß ist, und ein Dateioffset bei 0 anfängt). Die Descriptionlänge
er gibt aus der Description. Also geht man jede Zeile der Description durch,
fragt ab, wie lang sie ist mit Len(DieZeile$) addiert 2 (da Asc(13) und Asc(10)
zusammen den zeilenumbruch ergeben) und addiert das ganze zum
Descriptionlengtheintrag im Header:
PokeInt Header,12,PeekInt(Header,12) + Len(DieZeile$) + 2
(das ganze natürlich in einer Schleife, die alle Descriptionzeilen durchgeht)

Jetzt zum Codeteil:
Die Befehle werden auch durchgeparst, und durch ihren OpCode ersetzt.
Da oftmals auch mehr als nur max. 256 OpCodes zusamenkommen,
würde ich vorschlagen, die OpCodes als Short abzuspeichern.
Die OpCodes sind natürlich vom Variablen und f.v. Registerparameter abhängig.
Also: WriteShort ExeStream,OpCode
nun kommt man zu den Parametern. Die Regsiter sind shcon im OpCode
mit definiert, also brauch man bei MOV R0,25 R0 nicht noch extra anzugeben.
Die 25 ist 32 Bit (da R0 ein 32 Bit Register ist). Somit wird die 25 als
Int (das 32 Bit oder 4 Byte hat) abgespeichert:
WriteInt ExeStream,25
Ist alles fertisch assembiliert, wird die länge des Codeteiles genommen,
und im Header unter Codelength abspeichert. Das Offset ergibt sich aus
37 + Descriptionlength

Das Datasegment:
Ich würde das ganze so abspeichern:
Die Typbezeichnung (also byte short integer) als Byte abspeichern. Danach
kommt die größe die die Variable (oder auch Array) im Speicher einnimmt:
db Bla 25 nimmt nur 1 Byte ein
db Bla "Hallo" nimmt hingegen 6 Byte ein (Hallo = 5 Zeichen + 0 terminatedzeichen)
db Bla[] incbin("bla.dat",0,9) nimmt 10 Byte ein
und nach der größenangabe in Byte als Integer, kommt der eigentlich
Wert. Im header kann wieder Dataoffset und Datalength angegeben werden.

Jetzt ist alles fertisch assembeliert, somit kann in den ExeStream
erst der Header durch WriteBytes Header,ExeStream,0,37 geschrieben
werden, dann das assembvelierte Codesegment und dann das umgewandelte
Datasegment.
Fertisch ist der Assembler.

Nun gehts zum Emulator.
Wi müssen die Datei öffnen und den Header auf korrkte Signatur prüfen.
Ist das richtig, lesen wir zuerst die Description aus, und geben sie auf
dem Display wenn gewollt aus.
Nun legen wir ein Type namens Stack an
Code: [AUSKLAPPEN]
Type Stack_T
   Field Value
End Type

Und auch 4 32 Workregister
Code: [AUSKLAPPEN]
Global RegisterA = CreateBank(4)
Global RegisterB = CreateBank(4)
Global RegisterC = CreateBank(4)
Global RegisterD = CreateBank(4)

Den CP brauchen wir aus
Code: [AUSKLAPPEN]
Global RegisterCP = 0

Ein WorkRAM brauchen wir auch, um die Variablen auslagern zu können:
Code: [AUSKLAPPEN]
Global WRAM = CreateBank(1048576)

Meine ist übrigens 1024 KB (= 1024 * 1024 Byte) groß.
Nun gehen wir ins Datasegment, und schreiben alle Variablen in den
WRam. Speicheradresse die wir zuvor in der *.obj Datei umgewandelt
haben, gibt das Offset im WRAM an. Also wenn es z.b. ne
Bytevariable ist dann PokeByte WRAM,VariablenOffset,Variablenwert
Nun gehts zum Codesegment. Jeder befehl ist 2 Byte = Short groß
somit kann man ihn durch OPCode = ReadShort(ROMStream)
auslesen.
Man macht sich am besten ne select Caseabfrage inetwa so:
Code: [AUSKLAPPEN]

;...
Const MOV0 10 ; MOV Byte,Wert
Const MOV1 11 ; MOV Short,Wert
Const MOV2 12 ; MOV Integer,Wert
Const MOV3 13 ; MOV Integer,Wert
Const MOV4 14 ; MOV EAX,Wert
Const MOV5 15 ; MOV AX,Wert
Const MOV6 16 ; MOV AH,Wert
Const MOV7 17 ; MOV AL,Wert
Const MOV8 18 ; MOV EBX,Wert
;...
Select OPCode
   ; Der Programmcount muss natürlich erhöht werden
   CASE ADD0: fADD0 : CP = CP + 1
   ;...
   CASE MOV0: fMOV0 : CP = CP + 1
   CASE MOV1: fMOV1 : CP = CP + 1
   CASE MOV2: fMOV2 : CP = CP + 1
   ; ...
End Select
;...
Function fMOV0()
   Local Address,Value
   ; Es ist eine Bytevariable bzw. soll ein Bytewert in die Adresse
   ; übergeben, die im ersten Paramter steht, und immer 4 Byte groß ist
   Address = ReadInt(ROMStream)
   ; Wert auslesen, der in die Adresse geschrieben werden soll
   Value = ReadByte(ROMStream)
   ; Und da sganze in den WorkRAM damit
   PokeByte WRAM,Address,Value
End Function
; ...
Function fMOV0()
   Local Value
   ; Diesmal das selbe Spiel bloß mit einem 16 Bit Regsiter(AX)
   Value = ReadShort(ROMStream)
   PokeShort RegsiterA,0,Value
End Function
; ...


Wird ein Jump vollbracht, muss in den Stack der Filepointer
Code: [AUSKLAPPEN]
Stack.Stack_T = New Stack_T
Stack\Value = FilePos(ROMStream)

Nach einen Return wird sich der Wert noch gemerkt,
Code: [AUSKLAPPEN]
Address = Stack\Value

danach gelöscht,
Code: [AUSKLAPPEN]
Delete Stack.Stack_T

und wieder weiter gemacht
Code: [AUSKLAPPEN]
SeekFile ROMFile,Address


Ein kleiner debugger der die Register CP WRAM usw. anzeigt und auch
sverlangsamt alles abarbeitet wäre natürlcih auch möglich.

Kommen wir nun noch zum Disassembler. Er ist eine Mischung aus
EMulator und Assembler.
Erst wieder header auslesen und checken. Dann die OPCOdes auslesen
dazugehörigen Befehl mit den Parametern ausgeben lassen und fertisch
ist das Mondgesicht. Das Disassembelierte entspricht einer 1 zu 1 Kopie
von der *.obj Datei. Es Fehlen somit kommentare Variablennamen Labelnamen
und Includedateiangaben.

So das wärs dann mal. Alles ist antürlich nicht korrekt im Tut, aber bei der
eigenen Machine spielt da sauch keine Rolle.

Noch ein paar gute Links:
http://www.iconsoft.de/TUTORIAL/mnemonic.htm (OP-Codes)
http://www.robsite.de/tutorials.php?tut=assembly gute Assembler tuts.
http://www.cs.rit.edu/~tjh8300...teSpec.htm GBA CPU
(der GBA hat übrigens nen ARM7 Prozessor, sein Befehlssatz kann man im
INet heraussuchen)
http://www.classicgaming.com/EPR/ beispielemulatoren mit source
mfg olli
vertex.dreamfall.at | GitHub

Vertex

BeitragSa, März 06, 2004 21:54
Antworten mit Zitat
Benutzer-Profile anzeigen
So hier die Doku über meine machine. Es beschreibt den Aufbau einer
ausführbaren Datei. Der Header hat sich grundlegend geändert:
Zitat:

Aufbau einer ROM-Datei

Der Header:
Byte 0 - 3 entspricht "EXIT" oder ASCII 69, 88, 73, 84 oder als Hex 0x54495845
Byte 4 - 7 gibt an, wie viel Byte die Beschreibung(Description) einnimmt
Byte 8 - 11 gibt an, wie viel Byte das Codesegment einnimmt
Byte 12 - 15 gibt an, wie groß das Datasegment in Byte ist

Die Discription:
Sind normale Textzeilen die mit ASCII 13 + ASCII 10 abgeschlossen werden.

Das Codesegment:
Pro OpCode werden 3 Byte benötigt. Diese unterteilen sich folgendermaßen:
Byte 0(Bit 0 - 7) ist die Befehlsnummer. Hier eine Liste der Befehlsnummern:
- 0x00 = MOV (Kopiere Wert von Para2 in Para1)
- 0x01 = ADD (Para3 = Para1 + Para2)
- 0x02 = SUB (Para3 = Para1 - Para2)
- 0x03 = MUL (Para3 = Para1 * Para2)
- 0x04 = DIV (Para3 = Para1 / Para2)
- 0x05 = SQR (Para2 = Quadratwurzel aus Para1)
- 0x06 = NEG (Para2 = -|Para1|)
- 0x07 = DEC (Para1 = Para1+1)
- 0x08 = INC (Para1 = Para1-1)
- 0x09 = And (Para3 = Para1 & Para2)
- 0x0A = ORR (Para3 = Para1 | Para2)
- 0x0B = XOR (Para3 = Para1 ^ Para2)
- 0x0C = NOT (Para2 = !Para1)
- 0x0D = PUSH (Auf den Stack wird Para1 hinzugefügt)
- 0x0E = POP (1. Wert des Stacks wird in Para1 gespeichert anschließend gelöscht)
- 0x0F = INT (Interrupt Para1 ausführen)
- 0x10 = CLI (Keine Interrupts zulassen)
- 0x11 = STI (Interrupts wieder zulassen)
- 0x12 = JMP (Springe zu Label in Para1)
- 0x13 = JEQ (Springe zu Label in Para3 wenn Para1 == Para2)
- 0x14 = JNE (Springe zu Label in Para3 wenn Para1 != Para2)
- 0x15 = JIG (Springe zu Label in Para3 wenn Para1 > Para2)
- 0x16 = JNG (Springe zu Label in Para3 wenn Para1 <= Para2)
- 0x17 = JIL (Springe zu Label in Para3 wenn Para1 < Para2)
- 0x18 = JNL (Springe zu Label in Para3 wenn Para1 => Para2)
- 0x19 = RET (Kehre zum Label zurück)

Bit 8 - 12, 13 - 17, 18 - 22 geben an, welche Parameter folgen. Hier eine Liste mit den Parameternummern:
- 0x00 = Nix (Dieser Parameter und folgende werden nicht benötigt)
- 0x01 = Bytewert (Der 8-Bit-Wert wird direkt übergeben)
- 0x02 = Wordwert (Der 16-Bit-Wert wird direkt übergeben)
- 0x03 = DWordwert (Der 32-Bit-Wert wird direkt übergeben)
- 0x04 = Offset Byte (Offset eines 8-Bit Wertes im Speicher)
- 0x04 = Offset Word (Offset eines 16-Bit Wertes im Speicher)
- 0x05 = Offset DWord (Offset eines 32-Wertes im Speicher)
- 0x06 = Label
- 0x07 = AL (8-Bit-Register A-Low)
- 0x08 = AH (8-Bit-Register A-High)
- 0x09 = AX (16-Bit-Register AX)
- 0x0A = EAX (32-Bit-register EAX)
- 0x0B = BL (8-Bit-Register B-Low)
- 0x0C = BH (8-Bit-Register B-High)
- 0x0D = BX (16-Bit-Register BX)
- 0x0E = EBX (32-Bit-register EBX)
- 0x0F = CL (8-Bit-Register C-Low)
- 0x10 = CH (8-Bit-Register C-High)
- 0x11 = CX (16-Bit-Register CX)
- 0x12 = ECX (32-Bit-register ECX)
- 0x13 = DL (8-Bit-Register D-Low)
- 0x14 = DH (8-Bit-Register D-High)
- 0x15 = DX (16-Bit-Register DX)
- 0x16 = EDX (32-Bit-register EDX)
- 0x17 = FR (32-Bit Flagregister)
- 0x18 = SP (32-Bit-Register StackPointer)
- 0x19 = SS (32-Bit-Register StackSize)
- 0x1A = PC (32-Bit-Register ProgramCounter)
- 0x1B = IP (32-Bit-Register InstructionPointer)

Dann kommen die einzelnen Parameter. Bei den Parametern 0x07 - 0x1B sowie 0x00 folgen
Keine Parameterwerte mehr. Bei den Offsetparametern 0x04 - 0x05 folgt ein 32Bit DWord Wert
der das Offset enthält. Bei Parameter 0x06 folgt ebenfalls ein 32-Bit DWord-Wert, der auch ein
Offset enthält. Bit 23 bleibt unbenutzt.

Beispiel: MOV Al, 10
MOV hat die Befehlsnummer 0x00 oder binär 00000000
AL hat die Parameternummer 0x07 oder binär 00111
10 ist ein Bytewert somit hat er die Parameternummer 0x01 oder binär 00001
Es gibt kein Parameter3 somit bekommt es die Parameternummer 0x00 oder binär 00000
Bit 23 ist ungenutzt und bekommt dem binärwert 0
Der OpCode ergibt sich aus Befehlsnummer + den 3 Parameternummern + Bit 23:
OpCode = 00000000 00111 00001 00000 0, aufgeteilt in 3 Byte die jeder OpCode einnimmt
Sieht das so aus: Byte1: 00000000 oder 0 Byte2: 00111000 oder 56 Byte3: 01000000 oder 64
Dann folgen die jeweiligen Parameter: AL braucht nicht abgespeichert werden, da der Wert im
Prozessor gespeichert wird. 10 ist ein Bytewert benötigt somit auch 1 Byte. Parameternummer 3
ist 0 steht für ungenutzt, und brauch daher nicht abgespeichert werden. Der Befehl mit diesen
Parametern braucht also 4 Byte (3 Byte OpCode + 1 Byte Parameter). Diese sehen so aus
0, 56, 64, 10.

Beispiel2: MUL BL, CH, @meineVariable (meineVariable soll Bytevariable sein)
MUL wird zu 00000011
BL zu 01011
CH zu 01000
@MeineVariable zu 00100 (@ kennzeichnet das Offset einer Variable)
Bit 23 ist 0
OpCode = 00000011 01011 01000 00100 0
Para1 und Para2 müssen nicht abgespeichert werden nur das Offset der Variable.
Dieses Offset wird vom Assembler festgelegt. Er hat sich hier z.B. für 12000 entschieden.
Offsets werden als DWord abgespeichert, somit sind sie 32 Bit groß.
Offset von meineVariable: 00000000000000000010111011100000
Aufgeteilt in die einzelnen Bytes ergibt dies 7 Bytes (3 Byte OpCode + 4 Byte Offsetwert):
3, 90, 8, 0, 0, 64, 224

Beispiel3: INC @meinArray[2] (meinArray soll ein DWord-Array sein und sich am Offset 100 befinden)
INC wird zu 0x08 oder binär: 00001000
@meinArray[2] wird zu 0x05 oder binär: 00101
Para2 wird zu 0x00 oder binär 00000
Para3 wird zu 0x00 oder binär 00000
OpCode = 00001000 00101 00000 00000
Nun folgt das Offset des DWord-Arrays als DWordwert (ist auch DWord bei Byte- oder Wordarrays)
Offset: 100 + 2*4 = 108 (2 ist der Index, 4 die Größe die pro Wert des Arrays eingenommen wird)
oder binär: 00000000000000000000000001101100
Aufgeteilt in Bytes ergibt dies 7 Byte(3 Byte OpCode + 4 Byte Offset): 8, 5, 0, 0, 0, 0, 108

Das Datasegment:
Byte 0 steht für den Typ der Variable. Hier die Typliste:
- 0x00 = Bytevariable
- 0x01 = Wordvariable
- 0x02 = DWordvariable
- 0x03 = Bytearray
- 0x04 = Wordarray
- 0x05 = Dwordarray
Byte 1 - 4 enthält das Offset der/des Variable/Arrays als DWord
Wenn der Typ zwischen 0x00 und 0x02 liegt, dann folgt der Wert der Variable in Größe ihres Typs
(d.h. ist die Variable eine Wordvariable folgt nun ein Wordwert(2 Byte), das ihren Wert enthält)
Andernfalls folgt ein DWordwert wie viel Speicher in Byte das Array einnehmen wird, und danach
die einzelnen Werte ausgeteilt in Bytes.

Beispiel: meineVariable WORD 12 (Offset wurde vom Assembler als 13000 festgelegt)
Typ: 0x01 (1 Byte) binär: 00000001
Offset: 13000 (4 Byte) binär: 00000000000000000011001011001000
Wert: 12 (2 byte) binär: 0000000000001100
Aufgeteilt in 7 Bytes: 1, 200, 50, 0, 0, 0, 12

Beispiel2: meinArray[] BYTE "Hallo" (Offset wurde vom Assembler als 200 festgelegt)
Typ: 0x03 (1 Byte) binär: 00000011
Offset: 200 (4 Byte) binär: 00000000000000000000000011001000
Größe: 5 (4 Byte) binär: 00000000000000000000000000000101
Wert: 72, 97, 108, 108, 111(5 Byte) binär: 01001000 01100001 01101100 01101100 01101111
Aufgeteilt in 14 Byte: 3, 0, 0, 0, 200, 0, 0, 0, 5, 72, 97, 108, 108, 111


mfg olli
vertex.dreamfall.at | GitHub

Vertex

BeitragMo, Okt 11, 2004 21:00
Antworten mit Zitat
Benutzer-Profile anzeigen
Passend zum Thema arbeite ich seid langer Zeit an einem C64 Emulator. Er soll später einmal SID Sounds abspielen können. Die CPU ist zum größten Teil übersetzt wurden (es fehlen noch 53 illegale Instruktionen). Erst wenn die CPU vollständig emuliert werden kann, kann man beginnen den SID, ein Soundchip zu emulieren. Er hat dann die Adressen von 0xDC00 bis 0xD41C.

SIDcom.bb:
Code: [AUSKLAPPEN]
; ----------------------------------------------------------------------------

Include "cpu.bb" ; 6510 CPU Emulator
Include "sid.bb" ; 6585 SID Emulator

; file information
Global fName$, fSize, fStream

; header information
Global hSignature$, hVersion, hDataOffset, hLoadAddr, hInitAddr
Global hPlayAddr, hSongs, hStartSong, hSpeed, hName$, hAuthor$
Global hCopyright$, hFlags

; ----------------------------------------------------------------------------

fName$ = CommandLine$()
fSize = FileSize(fName$)

fStream = ReadFile(fName$)
If fStream = False Then
   RuntimeError "Can't open file!"
EndIf

loadHeader
checkHeader

cpuMem = CreateBank(64*1024)
ReadBytes(cpuMem, fStream, hLoadAddr, fSize-hDataOffset)
CloseFile fStream

cpuInit
While cpuRegPC < 64*1024 And KeyDown(1) = 0
   cpuExecute(PeekByte(cpuMem, cpuRegPC))
Wend

; ----------------------------------------------------------------------------

Function loadHeader()
   Local i, tmp
   
   For i = 0 To 3
      hSignature$ = hSignature$+Chr$(ReadByte(fStream))
   Next
   hVersion    = b2l(ReadShort(fStream))
   hDataOffset = b2l(ReadShort(fStream))
   hLoadAddr   = b2l(ReadShort(fStream))
   hInitAddr   = b2l(ReadShort(fStream))
   hPlayAddr   = b2l(ReadShort(fStream))
   hSongs      = b2l(ReadShort(fStream))
   hStartSong  = b2l(ReadShort(fStream))
   hSpeed      = ReadInt(fStream)
   For i = 0 To 31
      tmp = ReadByte(fStream)
      If tmp > 0 Then hName$ = hName$+Chr$(tmp)
   Next
   For i = 0 To 31
      tmp = ReadByte(fStream)
      If tmp > 0 Then hAuthor$ = hAuthor$+Chr$(tmp)
   Next
   For i = 0 To 31
      tmp = ReadByte(fStream)
      If tmp > 0 Then hCopyright$ = hCopyright$+Chr$(tmp)
   Next
   If hVersion = 2 Then
      hFlags = b2l(ReadShort(fStream))
      ReadInt(fStream) ; reserved
   EndIf
End Function

Function checkHeader()
   If hSignature$ <> "PSID" Then
      RuntimeError "No psid file!"
   EndIf
   If Not (hVersion = 1 Or hVersion = 2) Then
      RuntimeError "False psid version!"
   EndIf
   If hVersion = 1 Then
      If hDataOffset <> $0076 Then
         RuntimeError "False dataoffset!"
      EndIf
   Else
      If hDataOffset <> $007C Then
         RuntimeError "False dataoffset!"
      EndIf
   EndIf
   If hLoadAddr = 0 Then
      hLoadAddr = ReadShort(fStream) ; o_O
   EndIf
   If hSongs < 1 Then
      RuntimeError "No songs includet!"
   EndIf
   If hStartSong < 1 Or hStartSong > hSongs Then
      RuntimeError "False start song number!"
   EndIf
   If (hFlags And $0001) = True Then
      RuntimeError "Player not includet!"
   EndIf
End Function


cpu.bb:
Code: [AUSKLAPPEN]
; These commands are avariable:
; ADC, AND, ASL, BCC, BCS, BEQ, BIT, BMI, BNE, BPL, BRK, BVC, BVS, CLC
; CLD, CLI, CLV, CMP, CPX, CPY, DEC, DEX, DEY, EOR, INC, INX, INY, JMP
; JSR, LDA, LDX, LDY, LSR, NOP, ORA, PHA, PHP, PLA, PLP, ROL, ROR, RTI
; RTS, SBC, SEC, SED, SEI, STA, STX, STY, TAX, TAY, TSX, TXA, TXS, TYA

; Illegaly operations:
; NOP, KIL, SBC, SAX, LAS, LAX, AXS


Global cpuMem, cpuWaitCycles, cpuRegA, cpuRegX, cpuRegY, cpuRegSP, cpuRegPC
Global cpuRegP, address

Const CPU_CARRY     = %00000001
Const CPU_ZERO      = %00000010
Const CPU_INTERRUPT = %00000100
Const CPU_DECIMAL   = %00001000
Const CPU_BREAK     = %00010000
Const CPU_OVERFLOW  = %01000000
Const CPU_NEGATIVE  = %10000000

Function cpuInit()
   cpuRegA  = hStartSong
   cpuRegX  = $00
   cpuRegY  = $00
   cpuRegSP = $FD
   cpuRegPC = hLoadAddr
   cpuRegP  = %00110000
End Function

Function cpuExecute(op)
   Local tmp, i

   address = False
   
   Select op
      Case $00 ; BRK
         ; push cpuRegP
         ; push cpuRegPC
         ; RTI
         cpuRegP = cpuRegP Or CPU_BREAK
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 7
   
      Case $01 ; ORA Indirect, X
         cpuORA($01)
         
      Case $02 ; KIL Illegaly
         cpuRegPC = 64*1024-1
         
      Case $04 ; NOP Illegaly
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 1
         
      Case $05 ; ORA Zero Page
         cpuORA($05)
   
      Case $06 ; ASL Zero Page
         cpuASL($06)
         
      Case $08 ; PHP
         PokeByte cpuMem, $0100+cpuRegPC, cpuRegP
         cpuRegSP = cpuRegSP-1
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 3

      Case $09 ; ORA Immediant
         cpuORA($09)
         
      Case $0A ; ASL Akkumulator
         cpuASL($0A)

      Case $0C ; NOP Illegaly
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 1
                  
      Case $0D ; ORA Absolut
         cpuORA($0D)
         
      Case $0E ; ASL Absolut
         cpuASL($0E)
         
      Case $10 ; BPL
         If cpuRegP And CPU_NEGATIVE Then
            cpuRegPC = cpuRegPC+2
            cpuWaitCycles = 2
         Else
            tmp = PeekByte(cpuMem, cpuRegPC+1)
            If tmp And %10000000
               tmp = -(tmp And %1111111)
            EndIf
            cpuRegPC = cpuRegPC+tmp
            cpuWaitCycles = 3 ; 3+ !!!
         EndIf
         
      Case $11 ; ORA Indirect, Y
         cpuORA($11)
         
      Case $12 ; KIL Illegaly
         cpuRegPC = 64*1024-1
         
      Case $14 ; NOP Illegaly
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 1
         
      Case $15 ; ORA Zero Page, X
         cpuORA($15)
         
      Case $16 ; ASL Zero Page, X
         cpuASL($16)

      Case $18 ; CLC Implied
         cpuRegP = cpuRegP And %11111110
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 2
         
      Case $19 ; ORA Absolut, Y
         cpuORA($19)
         
      Case $1A ; NOP Illegaly
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 1
         
      Case $1C ; NOP Illegaly
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 1
         
      Case $1D ; ORA Absolut, X
         cpuORA($1D)
         
      Case $1E ; ASL Absolut, X
         cpuASL($1E)
         
      Case $20 ; JSR Absolut
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))
         PokeByte cpuMem, $0100+cpuRegPC, cpuRegPC+3-2
         cpuRegSP = cpuRegSP-1
         cpuRegPC = tmp
         cpuWaitCycles = 6
         
      Case $21 ; AND Indirect, X
         cpuAND($21)

      Case $22 ; KIL Illegaly
         cpuRegPC = 64*1024-1
         
      Case $24 ; BIT Zero Page
         ; do not forget overflow!
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         tmp = PeekByte(cpuMem, tmp)
         tmp = cpuRegA And tmp
         If tmp = 0 Then
            cpuRegP = cpuRegP Or CPU_ZERO
            cpuRegP = cpuRegP Or CPU_NEGATIVE
         ElseIf tmp And %10000000 Then
            cpuRegP = cpuRegP Or CPU_NEGATIVE
         EndIf
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 3
            
      Case $25 ; AND Zero Page
         cpuAND($25)
         
      Case $26 ; ROL Zero Page
         cpuROL($26)
         
      Case $28 ; PLP Implied
         cpuRegP = PeekByte(cpuMem, $0100+cpuRegPC)
         cpuRegSP = cpuRegSP+1
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 4
         
      Case $29 ; AND Immediant
         cpuAND($29)
         
      Case $2A ; ROL Akku
         cpuROL($2A)
         
      Case $2C ; BIT Absolut
         ; do not forget overflow!
         tmp = PeekShort(cpuMem, cpuRegPC+1)
         tmp = PeekByte(cpuMem, b2l(tmp))
         tmp = cpuRegA And tmp
         If tmp = 0 Then
            cpuRegP = cpuRegP Or CPU_ZERO
            cpuRegP = cpuRegP Or CPU_NEGATIVE
         ElseIf tmp And %10000000 Then
            cpuRegP = cpuRegP Or CPU_NEGATIVE
         EndIf
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 3
         
      Case $2D ; AND Absolut
         cpuAND($2D)
         
      Case $2E ; ROL Absolut
         cpuROL($2E)

      Case $30 ; BMI
         If cpuRegP And CPU_NEGATIVE Then
            tmp = PeekByte(cpuMem, cpuRegPC+1)
            If tmp And %10000000
               tmp = -(tmp And %1111111)
            EndIf
            cpuRegPC = cpuRegPC+tmp
            cpuWaitCycles = 3 ; 3+ !!!
         Else
            cpuRegPC = cpuRegPC+2
            cpuWaitCycles = 2
         EndIf
         
      Case $31 ; AND Indirect, Y
         cpuAND($31)
         
      Case $32 ; KIL Illegaly
         cpuRegPC = 64*1024-1
         
      Case $34 ; NOP Illegaly
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 1
         
      Case $35 ; AND Zero Page, X
         cpuAND($35)
         
      Case $36 ; ROL Zero Page, X
         cpuROL($36)
         
      Case $38 ; SEC Implied
         cpuRegP = cpuRegP Or CPU_CARRY
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 2
         
      Case $39 ; AND Absolut, Y
         cpuAND($39)
         
      Case $3A ; NOP Illegaly
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 1
         
      Case $3C ; NOP Illegaly
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 1
   
      Case $3D ; AND Absolut, X
         cpuAND($3D)
         
      Case $3E ; ROL Absolut, X
         cpuROL($3E)
         
      Case $40 ; RTI Implied
         cpuRegP = PeekByte(cpuMem, $0100+cpuRegSP)
         cpuRegSP = cpuRegSP+1
         cpuRegPC = PeekShort(cpuMem, $0100+cpuRegSP)
         cpuRegSP = cpuRegSP+2
         cpuWaitCycles = 6

      Case $41 ; EOR Indirect, X
         cpuEOR($41)
         
      Case $42 ; KIL Illegaly
         cpuRegPC = 64*1024-1
         
      Case $44 ; NOP Illegaly
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 1
                  
      Case $45 ; EOR Zero Page
         cpuEOR($45)
         
      Case $46 ; LSR Zero Page
         cpuLSR($46)
         
      Case $48 ; PHA Implied
         PokeByte cpuMem, $0100+cpuRegPC, cpuRegA
         cpuRegSP = cpuRegSP-1
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 3
         
      Case $49 ; EOR Immediant
         cpuEOR($49)
         
      Case $4A ; LSR Akku
         cpuLSR($4A)
         
      Case $4C ; JMP Absolut
         tmp = PeekShort(cpuMem, cpuRegPC+1)
         cpuRegPC = b2l(tmp)
         cpuWaitCycles = 3
   
      Case $4D ; EOR Absolut
         cpuEOR($4D)
         
      Case $4E ; LSR Absolut
         cpuLSR($4E)

      Case $50 ; BVC
         If cpuRegP And CPU_OVERFLOW Then
            cpuRegPC = cpuRegPC+2
            cpuWaitCycles = 2
         Else
            tmp = PeekByte(cpuMem, cpuRegPC+1)
            If tmp And %10000000
               tmp = -(tmp And %1111111)
            EndIf
            cpuRegPC = cpuRegPC+tmp
            cpuWaitCycles = 3 ; 3+ !!!
         EndIf

      Case $51 ; EOR Indirect, Y
         cpuEOR($51)
         
      Case $52 ; KIL Illegaly
         cpuRegPC = 64*1024-1
         
      Case $54 ; NOP Illegaly
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 1
                  
      Case $55 ; EOR Zero Page, X
         cpuEOR($55)
         
      Case $56 ; LSR Zero Page, X
         cpuLSR($4A)
         
      Case $58 ; CLI Implied
         cpuRegP = cpuRegP And %11111011
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 2
         
      Case $59 ; EOR Absolut, Y
         cpuEOR($59)

      Case $5A ; NOP Illegaly
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 1
         
      Case $5C ; NOP Illegaly
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 1
         
      Case $5D ; EOR Absolut, X
         cpuEOR($5D)
         
      Case $5E ; LSR Absolut, X
         cpuLSR($5E)
         
      Case $60 ; RTS Absolut
         tmp = PeekByte(cpuMem, $0100+cpuRegPC)
         cpuRegSP = cpuRegSP+1
         cpuRegPC = tmp
         cpuWaitCycles = 6
         
      Case $61 ; ADC Indirect, X
         cpuADC($61)
         
      Case $62 ; KIL Illegaly
         cpuRegPC = 64*1024-1
         
      Case $64 ; NOP Illegaly
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 1

      Case $65 ; ADC Zero Page
         cpuAND($65)
         
      Case $66 ; ROR Zero Page
         cpuROR($66)
         
      Case $68 ; PLA Implied
         cpuRegA = PeekByte(cpuMem, $0100+cpuRegPC)
         cpuRegPC = cpuRegPC+1
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 4
         
      Case $69 ; ADC Immediant
         cpuADC($69)
         
      Case $6A ; ROR Akku
         cpuROR($6A)
      
      Case $6C ; JMP Indirect
         tmp = PeekShort(cpuMem, cpuRegPC+1)
         tmp = PeekShort(cpuMem, b2l(tmp))
         cpuRegPC = b2l(tmp)
         cpuWaitCycles = 5
         
      Case $6D ; ADC Absolut
         cpuADC($6D)
         
      Case $6E ; ROR Absolut
         cpuROR($6E)
         
      Case $70 ; BVS
         If cpuRegP And CPU_OVERFLOW Then
            tmp = PeekByte(cpuMem, cpuRegPC+1)
            If tmp And %10000000
               tmp = -(tmp And %1111111)
            EndIf
            cpuRegPC = cpuRegPC+tmp
            cpuWaitCycles = 3 ; 3+ !!!
         Else
            cpuRegPC = cpuRegPC+2
            cpuWaitCycles = 2
         EndIf
         
      Case $71 ; ADC Indirect, Y
         cpuADC($71)
         
      Case $72 ; KIL Illegaly
         cpuRegPC = 64*1024-1
      
      Case $74 ; NOP Illegaly
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 1
         
      Case $75 ; ADC Zero Page, X
         cpuADC($75)
         
      Case $76 ; ROR Zero Page, X
         cpuROR($76)
         
      Case $78 ; SEI Implied
         cpuRegP = cpuRegP Or CPU_INTERRUPT
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 2
         
      Case $79 ; ADC Absolut, Y
         cpuADC($79)
         
      Case $7A ; NOP Illegaly
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 1
         
      Case $7C ; NOP Illegaly
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 1
      
      Case $7D ; ADC Absolut, X
         cpuADC($7D)
         
      Case $7E ; ROR Absolut, X
         cpuROR($7E)
         
      Case $80 ; NOP Illegaly
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 1
         
      Case $81 ; STA Indirect, X
         cpuSTA($81)
         
      Case $82 ; NOP Illegaly
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 1

      Case $83 ; SAX Illegaly
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         PokeByte cpuMem, tmp, cpuRegA And cpuRegX
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 4
         address = True
                  
      Case $84 ; STY Zero Page
         cpuSTY($84)
         
      Case $85 ; STA Zero Page
         cpuSTA($85)
         
      Case $86 ; STX Zero Page
         cpuSTX($86)
         
      Case $87 ; SAX Illegaly
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         PokeByte cpuMem, tmp, cpuRegA And cpuRegX
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 3
         address = True
         
      Case $88 ; DEY Implied
         cpuRegY = cpuRegY-1
         cpuRegY = cpuRegY And $FF
         If cpuRegY = 0 Then
            cpuRegP = cpuRegP Or CPU_ZERO
            cpuRegP = cpuRegP Or CPU_NEGATIVE
         ElseIf cpuRegY And %10000000 Then
            cpuRegP = cpuRegP Or CPU_NEGATIVE
         EndIf
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 2
         
      Case $89 ; NOP Illegaly
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 1
         
      Case $8A ; TXA Implied
         cpuRegA = cpuRegX
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 2
         
      Case $8C ; STY absolut
         cpuSTY($8C)
         
      Case $8D ; STA Absolut
         cpuSTA($8D)
         
      Case $8E ; STX Absolut
         cpuSTX($8E)
         
      Case $8F ; SAX Illegaly
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))
         PokeByte cpuMem, tmp, cpuRegA And cpuRegX
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 1
         address = True
         
      Case $90 ; BCC
         If cpuRegP And CPU_CARRY Then
            cpuRegPC = cpuRegPC+2
            cpuWaitCycles = 2
         Else
            tmp = PeekByte(cpuMem, cpuRegPC+1)
            If tmp And %10000000
               tmp = -(tmp And %1111111)
            EndIf
            cpuRegPC = cpuRegPC+tmp
            cpuWaitCycles = 3 ; 3+ !!!
         EndIf
         
      Case $91 ; STA Indirect, Y
         cpuSTA($91)

      Case $92 ; KIL Illegaly
         cpuRegPC = 64*1024-1
         
      Case $94 ; STY Zero Page, X
         cpuSTY($94)
         
      Case $95 ; STA Zero Page, X
         cpuSTA($95)
         
      Case $96 ; STX zero Page, Y
         cpuSTX($96)
         
      Case $97 ; SAX Illegaly
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         PokeByte cpuMem, zmp, cpuRegA And cpuRegX
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 3
         address = True
         
      Case $98 ; TYA Implied
         cpuRegA = cpuRegY
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 2
         
      Case $99 ; STA Absolut, Y
         cpuSTA($99)
         
      Case $9A ; TXS Implied
         cpuRegSP = cpuRegX
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 2
         
      Case $9D ; STA Absolut, X
         cpuSTA($9D)
         
      Case $A0 ; LDY Immediant
         cpuLDY($A0)
         
      Case $A1 ; LDA Indirect, X
         cpuLDA($A1)

      Case $A2 ; LDX Immediant
         cpuLDX($A2)
         
      Case $A3 ; LAX Illegaly
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         cpuRegA = PeekByte(cpuMem, tmp)
         cpuRegX = cpuRegA
         If cpuRegA = 0 Then
            cpuRegP = cpuRegP Or CPU_ZERO
            cpuRegP = cpuRegP Or CPU_NEGATIVE
         ElseIf cpuRegA And %10000000 Then
            cpuregP = cpuRegP Or CPU_NEGATIVE
         EndIf
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 7

      Case $A4 ; LDY Zero Page
         cpuLDY($A4)
      
      Case $A5 ; LDA Zero Page
         cpuLDA($A5)

      Case $A6 ; LDX Zero Page
         cpuLDX($A6)
         
      Case $A7 ; LAX Illegaly
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         cpuRegA = PeekByte(cpuMem, tmp)
         cpuRegX = cpuRegA
         If cpuRegA = 0 Then
            cpuRegP = cpuRegP Or CPU_ZERO
            cpuRegP = cpuRegP Or CPU_NEGATIVE
         ElseIf cpuRegA And %10000000 Then
            cpuregP = cpuRegP Or CPU_NEGATIVE
         EndIf
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 4
         
      Case $A8 ; TAY Implied
         cpuRegY = cpuRegA
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 2
      
      Case $A9 ; LDA Immediant
         cpuLDA($A9)
         
      Case $AA ; TAX Implied
         cpuRegX = cpuRegA
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 2
         
      Case $AC ; LDY Absolut
         cpuLDY($AC)
         
      Case $AD ; LDA Absolut
         cpuLDA($AD)

      Case $AE ; LDX Absolut
         cpuLDX($AE)
         
      Case $AF ; LAX Illegaly
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))
         cpuRegA = PeekByte(cpuMem, tmp)
         cpuRegX = cpuRegA
         If cpuRegA = 0 Then
            cpuRegP = cpuRegP Or CPU_ZERO
            cpuRegP = cpuRegP Or CPU_NEGATIVE
         ElseIf cpuRegA And %10000000 Then
            cpuregP = cpuRegP Or CPU_NEGATIVE
         EndIf
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 5
         
      Case $B0 ; BCS
         If cpuRegP And CPU_CARRY Then
            tmp = PeekByte(cpuMem, cpuRegPC+1)
            If tmp And %10000000
               tmp = -(tmp And %1111111)
            EndIf
            cpuRegPC = cpuRegPC+tmp
            cpuWaitCycles = 3 ; 3+ !!!
         Else
            cpuRegPC = cpuRegPC+2
            cpuWaitCycles = 2
         EndIf
         
      Case $B1 ; LDA Indirect, Y
         cpuLDA($B1)
         
      Case $B2 ; KIL Illegaly
         cpuRegPC = 64*1024-1
         
      Case $B3 ; LAX Illegaly
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegY
         cpuRegA = PeekByte(cpuMem, tmp)
         cpuRegX = cpuRegA
         If cpuRegA = 0 Then
            cpuRegP = cpuRegP Or CPU_ZERO
            cpuRegP = cpuRegP Or CPU_NEGATIVE
         ElseIf cpuRegA And %10000000 Then
            cpuregP = cpuRegP Or CPU_NEGATIVE
         EndIf
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 7
         
      Case $B4 ; LDY Zero Page, X
         cpuLDY($B4)
         
      Case $B5 ; LDA Zero Page, X
         cpuLDA($B5)
         
      Case $B6 ; LDX Zero Page, Y
         cpuLDX($B6)
         
      Case $B7 ; LAX Illegaly
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         cpuRegA = PeekByte(cpuMem, tmp)
         cpuRegX = cpuRegA
         If cpuRegA = 0 Then
            cpuRegP = cpuRegP Or CPU_ZERO
            cpuRegP = cpuRegP Or CPU_NEGATIVE
         ElseIf cpuRegA And %10000000 Then
            cpuregP = cpuRegP Or CPU_NEGATIVE
         EndIf
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 5
            
      Case $B8 ; CLV Implied
         If cpuRegP And CPU_OVERFLOW Then
            cpuRegP = cpuRegP Xor CPU_OVERFLOW
         EndIf
         cpuRegP = cpuRegP And %10111111
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 2
         
      Case $B9 ; LDA Absolut, Y
         cpuLDA($B9)
         
      Case $BA ; TSX Implied
         cpuRegX = cpuRegSP
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 2
         
      Case $BB ; LAS
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegY
         tmp = PeekByte(cpuMem, tmp)
         cpuRegA = tmp And cpuRegSP
         cpuRegX = cpuRegA
         cpuRegS = cpuRegA
         If cpuRegA = 0 Then
            cpuRegP = cpuRegP Or CPU_ZERO
            cpuRegP = cpuRegP Or CPU_NEGATIVE
         ElseIf cpuRegA And %10000000 Then
            cpuregP = cpuRegP Or CPU_NEGATIVE
         EndIf
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 7
         
      Case $BC ; LDY Absolut X
         cpuLDY($BC)
         
      Case $BD ; LDA Absolut, X
         cpuLDA($BD)
         
      Case $BE ; LDX Absolut, Y
         cpuLDX($BE)
         
      Case $BF ; LAX Illegaly
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegX
         cpuRegA = PeekByte(cpuMem, tmp)
         cpuRegX = cpuRegA
         If cpuRegA = 0 Then
            cpuRegP = cpuRegP Or CPU_ZERO
            cpuRegP = cpuRegP Or CPU_NEGATIVE
         ElseIf cpuRegA And %10000000 Then
            cpuregP = cpuRegP Or CPU_NEGATIVE
         EndIf
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 7
         
      Case $C0 ; CPY Immediant
         cpuCPY($C0)
         
      Case $C1 ; CMP Indirect, X
         cpuCMP($C1)

      Case $C2 ; NOP Illegaly
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 1
                  
      Case $C4 ; CPY Zero Page
         cpuCPY($C4)
         
      Case $C5 ; CMP Zero Page
         cpuCMP($C5)

      Case $C6 ; DEC Zero Page
         cpuDEC($C6)
               
      Case $C8 ; INY Implied
         cpuRegY = cpuRegY+1
         cpuRegY = cpuRegY And $FF
         If cpuRegY = 0 Then
            cpuRegP = cpuRegP Or CPU_ZERO
            cpuRegP = cpuRegP Or CPU_NEGATIVE
         ElseIf cpuRegY And %10000000 Then
            cpuRegP = cpuRegP Or CPU_NEGATIVE
         EndIf
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 2
         
      Case $C9 ; CMP Immediant
         cpuCMP($C9)

      Case $CA ; DEX Implied
         cpuRegX = cpuRegX-1
         cpuRegX = cpuRegX And $FF
         If cpuRegX = 0 Then
            cpuRegP = cpuRegP Or CPU_ZERO
            cpuRegP = cpuRegP Or CPU_NEGATIVE
         ElseIf cpuRegX And %10000000 Then
            cpuRegP = cpuRegP Or CPU_NEGATIVE
         EndIf
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 2
         
      Case $CB ; AXS Illegaly
         ; do not forget carry!
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         cpuRegX = (cpuRegA And cpuRegX)-tmp
         If cpuRegX = 0 Then
            cpuRegP = cpuRegP Or CPU_ZERO
            cpuRegP = cpuRegP Or CPU_NEGATIVE
         ElseIf cpuRegX And %10000000
            cpuRegP = cpuRegP Or CPU_NEGATIVE
         EndIf
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 4
         
      Case $CC ; CPY Absolut
         cpuCPY($CC)
         
      Case $CD ; CMP Absolut
         cpuCMP($CD)
         
      Case $CE ; DEC Absolut
         cpuDEC($CE)
         
      Case $D0 ; BNE relativ
         If cpuRegP And CPU_ZERO Then
            cpuRegPC = cpuRegPC+2
            cpuWaitCycles = 2
         Else
            tmp = PeekByte(cpuMem, cpuRegPC+1)
            If tmp And %10000000
               tmp = -(tmp And %1111111)
            EndIf
            cpuRegPC = cpuRegPC+tmp
            cpuWaitCycles = 3 ; 3+ !!!
         EndIf

      Case $D1 ; CMP Indirect, Y
         cpuCMP($D1)
         
      Case $D2 ; KIL Illegaly
         cpuRegPC = 64*1024-1
         
      Case $D4 ; NOP Illegaly
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 1
         
      Case $D5 ; CMP Zero Page, X
         cpuCMP($D5)

      Case $D6 ; DEC Zero Page, X
         cpuDEC($D6)
         
      Case $D8 ; CLD Implied
         cpuRegP = cpuRegP And %11110111
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 2
         
      Case $D9 ; CMP Absolut, Y
         cpuCMP($D9)
         
      Case $DA ; NOP Illegaly
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 1
         
      Case $DC ; NOP Illegaly
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 1
         
      Case $DD ; CMP Absolut, X
         cpuCMP($DD)
         
      Case $DE ; DEC Absolut, X
         cpuDEC($DE)
         
      Case $E0 ; CPX Immediant
         cpuCPX($E0)
         
      Case $E1 ; SBC Indirect, X
         cpuSBC($E1)
         
      Case $E2 ; NOP Illegaly
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 1
         
      Case $E4 ; CPX Zero Page
         cpuCPX($E4)
         
      Case $E5 ; SBC Zero Page
         cpuSBC($E5)
         
      Case $E6 ; INC Zero Page
         cpuINC($E6)
         
      Case $E8 ; INX Implied
         cpuRegX = cpuRegX+1
         cpuRegX = cpuRegX And $FF
         If cpuRegX = 0 Then
            cpuRegP = cpuRegP Or CPU_ZERO
            cpuRegP = cpuRegP Or CPU_NEGATIVE
         ElseIf cpuRegX And %10000000 Then
            cpuRegP = cpuRegP Or CPU_NEGATIVE
         EndIf
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 2
         
      Case $E9 ; SBC Implied
         cpuSBC($E9)
         
      Case $EA ; NOP Implied
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 2
         
      Case $EC ; CPX Absolut
         cpuCPX($EC)
         
      Case $ED ; SBC absolut
         cpuSBC($ED)

      Case $EE ; INC Absolut
         cpuINC($EE)
         
      Case $F0 ; BEQ Realtiv
         If cpuRegP And CPU_ZERO Then
            tmp = PeekByte(cpuMem, cpuRegPC+1)
            If tmp And %10000000
               tmp = -(tmp And %1111111)
            EndIf
            cpuRegPC = cpuRegPC+tmp
            cpuWaitCycles = 3 ; 3+ !!!
         Else
            cpuRegPC = cpuRegPC+2
            cpuWaitCycles = 2
         EndIf
         
      Case $F1 ; SBC Indirect, Y
         cpuSBC($F1)

      Case $F2 ; KIL Illegaly
         cpuRegPC = 64*1024-1
                  
      Case $F4 ; NOP Illegaly
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 1
         
      Case $F5 ; SBC Zero Page, X
         cpuSBC($F5)

      Case $F6 ; INC Zero Page, X
         cpuINC($F6)
         
      Case $F8 ; SED Implied
         cpuRegP = cpuRegP Or CPU_DECIMAL
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 2
         
      Case $F9 ; SBC Absolut, Y
         cpuSBC($F9)
         
      Case $FA ; NOP Illegaly
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 1
         
      Case $FC ; NOP Illegaly
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 1
         
      Case $FD ; SBC Absolut, X
         cpuSBC($FD)
      
      Case $FE ; INC Absolut, X
         cpuINC($FE)

      Default
         RuntimeError "$"+Right$(Hex$(op), 2)+" is not supported"
         
   End Select
   
   ; wait cycles
   For i = 1 To cpuWaitCycles*100
      ; do anything
      MilliSecs()
   Next
   
End Function

Function cpuADC(op)
   Local tmp
   
   Select op
      Case $61 ; ADC Indirect, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         tmp = PeekShort(cpuMem, tmp)
         tmp = PeekByte(cpuMem, b2l(tmp))
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 6

      Case $65 ; ADC Zero Page
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 3
                  
      Case $69 ; ADC Immediant
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 2
         
      Case $6D ; ADC Absolut
         tmp = PeekShort(cpuMem, cpuRegPC+1)
         tmp = PeekByte(cpuMem, b2l(tmp))
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4
         
      Case $71 ; ADC Indirect, Y
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         tmp = PeekShort(cpuMem, tmp)+cpuRegY
         tmp = PeekByte(cpuMem, b2l(tmp))
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 5 ; 5+ !!!
      
      Case $75 ; ADC Zero Page, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 4
         
      Case $79 ; ADC Absolut, Y
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegY
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4 ; 4+ !!!
      
      Case $7D ; ADC Absolut, X
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegX
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4 ; 4+ !!!
         
   End Select
   
   cpuRegA = cpuRegA+tmp+(cpuRegP And CPU_CARRY)
   If cpuRegA = 0 Then
      cpuRegP = cpuRegP Or CPU_ZERO
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   ElseIf cpuRegA And %10000000
      cpuRegP = cpuRegP Or CPU_NEGATIVE
      If cpuRegA > 255 Then
         ; !!!!!!!!!!!!!!!!!!!!!!!
         cpuRegP = cpuRegP Or CPU_OVERFLOW
         If cpuRegA And %100000000 Then
            cpuRegP = cpuRegP Or CPU_CARRY
         EndIf
      EndIf
   EndIf
End Function

Function cpuASL(op)
   Local tmp, tmp2
   
   Select op
      Case $06 ; ASL Zero Page
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         tmp2 = PeekByte(cpuMem, tmp)
         If tmp2 And %10000000 Then
            cpuRegP = cpuRegP Or CPU_CARRY
         ElseIf cpuRegP And CPU_CARRY
            cpuRegP = cpuRegP Xor CPU_CARRY
         EndIf
         tmp2 = (tmp Shl 1) And $FF
         PokeByte couMem, tmp, tmp2
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 5
         address = True
         
      Case $0A ; ASL Akkumulator
         If cpuRegA And %10000000 Then
            cpuRegP = cpuRegP Or CPU_CARRY
         ElseIf cpuRegP And CPU_CARRY
            cpuRegP = cpuRegP Xor CPU_CARRY
         EndIf
         cpuRegA = (cpuRegA Shl 1) And $FF
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 2
         
      Case $0E ; ASL Absolut
         tmp = PeekShort(cpuMem, cpuRegPC+1)
         tmp2 = PeekByte(cpuMem, b2l(tmp))
         If tmp2 And %10000000 Then
            cpuRegP = cpuRegP Or CPU_CARRY
         ElseIf cpuRegP And CPU_CARRY
            cpuRegP = cpuRegP Xor CPU_CARRY
         EndIf
         tmp2 = (tmp Shl 1) And $FF
         PokeByte couMem, b2l(tmp), tmp2
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 6
         address = True
         
      Case $16 ; ASL Zero Page, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         tmp2 = PeekByte(cpuMem, tmp)
         If tmp2 And %10000000 Then
            cpuRegP = cpuRegP Or CPU_CARRY
         ElseIf cpuRegP And CPU_CARRY
            cpuRegP = cpuRegP Xor CPU_CARRY
         EndIf
         tmp2 = (tmp Shl 1) And $FF
         PokeByte couMem, tmp, tmp2
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 6
         address = True
         
      Case $1E ; ASL Absolut, X
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegX
         tmp2 = PeekByte(cpuMem, tmp)
         If tmp2 And %10000000 Then
            cpuRegP = cpuRegP Or CPU_CARRY
         ElseIf cpuRegP And CPU_CARRY
            cpuRegP = cpuRegP Xor CPU_CARRY
         EndIf
         tmp2 = (tmp Shl 1) And $FF
         PokeByte couMem, b2l(tmp), tmp2
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 7
         address = True
         
   End Select
End Function

Function cpuAND(op)
   Local tmp
   
   Select op
      Case $21 ; AND Indirect, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         tmp = PeekShort(cpuMem, tmp)
         tmp = PeekByte(cpuMem, b2l(tmp))
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 6
         
      Case $25 ; AND Zero Page
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 2
         
      Case $29 ; AND Immediant
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 2
         
      Case $2D ; AND Absolut
         tmp = PeekShort(cpuMem, cpuRegPC+1)
         tmp = PeekByte(cpuMem, b2l(tmp))
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4
         
      Case $31 ; AND Indirect, Y
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         tmp = PeekShort(cpuMem, tmp)+cpuRegY
         tmp = PeekByte(cpuMem, b2l(tmp))
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 5 ; 5+ !!!
      
      Case $35 ; AND Zero Page, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 3
         
      Case $39 ; AND Absolut, Y
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegY
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4 ; 4+ !!!
      
      Case $3D ; AND Absolut, X
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegX
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4 ; 4+ !!!
         
   End Select
   
   cpuRegA = cpuRegA And tmp
   If cpuRegA = 0 Then
      cpuRegP = cpuRegP Or CPU_ZERO
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   ElseIf cpuRegA And %10000000
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   EndIf
End Function

Function cpuCMP(op)
   Local tmp
   
   Select op
      Case $C1 ; CMP Indirect, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         tmp = PeekShort(cpuMem, tmp)
         tmp = PeekByte(cpuMem, b2l(tmp))
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 6
         
      Case $C5 ; CMP Zero Page
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 3
         
      Case $C9 ; CMP Immediant
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 2
         
      Case $CD ; CMP Absolut
         tmp = PeekShort(cpuMem, cpuRegPC+1)
         tmp = PeekByte(cpuMem, b2l(tmp))
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4
         
      Case $D1 ; CMP Indirect, Y
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         tmp = PeekShort(cpuMem, tmp)+cpuRegY
         tmp = PeekByte(cpuMem, b2l(tmp))
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 5 ; 5+ !!!
      
      Case $D5 ; CMP Zero Page, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 4
         
      Case $D9 ; CMP Absolut, Y
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegY
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4 ; 4+ !!!
      
      Case $DD ; CMP Absolut, X
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegX
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4 ; 4+ !!!
         
   End Select
      
   tmp = cpuRegA-tmp
   If tmp = 0 Then cpuRegP = cpuRegP Or CPU_ZERO
   If tmp <= 0 Then cpuRegP = cpuRegP Or CPU_CARRY
   If tmp And %10000000 Then cpuRegP = cpuRegP Or CPU_NEGATIVE   
End Function

Function cpuCPX(op)
   Local tmp
   
   Select op
      Case $E0 ; CPX Immediant
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 2
         
      Case $E4 ; CPX Zero Page
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 3
         
      Case $EC ; CPX Absolut
         tmp = PeekShort(cpuMem, cpuRegPC+1)
         tmp = PeekByte(cpuMem, b2l(tmp))
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4

   End Select
      
   tmp = cpuRegX-tmp
   If tmp = 0 Then cpuRegP = cpuRegP Or CPU_ZERO
   If tmp <= 0 Then cpuRegP = cpuRegP Or CPU_CARRY
   If tmp And %10000000 Then cpuRegP = cpuRegP Or CPU_NEGATIVE   
End Function

Function cpuCPY(op)
   Local tmp
   
   Select op
      Case $C0 ; CPY Immediant
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 2
         
      Case $C4 ; CPY Zero Page
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 3
         
      Case $CC ; CPY Absolut
         tmp = PeekShort(cpuMem, cpuRegPC+1)
         tmp = PeekByte(cpuMem, b2l(tmp))
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4

   End Select
      
   tmp = cpuRegY-tmp
   If tmp = 0 Then cpuRegP = cpuRegP Or CPU_ZERO
   If tmp <= 0 Then cpuRegP = cpuRegP Or CPU_CARRY
   If tmp And %10000000 Then cpuRegP = cpuRegP Or CPU_NEGATIVE   
End Function

Function cpuDEC(op)
   Local tmp, tmp2
   
   Select op
      Case $C6 ; DEC Zero Page
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 5
         
      Case $CE ; DEC Absolut
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 6
         
      Case $D6 ; DEC Zero Page, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 6
         
      Case $DE ; DEC Absolut, X
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegX
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 7
   
   End Select
   
   tmp2 = PeekByte(cpuMem, tmp)-1
   PokeByte cpuMem, tmp, tmp2
   If tmp2 = 0 Then
      cpuRegP = cpuRegP Or CPU_ZERO
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   ElseIf tmp2 And %10000000 Then
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   EndIf
   address = True
End Function

Function cpuEOR(op)
   Local tmp
   
   Select op
      Case $41 ; EOR Indirect, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 6
      
      Case $45 ; EOR Zero Page
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 3
         
      Case $49 ; EOR Immediant
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 2
      
      Case $4D ; EOR Absolut
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4
         
      Case $51 ; EOR Indirect, Y
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         tmp = PeekShort(cpuMem, tmp)+cpuRegY
         tmp = PeekByte(cpuMem, b2l(tmp))
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 5 ; 5+ !!!
         
      Case $55 ; EOR Zero Page, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 4
         
      Case $59 ; EOR Absolut, Y
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegY
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4 ; 4+ !!!
         
      Case $5D ; EOR Absolut, X
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegX
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4 ; 4+ !!!
         
   End Select
   
   cpuRegA = cpuRegA Xor tmp
   If cpuRegA = 0 Then
      cpuRegP = cpuRegP Or CPU_ZERO
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   ElseIf cpuRegA And %10000000
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   EndIf
End Function

Function cpuINC(op)
   Local tmp, tmp2
   
   Select op
      Case $E6 ; INC Zero Page
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 5
         
      Case $EE ; INC Absolut
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 6
         
      Case $F6 ; INC Zero Page, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 6
         
      Case $FE ; INC Absolut, X
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegX
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 7
   
   End Select
   
   tmp2 = PeekByte(cpuMem, tmp)+1
   PokeByte cpuMem, tmp, tmp2
   If tmp2 = 0 Then
      cpuRegP = cpuRegP Or CPU_ZERO
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   ElseIf tmp2 And %10000000 Then
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   EndIf
   address = True
End Function

Function cpuLDA(op)
   Local tmp
   
   Select op
      Case $A1 ; LDA Indirect, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         tmp = PeekShort(cpuMem, tmp)
         tmp = PeekByte(cpuMem, b2l(tmp))
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 6
         
      Case $A5 ; LDA Zero Page
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 2
         
      Case $A9 ; LDA Immediant
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 2
         
      Case $AD ; LDA Absolut
         tmp = PeekShort(cpuMem, cpuRegPC+1)
         tmp = PeekByte(cpuMem, b2l(tmp))
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4
         
      Case $B1 ; LDA Indirect, Y
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         tmp = PeekShort(cpuMem, tmp)+cpuRegY
         tmp = PeekByte(cpuMem, b2l(tmp))
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 5 ; 5+ !!!
      
      Case $B5 ; LDA Zero Page, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 3
         
      Case $B9 ; LDA Absolut, Y
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegY
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4 ; 4+ !!!
      
      Case $BD ; LDA Absolut, X
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegX
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4 ; 4+ !!!
         
   End Select
   
   cpuRegA = tmp
   If cpuRegA = 0 Then
      cpuRegP = cpuRegP Or CPU_ZERO
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   ElseIf cpuRegA And %10000000
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   EndIf
End Function

Function cpuLDX(op)
   Local tmp
   
   Select op
      Case $A2 ; LDX Immediant
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 2
         
      Case $A6 ; LDX Zero Page
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 3
         
      Case $AE ; LDX Absolut
         tmp = PeekShort(cpuMem, cpuRegPC+1)
         tmp = PeekByte(cpuMem, b2l(tmp))
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4
         
      Case $B6 ; LDX Zero Page, Y
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegY
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 4
         
      Case $BE ; LDX Absolut, Y
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegY
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4 ; 4+ !!!

   End Select
   
   cpuRegX = tmp
   If cpuRegX = 0 Then
      cpuRegP = cpuRegP Or CPU_ZERO
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   ElseIf cpuRegX And %10000000
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   EndIf
End Function

Function cpuLDY(op)
   Local tmp
   
   Select op
         
      Case $A0 ; LDY Immediant
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 2
         
      Case $A4 ; LDY Zero Page
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 3
         
      Case $AE ; LDY Absolut
         tmp = PeekShort(cpuMem, cpuRegPC+1)
         tmp = PeekByte(cpuMem, b2l(tmp))
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4
         
      Case $B4 ; LDY Zero Page, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 4
         
      Case $BC ; LDY Absolut, X
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegX
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4 ; 4+ !!!

   End Select
   
   cpuRegY = tmp
   If cpuRegY = 0 Then
      cpuRegP = cpuRegP Or CPU_ZERO
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   ElseIf cpuRegY And %10000000
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   EndIf
End Function

Function cpuLSR(op)
   Local tmp, tmp2
   
   Select op
      Case $46 ; LSR Zero Page
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         tmp2 = PeekByte(cpuMem, tmp)
         If tmp2 And %00000001 Then
            cpuRegP = cpuRegP Or CPU_CARRY
         ElseIf cpuRegP And CPU_CARRY
            cpuRegP = cpuRegP Xor CPU_CARRY
         EndIf
         tmp2 = tmp Shr 1
         PokeByte cpuMem, tmp, tmp2
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 5
         address = True
         
      Case $4A ; LSR Akku
         If cpuRegA And %00000001 Then
            cpuRegP = cpuRegP Or CPU_CARRY
         ElseIf cpuRegP And CPU_CARRY
            cpuRegP = cpuRegP Xor CPU_CARRY
         EndIf
         cpuRegA = cpuRegA Shr 1
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 2
         address = True
         
      Case $4E ; LSR Absolut
         tmp = PeekShort(cpuMem, cpuRegPC+1)
         tmp2 = PeekByte(cpuMem, b2l(tmp))
         If tmp2 And %00000001 Then
            cpuRegP = cpuRegP Or CPU_CARRY
         ElseIf cpuRegP And CPU_CARRY
            cpuRegP = cpuRegP Xor CPU_CARRY
         EndIf
         tmp2 = tmp Shr 1
         PokeByte couMem, b2l(tmp), tmp2
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 6
         address = True
         
      Case $56 ; LSR Zero Page, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         tmp2 = PeekByte(cpuMem, tmp)
         If tmp2 And %00000001 Then
            cpuRegP = cpuRegP Or CPU_CARRY
         ElseIf cpuRegP And CPU_CARRY
            cpuRegP = cpuRegP Xor CPU_CARRY
         EndIf
         tmp2 = tmp Shr 1
         PokeByte couMem, tmp, tmp2
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 6
         address = True
         
      Case $5E ; LSR Absolut, X
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegX
         tmp2 = PeekByte(cpuMem, tmp)
         If tmp2 And %00000001 Then
            cpuRegP = cpuRegP Or CPU_CARRY
         ElseIf cpuRegP And CPU_CARRY
            cpuRegP = cpuRegP Xor CPU_CARRY
         EndIf
         tmp2 = tmp Shr 1
         PokeByte couMem, b2l(tmp), tmp2
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 7
         address = True
         
   End Select
End Function

Function cpuORA(op)
   Local tmp
   
   Select op
      Case $01 ; ORA Indirect, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 6
      
      Case $05 ; ORA Zero Page
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 3
         
      Case $09 ; ORA Immediant
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 2
      
      Case $0D ; ORA Absolut
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4
         
      Case $11 ; ORA Indirect, Y
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         tmp = PeekShort(cpuMem, tmp)+cpuRegY
         tmp = PeekByte(cpuMem, b2l(tmp))
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 5 ; 5+ !!!
         
      Case $15 ; ORA Zero Page, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 4
         
      Case $19 ; ORA Absolut, Y
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegY
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4 ; 4+ !!!
         
      Case $1D ; ORA Absolut, X
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegX
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4 ; 4+ !!!
         
   End Select
   
   cpuRegA = cpuRegA Or tmp
   If cpuRegA = 0 Then
      cpuRegP = cpuRegP Or CPU_ZERO
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   ElseIf cpuRegA And %10000000
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   EndIf
End Function

Function cpuROL(op)
   Local tmp, tmp2, tmp3
   
   Select op
      Case $26 ; ROL Zero Page
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         tmp2 = PeekByte(cpuMem, tmp)
         tmp3 = tmp2 Shl 1 Or (cpuRegP And CPU_CARRY)
         cpuRegP = (cpuRegP And %11111110) Or ((tmp2 And %10000000) Shr 7)
         PokeByte cpuMem, tmp, tmp3
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 5
         address = True
         
      Case $2A ; ROL Akku
         tmp2 = cpuRegA
         tmp3 = tmp2 Shl 1 Or (cpuRegP And CPU_CARRY)
         cpuRegP = (cpuRegP And %11111110) Or ((tmp2 And %10000000) Shr 7)
         cpuRegA = tmp3
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 2
      
      Case $2E ; ROL Absolut
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))
         tmp2 = PeekByte(cpuMem, tmp)
         tmp3 = tmp2 Shl 1 Or (cpuRegP And CPU_CARRY)
         cpuRegP = (cpuRegP And %11111110) Or ((tmp2 And %10000000) Shr 7)
         PokeByte cpuMem, tmp, tmp3
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 6
         address = True
         
      Case $36 ; ROL Zero Page, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         tmp2 = PeekByte(cpuMem, tmp)
         tmp3 = tmp2 Shl 1 Or (cpuRegP And CPU_CARRY)
         cpuRegP = (cpuRegP And %11111110) Or ((tmp2 And %10000000) Shr 7)
         PokeByte cpuMem, tmp, tmp3
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 6
         address = True
         
      Case $3E ; ROL Absolut, X
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegX
         tmp2 = PeekByte(cpuMem, tmp)
         tmp3 = tmp2 Shl 1 Or (cpuRegP And CPU_CARRY)
         cpuRegP = (cpuRegP And %11111110) Or ((tmp2 And %10000000) Shr 7)
         PokeByte cpuMem, tmp, tmp3
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 7
         address = True
         
   End Select
   
   If tmp3 = 0 Then
      cpuRegP = cpuRegP Or CPU_ZERO
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   ElseIf tmp3 And %10000000
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   EndIf
End Function

Function cpuROR(op)
   Local tmp, tmp2, tmp3
   
   Select op
      Case $66 ; ROR Zero Page
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         tmp2 = PeekByte(cpuMem, tmp)
         tmp3 = tmp2 Shr 2 Or ((cpuRegP And CPU_CARRY) Shl 7)
         cpuRegP = (cpuRegP And %11111110) Or (tmp2 And %00000001)
         PokeByte cpuMem, tmp, tmp3
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 5
         address = True
         
      Case $6A ; ROR Akku
         tmp2 = cpuRegA
         tmp3 = tmp2 Shr 2 Or ((cpuRegP And CPU_CARRY) Shl 7)
         cpuRegP = (cpuRegP And %11111110) Or (tmp2 And %00000001)
         cpuRegA = tmp3
         cpuRegPC = cpuRegPC+1
         cpuWaitCycles = 2
      
      Case $6E ; ROR Absolut
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))
         tmp2 = PeekByte(cpuMem, tmp)
         tmp3 = tmp2 Shr 2 Or ((cpuRegP And CPU_CARRY) Shl 7)
         cpuRegP = (cpuRegP And %11111110) Or (tmp2 And %00000001)
         PokeByte cpuMem, tmp, tmp3
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 6
         address = True
         
      Case $76 ; ROR Zero Page, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         tmp2 = PeekByte(cpuMem, tmp)
         tmp3 = tmp2 Shr 2 Or ((cpuRegP And CPU_CARRY) Shl 7)
         cpuRegP = (cpuRegP And %11111110) Or (tmp2 And %00000001)
         PokeByte cpuMem, tmp, tmp3
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 6
         address = True
         
      Case $7E ; ROR Absolut, X
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegX
         tmp2 = PeekByte(cpuMem, tmp)
         tmp3 = tmp2 Shr 2 Or ((cpuRegP And CPU_CARRY) Shl 7)
         cpuRegP = (cpuRegP And %11111110) Or (tmp2 And %00000001)
         PokeByte cpuMem, tmp, tmp3
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 7
         address = True
         
   End Select
   
   If tmp3 = 0 Then
      cpuRegP = cpuRegP Or CPU_ZERO
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   ElseIf tmp3 And %10000000
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   EndIf
End Function

Function cpuSBC(op)
   Local tmp
   
   Select op
      Case $E1 ; SBC Indirect, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         tmp = PeekShort(cpuMem, tmp)
         tmp = PeekByte(cpuMem, b2l(tmp))
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 6
         
      Case $E5 ; SBC Zero Page
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 3
         
      Case $E9 ; SBC Immediant
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 2
         
      Case $EB ; SBS Illegaly
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 2
         
      Case $ED ; SBC Absolut
         tmp = PeekShort(cpuMem, cpuRegPC+1)
         tmp = PeekByte(cpuMem, b2l(tmp))
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4
         
      Case $F1 ; SBC Indirect, Y
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         tmp = PeekShort(cpuMem, tmp)+cpuRegY
         tmp = PeekByte(cpuMem, b2l(tmp))
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 5 ; 5+ !!!
      
      Case $F5 ; SBC Zero Page, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 4
         
      Case $F9 ; SBC Absolut, Y
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegY
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4 ; 4+ !!!
      
      Case $FD ; SBC Absolut, X
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegX
         tmp = PeekByte(cpuMem, tmp)
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4 ; 4+ !!!
         
   End Select
   
   cpuRegA = cpuRegA-tmp-(Not (cpuRegA And CPU_CARRY))
   If cpuRegA = 0 Then
      cpuRegP = cpuRegP Or CPU_ZERO
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   ElseIf cpuRegA And %10000000
      cpuRegP = cpuRegP Or CPU_NEGATIVE
   EndIf
   If (cpuRegP And CPU_CARRY) Then
      cpuRegP = couRegP Or CPU_OVERFLOW
   EndIf
   If cpuRegA And $FF <> cpuRegA Then
      cpuRegP = cpuRegP Or CPU_CARRY
      cpuRegA = cpuRegA And $FF
   EndIf
End Function

Function cpuSTA(op)
   Local tmp

   Select op
      Case $81 ; STA Indirect, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 6
         
      Case $85 ; STA Zero Page
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 3
         
      Case $8D ; STA Absolut
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4
         
      Case $91 ; STA Indirect, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegY
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 6
         
      Case $95 ; STA Zero Page, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 4
         
      Case $99 ; STA Absolut, Y
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegY
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 5
         
      Case $9D ; STA Absolut, X
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))+cpuRegX
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 5
         
   End Select
   
   cpuRegA = PeekByte(cpuMem, tmp)
End Function

Function cpuSTX(op)
   Local tmp

   Select op
      Case $86 ; STX Zero Page
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 3
         
      Case $8E ; STX Absolut
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4
         
      Case $96 ; STX Zero Page, Y
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegY
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 4
         
   End Select
   
   cpuRegX = PeekByte(cpuMem, tmp)
End Function

Function cpuSTY(op)
   Local tmp

   Select op
      Case $84 ; STY Zero Page
         tmp = PeekByte(cpuMem, cpuRegPC+1)
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 3
         
      Case $8C ; STY Absolut
         tmp = b2l(PeekShort(cpuMem, cpuRegPC+1))
         cpuRegPC = cpuRegPC+3
         cpuWaitCycles = 4
         
      Case $94 ; STY Zero Page, X
         tmp = PeekByte(cpuMem, cpuRegPC+1)+cpuRegX
         cpuRegPC = cpuRegPC+2
         cpuWaitCycles = 4
         
   End Select
   
   cpuRegY = PeekByte(cpuMem, tmp)
End Function

Function b2l(value)
   ; big endian to low endian (by swapping last 2 bytes)
   Return (value And $FF) Shl 8 + ((value Shr 8) And $FF)
End Function


sid.bb:
Code: [AUSKLAPPEN]
-


Bei so einem großen code, den man nur schlecht debuggen kann, da man nicht direkt sehen kann, ob er richtig funktioniert, fällt es schwer, die Übersicht zu behalten. Somit dürften ein paar Sachen fehlerhaft sein.

mfg olli
vertex.dreamfall.at | GitHub
 

OJay

BeitragMo, Okt 11, 2004 21:31
Antworten mit Zitat
Benutzer-Profile anzeigen
ein C64 emu in bb? Laughing

nunja, wenns funktioniert... ^^

aber ich glaube, das hier nicht einer im forum was damit anfangen kann, aber lob an deine mühen! vielleicht wäre ein thread im projekte bereich angebrachter gewesen, bzw ist es noch. da kann man doch besser diskutieren, als hier im tut-only bereich, oder?

naja...viel glück noch damit! Wink
 

Sebe

BeitragMo, Okt 11, 2004 21:32
Antworten mit Zitat
Benutzer-Profile anzeigen
Hammer. Aber erwähnenswert wäre vielleicht, dass JEDER der A,B,C und D Register in jeweils ein High und Low Register geteilt sind.
Aber beeindruckend Very Happy Wink

BladeRunner

Moderator

BeitragMo, Okt 11, 2004 22:17
Antworten mit Zitat
Benutzer-Profile anzeigen
Bin wie immer sehr beeindruckt, Vertex.
@sebe: der 64er hatte nur 8bit register (X,Y und A).
Zu Diensten, Bürger.
Intel T2300, 2.5GB DDR 533, Mobility Radeon X1600 Win XP Home SP3
Intel T8400, 4GB DDR3, Nvidia GF9700M GTS Win 7/64
B3D BMax MaxGUI

Stolzer Gewinner des BAC#48, #52 & #92
 

Timo

BeitragMo, Okt 11, 2004 22:19
Antworten mit Zitat
Benutzer-Profile anzeigen
was ein fetter quelltext Very Happy RESPEKT!! Wink

Neue Antwort erstellen


Übersicht BlitzBasic FAQ und Tutorials

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group