home *** CD-ROM | disk | FTP | other *** search
- *
- * 6510.asm - 6510-Emulation (eigener Task)
- *
- * Copyright (C) 1994-1995 by Christian Bauer
- *
-
- *
- * Anmerkungen:
- * ------------
- *
- * Register d0/d1 - WICHTIG:
- * - Der Emulator geht davon aus, daß die MSWs von d0 und d1 immer Null
- * sind. Denn dadurch kann das C64-RAM mittels (RAMPTR,d0.l) ohne
- * Vorzeichen indiziert angesprochen werden.
- * - Die Makros Read#?Zero#? und Read#?Ind#? gehen zusätlich davon aus,
- * daß nur das untere Byte von d0 Null ist, da diese Makros immer nur
- * am Anfang eines Befehls stehen und d0 vom Next-Makro noch gelöscht
- * ist
- *
- * Speicherkonfigurationen:
- *
- * $01 $a000-$bfff $d000-$dfff $e000-$ffff
- * -----------------------------------------------
- * 0 RAM RAM RAM
- * 1 RAM Char-ROM RAM
- * 2 RAM Char-ROM Kernal-ROM
- * 3 Basic-ROM Char-ROM Kernal-ROM
- * 4 RAM RAM RAM
- * 5 RAM I/O RAM
- * 6 RAM I/O Kernal-ROM
- * 7 Basic-ROM I/O Kernal-ROM
- *
- * Zugriff auf den C64-Speicher:
- * - Fast alle Speicherzugriffe laufen über die ReadByte/WriteByte-Makros,
- * die die eingestellte Speicherkonfiguration dadurch berücksichtigen,
- * daß die oberen 8 Adreßbits als Index in eine Sprungtabelle
- * (ReadTab/WriteTab) dienen, die Zeiger auf die ReadByte*/WriteByte*-
- * Routinen enthalten, über die der tatsächliche Zugriff erfolgt.
- * Für jede der 8 Speicherkonfigurationen existiert jeweils eine solche
- * Tabelle Bei einer Änderung der Speicherkonfiguration (NewConfig)
- * werden die Zeiger auf die Tabellen (RDTAB/WRTAB) geändert.
- * - Das LESEN aus der Zero-Page geschieht immer direkt,
- * da dort keine Register liegen ($01 wird auch im RAM abgelegt)
- * - Beim Schreiben in die Zero-Page wird nur auf $00/$01 getestet,
- * ansonsten direkt zugegriffen
- * - Der Stack wird immer direkt angesprochen
- * - Die ReadByte-Routinen dürfen nur d0-d1/a0 verändern.
- * a1 enthält die Rücksprungadresse, die Routinen müssen also mit
- * "jmp (a1)" enden.
- * - Die WriteByte-Routinen dürfen nur d0-d1/a0-a1 verändern
- *
- * Programmzähler:
- * - Aus Geschwindigkeitsgründen wird der PC durch einen 32-Bit-
- * Amiga-Zeiger repräsentiert und über diesen direkt auf den
- * Speicher zugegriffen (und nicht über ReadByte). Bei einem
- * Sprungbefehl wird aus dem 16-Bit Sprungziel und der aktuellen
- * Speicherkonfiguration die neue 32-Bit-Adresse berechnet,
- * indem ähnlich zur ReadTab die oberen 8 Bit des Sprungziels
- * als Index in die JumpTab verwendet werden. Die darüber aufgerufenen
- * Routinen führen die Umrechnung durch.
- * - Durch die Art, wie das Hauptprogramm den Speicher anfordert,
- * entsprechen die unteren 16 Bit des 32-Bit-PCs immer der
- * 16-Bit-C64-Adresse. Das erleichtert erheblich das Ablegen des
- * PC auf dem Stack, da dazu einfach nur die unteren 16 Bit
- * genommen werden müssen (ansonsten müßte man je nach RAM/ROM-
- * Bereich erst die jeweilige Basisadresse subtrahieren).
- * - Im RAM-Bereich $10000-$100ff wird der Opcode $d2 installiert,
- * der den PC auf $0000-$00ff umrechnet, falls ein Programm den
- * Wraparound macht
- * - Durch diese Art der PC-Verwaltung bestehen folgende Inkompatibilitäten:
- * - Ein Branch oder ein Hineinlaufen in einen anderen Speicherbereich
- * (z.B. RAM->ROM) funktioniert nicht. Das sollte allerdings kein
- * Problem darstellen.
- * - Ein Sprung in den I/O-Bereich ist z.Z. nicht möglich
- *
- * Condition-Codes:
- * - Die Emulation verwendet zwei Register, um die Prozessorflags zu
- * speichern: RCCR und RP.
- * - RCCR ist ein Abbild des 680x0-CCR und wird nach den entsprechenden
- * Operationen mit "move ccr,RCCR" gelesen. Von RCCR werden nur das N-
- * und das Z-Flag verwendet.
- * - Die einzigen Opcodes, die V ändern, sind ADC, SBC, CLV, PLP und RTI.
- * Darum wird das V-Flag nicht aus dem 680x0-V-Flag erzeugt, sondern
- * gegebenenfalls von Hand gesetzt.
- * - Im oberen Byte (Bit 8-15) von RP sind die 6510-Flags V,B,D und I
- * in der selben Anordnung wie beim 6510 gespeichert. Das untere Byte
- * enthält in Bit 0 das Carry-Flag in 6510-Interpretation (bei SBC und
- * CMP/CPX/CPY inverse Bedeutung zum 680x0), das bei den entsprechenden
- * Opcodes aus dem CCR gelesen (und ggf. invertiert) wird. Der Einfachheit
- * halber wird immer das ganze untere Byte von CCR gelesen, da nur Bit 0
- * interessant ist.
- *
- * Opcode-Ausführung:
- * - Es gibt keine Fetch-Decode-Schleife, sondern jede Opcode-Routine
- * enthält am Schluß den Code, der den nächsten Befehl ausführt
- * ("Next"-Makro).
- * - Die Verzweigung in die einzelnen Opcode-Routinen geschieht über
- * eine Sprungtabelle, die OpcodeTable. Das Register OPTABPTR enthält
- * einen Zeiger auf diese Tabelle (vor der Tabelle steht noch der
- * Zyklenzähler, auf den so schneller zugegriffen werden kann).
- *
- * Zyklenzähler/Periodic/Interrupts:
- * - Die Variable CyclesLeft (erreichbar über (OPTABPTR)) enthält die
- * Anzahl Zyklen, die dem 6510 in der augenblicklichen Rasterzeile noch
- * zur Verfügung stehen
- * - Nach jeder Opcode-Ausführung wird dieser Zähler um die Zyklenzahl
- * des gerade ausgeführten Befehls erniedrigt. Dazu wird dem Next-Makro
- * die Anzahl Zyklen übergeben. Unterschreitet der Zähler Null, wird
- * die Routine "Periodic" aufgerufen.
- * - In dieser Routine werden die Unterroutinen von VIC und CIA
- * ausgeführt, die die Aktionen für eine Rasterzeile durchführen
- * (VIC (Periodic6569): Eine Bildschirmzeile aufbauen, CIA
- * (Periodic6526): Timer zählen)
- * - In Periodic6569 wird der Zyklenzähler neu gesetzt (der Wert hängt
- * davon ab, ob eine Bad Line stattfand oder nicht)
- *
- * Interrupts:
- * - Die Haupt-Interruptquellen sind VIC und CIA, daher prüft der
- * Emulator das Auftreten eines Interrupts im Rahmen der Periodic-
- * Routine
- * - Es gibt folgende Interrupt-Möglichkeiten (Prioritäten):
- * - RESET, Sprung nach ($FFFC) oder 6510-Task beenden (RESETIsEXIT-Flag)
- * - NMI, Sprung nach ($FFFA)
- * - VIC-IRQ, I-Flag wird geprüft, Sprung nach ($FFFE)
- * - CIA-IRQ, I-Flag wird geprüft, Sprung nach ($FFFE)
- * - Die Aufteilung in VIC- und CIA-IRQ erleichtert die Handhabung, wenn
- * beide IRQs gleichzeitig auftreten
- * - Die einzige Möglichkeit, außerhalb des Periodic einen Interrupt
- * auszulösen, ist das Löschen des I-Flags, wenn ein IRQ ansteht.
- * Die Opcode-Routinen für PLP, RTI und CLI enthalten deswegen besondere
- * Abfragen, die ggf. in den Interrupt-Handler verzweigen.
- *
- * Erweiterungen:
- * - Über den Opcode $f2 sind die 1541-Routinen implementiert. Dem Opcode
- * folgt ein Byte, das die Nummer der auzurufenden Routine angibt.
- *
- * Inkompatibilitäten:
- * - ($ff),Y-Adressierung liest das zweite Byte der indirekten Adresse
- * aus $0100 statt $0000. Dies geschieht aus Geschwindigkeitsgründen,
- * der korrekte Code ist im Makro ReadAdrIndY auskommentiert.
- * - In der Verwaltung des PCs bestehen einige Ungenauigkeiten (siehe
- * Abschnitt "Programmzähler")
- * - RMW-Befehle sollten erst die Originaldaten und dann die geänderten
- * schreiben, aber das spielt nur eine Rolle für Register wie das
- * VIC-IRQFLAG-Register, das in 6569.asm deswegen speziell behandelt wird
- * - Zyklen werden nur für ganze Befehle gezählt, Extra-Zyklen für
- * Seitenüberschreitungen werden nicht berechnet (dies betrifft die
- * Adressierungsarten xxxx,X xxxx,Y (xx),Y und die Branch-Befehle)
- * - ADC und SBC im Dezimalmodus setzen die Flags nicht korrekt
- * - RRA und ISB berücksichtigen das D-Flag nicht
- *
-
-
- MACHINE 68020
-
- INCLUDE "exec/types.i"
- INCLUDE "exec/macros.i"
- INCLUDE "exec/execbase.i"
- INCLUDE "exec/nodes.i"
- INCLUDE "dos/dos.i"
- INCLUDE "dos/dostags.i"
- INCLUDE "Frodo_rev.i"
- CATCOMP_NUMBERS = 1
- INCLUDE "Strings.i"
-
- XREF _SysBase
- XREF _DOSBase
- XREF _IntuitionBase
-
- XREF GetString ;Strings.o
- XREF TheLocale
-
- XDEF TheRAM ;Main.asm
- XDEF TheBasic
- XDEF TheKernal
- XDEF TheChar
- XDEF TheColor
- XREF MainTask
- XREF Random
-
- XREF ReadFrom6526A ;6526.asm
- XREF ReadFrom6526B
- XREF WriteTo6526A
- XREF WriteTo6526B
- XREF Reset6526
-
- XREF Init6569 ;6569.asm
- XREF Exit6569
- XREF ReadFrom6569
- XREF WriteTo6569
- XREF Periodic6569
- XREF AmigaToFront
- XREF EmulToFront
-
- XREF ReadFrom6581 ;6581.asm
- XREF WriteTo6581
- XREF Reset6581
-
- XREF IECOut ;1541.asm
- XREF IECOutATN
- XREF IECOutSec
- XREF IECIn
- XREF IECSetATN
- XREF IECRelATN
- XREF IECTurnaround
- XREF IECRelease
-
- XDEF Init6510
- XDEF Start6510
- XDEF Stop6510
- XDEF Pause6510
- XDEF Resume6510
- XDEF Localize6510
- XDEF IntIsRESET
- XDEF IntIsNMI
- XDEF IntIsVICIRQ
- XDEF IntIsCIAIRQ
- XDEF CyclesLeft
- XDEF CPUTask
- XDEF Peri6569Cont
- XDEF Peri6526Cont
-
- SECTION "CODE",CODE
-
-
- **
- ** Definitionen
- **
-
- ; Bitdefinitionen für RP (6510-Statusregister)
- CarryBit = 0 ;Carry (nach 6510-Definition)
- InterruptBit = 10 ;Interrupts abgeschaltet
- InterruptMask = $0400
- DecimalBit = 11 ;Dezimalmodus
- DecimalMask = $0800
- BreakBit = 12 ;Break-Befehl (nur auf dem Stack)
- BreakMask = $1000
- OverflowBit = 14 ;Arith. Überlauf
- OverflowMask = $4000
-
- ; Registerbelegung (Achtung: In 1541.asm sind ebenfalls solche
- ; Definitionen, die hiermit übereinstimmen müssen!)
- RA EQUR d2 ;A
- RX EQUR d3 ;X
- RY EQUR d4 ;Y
- RS EQUR d5 ;S (16-Bit, $01xx)
- RCCR EQUR d6 ;CCR, nur N und Z
- RP EQUR d7 ;Oberes Byte: 6510-Status ohne N,Z und C.
- ;Bit #0: Carry
- RDTAB EQUR a2 ;Zeiger auf ReadByte-Sprungtabelle
- WRTAB EQUR a3 ;Zeiger auf WriteByte-Sprungtabelle
- ;256*8*4+WRTAB zeigt auf JumpTab
- RAMPTR EQUR a4 ;Zeiger auf C64-RAM
- RPC EQUR a5 ;PC (32-Bit Amiga-Adresse, untere 16 Bit
- ; stimmen mit C64-PC überein)
- OPTABPTR EQUR a6 ;Zeiger auf die Opcode-Dispatch-Tabelle
- ; und den Zyklenzähler
-
-
- *
- * Makros für Speicherzugriffe und Adreßberechnungen
- *
-
- ; Ein C64-Byte lesen
- ; -> d0.w: Adresse
- ; <- d0.b: Byte
- ReadByte MACRO
- cmp.w #$a000,d0 ;Unterhalb von $a000 ist nur Speicher
- blo \@1$
- move.w d0,d1
- lsr.w #8,d1
- lea \@2$(pc),a1 ;Ist hier schneller, weil sonst
- move.l (RDTAB,d1.w*4),a0 ;hinter dem jmp (a0) ein bra \@2$
- jmp (a0) ;stehen müßte
- \@1$ move.b (RAMPTR,d0.l),d0
- \@2$
- ENDM
-
- ; Ein C64-Wort lesen (Als Makro schneller)
- ; -> d0.w: Adresse
- ; <- d0.w: Wort (Bytefolge korrigiert)
- ReadWord MACRO
- move.l d0,-(sp) ;Adresse merken
- ReadByte
- move.b d0,d1
- move.l (sp)+,d0 ;Adresse zurückholen
- addq.w #1,d0 ;Nächstes Byte
- move.l d1,-(sp) ;Lo-Byte merken
- ReadByte
- lsl.w #8,d0 ;Hi-Byte richtig schieben
- move.l (sp)+,d1
- move.b d1,d0 ;Lo-Byte dazunehmen
- ENDM
-
- ; Ein C64-Byte schreiben
- ; -> d0.w: Adresse (16 bit)
- ; -> d1.b: Byte
- ; Adresse steht dann in a1
- WriteByte MACRO
- cmp.w #$a000,d0
- blo \@1$
- move.l d0,a1
- lsr.w #8,d0
- move.l (WRTAB,d0.w*4),a0
- jsr (a0)
- bra \@2$
- \@1$ move.b d1,(RAMPTR,d0.l)
- cmp.b #2,d0
- bhs \@2$
- NewConfig
- \@2$
- ENDM
-
- ; Ein C64-Wort am PC lesen und PC erhöhen
- ReadPCWord MACRO
- move.w (RPC)+,d0
- rol.w #8,d0
- ENDM
-
- ; Relative Adressierung
- ReadByteRel MACRO
- move.b (RPC)+,d0
- ext.w d0
- ENDM
-
- ; Absolute Adressierung
- ReadAdrAbs MACRO
- ReadPCWord
- ENDM
-
- ReadByteAbs MACRO
- ReadAdrAbs
- ReadByte
- ENDM
-
- ; Indirekte Adressierung
- ReadAdrInd MACRO
- ReadPCWord
- move.l d0,-(sp) ;Adresse merken
- ReadByte
- move.b d0,d1
- move.l (sp)+,d0 ;Adresse zurückholen
- addq.b #1,d0 ;Nächstes Byte OHNE Page-Crossing
- move.l d1,-(sp) ;Lo-Byte merken
- ReadByte
- lsl.w #8,d0 ;Hi-Byte richtig schieben
- move.l (sp)+,d1
- move.b d1,d0 ;Lo-Byte dazunehmen
- ENDM
-
- ; Zero-Page Adressierung
- ReadAdrZero MACRO
- move.b (RPC)+,d0
- ENDM
-
- ReadByteZero MACRO ;Register
- ReadAdrZero
- move.b (RAMPTR,d0.w),\1
- ENDM
-
- ; Absolut,X
- ReadAdrAbsX MACRO
- ReadPCWord
- add.w RX,d0
- ENDM
-
- ReadByteAbsX MACRO
- ReadAdrAbsX
- ReadByte
- ENDM
-
- ; Absolut,Y
- ReadAdrAbsY MACRO
- ReadPCWord
- add.w RY,d0
- ENDM
-
- ReadByteAbsY MACRO
- ReadAdrAbsY
- ReadByte
- ENDM
-
- ; Zero-Page,X
- ReadAdrZeroX MACRO
- move.b (RPC)+,d0
- add.b RX,d0
- ENDM
-
- ReadByteZeroX MACRO ;Register
- ReadAdrZeroX
- move.b (RAMPTR,d0.w),\1
- ENDM
-
- ; Zero-Page,Y
- ReadAdrZeroY MACRO
- move.b (RPC)+,d0
- add.b RY,d0
- ENDM
-
- ReadByteZeroY MACRO ;Register
- ReadAdrZeroY
- move.b (RAMPTR,d0.w),\1
- ENDM
-
- ; (Ind,X)
- ReadAdrIndX MACRO
- move.b (RPC)+,d0
- add.b RX,d0
- move.b (RAMPTR,d0.w),d1 ;LSB lesen
- addq.b #1,d0
- move.b (RAMPTR,d0.w),d0 ;MSB lesen
- lsl.w #8,d0
- move.b d1,d0 ;LSB einfügen
- ENDM
-
- ReadByteIndX MACRO
- ReadAdrIndX
- ReadByte
- ENDM
-
- ; (Ind),Y
- ReadAdrIndY MACRO
- move.b (RPC)+,d0
-
- ;(Korrekt) move.b (RAMPTR,d0.w),d1 ;LSB lesen
- ; addq.b #1,d0
- ; move.b (RAMPTR,d0.w),d0 ;MSB lesen
- ; lsl.w #8,d0
- ; move.b d1,d0 ;LSB einfügen
-
- move.w (RAMPTR,d0.w),d0 ;(Abgekürzt)
- rol.w #8,d0 ;Geht bei ($ff),y schief
-
- add.w RY,d0
- ENDM
-
- ReadByteIndY MACRO
- ReadAdrIndY
- ReadByte
- ENDM
-
- ; Ein Byte (Arg1) auf den Stapel schieben
- PushByte MACRO ;Register
- move.b \1,(RAMPTR,RS.w)
- subq.b #1,RS
- ENDM
-
- ; PC auf Stack schieben
- PushPC MACRO
- move.w RPC,d0
- move.w d0,d1
- lsr.w #8,d0
- PushByte d0
- PushByte d1
- ENDM
-
- ; PC+1 auf den Stack schieben
- PushPCPlus1 MACRO
- move.w RPC,d0
- addq.w #1,d0
- move.w d0,d1
- lsr.w #8,d0
- PushByte d0
- PushByte d1
- ENDM
-
- ; Status auf Stack schieben
- PushP MACRO
- move.w RP,d0 ;6510-Status holen
- lsr.w #8,d0
- and.b #$5c,d0 ;V,B,D,I behalten
- or.b #$20,d0 ;1-Bit setzen
- btst #CarryBit,RP ;C dazunehmen
- beq \@1$
- or.b #$01,d0
- \@1$ btst #3,RCCR ;N dazunehmen
- beq \@2$
- or.b #$80,d0
- \@2$ btst #2,RCCR ;Z dazunehmen
- beq \@3$
- or.b #$02,d0
- \@3$ PushByte d0
- ENDM
-
- ; Ein Byte vom Stapel nach Arg1 lesen
- PopByte MACRO ;Register
- addq.b #1,RS
- move.b (RAMPTR,RS.w),\1
- ENDM
-
- ; Status vom Stack holen
- PopP MACRO
- PopByte d0
- move ccr,RCCR
- and.b #$08,RCCR ;N holen
- move.b d0,RP
- and.b #$4c,RP ;V,D,I behalten
- lsl.w #8,RP
- btst #1,d0 ;Z holen
- beq \@1$
- or.b #$04,RCCR
- \@1$ btst #0,d0 ;C holen
- beq \@2$
- or.b #$01,RP
- \@2$
- ENDM
-
- ; PC setzen
- ; -> d0.w: 16-Bit-Adresse
- ; <- RPC.l: Amiga-Adresse
- Jump MACRO
- move.w d0,d1
- lsr.w #8,d1
- move.l 256*8*4(WRTAB,d1.w*4),a0
- jsr (a0)
- ENDM
-
- ; Nächsten Befehl ausführen
- Next MACRO ;Zyklenzahl
- IFNE \1
- subq.w #\1,(OPTABPTR) ;Anzahl Zyklen abziehen
- bmi Periodic ;Alle verbraucht: Periodic
- ENDC
-
- moveq #0,d0
- move.b (RPC)+,d0 ;Opcode lesen
- move.l 4(OPTABPTR,d0.w*4),a0 ;Zeiger auf die Opcode-Routine holen
- jmp (a0) ;Routine aufrufen
- ENDM
-
- ; Speicherkonfiguration anpassen
- NewConfig MACRO
- move.b 1(RAMPTR),d0 ;Config lesen
- and.w #7,d0 ;Relevante Bits maskieren
- movem.l (ConfigTab,pc,d0.w*8),RDTAB/WRTAB
- ENDM
-
- ; Ein C64-Byte in die Zero-Page schreiben und nächsten Befehl ausführen.
- ; Prüfen, ob sich die Speicherkonfiguration geändert hat.
- ; -> d0.w: Adresse (16 bit)
- ; -> Arg1: Byte
- WriteZeroNext MACRO ;Register, Zyklenzahl
- move.b \1,(RAMPTR,d0.w)
- cmp.b #2,d0
- bhs \@1$
- NewConfig
- \@1$ Next \2
- ENDM
-
-
- **
- ** Emulation vorbereiten (Sprungtabellen aufbauen)
- **
-
- ; ReadTabs aufbauen
- Init6510 lea ReadTab0,a0 ;Alle mit RAM vorbelegen
- move.w #256*8-1,d0
- 1$ move.l #ReadByteRAM,(a0)+
- dbra d0,1$
-
- lea ReadTab3+160*4,a0 ;Basic-ROM
- moveq #31,d0
- 21$ move.l #ReadByteBasic,(a0)+
- dbra d0,21$
-
- lea ReadTab7+160*4,a0
- moveq #31,d0
- 22$ move.l #ReadByteBasic,(a0)+
- dbra d0,22$
-
- lea ReadTab2+224*4,a0 ;Kernal-ROM
- moveq #31,d0
- 31$ move.l #ReadByteKernal,(a0)+
- dbra d0,31$
-
- lea ReadTab3+224*4,a0
- moveq #31,d0
- 32$ move.l #ReadByteKernal,(a0)+
- dbra d0,32$
-
- lea ReadTab6+224*4,a0
- moveq #31,d0
- 33$ move.l #ReadByteKernal,(a0)+
- dbra d0,33$
-
- lea ReadTab7+224*4,a0
- moveq #31,d0
- 34$ move.l #ReadByteKernal,(a0)+
- dbra d0,34$
-
- lea ReadTab5+208*4,a0 ;I/O-Bereich
- move.l #ReadByteVIC,(a0)+
- move.l #ReadByteVIC,(a0)+
- move.l #ReadByteVIC,(a0)+
- move.l #ReadByteVIC,(a0)+
- move.l #ReadByteSID,(a0)+
- move.l #ReadByteSID,(a0)+
- move.l #ReadByteSID,(a0)+
- move.l #ReadByteSID,(a0)+
- move.l #ReadByteColor,(a0)+
- move.l #ReadByteColor,(a0)+
- move.l #ReadByteColor,(a0)+
- move.l #ReadByteColor,(a0)+
- move.l #ReadByteCIA1,(a0)+
- move.l #ReadByteCIA2,(a0)+
- move.l #ReadByteUndef,(a0)+
- move.l #ReadByteUndef,(a0)
-
- lea ReadTab6+208*4,a0
- move.l #ReadByteVIC,(a0)+
- move.l #ReadByteVIC,(a0)+
- move.l #ReadByteVIC,(a0)+
- move.l #ReadByteVIC,(a0)+
- move.l #ReadByteSID,(a0)+
- move.l #ReadByteSID,(a0)+
- move.l #ReadByteSID,(a0)+
- move.l #ReadByteSID,(a0)+
- move.l #ReadByteColor,(a0)+
- move.l #ReadByteColor,(a0)+
- move.l #ReadByteColor,(a0)+
- move.l #ReadByteColor,(a0)+
- move.l #ReadByteCIA1,(a0)+
- move.l #ReadByteCIA2,(a0)+
- move.l #ReadByteUndef,(a0)+
- move.l #ReadByteUndef,(a0)
-
- lea ReadTab7+208*4,a0
- move.l #ReadByteVIC,(a0)+
- move.l #ReadByteVIC,(a0)+
- move.l #ReadByteVIC,(a0)+
- move.l #ReadByteVIC,(a0)+
- move.l #ReadByteSID,(a0)+
- move.l #ReadByteSID,(a0)+
- move.l #ReadByteSID,(a0)+
- move.l #ReadByteSID,(a0)+
- move.l #ReadByteColor,(a0)+
- move.l #ReadByteColor,(a0)+
- move.l #ReadByteColor,(a0)+
- move.l #ReadByteColor,(a0)+
- move.l #ReadByteCIA1,(a0)+
- move.l #ReadByteCIA2,(a0)+
- move.l #ReadByteUndef,(a0)+
- move.l #ReadByteUndef,(a0)
-
- lea ReadTab1+208*4,a0 ;Char-ROM
- moveq #15,d0
- 41$ move.l #ReadByteChar,(a0)+
- dbra d0,41$
-
- lea ReadTab2+208*4,a0
- moveq #15,d0
- 42$ move.l #ReadByteChar,(a0)+
- dbra d0,42$
-
- lea ReadTab3+208*4,a0
- moveq #15,d0
- 43$ move.l #ReadByteChar,(a0)+
- dbra d0,43$
-
- ; WriteTabs aufbauen
- lea WriteTab0,a0 ;Alle mit RAM vorbelegen
- move.w #256*8-1,d0
- 5$ move.l #WriteByteRAM,(a0)+
- dbra d0,5$
-
- move.l #WriteBytePage0,WriteTab0 ;Zeropage immer speziell
- move.l #WriteBytePage0,WriteTab1
- move.l #WriteBytePage0,WriteTab2
- move.l #WriteBytePage0,WriteTab3
- move.l #WriteBytePage0,WriteTab4
- move.l #WriteBytePage0,WriteTab5
- move.l #WriteBytePage0,WriteTab6
- move.l #WriteBytePage0,WriteTab7
-
- lea WriteTab5+208*4,a0 ;I/O-Bereich
- move.l #WriteByteVIC,(a0)+
- move.l #WriteByteVIC,(a0)+
- move.l #WriteByteVIC,(a0)+
- move.l #WriteByteVIC,(a0)+
- move.l #WriteByteSID,(a0)+
- move.l #WriteByteSID,(a0)+
- move.l #WriteByteSID,(a0)+
- move.l #WriteByteSID,(a0)+
- move.l #WriteByteColor,(a0)+
- move.l #WriteByteColor,(a0)+
- move.l #WriteByteColor,(a0)+
- move.l #WriteByteColor,(a0)+
- move.l #WriteByteCIA1,(a0)+
- move.l #WriteByteCIA2,(a0)+
- move.l #WriteByteUndef,(a0)+
- move.l #WriteByteUndef,(a0)
-
- lea WriteTab6+208*4,a0
- move.l #WriteByteVIC,(a0)+
- move.l #WriteByteVIC,(a0)+
- move.l #WriteByteVIC,(a0)+
- move.l #WriteByteVIC,(a0)+
- move.l #WriteByteSID,(a0)+
- move.l #WriteByteSID,(a0)+
- move.l #WriteByteSID,(a0)+
- move.l #WriteByteSID,(a0)+
- move.l #WriteByteColor,(a0)+
- move.l #WriteByteColor,(a0)+
- move.l #WriteByteColor,(a0)+
- move.l #WriteByteColor,(a0)+
- move.l #WriteByteCIA1,(a0)+
- move.l #WriteByteCIA2,(a0)+
- move.l #WriteByteUndef,(a0)+
- move.l #WriteByteUndef,(a0)
-
- lea WriteTab7+208*4,a0
- move.l #WriteByteVIC,(a0)+
- move.l #WriteByteVIC,(a0)+
- move.l #WriteByteVIC,(a0)+
- move.l #WriteByteVIC,(a0)+
- move.l #WriteByteSID,(a0)+
- move.l #WriteByteSID,(a0)+
- move.l #WriteByteSID,(a0)+
- move.l #WriteByteSID,(a0)+
- move.l #WriteByteColor,(a0)+
- move.l #WriteByteColor,(a0)+
- move.l #WriteByteColor,(a0)+
- move.l #WriteByteColor,(a0)+
- move.l #WriteByteCIA1,(a0)+
- move.l #WriteByteCIA2,(a0)+
- move.l #WriteByteUndef,(a0)+
- move.l #WriteByteUndef,(a0)
-
- ; JumpTabs aufbauen
- lea JumpTab0,a0 ;Alle mit RAM vorbelegen
- move.w #256*8-1,d0
- 6$ move.l #JumpToRAM,(a0)+
- dbra d0,6$
-
- lea JumpTab3+160*4,a0 ;Basic-ROM
- moveq #31,d0
- 71$ move.l #JumpToBasic,(a0)+
- dbra d0,71$
-
- lea JumpTab7+160*4,a0
- moveq #31,d0
- 72$ move.l #JumpToBasic,(a0)+
- dbra d0,72$
-
- lea JumpTab2+224*4,a0 ;Kernal-ROM
- moveq #31,d0
- 81$ move.l #JumpToKernal,(a0)+
- dbra d0,81$
-
- lea JumpTab3+224*4,a0
- moveq #31,d0
- 82$ move.l #JumpToKernal,(a0)+
- dbra d0,82$
-
- lea JumpTab6+224*4,a0
- moveq #31,d0
- 83$ move.l #JumpToKernal,(a0)+
- dbra d0,83$
-
- lea JumpTab7+224*4,a0
- moveq #31,d0
- 84$ move.l #JumpToKernal,(a0)+
- dbra d0,84$
-
- lea JumpTab1+208*4,a0 ;Char-ROM
- moveq #15,d0
- 85$ move.l #JumpToChar,(a0)+
- dbra d0,85$
-
- lea JumpTab2+208*4,a0
- moveq #15,d0
- 86$ move.l #JumpToChar,(a0)+
- dbra d0,86$
-
- lea JumpTab3+208*4,a0
- moveq #15,d0
- 87$ move.l #JumpToChar,(a0)+
- dbra d0,87$
-
- lea JumpTab5+208*4,a0 ;I/O-Bereich
- moveq #15,d0
- 88$ move.l #JumpToIO,(a0)+
- dbra d0,88$
-
- lea JumpTab6+208*4,a0
- moveq #15,d0
- 89$ move.l #JumpToIO,(a0)+
- dbra d0,89$
-
- lea JumpTab7+208*4,a0
- moveq #15,d0
- 810$ move.l #JumpToIO,(a0)+
- dbra d0,810$
- rts
-
-
- **
- ** 6510-Task starten
- ** Rückgabe: d0#0 = Fehler
- **
-
- ; Signal einrichten
- Start6510 move.l _SysBase,a6
- moveq #-1,d0
- JSRLIB AllocSignal
- move.b d0,ReadySig
- moveq #0,d1
- bset d0,d1
- move.l d1,ReadySet
-
- ; Task starten
- move.l _DOSBase,a6
- move.l #ProcTags,d1
- JSRLIB CreateNewProc
- move.l d0,CPUProc
- beq 1$
-
- ; Auf Signal warten
- move.l _SysBase,a6
- move.l ReadySet,d0
- JSRLIB Wait
- moveq #0,d0 ;Alles OK
- rts
-
- ; Fehler aufgetreten
- 1$ moveq #-1,d0
- rts
-
-
- **
- ** 6510-Task stoppen
- **
-
- ; Task stoppen
- Stop6510 move.l _SysBase,a6
- tst.l CPUProc(pc)
- beq 1$
- st.b RESETIsEXIT ;EXIT-Reset auslösen
- st.b IntIsRESET
- move.l ReadySet,d0
- JSRLIB Wait
-
- ; Signal freigeben
- 1$ move.b ReadySig,d0
- JMPLIB FreeSignal
-
-
- **
- ** 6510-Task anhalten
- **
-
- Pause6510 move.l _SysBase,a6
- st.b RESETIsPause ;Pause-Reset auslösen
- st.b IntIsRESET
- move.l ReadySet,d0
- JMPLIB Wait
-
-
- **
- ** 6510-Task fortsetzen
- **
-
- Resume6510 move.l _SysBase,a6
- move.l CPUTask,a1 ;Continue-Signal schicken
- move.l ContinueSet,d0
- JMPLIB Signal
-
-
- **
- ** Strings in Datenstrukturen lokalisieren
- **
-
- GetStr MACRO ;Label
- lea TheLocale,a0
- move.l #\1,d0
- jsr GetString
- ENDM
-
- Localize6510 GetStr MSG_REQTITLE
- move.l d0,IllegalOpReq+8
- move.l d0,JumpToIOReq+8
-
- GetStr MSG_REQGADS3
- move.l d0,IllegalOpReq+16
-
- GetStr MSG_REQGADS4
- move.l d0,JumpToIOReq+16
-
- GetStr MSG_ILLEGALOP
- move.l d0,IllegalOpReq+12
-
- GetStr MSG_JUMPTOIO
- move.l d0,JumpToIOReq+12
- rts
-
-
- **
- ** 6510-Emulator
- **
- ** Register:
- ** d0: Scratch (Oberes Wort muß IMMER Null sein!)
- ** d1: Scratch (Oberes Wort muß IMMER Null sein!)
- **
-
- ; Task ermitteln
- CPUTaskProc move.l _SysBase,a6
- sub.l a1,a1
- JSRLIB FindTask
- move.l d0,CPUTask
-
- ; Continue-Signal holen
- moveq #-1,d0
- JSRLIB AllocSignal
- move.b d0,ContinueSig
- moveq #0,d1
- bset d0,d1
- move.l d1,ContinueSet
-
- ; 6569 initialisieren
- bsr Init6569
-
- ; Signal an den Emulator schicken
- move.l _SysBase,a6
- move.l MainTask,a1
- move.l ReadySet,d0
- JSRLIB Signal
-
- ; Variablen initilisieren
- clr.l Interrupt
- clr.b RESETIsEXIT
- clr.b RESETIsPause
- move.w #63,CyclesLeft
-
- ; Speicherkonfiguration initialisieren
- move.l TheRAM,RAMPTR
- move.w #$ff07,(RAMPTR)
- NewConfig
-
- ; Register setzen
- moveq #0,d0
- moveq #0,d1
- moveq #0,RA
- moveq #0,RX
- moveq #0,RY
- move.l #$01ff,RS
- moveq #0,RCCR
- move.l #InterruptMask,RP
- lea OpcodeTable,OPTABPTR
-
- ; Reset-Vektor lesen, PC setzen und ersten Befehl ausführen
- move.w #$fffc,d0
- ReadWord
- Jump
- Next 0
-
- ; Unbekannten Opcode entdeckt: Requester darstellen
- IllegalOp movem.l a2-a6,-(sp)
-
- and.w #$00ff,d0 ;Opcode
- move.w d0,RequestStream
- move.l RPC,d0 ;und PC anzeigen
- subq.w #1,d0
- move.w d0,RequestStream+2
-
- bsr AmigaToFront
-
- move.l _IntuitionBase,a6
- sub.l a0,a0
- lea IllegalOpReq,a1
- move.l a0,a2
- lea RequestStream,a3
- JSRLIB EasyRequestArgs
-
- move.l d0,-(sp)
- bsr EmulToFront
- move.l (sp)+,d0
-
- movem.l (sp)+,a2-a6
-
- tst.l d0
- beq 1$
-
- bsr Reset6526 ;Reset
- bsr Reset6581
- moveq #0,d0 ;MSWs von d0 und d1
- moveq #0,d1 ; müssen Null sein
- bra HandleRESET
-
- 1$ moveq #0,d0 ;Weiter
- moveq #0,d1
- Next 0
-
-
- **
- ** Speicherzugriff Lesen
- ** In a1 steht die Rücksprungadresse
- **
-
- ; Lesen aus dem RAM
- ReadByteRAM move.b (RAMPTR,d0.l),d0
- jmp (a1)
-
- ; Lesen aus dem Basic-ROM
- ReadByteBasic and.w #$1fff,d0
- move.b ([TheBasic,pc],d0.w),d0
- jmp (a1)
-
- ; Lesen aus einem VIC-Register
- ReadByteVIC and.w #$3f,d0
- bsr ReadFrom6569
- jmp (a1)
-
- ; Lesen aus einem SID-Register
- ReadByteSID and.w #$1f,d0
- bsr ReadFrom6581
- jmp (a1)
-
- ; Lesen aus dem Farb-RAM
- ReadByteColor and.w #$03ff,d0
- move.b ([TheColor,pc],d0.w),d1
- and.b #$0f,d1
-
- move.l d1,-(sp)
- bsr Random ;Oberes Nibble ist Zufallswert
- and.b #$f0,d0
- move.l (sp)+,d1
-
- or.b d1,d0
- jmp (a1)
-
- ; Lesen aus einem CIA 1-Register
- ReadByteCIA1 and.w #$0f,d0
- bsr ReadFrom6526A
- jmp (a1)
-
- ; Lesen aus einem CIA 2-Register
- ReadByteCIA2 and.w #$0f,d0
- bsr ReadFrom6526B
- jmp (a1)
-
- ; Lesen einer offenen Adresse
- ReadByteUndef cmp.l #$dfa0,d0
- bhs 1$
- bsr Random ;Zufallswert
- moveq #0,d1 ;MSW löschen
- jmp (a1)
-
- ; $dfa0-$dfff: Emulator-Identifikation
- 1$ cmp.w #$dfff,d0 ;$dfff liest abwechselnd $55/$aa
- bne 2$
- move.b DFFFByte,d0
- not.b DFFFByte
- jmp (a1)
-
- 2$ cmp.w #$dffe,d0 ;$dffe liest "F" (Frodo-Kennung)
- bne 3$
- moveq #'F',d0
- jmp (a1)
-
- 3$ cmp.w #$dffd,d0 ;$dffd: Version
- bne 4$
- move.b #VERSION,d0
- jmp (a1)
-
- 4$ cmp.w #$dffc,d0 ;$dffc: Revision
- bne 5$
- move.b #REVISION,d0
- jmp (a1)
-
- 5$ sub.w #$dfa0,d0 ;$dfa0-$dffb: ID-String
- move.b IDString(pc,d0.w),d0
- jmp (a1)
-
- ; Lesen aus dem Kernal-ROM
- ReadByteKernal and.w #$1fff,d0
- move.b ([TheKernal,pc],d0.w),d0
- jmp (a1)
-
- ; Lesen aus dem Char-ROM
- ReadByteChar and.w #$0fff,d0
- move.b ([TheChar,pc],d0.w),d0
- jmp (a1)
-
-
- **
- ** Speicherzugriff Schreiben
- ** In a1 steht die 16-Bit-Adresse
- **
-
- ; Schreiben in Seite 0
- WriteBytePage0 move.l a1,d0
- move.b d1,(RAMPTR,d0.w)
- cmp.b #2,d0
- bhs 1$
- NewConfig
- 1$ rts
-
- ; Schreiben ins RAM
- WriteByteRAM move.b d1,(RAMPTR,a1.l)
- rts
-
- ; Schreiben in ein VIC-Register
- WriteByteVIC move.l a1,d0
- and.w #$3f,d0
- bra WriteTo6569
-
- ; Schreiben in ein SID-Register
- WriteByteSID move.l a1,d0
- and.w #$1f,d0
- bra WriteTo6581
-
- ; Schreiben ins Farb-RAM
- WriteByteColor move.l a1,d0
- and.w #$03ff,d0
- move.b d1,([TheColor],d0.w)
- rts
-
- ; Schreiben in ein CIA 1-Register
- WriteByteCIA1 move.l a1,d0
- and.w #$0f,d0
- bra WriteTo6526A
-
- ; Schreiben in ein CIA 2-Register
- WriteByteCIA2 move.l a1,d0
- and.w #$0f,d0
- bra WriteTo6526B
-
- ; Schreiben an einer offenen Adresse
- WriteByteUndef move.l a1,d0
- rts
-
-
- **
- ** Sprungbefehle
- **
-
- ; Sprung ins RAM
- JumpToRAM lea (RAMPTR,d0.l),RPC
- rts
-
- ; Sprung ins Basic-ROM
- JumpToBasic move.l TheBasic(pc),RPC
- and.w #$1fff,d0
- add.l d0,RPC
- rts
-
- ; Sprung ins Kernal-ROM
- JumpToKernal move.l TheKernal(pc),RPC
- and.w #$1fff,d0
- add.l d0,RPC
- rts
-
- ; Sprung ins Char-ROM (warum sollte jemand sowas tun? Aber egal.)
- JumpToChar move.l TheChar(pc),RPC
- and.w #$0fff,d0
- add.l d0,RPC
- rts
-
- ; Sprung in den I/O-Bereich (in VIC-Register wird ab und zu gerne gesprungen,
- ; $de00 und das Farb-RAM sind auch sehr beliebt :-)
- JumpToIO movem.l a2-a6,-(sp)
-
- move.w d0,RequestStream ;PC anzeigen
-
- bsr AmigaToFront
-
- move.l _IntuitionBase,a6
- sub.l a0,a0
- lea JumpToIOReq,a1
- move.l a0,a2
- lea RequestStream,a3
- JSRLIB EasyRequestArgs
-
- bsr EmulToFront
-
- movem.l (sp)+,a2-a6
-
- bsr Reset6526
- bsr Reset6581
- moveq #0,d0 ;MSWs von d0 und d1
- moveq #0,d1 ; müssen Null sein
-
- addq.l #4,sp ;Rücksprungadresse löschen
- bra HandleRESET
-
-
- **
- ** Opcode-Routinen
- **
-
- *
- * Interrupts handhaben
- *
-
- ; Art des Interrupt feststellen (Priorität)
- HandleInt tst.b IntIsRESET(pc)
- bne HandleRESET
- tst.b IntIsNMI(pc)
- bne HandleNMI
- tst.b IntIsVICIRQ(pc)
- bne HandleVICIRQ
- tst.b IntIsCIAIRQ(pc)
- bne HandleCIAIRQ
-
- ; Kein Interrupt, nächsten Befehl ausführen
- HandleIntDone Next 0
-
- ; IRQ: Interrupt-Bit testen, nach ($fffe) springen
- HandleVICIRQ btst #InterruptBit,RP
- beq HandleIRQ
- Next 0
-
- HandleCIAIRQ btst #InterruptBit,RP
- beq HandleIRQ
- Next 0
-
- HandleIRQ PushPC
- PushP
-
- or.w #InterruptMask,RP
- move.w #$fffe,d0 ;IRQ-Vektor
- ReadWord
- Jump
- Next 7
-
- ; NMI: Nach ($fffa) springen
- HandleNMI clr.b IntIsNMI ;Simuliert einen flankengetriggerten Eingang
-
- PushPC
- PushP
-
- or.w #InterruptMask,RP
- move.w #$fffa,d0 ;NMI-Vektor
- ReadWord
- Jump
- Next 7
-
- ; RESET: Emulator beenden oder nach ($fffc) springen
- HandleRESET tst.b RESETIsEXIT ;Beenden?
- bne HandleEXIT
- tst.b RESETIsPause ;Pause?
- bne HandlePause
-
- clr.l Interrupt ;Nein, RESET
-
- cmp.l #$c3c2cd38,$8004(RAMPTR)
- bne 1$
- cmp.b #$30,$8008(RAMPTR)
- bne 1$
- clr.b $8004(RAMPTR) ;CBM80 löschen, wenn vorhanden
-
- 1$ move.w #$ff07,(RAMPTR) ;Speicherkonfiguration initialisieren
- NewConfig
-
- move.w #$fffc,d0 ;RESET-Vektor
- ReadWord
- Jump
- Next 0
-
- ; EXIT: Signal an den Emulator schicken
- HandleEXIT bsr Exit6569 ;6569 aufräumen
-
- move.l _SysBase,a6
-
- moveq #0,d0
- move.b ContinueSig,d0
- JSRLIB FreeSignal
-
- JSRLIB Forbid
- move.l MainTask,a1
- move.l ReadySet,d0
- JSRLIB Signal
- moveq #0,d0
- rts
-
- ; Pause: Signal an den Emulator schicken und dann selbst auf
- ; ein Signal warten
- HandlePause clr.l Interrupt
- clr.b RESETIsPause
-
- movem.l d2-d7/a2-a6,-(sp)
-
- move.l _SysBase,a6
- move.l MainTask,a1
- move.l ReadySet,d0
- JSRLIB Signal
-
- move.l ContinueSet,d0
- JSRLIB Wait
-
- movem.l (sp)+,d2-d7/a2-a6
- moveq #0,d0
- moveq #0,d1
-
- Next 0
-
-
- *
- * Opcodes
- *
-
- ; Laden
- LoadA MACRO ;Quelle, Zyklenzahl
- move.b \1,RA
- move ccr,RCCR
- Next \2
- ENDM
-
- LoadX MACRO ;Quelle, Zyklenzahl
- move.b \1,RX
- move ccr,RCCR
- Next \2
- ENDM
-
- LoadY MACRO ;Quelle, Zyklenzahl
- move.b \1,RY
- move ccr,RCCR
- Next \2
- ENDM
-
- LoadAX MACRO ;Quelle, Zyklenzahl
- move.b \1,RA
- move.b RA,RX
- move ccr,RCCR
- Next \2
- ENDM
-
- LDAImm LoadA (RPC)+,2
-
- LDAZero ReadAdrZero
- LoadA (RAMPTR,d0.w),3
-
- LDAZeroX ReadAdrZeroX
- LoadA (RAMPTR,d0.w),4
-
- LDAAbs ReadByteAbs
- LoadA d0,4
-
- LDAAbsX ReadByteAbsX
- LoadA d0,4
-
- LDAAbsY ReadByteAbsY
- LoadA d0,4
-
- LDAIndX ReadByteIndX
- LoadA d0,6
-
- LDAIndY ReadByteIndY
- LoadA d0,5
-
- LDXImm LoadX (RPC)+,2
-
- LDXZero ReadAdrZero
- LoadX (RAMPTR,d0.w),3
-
- LDXZeroY ReadAdrZeroY
- LoadX (RAMPTR,d0.w),4
-
- LDXAbs ReadByteAbs
- LoadX d0,4
-
- LDXAbsY ReadByteAbsY
- LoadX d0,4
-
- LDYImm LoadY (RPC)+,2
-
- LDYZero ReadAdrZero
- LoadY (RAMPTR,d0.w),3
-
- LDYZeroX ReadAdrZeroX
- LoadY (RAMPTR,d0.w),4
-
- LDYAbs ReadByteAbs
- LoadY d0,4
-
- LDYAbsX ReadByteAbsX
- LoadY d0,4
-
- LAXZero ReadAdrZero
- LoadAX (RAMPTR,d0.w),3
-
- LAXZeroY ReadAdrZeroY
- LoadAX (RAMPTR,d0.w),4
-
- LAXAbs ReadByteAbs
- LoadAX d0,4
-
- LAXAbsY ReadByteAbsY
- LoadAX d0,4
-
- LAXIndX ReadByteIndX
- LoadAX d0,6
-
- LAXIndY ReadByteIndY
- LoadAX d0,5
-
- ; Speichern
- StoreA MACRO ;Zyklenzahl
- move.b RA,d1
- WriteByte
- Next \1
- ENDM
-
- StoreAX MACRO ;Zyklenzahl
- move.b RA,d1
- and.b RX,d1
- WriteByte
- Next \1
- ENDM
-
- STAZero ReadAdrZero
- WriteZeroNext RA,3
-
- STAZeroX ReadAdrZeroX
- WriteZeroNext RA,4
-
- STAAbs ReadAdrAbs
- StoreA 4
-
- STAAbsX ReadAdrAbsX
- StoreA 5
-
- STAAbsY ReadAdrAbsY
- StoreA 5
-
- STAIndX ReadAdrIndX
- StoreA 6
-
- STAIndY ReadAdrIndY
- StoreA 6
-
- STXZero ReadAdrZero
- WriteZeroNext RX,3
-
- STXZeroY ReadAdrZeroY
- WriteZeroNext RX,4
-
- STXAbs ReadAdrAbs
- move.b RX,d1
- WriteByte
- Next 4
-
- STYZero ReadAdrZero
- WriteZeroNext RY,3
-
- STYZeroX ReadAdrZeroX
- WriteZeroNext RY,4
-
- STYAbs ReadAdrAbs
- move.b RY,d1
- WriteByte
- Next 4
-
- SAXZero ReadAdrZero
- StoreAX 3
-
- SAXZeroY ReadAdrZeroY
- StoreAX 4
-
- SAXAbs ReadAdrAbs
- StoreAX 4
-
- SAXIndX ReadAdrIndX
- StoreAX 6
-
- ; Datentransport zwischen Registern
- TAX move.b RA,RX
- move ccr,RCCR
- Next 2
-
- TAY move.b RA,RY
- move ccr,RCCR
- Next 2
-
- TXA move.b RX,RA
- move ccr,RCCR
- Next 2
-
- TYA move.b RY,RA
- move ccr,RCCR
- Next 2
-
- TXS move.b RX,RS
- Next 2
-
- TSX move.b RS,RX
- move ccr,RCCR
- Next 2
-
- ; Stack
- PHA PushByte RA
- Next 3
-
- PLA PopByte RA
- move ccr,RCCR
- Next 4
-
- PHP or.w #BreakMask,RP ;Prozessorfehler: Break-Flag
- PushP ; wird auf dem Stack gesetzt
- and.w #~BreakMask,RP
- Next 3
-
- PLP PopP
- tst.w IntIsIRQ(pc) ;Steht ein IRQ an?
- beq 1$
- btst #InterruptBit,RP ;Ja, I-Flag gelöscht?
- beq HandleIRQ ;Ja, Interrupt auslösen
- 1$ Next 4
-
- ; Vergleiche
- CompareA MACRO ;Quelle, Zyklenzahl
- cmp.b \1,RA
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen und invertieren
- not.b RP
- Next \2
- ENDM
-
- CMPImm CompareA (RPC)+,2
-
- CMPZero ReadAdrZero
- CompareA (RAMPTR,d0.w),3
-
- CMPZeroX ReadAdrZeroX
- CompareA (RAMPTR,d0.w),4
-
- CMPAbs ReadByteAbs
- CompareA d0,4
-
- CMPAbsX ReadByteAbsX
- CompareA d0,4
-
- CMPAbsY ReadByteAbsY
- CompareA d0,4
-
- CMPIndX ReadByteIndX
- CompareA d0,6
-
- CMPIndY ReadByteIndY
- CompareA d0,5
-
- CPXImm cmp.b (RPC)+,RX
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen und invertieren
- not.b RP
- Next 2
-
- CPXZero ReadAdrZero
- cmp.b (RAMPTR,d0.w),RX
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen und invertieren
- not.b RP
- Next 3
-
- CPXAbs ReadByteAbs
- cmp.b d0,RX
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen und invertieren
- not.b RP
- Next 4
-
- CPYImm cmp.b (RPC)+,RY
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen und invertieren
- not.b RP
- Next 2
-
- CPYZero ReadAdrZero
- cmp.b (RAMPTR,d0.w),RY
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen und invertieren
- not.b RP
- Next 3
-
- CPYAbs ReadByteAbs
- cmp.b d0,RY
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen und invertieren
- not.b RP
- Next 4
-
- ; Arithmetische Operationen
- AdcA MACRO ;Zyklenzahl
- lsr.b #1,RP ;Carry -> X
- btst #DecimalBit,RP
- bne \@1$
- addx.b d0,RA
- move ccr,RCCR
- bvc \@2$ ;Overflow holen
- or.w #OverflowMask,RP
- move.b RCCR,RP ;Carry holen
- Next \1
- \@2$ and.w #~OverflowMask,RP
- move.b RCCR,RP ;Carry holen
- Next \1
- \@1$ moveq #0,d1 ;V und C löschen
- abcd.b d0,RA
- move ccr,RCCR
- bvc \@2$ ;Overflow holen
- or.w #OverflowMask,RP
- move.b RCCR,RP ;Carry holen
- Next \1
- ENDM
-
- ADCImm move.b (RPC)+,d0
- AdcA 2
-
- ADCZero ReadByteZero d0
- AdcA 3
-
- ADCZeroX ReadByteZeroX d0
- AdcA 4
-
- ADCAbs ReadByteAbs
- AdcA 4
-
- ADCAbsX ReadByteAbsX
- AdcA 4
-
- ADCAbsY ReadByteAbsY
- AdcA 4
-
- ADCIndX ReadByteIndX
- AdcA 6
-
- ADCIndY ReadByteIndY
- AdcA 5
-
- SbcA MACRO ;Zyklenzahl
- not.b RP
- lsr.b #1,RP ;Carry invertieren und nach X
- btst #DecimalBit,RP
- bne \@1$
- subx.b d0,RA
- move ccr,RCCR
- bvc \@2$ ;Overflow holen
- or.w #OverflowMask,RP
- move.b RCCR,RP ;Carry holen und invertieren
- not.b RP
- Next \1
- \@2$ and.w #~OverflowMask,RP
- move.b RCCR,RP ;Carry holen und invertieren
- not.b RP
- Next \1
- \@1$ moveq #0,d1 ;V und C löschen
- sbcd.b d0,RA
- move ccr,RCCR
- bvc \@2$ ;Overflow holen
- or.w #OverflowMask,RP
- move.b RCCR,RP ;Carry holen und invertieren
- not.b RP
- Next \1
- ENDM
-
- SBCImm move.b (RPC)+,d0
- SbcA 2
-
- SBCZero ReadByteZero d0
- SbcA 3
-
- SBCZeroX ReadByteZeroX d0
- SbcA 4
-
- SBCAbs ReadByteAbs
- SbcA 4
-
- SBCAbsX ReadByteAbsX
- SbcA 4
-
- SBCAbsY ReadByteAbsY
- SbcA 4
-
- SBCIndX ReadByteIndX
- SbcA 6
-
- SBCIndY ReadByteIndY
- SbcA 5
-
- Increment MACRO ;Zyklenzahl
- move.l d0,-(sp)
- ReadByte
- addq.b #1,d0
- move ccr,RCCR
- move.b d0,d1
- move.l (sp)+,d0
- WriteByte
- Next \1
- ENDM
-
- IncrementZero MACRO ;Zyklenzahl
- addq.b #1,(RAMPTR,d0.w)
- move ccr,RCCR
- cmp.b #2,d0
- bhs \@1$
- NewConfig
- \@1$ Next \1
- ENDM
-
- INCZero ReadAdrZero
- IncrementZero 5
-
- INCZeroX ReadAdrZeroX
- IncrementZero 6
-
- INCAbs ReadAdrAbs
- Increment 6
-
- INCAbsX ReadAdrAbsX
- Increment 7
-
- Decrement MACRO ;Zyklenzahl
- move.l d0,-(sp)
- ReadByte
- subq.b #1,d0
- move ccr,RCCR
- move.b d0,d1
- move.l (sp)+,d0
- WriteByte
- Next \1
- ENDM
-
- DecrementZero MACRO ;Zyklenzahl
- subq.b #1,(RAMPTR,d0.w)
- move ccr,RCCR
- cmp.b #2,d0
- bhs \@1$
- NewConfig
- \@1$ Next \1
- ENDM
-
- DECZero ReadAdrZero
- DecrementZero 5
-
- DECZeroX ReadAdrZeroX
- DecrementZero 6
-
- DECAbs ReadAdrAbs
- Decrement 6
-
- DECAbsX ReadAdrAbsX
- Decrement 7
-
- INX addq.b #1,RX
- move ccr,RCCR
- Next 2
-
- DEX subq.b #1,RX
- move ccr,RCCR
- Next 2
-
- INY addq.b #1,RY
- move ccr,RCCR
- Next 2
-
- DEY subq.b #1,RY
- move ccr,RCCR
- Next 2
-
- ; Logische Operationen
- AndA MACRO ;Quelle, Zyklenzahl
- and.b \1,RA
- move ccr,RCCR
- Next \2
- ENDM
-
- ANDImm AndA (RPC)+,2
-
- ANDZero ReadAdrZero
- AndA (RAMPTR,d0.w),3
-
- ANDZeroX ReadAdrZeroX
- AndA (RAMPTR,d0.w),4
-
- ANDAbs ReadByteAbs
- AndA d0,4
-
- ANDAbsX ReadByteAbsX
- AndA d0,4
-
- ANDAbsY ReadByteAbsY
- AndA d0,4
-
- ANDIndX ReadByteIndX
- AndA d0,6
-
- ANDIndY ReadByteIndY
- AndA d0,5
-
- OrA MACRO ;Quelle, Zyklenzahl
- or.b \1,RA
- move ccr,RCCR
- Next \2
- ENDM
-
- ORAImm OrA (RPC)+,2
-
- ORAZero ReadAdrZero
- OrA (RAMPTR,d0.w),3
-
- ORAZeroX ReadAdrZeroX
- OrA (RAMPTR,d0.w),4
-
- ORAAbs ReadByteAbs
- OrA d0,4
-
- ORAAbsX ReadByteAbsX
- OrA d0,4
-
- ORAAbsY ReadByteAbsY
- OrA d0,4
-
- ORAIndX ReadByteIndX
- OrA d0,6
-
- ORAIndY ReadByteIndY
- OrA d0,5
-
- EorA MACRO ;Zyklenzahl
- eor.b d0,RA ;eor.b (ea),RA geht nicht
- move ccr,RCCR ;(Warum nicht, Motorola ?) :-(
- Next \1
- ENDM
-
- EORImm move.b (RPC)+,d0
- EorA 2
-
- EORZero ReadAdrZero
- move.b (RAMPTR,d0.w),d0
- EorA 3
-
- EORZeroX ReadAdrZeroX
- move.b (RAMPTR,d0.w),d0
- EorA 4
-
- EORAbs ReadByteAbs
- EorA 4
-
- EORAbsX ReadByteAbsX
- EorA 4
-
- EORAbsY ReadByteAbsY
- EorA 4
-
- EORIndX ReadByteIndX
- EorA 6
-
- EORIndY ReadByteIndY
- EorA 5
-
- BitTest MACRO ;Zyklenzahl
- tst.b d0 ;N holen
- move ccr,RCCR
- and.w #$1cff,RP ;B,D,I und C behalten
-
- btst #6,d0 ;Bit 6 -> V
- beq \@1$
- or.w #OverflowMask,RP
-
- \@1$ and.b RA,d0 ;A AND M -> Z
- beq \@2$
- and.b #$fb,RCCR
- Next \1
- \@2$ or.b #$04,RCCR
- Next \1
- ENDM
-
- BITZero ReadByteZero d0
- BitTest 3
-
- BITAbs ReadByteAbs
- BitTest 4
-
- ; Verschiebungen
- ShiftLeft MACRO ;Zyklenzahl
- move.l d0,-(sp)
- ReadByte
- add.b d0,d0
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen
- move.b d0,d1
- move.l (sp)+,d0
- WriteByte
- Next \1
- ENDM
-
- ShiftLeftZero MACRO ;Zyklenzahl
- lea (RAMPTR,d0.w),a0
- move.b (a0),d1
- add.b d1,d1
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen
- move.b d1,(a0)
- cmp.b #2,d0
- bhs \@1$
- NewConfig
- \@1$ Next \1
- ENDM
-
- ASLA add.b RA,RA
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen
- Next 2
-
- ASLZero ReadAdrZero
- ShiftLeftZero 5
-
- ASLZeroX ReadAdrZeroX
- ShiftLeftZero 6
-
- ASLAbs ReadAdrAbs
- ShiftLeft 6
-
- ASLAbsX ReadAdrAbsX
- ShiftLeft 7
-
- ShiftRight MACRO ;Zyklenzahl
- move.l d0,-(sp)
- ReadByte
- lsr.b #1,d0
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen
- move.b d0,d1
- move.l (sp)+,d0
- WriteByte
- Next \1
- ENDM
-
- ShiftRightZero MACRO ;Zyklenzahl
- lea (RAMPTR,d0.w),a0
- move.b (a0),d1
- lsr.b #1,d1
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen
- move.b d1,(a0)
- cmp.b #2,d0
- bhs \@1$
- NewConfig
- \@1$ Next \1
- ENDM
-
- LSRA lsr.b #1,RA
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen
- Next 2
-
- LSRZero ReadAdrZero
- ShiftRightZero 5
-
- LSRZeroX ReadAdrZeroX
- ShiftRightZero 6
-
- LSRAbs ReadAdrAbs
- ShiftRight 6
-
- LSRAbsX ReadAdrAbsX
- ShiftRight 7
-
- RotateLeft MACRO ;Zyklenzahl
- move.l d0,-(sp)
- ReadByte
- lsr.b #1,RP ;Carry -> X
- roxl.b #1,d0
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen
- move.b d0,d1
- move.l (sp)+,d0
- WriteByte
- Next \1
- ENDM
-
- RotateLeftZero MACRO ;Zyklenzahl
- lea (RAMPTR,d0.w),a0
- move.b (a0),d1
- lsr.b #1,RP ;Carry -> X
- roxl.b #1,d1
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen
- move.b d1,(a0)
- cmp.b #2,d0
- bhs \@1$
- NewConfig
- \@1$ Next \1
- ENDM
-
- ROLA lsr.b #1,RP ;Carry -> X
- roxl.b #1,RA
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen
- Next 2
-
- ROLZero ReadAdrZero
- RotateLeftZero 5
-
- ROLZeroX ReadAdrZeroX
- RotateLeftZero 6
-
- ROLAbs ReadAdrAbs
- RotateLeft 6
-
- ROLAbsX ReadAdrAbsX
- RotateLeft 7
-
- RotateRight MACRO ;Zyklenzahl
- move.l d0,-(sp)
- ReadByte
- lsr.b #1,RP ;Carry -> X
- roxr.b #1,d0
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen
- move.b d0,d1
- move.l (sp)+,d0
- WriteByte
- Next \1
- ENDM
-
- RotateRightZero MACRO ;Zyklenzahl
- lea (RAMPTR,d0.w),a0
- move.b (a0),d1
- lsr.b #1,RP ;Carry -> X
- roxr.b #1,d1
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen
- move.b d1,(a0)
- cmp.b #2,d0
- bhs \@1$
- NewConfig
- \@1$ Next \1
- ENDM
-
- RORA lsr.b #1,RP ;Carry -> X
- roxr.b #1,RA
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen
- Next 2
-
- RORZero ReadAdrZero
- RotateRightZero 5
-
- RORZeroX ReadAdrZeroX
- RotateRightZero 6
-
- RORAbs ReadAdrAbs
- RotateRight 6
-
- RORAbsX ReadAdrAbsX
- RotateRight 7
-
- ; Sprünge/Verzweigungen
- JMPAbs ReadAdrAbs
- Jump
- Next 3
-
- JMPInd ReadAdrInd
- Jump
- Next 5
-
- JSRAbs PushPCPlus1
- ReadAdrAbs
- Jump
- Next 6
-
- RTSImpl PopByte d1 ;LSB
- PopByte d0 ;MSB
- lsl.w #8,d0 ;schieben
- move.b d1,d0 ;LSB dazunehmen
- addq.w #1,d0 ;Adresse um eins erhöhen
- Jump
- Next 6
-
- RTIImpl PopP
- PopByte d1 ;LSB
- PopByte d0 ;MSB
- lsl.w #8,d0 ;schieben
- move.b d1,d0 ;LSB dazunehmen
- Jump
- tst.w IntIsIRQ(pc) ;Steht ein IRQ an?
- beq 1$
- btst #InterruptBit,RP ;Ja, I-Flag gelöscht?
- beq HandleIRQ ;Ja, Interrupt auslösen
- 1$ Next 6
-
- BRK PushPC
- or.w #BreakMask,RP ;Break-Flag nur auf dem Stapel setzen
- PushP
- and.w #~BreakMask,RP
- or.w #InterruptMask,RP
- move.w #$fffe,d0 ;IRQ-Vektor
- ReadWord
- Jump
- Next 7
-
- Branch MACRO
- ReadByteRel
- move.l RPC,d1
- add.w d0,d1
- move.l d1,RPC
- moveq #0,d1
- Next 3
- ENDM
-
- BVCRel btst #OverflowBit,RP
- bne BVCNot
- Branch
- BVCNot addq.l #1,RPC
- Next 2
-
- BVSRel btst #OverflowBit,RP
- beq BVSNot
- Branch
- BVSNot addq.l #1,RPC
- Next 2
-
- BEQRel btst #2,RCCR
- beq BEQNot
- Branch
- BEQNot addq.l #1,RPC
- Next 2
-
- BNERel btst #2,RCCR
- bne BNENot
- Branch
- BNENot addq.l #1,RPC
- Next 2
-
- BPLRel btst #3,RCCR
- bne BPLNot
- Branch
- BPLNot addq.l #1,RPC
- Next 2
-
- BMIRel btst #3,RCCR
- beq BMINot
- Branch
- BMINot addq.l #1,RPC
- Next 2
-
- BCCRel btst #CarryBit,RP
- bne BCCNot
- Branch
- BCCNot addq.l #1,RPC
- Next 2
-
- BCSRel btst #CarryBit,RP
- beq BCSNot
- Branch
- BCSNot addq.l #1,RPC
- Next 2
-
- ; Statusregister
- SEI or.w #InterruptMask,RP
- Next 2
-
- CLI and.w #~InterruptMask,RP
- tst.w IntIsIRQ(pc) ;Steht ein IRQ an?
- bne HandleIRQ ;Ja, auslösen
- Next 2
-
- CLC clr.b RP
- Next 2
-
- SEC st.b RP
- Next 2
-
- SED or.w #DecimalMask,RP
- Next 2
-
- CLD and.w #~DecimalMask,RP
- Next 2
-
- CLV and.w #~OverflowMask,RP
- Next 2
-
- *
- * Periodic: Wird über den Opcode-Fetch aufgerufen,
- * wenn der Zyklenzähler unterläuft
- * Sitzt hier in der Mitte, um kurze Branches ausnutzen zu können
- *
-
- ; VIC und CIA aufrufen
- Periodic lea RegStore+24,a0
- movem.w d2-d7,-(a0) ;Gerade Anzahl von Registern
- movem.l a2-a3/a5,-(a0)
- bra Periodic6569 ;Springt nach Periodic6526 und hierher zurück
- Peri6526Cont movem.l RegStore,a2-a3/a5
- movem.w RegStore+12,d2-d7
- move.l TheRAM,RAMPTR ;a4
- lea OpcodeTable,OPTABPTR ;a6
- moveq #0,d0
- moveq #0,d1
-
- ; Interrupt aufgetreten?
- tst.l Interrupt(pc)
- bne HandleInt
-
- ; Nein, Nächsten Befehl ausführen
- Next 0
-
-
- ; Leerbefehle
- NOPImpl Next 2
-
- NOPZero addq.w #1,RPC
- Next 3
-
- NOPZeroX addq.w #1,RPC
- Next 4
-
- NOPAbsX
- NOPAbs addq.w #2,RPC
- Next 4
-
- ; ASL/ORA-Gruppe
- ShLeftOr MACRO ;Zyklenzahl
- move.l d0,-(sp)
- ReadByte
- add.b d0,d0
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen
- or.b d0,RA
- move.b d0,d1
- move.l (sp)+,d0
- WriteByte
- Next \1
- ENDM
-
- ShLeftOrZero MACRO ;Zyklenzahl
- lea (RAMPTR,d0.w),a0
- move.b (a0),d1
- add.b d1,d1
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen
- or.b d1,RA
- move.b d1,(a0)
- cmp.b #2,d0
- bhs \@1$
- NewConfig
- \@1$ Next \1
- ENDM
-
- SLOZero ReadAdrZero
- ShLeftOrZero 5
-
- SLOZeroX ReadAdrZeroX
- ShLeftOrZero 6
-
- SLOAbs ReadAdrAbs
- ShLeftOr 6
-
- SLOAbsX ReadAdrAbsX
- ShLeftOr 7
-
- SLOAbsY ReadAdrAbsY
- ShLeftOr 7
-
- SLOIndX ReadAdrIndX
- ShLeftOr 8
-
- SLOIndY ReadAdrIndY
- ShLeftOr 8
-
- ; ROL/AND-Gruppe
- RoLeftAnd MACRO ;Zyklenzahl
- move.l d0,-(sp)
- ReadByte
- lsr.b #1,RP ;Carry -> X
- roxl.b #1,d0
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen
- and.b d0,RA
- move ccr,RCCR ;N und Z holen
- move.b d0,d1
- move.l (sp)+,d0
- WriteByte
- Next \1
- ENDM
-
- RoLeftAndZero MACRO ;Zyklenzahl
- lea (RAMPTR,d0.w),a0
- move.b (a0),d1
- lsr.b #1,RP ;Carry -> X
- roxl.b #1,d1
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen
- and.b d1,RA
- move ccr,RCCR ;N und Z holen
- move.b d1,(a0)
- cmp.b #2,d0
- bhs \@1$
- NewConfig
- \@1$ Next \1
- ENDM
-
- RLAZero ReadAdrZero
- RoLeftAndZero 5
-
- RLAZeroX ReadAdrZeroX
- RoLeftAndZero 6
-
- RLAAbs ReadAdrAbs
- RoLeftAnd 6
-
- RLAAbsX ReadAdrAbsX
- RoLeftAnd 7
-
- RLAAbsY ReadAdrAbsY
- RoLeftAnd 7
-
- RLAIndX ReadAdrIndX
- RoLeftAnd 8
-
- RLAIndY ReadAdrIndY
- RoLeftAnd 8
-
- ; LSR/EOR-Gruppe
- ShRightEor MACRO ;Zyklenzahl
- move.l d0,-(sp)
- ReadByte
- lsr.b #1,d0
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen
- eor.b d0,RA
- move.b d0,d1
- move.l (sp)+,d0
- WriteByte
- Next \1
- ENDM
-
- ShRightEorZero MACRO ;Zyklenzahl
- lea (RAMPTR,d0.w),a0
- move.b (a0),d1
- lsr.b #1,d1
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen
- eor.b d1,RA
- move.b d1,(a0)
- cmp.b #2,d0
- bhs \@1$
- NewConfig
- \@1$ Next \1
- ENDM
-
- SREZero ReadAdrZero
- ShRightEorZero 5
-
- SREZeroX ReadAdrZeroX
- ShRightEorZero 6
-
- SREAbs ReadAdrAbs
- ShRightEor 6
-
- SREAbsX ReadAdrAbsX
- ShRightEor 7
-
- SREAbsY ReadAdrAbsY
- ShRightEor 7
-
- SREIndX ReadAdrIndX
- ShRightEor 8
-
- SREIndY ReadAdrIndY
- ShRightEor 8
-
- ; ROR/ADC-Gruppe
- RoRightAdc MACRO ;Zyklenzahl
- move.l d0,-(sp)
- ReadByte
- lsr.b #1,RP ;Carry -> X
- roxr.b #1,d0
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen
- lsr.b #1,RP ;Carry -> X
- addx.b d0,RA
- move ccr,RCCR
- bvc \@2$ ;Overflow holen
- or.w #OverflowMask,RP
- bra \@3$
- \@2$ and.w #~OverflowMask,RP
- \@3$ move.b RCCR,RP ;Carry holen
- move.b d0,d1
- move.l (sp)+,d0
- WriteByte
- Next \1
- ENDM
-
- RoRightAdcZero MACRO ;Zyklenzahl
- lea (RAMPTR,d0.w),a0
- move.b (a0),d1
- lsr.b #1,RP ;Carry -> X
- roxr.b #1,d1
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen
- lsr.b #1,RP ;Carry -> X
- addx.b d1,RA
- move ccr,RCCR
- bvc \@2$ ;Overflow holen
- or.w #OverflowMask,RP
- bra \@3$
- \@2$ and.w #~OverflowMask,RP
- \@3$ move.b RCCR,RP ;Carry holen
- move.b d1,(a0)
- cmp.b #2,d0
- bhs \@1$
- NewConfig
- \@1$ Next \1
- ENDM
-
- RRAZero ReadAdrZero
- RoRightAdcZero 5
-
- RRAZeroX ReadAdrZeroX
- RoRightAdcZero 6
-
- RRAAbs ReadAdrAbs
- RoRightAdc 6
-
- RRAAbsX ReadAdrAbsX
- RoRightAdc 7
-
- RRAAbsY ReadAdrAbsY
- RoRightAdc 7
-
- RRAIndX ReadAdrIndX
- RoRightAdc 8
-
- RRAIndY ReadAdrIndY
- RoRightAdc 8
-
- ; DEC/CMP-Gruppe
- DecCompare MACRO ;Zyklenzahl
- move.l d0,-(sp)
- ReadByte
- subq.b #1,d0
- cmp.b d0,RA
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen und invertieren
- not.b RP
- move.b d0,d1
- move.l (sp)+,d0
- WriteByte
- Next \1
- ENDM
-
- DecCompareZero MACRO ;Zyklenzahl
- lea (RAMPTR,d0.w),a0
- move.b (a0),d1
- subq.b #1,d1
- cmp.b d1,RA
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen und invertieren
- not.b RP
- move.b d1,(a0)
- cmp.b #2,d0
- bhs \@1$
- NewConfig
- \@1$ Next \1
- ENDM
-
- DCPZero ReadAdrZero
- DecCompareZero 5
-
- DCPZeroX ReadAdrZeroX
- DecCompareZero 6
-
- DCPAbs ReadAdrAbs
- DecCompare 6
-
- DCPAbsX ReadAdrAbsX
- DecCompare 7
-
- DCPAbsY ReadAdrAbsY
- DecCompare 7
-
- DCPIndX ReadAdrIndX
- DecCompare 8
-
- DCPIndY ReadAdrIndY
- DecCompare 8
-
- ; INC/SBC-Gruppe
- IncSbc MACRO ;Zyklenzahl
- move.l d0,-(sp)
- ReadByte
- addq.b #1,d0
- not.b RP
- lsr.b #1,RP ;Carry invertieren und nach X
- subx.b d0,RA
- move ccr,RCCR
- bvc \@2$ ;Overflow holen
- or.w #OverflowMask,RP
- bra \@3$
- \@2$ and.w #~OverflowMask,RP
- \@3$ move.b RCCR,RP ;Carry holen und invertieren
- not.b RP
- move.b d0,d1
- move.l (sp)+,d0
- WriteByte
- Next \1
- ENDM
-
- IncSbcZero MACRO ;Zyklenzahl
- lea (RAMPTR,d0.w),a0
- move.b (a0),d1
- addq.b #1,d1
- not.b RP
- lsr.b #1,RP ;Carry invertieren und nach X
- subx.b d1,RA
- move ccr,RCCR
- bvc \@2$ ;Overflow holen
- or.w #OverflowMask,RP
- bra \@3$
- \@2$ and.w #~OverflowMask,RP
- \@3$ move.b RCCR,RP ;Carry holen und invertieren
- not.b RP
- move.b d1,(a0)
- cmp.b #2,d0
- bhs \@1$
- NewConfig
- \@1$ Next \1
- ENDM
-
- ISBZero ReadAdrZero
- IncSbcZero 5
-
- ISBZeroX ReadAdrZeroX
- IncSbcZero 6
-
- ISBAbs ReadAdrAbs
- IncSbc 6
-
- ISBAbsX ReadAdrAbsX
- IncSbc 7
-
- ISBAbsY ReadAdrAbsY
- IncSbc 7
-
- ISBIndX ReadAdrIndX
- IncSbc 8
-
- ISBIndY ReadAdrIndY
- IncSbc 8
-
- ; Komplexe (undokumentierte) Funktionen
- ANCImm and.b (RPC)+,RA ;??? ($0b, $2b)
- move ccr,RCCR
- smi.b RP ;N -> C
- Next 2
-
- ASRImm and.b (RPC)+,RA
- lsr.b #1,RA
- move ccr,RCCR
- move.b RCCR,RP
- Next 2
-
- ARRImm and.b (RPC)+,RA
- lsr.b #1,RP ;Carry -> X
- roxr.b #1,RA
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen
- Next 2
-
- ANEImm or.b #$ee,RA
- and.b (RPC)+,RA
- and.b RX,RA
- move ccr,RCCR
- Next 2
-
- LXAImm and.b (RPC)+,RA
- move.b RA,RX
- move ccr,RCCR
- Next 2
-
- LASAbsY ReadByteAbsY ;??? ($bb)
- and.b RS,d0
- move.b d0,RX
- move.b d0,RA
- move ccr,RCCR
- Next 4
-
- SHAAbsY ReadPCWord
- move.w d0,d1
- lsr.w #8,d1
- addq.b #1,d1
- and.b RX,d1
- and.b RA,d1
- add.w RY,d0
- WriteByte
- Next 5
-
- SHAIndY moveq #0,d0
- move.b (RPC)+,d0
- move.w (RAMPTR,d0.w),d0 ;(Abgekürzt)
- rol.w #8,d0 ;Geht bei ($ff),y schief
- move.w d0,d1
- lsr.w #8,d1
- addq.b #1,d1
- and.b RX,d1
- and.b RA,d1
- add.w RY,d0
- WriteByte
- Next 6
-
- SHXAbsY ReadPCWord
- move.w d0,d1
- lsr.w #8,d1
- addq.b #1,d1
- and.b RY,d1
- add.w RY,d0
- WriteByte
- Next 5
-
- SHYAbsX ReadPCWord
- move.w d0,d1
- lsr.w #8,d1
- addq.b #1,d1
- and.b RX,d1
- add.w RX,d0
- WriteByte
- Next 5
-
- SHSAbsY move.b RA,RS
- and.b RX,RS
- ReadPCWord
- move.w d0,d1
- lsr.w #8,d1
- addq.b #1,d1
- and.b RS,d1
- WriteByte
- Next 5
-
- SBXImm and.b RA,RX
- sub.b (RPC)+,RX
- move ccr,RCCR
- move.b RCCR,RP ;Carry holen und invertieren
- not.b RP
- Next 2
-
- *
- * Erweiterte Opcodes
- *
-
- ; $d2
- OpWrap move.l RPC,d1 ;Wraparound nach $100xx?
- sub.l RAMPTR,d1
- swap d1
- cmp.w #1,d1
- bne IllegalOp
- sub.l #$10001,RPC ;Ja, zu $00xx umleiten
- moveq #0,d1
- Next 0
-
- ; $f2 $xx
- OpIEC move.b (RPC)+,d0 ;Selektor holen
- beq OpIECOut
- cmp.b #1,d0
- beq OpIECOutATN
- cmp.b #2,d0
- beq OpIECOutSec
- cmp.b #3,d0
- beq OpIECIn
- cmp.b #4,d0
- beq OpIECSetATN
- cmp.b #5,d0
- beq OpIECRelATN
- cmp.b #6,d0
- beq OpIECTurnaround
- cmp.b #7,d0
- beq OpIECRelease
- bra IllegalOp
-
- OpIECOut move.b $95(RAMPTR),d0 ;Auszugebendes Byte holen
- move.b $a3(RAMPTR),d1 ;EOI-Flag holen
- bsr IECOut
- bra IECSetST
-
- OpIECOutATN move.b $95(RAMPTR),d0 ;Auszugebendes Byte holen
- bsr IECOutATN
- bra IECSetST
-
- OpIECOutSec move.b $95(RAMPTR),d0 ;Auszugebendes Byte holen
- bsr IECOutSec
- bra IECSetST
-
- OpIECIn bsr IECIn
- move.b d1,RA ;Byte in den Akku
- move ccr,RCCR ;Flags entsprechend setzen
- bra IECSetST
-
- OpIECSetATN bsr IECSetATN
- moveq #0,d0 ;MSWs von d0 und d1 löschen
- moveq #0,d1
- move.w #$edfb,d0 ;Nach $edfb springen
- Jump
- Next 0
-
- OpIECRelATN bsr IECRelATN
- bra IECReturn
-
- OpIECTurnaround bsr IECTurnaround
- bra IECReturn
-
- OpIECRelease bsr IECRelease
- bra IECReturn
-
- IECSetST or.b d0,$90(RAMPTR) ;Status setzen
- clr.b RP ;Carry löschen
- IECReturn moveq #0,d0 ;MSWs von d0 und d1 löschen
- moveq #0,d1
- bra RTSImpl ;RTS ausführen
-
-
- **
- ** Konstanten
- **
-
- ; Strings
- CPUTaskName dc.b "6510",0
- TimerIntName dc.b "Frodo Timer Int",0
-
- IDString dc.b "FRODO V1.4",13
- dc.b "(C)1994-1995 CHRISTIAN BAUER",0
- ds.b 64 ;Muß mind. 92 Zeichen lang sein
- CNOP 0,4
-
-
- *
- * Speicherkonfigurationstabelle
- *
-
- ; Diese Tabelle enthält für alle 8 Speicherkonfigurationen
- ; die Zeiger auf die zugehörigen Read- und WriteTabs
- CNOP 0,4
- ConfigTab dc.l ReadTab0,WriteTab0
- dc.l ReadTab1,WriteTab1
- dc.l ReadTab2,WriteTab2
- dc.l ReadTab3,WriteTab3
- dc.l ReadTab4,WriteTab4
- dc.l ReadTab5,WriteTab5
- dc.l ReadTab6,WriteTab6
- dc.l ReadTab7,WriteTab7
-
-
- *
- * Opcode Dispatch Table
- * "*" bezeichnet einen undokumentierten Opcode
- *
-
- CNOP 0,4
- OpcodeTable
- CyclesLeft dc.w 0 ;Anzahl zur Verfügung stehender CPU-Zyklen
- ; bis zum nächsten Periodic
- dc.w 0
- dc.l BRK ;$00
- dc.l ORAIndX
- dc.l IllegalOp
- dc.l SLOIndX ;*
- dc.l NOPZero ;*
- dc.l ORAZero
- dc.l ASLZero
- dc.l SLOZero ;*
-
- dc.l PHP ;$08
- dc.l ORAImm
- dc.l ASLA
- dc.l ANCImm ;*
- dc.l NOPAbs ;*
- dc.l ORAAbs
- dc.l ASLAbs
- dc.l SLOAbs ;*
-
- dc.l BPLRel ;$10
- dc.l ORAIndY
- dc.l IllegalOp
- dc.l SLOIndY ;*
- dc.l NOPZeroX ;*
- dc.l ORAZeroX
- dc.l ASLZeroX
- dc.l SLOZeroX ;*
-
- dc.l CLC ;$18
- dc.l ORAAbsY
- dc.l NOPImpl ;*
- dc.l SLOAbsY ;*
- dc.l NOPAbsX ;*
- dc.l ORAAbsX
- dc.l ASLAbsX
- dc.l SLOAbsX
-
- dc.l JSRAbs ;$20
- dc.l ANDIndX
- dc.l IllegalOp
- dc.l RLAIndX ;*
- dc.l BITZero
- dc.l ANDZero
- dc.l ROLZero
- dc.l RLAZero ;*
-
- dc.l PLP ;$28
- dc.l ANDImm
- dc.l ROLA
- dc.l ANCImm ;*
- dc.l BITAbs
- dc.l ANDAbs
- dc.l ROLAbs
- dc.l RLAAbs ;*
-
- dc.l BMIRel ;$30
- dc.l ANDIndY
- dc.l IllegalOp
- dc.l RLAIndY ;*
- dc.l NOPZeroX ;*
- dc.l ANDZeroX
- dc.l ROLZeroX
- dc.l RLAZeroX ;*
-
- dc.l SEC ;$38
- dc.l ANDAbsY
- dc.l NOPImpl ;*
- dc.l RLAAbsY ;*
- dc.l NOPAbsX ;*
- dc.l ANDAbsX
- dc.l ROLAbsX
- dc.l RLAAbsX ;*
-
- dc.l RTIImpl ;$40
- dc.l EORIndX
- dc.l IllegalOp
- dc.l SREIndX ;*
- dc.l NOPZero ;*
- dc.l EORZero
- dc.l LSRZero
- dc.l SREZero ;*
-
- dc.l PHA ;$48
- dc.l EORImm
- dc.l LSRA
- dc.l ASRImm ;*
- dc.l JMPAbs
- dc.l EORAbs
- dc.l LSRAbs
- dc.l SREAbs ;*
-
- dc.l BVCRel ;$50
- dc.l EORIndY
- dc.l IllegalOp
- dc.l SREIndY ;*
- dc.l NOPZeroX ;*
- dc.l EORZeroX
- dc.l LSRZeroX
- dc.l SREZeroX ;*
-
- dc.l CLI ;$58
- dc.l EORAbsY
- dc.l NOPImpl ;*
- dc.l SREAbsY ;*
- dc.l NOPAbsX ;*
- dc.l EORAbsX
- dc.l LSRAbsX
- dc.l SREAbsX ;*
-
- dc.l RTSImpl ;$60
- dc.l ADCIndX
- dc.l IllegalOp
- dc.l RRAIndX ;*
- dc.l NOPZero ;*
- dc.l ADCZero
- dc.l RORZero
- dc.l RRAZero ;*
-
- dc.l PLA ;$68
- dc.l ADCImm
- dc.l RORA
- dc.l ARRImm ;*
- dc.l JMPInd
- dc.l ADCAbs
- dc.l RORAbs
- dc.l RRAAbs ;*
-
- dc.l BVSRel ;$70
- dc.l ADCIndY
- dc.l IllegalOp
- dc.l RRAIndY ;*
- dc.l NOPZeroX ;*
- dc.l ADCZeroX
- dc.l RORZeroX
- dc.l RRAZeroX ;*
-
- dc.l SEI ;$78
- dc.l ADCAbsY
- dc.l NOPImpl ;*
- dc.l RRAAbsY ;*
- dc.l NOPAbsX ;*
- dc.l ADCAbsX
- dc.l RORAbsX
- dc.l RRAAbsX ;*
-
- dc.l NOPZero ;* $80
- dc.l STAIndX
- dc.l NOPZero ;*
- dc.l SAXIndX ;*
- dc.l STYZero
- dc.l STAZero
- dc.l STXZero
- dc.l SAXZero ;*
-
- dc.l DEY ;$88
- dc.l NOPZero ;*
- dc.l TXA
- dc.l ANEImm ;*
- dc.l STYAbs
- dc.l STAAbs
- dc.l STXAbs
- dc.l SAXAbs ;*
-
- dc.l BCCRel ;$90
- dc.l STAIndY
- dc.l IllegalOp
- dc.l SHAIndY ;*
- dc.l STYZeroX
- dc.l STAZeroX
- dc.l STXZeroY
- dc.l SAXZeroY ;*
-
- dc.l TYA ;$98
- dc.l STAAbsY
- dc.l TXS
- dc.l SHSAbsY ;*
- dc.l SHYAbsX ;*
- dc.l STAAbsX
- dc.l SHXAbsY ;*
- dc.l SHAAbsY ;*
-
- dc.l LDYImm ;$a0
- dc.l LDAIndX
- dc.l LDXImm
- dc.l LAXIndX ;*
- dc.l LDYZero
- dc.l LDAZero
- dc.l LDXZero
- dc.l LAXZero ;*
-
- dc.l TAY ;$a8
- dc.l LDAImm
- dc.l TAX
- dc.l LXAImm ;*
- dc.l LDYAbs
- dc.l LDAAbs
- dc.l LDXAbs
- dc.l LAXAbs ;*
-
- dc.l BCSRel ;$b0
- dc.l LDAIndY
- dc.l IllegalOp
- dc.l LAXIndY ;*
- dc.l LDYZeroX
- dc.l LDAZeroX
- dc.l LDXZeroY
- dc.l LAXZeroY ;*
-
- dc.l CLV ;$b8
- dc.l LDAAbsY
- dc.l TSX
- dc.l LASAbsY ;*
- dc.l LDYAbsX
- dc.l LDAAbsX
- dc.l LDXAbsY
- dc.l LAXAbsY ;*
-
- dc.l CPYImm ;$c0
- dc.l CMPIndX
- dc.l NOPZero ;*
- dc.l DCPIndX ;*
- dc.l CPYZero
- dc.l CMPZero
- dc.l DECZero
- dc.l DCPZero ;*
-
- dc.l INY ;$c8
- dc.l CMPImm
- dc.l DEX
- dc.l SBXImm ;*
- dc.l CPYAbs
- dc.l CMPAbs
- dc.l DECAbs
- dc.l DCPAbs ;*
-
- dc.l BNERel ;$d0
- dc.l CMPIndY
- dc.l OpWrap
- dc.l DCPIndY ;*
- dc.l NOPZeroX ;*
- dc.l CMPZeroX
- dc.l DECZeroX
- dc.l DCPZeroX ;*
-
- dc.l CLD ;$d8
- dc.l CMPAbsY
- dc.l NOPImpl ;*
- dc.l DCPAbsY ;*
- dc.l NOPAbsX ;*
- dc.l CMPAbsX
- dc.l DECAbsX
- dc.l DCPAbsX ;*
-
- dc.l CPXImm ;$e0
- dc.l SBCIndX
- dc.l NOPZero ;*
- dc.l ISBIndX ;*
- dc.l CPXZero
- dc.l SBCZero
- dc.l INCZero
- dc.l ISBZero ;*
-
- dc.l INX ;$e8
- dc.l SBCImm
- dc.l NOPImpl
- dc.l SBCImm ;*
- dc.l CPXAbs
- dc.l SBCAbs
- dc.l INCAbs
- dc.l ISBAbs ;*
-
- dc.l BEQRel ;$f0
- dc.l SBCIndY
- dc.l OpIEC ;Patch
- dc.l ISBIndY ;*
- dc.l NOPZeroX ;*
- dc.l SBCZeroX
- dc.l INCZeroX
- dc.l ISBZeroX ;*
-
- dc.l SED ;$f8
- dc.l SBCAbsY
- dc.l NOPImpl ;*
- dc.l ISBAbsY ;*
- dc.l NOPAbsX ;*
- dc.l SBCAbsX
- dc.l INCAbsX
- dc.l ISBAbsX ;*
-
-
- **
- ** Datenbereich
- **
-
- ; 6510-Task
- CPUProc dc.l 0 ;Prozess-Handle
- CPUTask dc.l 0 ;Task des Prozesses
- ReadySet dc.l 0 ;Signal des Hauptprogramms
- ContinueSet dc.l 0 ;Signal des CPU-Tasks
- ReadySig dc.b 0
- ContinueSig dc.b 0
-
- ; Emulator-Kennung
- DFFFByte dc.b $55 ;Wechselt bei jedem Lesen zwischen $55 und $aa
-
- ; Interrupt-Flags. Bei einem Interrupt wird eins dieser Flags gesetzt.
- ; Das bewirkt, daß nach dem nächsten Periodic der 6510-Task in die
- ; Routine "HandleInt" springt. Dort werden diese Flags ausgewertet und
- ; entsprechend verzweigt.
- CNOP 0,4
- Interrupt ;Zusammenfassung als Langwort
- IntIsRESET dc.b 0 ;RESET aufgetreten, 6510 beenden oder Pause
- IntIsNMI dc.b 0 ;NMI aufgetreten
- IntIsIRQ ;Zusammenfassung als Wort
- IntIsVICIRQ dc.b 0 ;IRQ durch VIC aufgetreten
- IntIsCIAIRQ dc.b 0 ;IRQ durch CIA-A aufgetreten
-
- RESETIsEXIT dc.b 0 ;Zur Unterscheidung von RESET und EXIT
- RESETIsPause dc.b 0 ;Zur Unterscheidung von RESET und Pause
-
- CNOP 0,4
- RegStore ds.l 6
-
- ; Speicherzeiger (außer bei TheChar stimmt bei allen das untere Wort
- ; mit der tatsächlichen C64-Adresse überein, also
- ; TheRAM : xxxx0000
- ; TheBasic : xxxxa000
- ; TheKernal: xxxxe000
- ; TheColor : xxxxd800
- CNOP 0,4
- TheRAM dc.l 0 ;Zeiger auf C64-RAM (64K)
- TheBasic dc.l 0 ;Zeiger auf Basic-ROM
- TheKernal dc.l 0 ;Zeiger auf Kernal-ROM
- TheChar dc.l 0 ;Zeiger auf Char-ROM
- TheColor dc.l 0 ;Zeiger auf Farb-RAM
-
- ; Taglist für CreateNewProc
- ProcTags dc.l NP_Entry,CPUTaskProc
- dc.l NP_Name,CPUTaskName
- dc.l NP_Priority,-1
- dc.l 0,0
-
- ; Requester
- IllegalOpReq dc.l 20,0,0,0,0
- JumpToIOReq dc.l 20,0,0,0,0
-
- RequestStream ds.l 16 ;Argumente
-
- SECTION "BSS",BSS
-
- ; Sprungtabellen für Speicherzugriff: Ein Eintrag pro Seite
- ; Eine Tabelle für jede der 8 Speicherkonfigurationen
- ReadTab0 ds.l 256
- ReadTab1 ds.l 256
- ReadTab2 ds.l 256
- ReadTab3 ds.l 256
- ReadTab4 ds.l 256
- ReadTab5 ds.l 256
- ReadTab6 ds.l 256
- ReadTab7 ds.l 256
-
- WriteTab0 ds.l 256
- WriteTab1 ds.l 256
- WriteTab2 ds.l 256
- WriteTab3 ds.l 256
- WriteTab4 ds.l 256
- WriteTab5 ds.l 256
- WriteTab6 ds.l 256
- WriteTab7 ds.l 256
-
- JumpTab0 ds.l 256
- JumpTab1 ds.l 256
- JumpTab2 ds.l 256
- JumpTab3 ds.l 256
- JumpTab4 ds.l 256
- JumpTab5 ds.l 256
- JumpTab6 ds.l 256
- JumpTab7 ds.l 256
-
- END
-