Eine eigene virtuelle Machine
Übersicht

![]() |
VertexBetreff: Eine eigene virtuelle Machine |
![]() Antworten mit Zitat ![]() |
---|---|---|
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 |
![]() Antworten mit Zitat ![]() |
---|---|---|
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 |
![]() Antworten mit Zitat ![]() |
---|---|---|
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 |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
ein C64 emu in bb? ![]() 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! ![]() |
||
Sebe |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
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 ![]() ![]() |
||
![]() |
BladeRunnerModerator |
![]() Antworten mit Zitat ![]() |
---|---|---|
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 |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
was ein fetter quelltext ![]() ![]() |
||
Übersicht


Powered by phpBB © 2001 - 2006, phpBB Group