*
* 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).
*  - Durch diese Art der PC-Verwaltung bestehen folgende Inkompatibilitäten:
*     - Es gibt keinen Wraparound über Adresse $ffff/$0000 hinweg
*     - 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	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	DontPause
		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
		JSRLIB	FreeSignal
		rts


**
** 6510-Task anhalten
**

Pause6510	move.l	_SysBase,a6
		JSRLIB	Forbid

2$		tst.w	DontPause(pc)	;Pause erlaubt?
		beq	1$
		move.l	_DOSBase,a6	;Nein, kurz warten und dann
		moveq	#1,d1		;nochmal probieren
		JSRLIB	Delay
		bra	2$

1$		move.l	_SysBase,a6	;OK, Task entfernen
		move.l	CPUTask,a1
		JSRLIB	Remove
		JSRLIB	Permit
		rts


**
** 6510-Task fortsetzen
**

Resume6510	move.l	_SysBase,a6
		JSRLIB	Forbid
		lea	TaskReady(a6),a0
		move.l	CPUTask,a1	;Task wieder einhängen
		JSRLIB	Enqueue
		JSRLIB	Permit
		rts


**
** 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

; 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.w	DontPause
		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	move.w	#-1,DontPause		;Nicht hier anhalten
		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
		clr.w	DontPause		;Darf wieder angehalten werden

		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),d0
		and.b	#$0f,d0
		move.b	$dff007,d1	;Oberes Nibble ist Zufallswert
		lsl.b	#4,d1		;Ist so zufälliger
		and.b	#$f0,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$
		move.b	$dff007,d0	;Zufallswert
		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	move.w	#-1,DontPause		;Nicht hier anhalten
		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
		clr.w	DontPause		;Darf wieder angehalten werden

		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(pc)	;Beenden?
		bne	HandleEXIT

		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
		JSRLIB	Forbid
		move.l	MainTask,a1
		move.l	ReadySet,d0
		JSRLIB	Signal
		moveq	#0,d0
		rts

*
* 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
		add.w	d0,RPC		;!! Kein Wraparound
		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
		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

*
* Patches
*

OpIEC		move.w	#-1,DontPause	;Nicht hier anhalten
		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
		clr.w	DontPause
		Next	0

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
		clr.w	DontPause
		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
		clr.w	DontPause
		bra	RTSImpl		;RTS ausführen


**
** Konstanten
**

; Strings
CPUTaskName	dc.b	"6510",0
TimerIntName	dc.b	"Frodo Timer Int",0

IDString	dc.b	"FRODO V1.3",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	IllegalOp
		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
ReadySig	dc.w	0
DontPause	dc.w	0	;#0: Task darf nicht angehalten werden

; 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 oder 6510 beenden
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	;Zu Unterscheidung von RESET und EXIT

		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
