*
* 6569.asm - VIC-Emulation
*
* Copyright (C) 1994-1996 by Christian Bauer
*

*
* Anmerkungen:
* ------------
*
* Funktionsweise/Periodic:
*  - Die VIC-Emulation arbeitet zeilenweise. Pro (simulierter)
*    C64-Rasterzeile wird vom 6510-Task die Routine Periodic6569
*    aufgerufen, die eine Pixelzeile der Grafik anhand der aktuellen
*    Einstellungen in den VIC-Registern aufbaut. Dadurch können
*    Rastereffekte sehr gut emuliert werden.
*  - Die Emulation schreibt die Grafikdaten für eine Rasterzeile in einen
*    8-Bit-Chunky-Puffer, der in jeder Rasterzeile in die Anzeige kopiert
*    wird. Bei 4 Bit werden die Daten für ein ganzes Bild in den Puffer
*    kopiert, der dann im VIC-VBlank konvertiert wird.
*  - Die Auswahl der 5 verschiedenen Darstellungsmodi (plus 3 ungültige,
*    die einen schwarzen Bildschirm erzeugen) geschieht über den
*    Zeiger DisplayProc, der auf die entsprechende Routine (z.B. TextStd,
*    BitMapMulti etc.) zeigt und der bei einem Schreibzugriff auf eines
*    der beiden Kontrollregister CTRL1/CTRL2 neu gesetzt wird
*
* 6510-Zyklenzähler
*  - In jeder Rasterzeile wird der Zyklenzähler für die CPU neu gesetzt,
*    und zwar unterschiedlich je nachdem, ob eine Bad Line stattfand
*    oder nicht
*  - Für jedes dargestellte Sprite werden nochmal je 2 Zyklen abgezogen
*
* Bad Lines:
*  - Eine Bad Line ist dann, wenn $30 <= RASTER <= $f7 und
*    die unteren drei Bits von RASTER mit den unteren drei Bits von
*    Reg. $11 (Y-Scroll) übereinstimmen
*  - In einer Bad Line werden 40 Bytes aus Videomatrix und Farb-RAM geholt
*
* Rasterzähler RC/Grafikdarstellung:
*  - Der RC wird in jeder Bad Line auf Null gesetzt, gleichzeitig wird
*    die Darstellung der Grafik angeschaltet (DISPLAYOFF wird gelöscht)
*  - Am Ende einer Rasterzeile wird der RC um 1 erhöht, es sei denn,
*    er steht auf 7. In diesem Fall wird die Darstellung ausgeschaltet.
*  - Ist DISPLAYOFF gesetzt, wird in der Textspalte $3fff dargestellt,
*    ansonsten Text oder Bitmapgrafik
*  - Deshalb wird im oberen/unteren Rahmen immer $3fff dargestellt, weil
*    es dort keine Bad Lines gibt und der RC nie zurückgesetzt wird
*
* Videomatrixzähler VC:
*  - Es gibt zwei Register, VCBASE und VCCOUNT. Zum Zugriff auf die
*    Grafikdaten wird VCCOUNT benutzt.
*  - Beim VBlank wird VCBASE auf Null gesetzt
*  - Zu Beginn jeder Zeile wird VCCOUNT mit dem Wert aus VCBASE geladen
*  - Wenn DISPLAYOFF gelöscht ist und Grafik dargestellt wird, wird
*    VCCOUNT um 40 erhöht (symbolisch für die 40 Zugriffe des VIC)
*  - Wenn die Darstellung abgeschaltet wird, weil RC=7 ist (am Ende
*    einer Zeile) wird VCBASE mit dem Wert aus VCCOUNT geladen
*
* Spritedatenzähler MCx/Spritedarstellung:
*  - Da die Spritedaten beim VIC am Ende einer Rasterzeile geholt werden
*    und daher die Y-Positionen der Sprites eins niedriger als die
*    Rasterzeilennummern sind, werden die Spritedatenzähler in der
*    Emulation am Ende einer Rasterzeile gehandhabt (nachdem die Sprites
*    gezeichnet wurden)
*  - Wenn ein Sprite eingeschaltet ist und die Y-Koordinate gleich den
*    unteren 8 Bit von RASTER ist, wird der Datenzähler auf Null gesetzt
*    und die Darstellung des Sprite eingeschaltet (Bit in SPRITEON).
*    Jede folgende Rasterzeile wird der Zähler um 3 erhöht, solange er
*    kleiner als 60 ist. Erreicht er 60, wird die Darstellung des Sprite
*    ausgeschaltet. Wenn das Sprite Y-expandiert ist, wird der Zähler nur
*    in den Zeilen erhöht, in denen die unteren Bits von Y-Koordinate und
*    Zeilennummer gleich sind.
*  - Der Puffer GfxCollBuf wird beim Malen der Grafikdaten mit Flags
*    gefüllt, ob das zugehörige Pixel ein Vorder- oder Hintergrundpixel
*    ist. Dieser Puffer wird für die Sprite-Grafik-Kollisionserkennung
*    und für das Zeichnen von Hintergrundsprites benutzt.
*
* X-Scroll>0 und 40 Spalten:
*  - Wenn der X-Scroll>0 und die 40-Spalten-Darstellung eingeschaltet
*    ist, hängt das, was am linken Bildrand dargestellt wird, vom
*    aktuellen Grafikmodus ab
*  - Im Standard-Text-, Multicolor-Text- und Multicolor-Bitmap-Modus wird
*    dort die Hintergrundfarbe aus Reg.$21 dargestellt
*  - Im Standard-Bitmap- und ECM-Text-Modus wird die Hintergrundfarbe
*    der letzten 8 Pixel der vorherigen Zeile dargestellt
*
* Inkompatibilitäten:
*  - Effekte, die durch die Änderung von VIC-Registern innerhalb einer
*    Rasterzeile erreicht werden, können nicht emuliert werden
*  - Sprite-Kollisionen werden nur innerhalb des sichtbaren Bereiches
*    erkannt, Kollisionen mit $3fff werden gar nicht erkannt
*  - X-expandierte Sprites mit X-Koordinaten >=$140 werden nicht angezeigt.
*    Genaugenommen sollte ein Sprite nur dann unsichtbar sein, wenn die
*    X-Koordinate zwischen $1f8 und $1ff liegt.
*  - In den Bitmap-Darstellungen ab den Adressen $0000 und $8000 sollte
*    eigentlich ab $1000/$9000 das Char-ROM sichtbar sein. Aus
*    Geschwindigkeitsgründen wird in der Emulation das RAM darunter
*    dargestellt. Dies sollte keine Rolle spielen, da diese Bitmap-Seiten
*    aus dem genannten Grund von keinem Programm komplett verwendet werden.
*  - Der IRQ wird bei jedem Schreibzugriff in das Flag-Register gelöscht.
*    Das ist ein Hack für die RMW-Befehle des 6510, die zuerst den
*    Originalwert schreiben.
*  - Kein Lightpen-Interrupt
*

SPR_DATA_COLL	SET 1	;0 - Keine Sprite-Hintergrund-Prioritäten/-Kollisionen

		MACHINE	68020

		INCLUDE	"exec/types.i"
		INCLUDE	"exec/macros.i"
		INCLUDE	"exec/nodes.i"
		INCLUDE	"graphics/rastport.i"
		INCLUDE	"libraries/cybergraphics.i"

		XREF	_SysBase	;Main.asm
		XREF	_GfxBase
		XREF	_CyberGfxBase

		XREF	TheRAM		;6510.asm
		XREF	TheChar
		XREF	TheColor
		XREF	IntIsVICIRQ
		XREF	CyclesLeft

		XREF	CountTODs	;6526.asm
		XREF	Periodic6526

		XREF	_OpenDisplay	;Display.c
		XREF	_RedrawDisplay
		XREF	_the_rast_port
		XREF	_temp_rp

		XDEF	Init6569
		XDEF	_GetVICDump
		XDEF	OpenGraphics
		XDEF	ChangedVA
		XDEF	ReadFrom6569
		XDEF	WriteTo6569
		XDEF	Periodic6569

		XDEF	DisplayID	;Prefs
		XDEF	ScreenType
		XDEF	NormalCycles
		XDEF	BadLineCycles
		XDEF	SpritesOn
		XDEF	Collisions
		XDEF	Overscan
		XDEF	SkipLatch
		XDEF	LimitSpeed
		XDEF	DirectVideo

		SECTION	"text",CODE


**
** Definitionen
**

; VIC-Register
M0Y		= $01	;Y-Position von Sprite 0
M1Y		= $03	;Y-Position von Sprite 1
M2Y		= $05	;Y-Position von Sprite 2
M3Y		= $07	;Y-Position von Sprite 3
M4Y		= $09	;Y-Position von Sprite 4
M5Y		= $0b	;Y-Position von Sprite 5
M6Y		= $0d	;Y-Position von Sprite 6
M7Y		= $0f	;Y-Position von Sprite 7
MX8		= $10	;Höchste Bits der Sprite X-Positionen
CTRL1		= $11	;Steuerreg. 1
RASTER		= $12	;Rasterzähler
LPX		= $13	;Lightpen X
LPY		= $14	;Lightpen Y
SPREN		= $15	;Sprite eingeschaltet
CTRL2		= $16	;Steuerreg. 2
MYE		= $17	;Sprite Y-Expansion
VBASE		= $18	;Basisadressen
IRQFLAG		= $19	;Interruptreg.
IRQMASK		= $1a
MDP		= $1b	;Sprite Priorität
MMC		= $1c	;Sprite Multicolor
MXE		= $1d	;Sprite X-Expansion
CLXSPR		= $1e	;Kollisionsreg.
CLXBGR		= $1f
EC		= $20	;Rahmenfarbe
B0C		= $21	;Hintergrundfarbe

; Zusätzliche Register
DISPLAYOFF	= $2f	;Flag: $3fff wird dargestellt
IRQRASTER	= $30	;Rasterzeile, bei der ein IRQ ausgelöst wird (Wort)
XSCROLL		= $32	;X-Scroll-Wert (Wort)
YSCROLL		= $34	;Y-Scroll-Wert (Wort)
DXSTART		= $36	;Aktuelle Werte des Randbereichs
DXSTOP		= $38
DYSTART		= $3a
DYSTOP		= $3c
RC		= $3e	;Rasterzähler RC
MATRIXBASE	= $40	;Videomatrix-Basis (Amiga-Adresse)
CHARBASE	= $44	;Zeichengenerator-Basis (Amiga-Adresse)
BITMAPBASE	= $48	;Bitmap-Basis (Amiga-Adresse)
CURRENTA5	= $4c	;Augenblicklicher Zeiger im ChunkyBuf
			;Speicher für a5 zwischen Aufrufen von Periodic6569
CURRENTRASTER	= $50	;Augenblickliche Rasterzeile
			;Speicher für d7 zwischen Aufrufen von Periodic6569
LASTBKGD	= $52	;Letzte dargestellte Hintergrundfarbe
SPRITEON	= $53	;Sprite wird dargestellt, pro Sprite ein Bit
BORDERON	= $54	;Flag: Oberer/unterer Rahmen wird dargestellt
IS38COL		= $55	;Flag: 38 Spalten
BADLINEENABLE	= $56	;Flag: Bad Lines sind zugelassen
			;In Zeile $30 wird Bit 4 in $D011 getestet und
			; dieses Flag entsprechend gesetzt
SKIPFRAME	= $57	;Flag: Dieses Frame überspringen, nichts zeichnen
BADLINE		= $58	;Flag: Bad-Line-Zustand
MC0		= $5a	;Spritedatenzähler 0
MC1		= $5c
MC2		= $5e
MC3		= $60
MC4		= $62
MC5		= $64
MC6		= $66
MC7		= $68	;Spritedatenzähler 7
VCBASE		= $6a	;VC-Zwischenspeicher
VCCOUNT		= $6c	;VC-Zähler
CIAVABASE	= $6e	;16-Bit Basisadresse durch Cia-VA14/15
BORDERLONG	= $70	;Vorberechnete Farbwerte
BACK0LONG	= $74
SPRX0		= $78	;16-Bit Sprite-X-Koordinaten
SPRX1		= $7a
SPRX2		= $7c
SPRX3		= $7e
SPRX4		= $80
SPRX5		= $82
SPRX6		= $84
SPRX7		= $86
SPR0BASE	= $88
SPR1BASE	= $8a
SPR2BASE	= $8c
SPR3BASE	= $8e
SPR4BASE	= $90
SPR5BASE	= $92
SPR6BASE	= $94
SPR7BASE	= $96
VICRegLength	= $98

; Anzahl Rasterzeilen
TotalRasters	= $138

; Textfenster-Koordinaten (Stop-Werte sind immer eins mehr)
Row25YStart	= $33
Row25YStop	= $fb
Row24YStart	= $37
Row24YStop	= $f7

Col40XStart	= $20
Col40XStop	= $160
Col38XStart	= $27
Col38XStop	= $157

; Erste und letzte mögliche Zeile für Bad Lines
FirstDMALine	= $30
LastDMALine	= $f7

; Erste und letzte dargestellte Zeile
FirstDispLine	= $10
LastDispLine	= $11f	;eigentlich $12b

; Größe der Anzeige
DisplayX	= $180	;Muß ein Vielfaches von 32 sein (wg. c2p4)!
DisplayY	= LastDispLine-FirstDispLine+1

; ScreenTypes
STYP_8BIT	= 0	;8-Bit-Screen, WritePixelLine8/
STYP_4BIT	= 1	;4-Bit-Screen, c2p4
STYP_1BIT	= 2	:1-Bit-Screen, Amiga Mono

; cybergraphics.library
CYBRMATTR_ISLINEARMEM = $80000009
GetCyberMapAttr	= -96
DoCDrawMethod	= -156


*
* Makros
*

; Sprite darstellen
DoSprite	MACRO	;Nummer
		btst	#\1,SPRITEON(a4) ;Wird das Sprite dargestellt?
		beq	\@1$

		move.l	MATRIXBASE(a4),a0
		moveq	#0,d0
		move.b	$03f8+\1(a0),d0	;Datenzeiger
		lsl.w	#6,d0		;*64
		add.w	MC\1(a4),d0	;MC dazunehmen
		bsr	GetPhysical
		move.l	(a0),d0		;d0: Spritedaten

		move.w	SPRX\1(a4),d1	;d1: X-Koordinate
		move.l	a5,a1
		add.w	d1,a1
		addq.l	#8,a1		;a1: Ziel im Bildschirmspeicher
		lea	SprCollBuf+8,a2
		add.w	d1,a2		;a2: Ziel im Kollisionspuffer
	IFNE	SPR_DATA_COLL
		lea	GfxCollBuf+8,a3
		add.w	d1,a3		;a3: Zeiger auf Grafik-Kollisionspuffer
	ENDC

		move.b	$27+\1(a4),d2	;d2: Spritefarbe

		move.b	#1<<\1,d7	;d7: Sprite-Bit
		move.l	Sprite\1Proc,a0
		jsr	(a0)
\@1$
		ENDM


**
** Emulation vorbereiten
**

*
* Register vorbereiten
*

Init6569	lea	Registers,a0
		move.w	#7,RC(a0)
		move.w	#-1,CURRENTRASTER(a0)
		move.l	TheRAM,MATRIXBASE(a0)
		move.l	TheRAM,CHARBASE(a0)
		move.l	TheRAM,BITMAPBASE(a0)
		clr.w	CIAVABASE(a0)
		move.w	#63,MC0(a0)
		move.w	#63,MC1(a0)
		move.w	#63,MC2(a0)
		move.w	#63,MC3(a0)
		move.w	#63,MC4(a0)
		move.w	#63,MC5(a0)
		move.w	#63,MC6(a0)
		move.w	#63,MC7(a0)

		bsr	SetDispProc
		bsr	SetSpriteProcs
		rts

*
* Screen und Fenster öffnen
* d0=0: Alles OK
* d0=1: Konnte Screen nicht öffnen
* d0=2: Kein Speicher
*

OpenGraphics	pea	DisplayY
		pea	DisplayX
		moveq	#0,d0
		move.w	Overscan,d0
		move.l	d0,-(sp)
		move.l	DisplayID,-(sp)
		move.w	ScreenType,d0
		move.l	d0,-(sp)
		jsr	_OpenDisplay
		lea	20(sp),sp
		tst.l	d0
		bne	1$

		move.l	_CURRENTA5,Registers+CURRENTA5

		move.l	_CyberGfxBase,d0
		beq	2$
		move.l	a6,-(sp)
		move.l	d0,a6

		move.l	_the_rast_port,a0	;Ist es eine CyberGfx-Bitmap?
		move.l	rp_BitMap(a0),a0
		move.l	#CYBRMATTR_ISCYBERGFX,d0
		jsr	GetCyberMapAttr(a6)
		tst.l	d0
		beq	3$

		move.l	_the_rast_port,a0	;Ja, Direkter Zugriff erlaubt?
		move.l	rp_BitMap(a0),a0
		move.l	#CYBRMATTR_ISLINEARMEM,d0
		jsr	GetCyberMapAttr(a6)
		tst.l	d0
		beq	3$
		sne	IsCyber			;Ja, DoCDrawMethod kann benutzt werden

		tst.w	DirectVideo		;Zugriff ohne DoCDrawMethod gewünscht?
		beq	3$

		move.l	_the_rast_port,a0	;Ja, XMod und Basisadresse bestimmen
		move.l	rp_BitMap(a0),a0
		move.l	#CYBRMATTR_XMOD,d0
		jsr	GetCyberMapAttr(a6)
		move.l	d0,CyberXMod

		move.l	_the_rast_port,a0
		move.l	rp_BitMap(a0),a0
		move.l	#CYBRMATTR_DISPADR,d0
		jsr	GetCyberMapAttr(a6)
		move.l	d0,CyberBase
		spl	IsCyberDirect
3$
		move.l	(sp)+,a6
2$
		moveq	#0,d0
1$		rts


**
** VIC-Status in Datenstruktur schreiben
**

_GetVICDump	lea	Registers,a0
		move.l	4(sp),a1

		move.b	SPRX0+1(a0),(a1)+
		move.b	M0Y(a0),(a1)+
		move.b	SPRX1+1(a0),(a1)+
		move.b	M1Y(a0),(a1)+
		move.b	SPRX2+1(a0),(a1)+
		move.b	M2Y(a0),(a1)+
		move.b	SPRX3+1(a0),(a1)+
		move.b	M3Y(a0),(a1)+
		move.b	SPRX4+1(a0),(a1)+
		move.b	M4Y(a0),(a1)+
		move.b	SPRX5+1(a0),(a1)+
		move.b	M5Y(a0),(a1)+
		move.b	SPRX6+1(a0),(a1)+
		move.b	M6Y(a0),(a1)+
		move.b	SPRX7+1(a0),(a1)+
		move.b	M7Y(a0),(a1)+
		move.b	MX8(a0),(a1)+

		move.b	CTRL1(a0),d0
		and.b	#$7f,d0
		move.b	CURRENTRASTER(a0),d1
		lsl.b	#7,d1
		or.b	d1,d0
		move.b	d0,(a1)+
		move.b	CURRENTRASTER+1(a0),(a1)+

		lea	LPX(a0),a0
		moveq	#27,d0		;LPX..M7C
1$		move.b	(a0)+,(a1)+
		dbra	d0,1$

		lea	Registers,a0
		addq.l	#1,a1
		move.w	IRQRASTER(a0),(a1)+
		move.w	VCCOUNT(a0),(a1)+
		move.w	VCBASE(a0),(a1)+
		move.b	RC+1(a0),(a1)+
		move.b	SPRITEON(a0),(a1)+

		move.b	MC0+1(a0),(a1)+
		move.b	MC1+1(a0),(a1)+
		move.b	MC2+1(a0),(a1)+
		move.b	MC3+1(a0),(a1)+
		move.b	MC4+1(a0),(a1)+
		move.b	MC5+1(a0),(a1)+
		move.b	MC6+1(a0),(a1)+
		move.b	MC7+1(a0),(a1)+

		tst.b	DISPLAYOFF(a0)
		sne.b	(a1)+
		sne.b	(a1)+
		tst.b	BADLINE(a0)
		sne.b	(a1)+
		sne.b	(a1)+
		tst.b	BADLINEENABLE(a0)
		sne.b	(a1)+
		sne.b	(a1)+
		move.w	CIAVABASE(a0),(a1)+
		move.w	MATRIXBASE+2(a0),(a1)+
		move.w	CHARBASE+2(a0),(a1)+
		move.w	BITMAPBASE+2(a0),(a1)+

		move.l	d2,-(sp)
		move.w	CIAVABASE(a0),d2
		move.l	MATRIXBASE(a0),a0
		moveq	#7,d1
		lea	$03f8(a0),a0
2$		moveq	#0,d0
		move.b	(a0)+,d0
		lsl.w	#6,d0
		or.w	d2,d0
		move.w	d0,(a1)+
		dbra	d1,2$
		move.l	(sp)+,d2
		rts


**
** CIA-VA14/15 hat sich geändert, Video-Bank wechseln
** d0.b: Neue VA ($00-$03)
**

ChangedVA	lea	Registers,a0	;Wichtig für WrVBASE
		clr.w	d1		;VABase speichern
		move.b	d0,d1
		ror.w	#2,d1
		move.w	d1,CIAVABASE(a0)

		move.b	VBASE(a0),d1 ;Zeiger neu berechnen
		bra	WrVBASE


**
** Aus einer VIC-16-Bit-Adresse die entsprechende Amiga-Adresse berechnen
** -> d0.w: 16-Bit-Adresse
** <- a0.l: 32-Bit-Adresse
**

GetPhysical	or.w	CIAVABASE(a4),d0 ;VA14/15 dazunehmen
		move.w	d0,d1
		and.w	#$7000,d1
		cmp.w	#$1000,d1
		beq	1$
		move.l	TheRAM,a0
		moveq	#0,d1
		move.w	d0,d1
		add.l	d1,a0
		rts
1$		and.w	#$0fff,d0	;$1000-$1fff, $9000-$9fff: Char-ROM
		move.l	TheChar,a0
		add.w	d0,a0
		rts


**
** Aus einem VIC-Register lesen
** d0.l: Registernummer ($00-$3f)
** Rückgabe: d0.b: Byte
**
** Darf das obere Wort von d0 und d1 nicht verändern!
**

ReadFrom6569	lea	Registers,a0
		move.l	ReadTab(pc,d0.l*4),a1
		jmp	(a1)

		CNOP	0,4
ReadTab		dc.l	RdSprX
		dc.l	RdNormal
		dc.l	RdSprX
		dc.l	RdNormal
		dc.l	RdSprX
		dc.l	RdNormal
		dc.l	RdSprX
		dc.l	RdNormal
		dc.l	RdSprX
		dc.l	RdNormal
		dc.l	RdSprX
		dc.l	RdNormal
		dc.l	RdSprX
		dc.l	RdNormal
		dc.l	RdSprX
		dc.l	RdNormal

		dc.l	RdNormal
		dc.l	RdCTRL1
		dc.l	RdRASTER
		dc.l	RdNormal
		dc.l	RdNormal
		dc.l	RdNormal
		dc.l	RdCTRL2
		dc.l	RdNormal
		dc.l	RdVBASE
		dc.l	RdIRQFLAG
		dc.l	RdIRQMASK
		dc.l	RdNormal
		dc.l	RdNormal
		dc.l	RdNormal
		dc.l	RdCLXSPR
		dc.l	RdCLXBGR

		dc.l	RdColor
		dc.l	RdColor
		dc.l	RdColor
		dc.l	RdColor
		dc.l	RdColor
		dc.l	RdColor
		dc.l	RdColor
		dc.l	RdColor
		dc.l	RdColor
		dc.l	RdColor
		dc.l	RdColor
		dc.l	RdColor
		dc.l	RdColor
		dc.l	RdColor
		dc.l	RdColor
		dc.l	RdUndef

		dc.l	RdUndef
		dc.l	RdUndef
		dc.l	RdUndef
		dc.l	RdUndef
		dc.l	RdUndef
		dc.l	RdUndef
		dc.l	RdUndef
		dc.l	RdUndef
		dc.l	RdUndef
		dc.l	RdUndef
		dc.l	RdUndef
		dc.l	RdUndef
		dc.l	RdUndef
		dc.l	RdUndef
		dc.l	RdUndef
		dc.l	RdUndef

RdNormal	move.b	(a0,d0.l),d0
		rts

RdSprX		move.b	SPRX0+1(a0,d0.l),d0	;LSB lesen
		rts

RdCTRL1		move.b	CTRL1(a0),d0
		and.b	#$7f,d0
		move.b	CURRENTRASTER(a0),d1	;MSB des Rasterzählers lesen
		lsl.b	#7,d1
		or.b	d1,d0			;und dazunehmen
		rts

RdRASTER	move.b	CURRENTRASTER+1(a0),d0	;Rasterzähler lesen
		rts

RdCTRL2		move.b	CTRL2(a0),d0
		or.b	#$c0,d0			;Unbenutzte Bits auf 1
		rts

RdVBASE		move.b	VBASE(a0),d0
		or.b	#$01,d0			;Unbenutzte Bits auf 1
		rts

RdIRQFLAG	move.b	IRQFLAG(a0),d0
		or.b	#$70,d0			;Unbenutzte Bits auf 1
		rts

RdIRQMASK	move.b	IRQMASK(a0),d0
		or.b	#$f0,d0			;Unbenutzte Bits auf 1
		rts

RdCLXSPR	lea	CLXSPR(a0),a0
		move.b	(a0),d0			;Lesen und löschen
		clr.b	(a0)
		rts

RdCLXBGR	lea	CLXBGR(a0),a0
		move.b	(a0),d0			;Lesen und löschen
		clr.b	(a0)
		rts

RdColor		move.b	(a0,d0.l),d0		;Bei den Farbregistern
		or.b	#$f0,d0			;das obere Nibble setzen
		rts

RdUndef		st.b	d0			;Nicht existierendes Register
		rts


**
** In ein VIC-Register schreiben
** d0.l: Registernummer ($00-$3f)
** d1.b: Byte
**
** Darf das obere Wort von d0 und d1 nicht verändern!
**

WriteTo6569	lea	Registers,a0
		move.l	WriteTab(pc,d0.l*4),a1
		jmp	(a1)

		CNOP	0,4
WriteTab	dc.l	WrSprX
		dc.l	WrNormal
		dc.l	WrSprX
		dc.l	WrNormal
		dc.l	WrSprX
		dc.l	WrNormal
		dc.l	WrSprX
		dc.l	WrNormal
		dc.l	WrSprX
		dc.l	WrNormal
		dc.l	WrSprX
		dc.l	WrNormal
		dc.l	WrSprX
		dc.l	WrNormal
		dc.l	WrSprX
		dc.l	WrNormal

		dc.l	WrSprXMSB
		dc.l	WrCTRL1
		dc.l	WrRASTER
		dc.l	WrNormal
		dc.l	WrNormal
		dc.l	WrNormal
		dc.l	WrCTRL2
		dc.l	WrNormal
		dc.l	WrVBASE
		dc.l	WrIRQFLAG
		dc.l	WrIRQMASK
		dc.l	WrMDP
		dc.l	WrMMC
		dc.l	WrMXE
		dc.l	WrUndef
		dc.l	WrUndef

		dc.l	WrBorder
		dc.l	WrBack0
		dc.l	WrNormal
		dc.l	WrNormal
		dc.l	WrNormal
		dc.l	WrNormal
		dc.l	WrNormal
		dc.l	WrNormal
		dc.l	WrNormal
		dc.l	WrNormal
		dc.l	WrNormal
		dc.l	WrNormal
		dc.l	WrNormal
		dc.l	WrNormal
		dc.l	WrNormal
		dc.l	WrUndef

		dc.l	WrUndef
		dc.l	WrUndef
		dc.l	WrUndef
		dc.l	WrUndef
		dc.l	WrUndef
		dc.l	WrUndef
		dc.l	WrUndef
		dc.l	WrUndef
		dc.l	WrUndef
		dc.l	WrUndef
		dc.l	WrUndef
		dc.l	WrUndef
		dc.l	WrUndef
		dc.l	WrUndef
		dc.l	WrUndef
		dc.l	WrUndef

WrNormal	move.b	d1,(a0,d0.l)
WrUndef		rts

WrSprX		move.b	d1,SPRX0+1(a0,d0.l)
		rts

WrSprXMSB	move.b	d1,MX8(a0)
		lea	SPRX7(a0),a0	;MSBs in 16-Bit-Werte umrechnen
		moveq	#7,d0
1$		add.b	d1,d1
		bcs	2$
		clr.b	(a0)
		bra	3$
2$		move.b	#1,(a0)
3$		subq.w	#2,a0
		dbra	d0,1$
		rts

WrCTRL1		move.b	d1,CTRL1(a0)

		move.b	d1,d0		;Y-Scroll
		and.w	#7,d0
		move.w	d0,YSCROLL(a0)

		move.b	d1,d0		;MSB der IRQ-Rasterzeile
		lsr.b	#7,d0
		move.b	d0,IRQRASTER(a0)

		btst	#3,d1		;24/25 Zeilen
		beq	1$
		move.w	#Row25YStart,DYSTART(a0)
		move.w	#Row25YStop,DYSTOP(a0)
		bra	SetDispProc
1$		move.w	#Row24YStart,DYSTART(a0)
		move.w	#Row24YStop,DYSTOP(a0)
		bra	SetDispProc

SetDispProc	moveq	#0,d0		;ECM, BMM und MCM holen
		move.b	CTRL1(a0),d0
		and.b	#$60,d0
		move.b	CTRL2(a0),d1
		and.b	#$10,d1
		or.b	d1,d0
		lsr.b	#2,d0		;Als Index in DispProcTab benutzen
		cmp.w	#STYP_1BIT,ScreenType
		beq	1$
		move.l	(DispProcTab,pc,d0.l),DisplayProc
		rts
1$		move.l	(MonoDispProcTab,pc,d0.l),DisplayProc
		rts

WrRASTER	move.b	d1,IRQRASTER+1(a0)
		rts

WrCTRL2		move.b	d1,CTRL2(a0)

		move.b	d1,d0		;X-Scroll
		and.w	#7,d0
		move.w	d0,XSCROLL(a0)

		btst	#3,d1		;38/40 Zeilen
		seq.b	IS38COL(a0)
		beq	1$
		move.w	#Col40XStart,DXSTART(a0)
		move.w	#Col40XStop,DXSTOP(a0)
		bra	SetDispProc
1$		move.w	#Col38XStart,DXSTART(a0)
		move.w	#Col38XStop,DXSTOP(a0)
		bra	SetDispProc

WrVBASE		move.l	a0,a1		;a1: Zeiger auf Register
		move.b	d1,VBASE(a1)

		move.l	a4,-(sp)
		move.l	a1,a4		;Für GetPhysical

		move.w	d1,-(sp)
		move.b	d1,d0		;Videomatrixbasis berechnen
		and.w	#$f0,d0
		lsl.w	#6,d0
		bsr	GetPhysical
		move.l	a0,MATRIXBASE(a1)
		move.w	(sp),d1		;Nur lesen, nicht entfernen

		move.b	d1,d0		;Zeichengeneratorbasis berechnen
		and.w	#$0e,d0
		ror.w	#6,d0
		bsr	GetPhysical
		move.l	a0,CHARBASE(a1)
		move.w	(sp)+,d1

		move.b	d1,d0
		and.w	#$08,d0
		ror.w	#6,d0
		bsr	GetPhysical
		move.l	a0,BITMAPBASE(a1)

		move.l	(sp)+,a4
		rts

WrIRQFLAG	not.b	d1		;Gesetztes Bit: Flag löschen
		and.b	#$0f,d1
		move.b	IRQFLAG(a0),d0
		and.b	d1,d0

		clr.b	IntIsVICIRQ	;IRQ zurücknehmen (Hack!)

		move.b	d0,d1		;Erlaubter IRQ noch gesetzt?
		and.b	IRQMASK(a0),d1
		beq	1$
		or.b	#$80,d0		;Ja, Master-Bit setzen
1$		move.b	d0,IRQFLAG(a0)
		rts

WrIRQMASK	and.b	#$0f,d1
		move.b	d1,IRQMASK(a0)

		and.b	IRQFLAG(a0),d1	;Gesetzter IRQ jetzt erlaubt?
		beq	1$
		or.b	#$80,IRQFLAG(a0) ;Ja, Master-Bit setzen
		st.b	IntIsVICIRQ	; und Interrupt auslösen
		rts
1$		clr.b	IntIsVICIRQ	;Nein, Interrupt zurücknehmen
		and.b	#$7f,IRQFLAG(a0) ; und Master-Bit löschen
		rts

WrMDP		move.b	d1,MDP(a0)
		bra	SetSpriteProcs

WrMMC		move.b	d1,MMC(a0)
		bra	SetSpriteProcs

WrMXE		move.b	d1,MXE(a0)		;Fällt durch!

SetSpriteProcs	moveq	#7,d1
		lea	Sprite7Proc,a1
1$		moveq	#0,d0
		btst	d1,MXE(a0)
		beq	2$
		or.b	#1,d0
2$		btst	d1,MMC(a0)
		beq	3$
		or.b	#2,d0
3$		btst	d1,MDP(a0)
		beq	4$
		or.b	#4,d0
4$		move.l	(SpriteProcTab,pc,d0.l*4),(a1)
		subq.w	#4,a1
		dbra	d1,1$
		rts

WrBorder	move.b	d1,EC(a0)
		move.b	d1,d0		;In ein Langwort konvertieren
		lsl.w	#8,d0
		move.b	d1,d0
		move.w	d0,d1
		swap	d0
		move.w	d1,d0
		move.l	d0,BORDERLONG(a0)
		moveq	#0,d0
		rts

WrBack0		move.b	d1,B0C(a0)
		move.b	d1,d0		;In ein Langwort konvertieren
		lsl.w	#8,d0
		move.b	d1,d0
		move.w	d0,d1
		swap	d0
		move.w	d1,d0
		move.l	d0,BACK0LONG(a0)
		moveq	#0,d0
		rts


**
** Eine Rasterzeile des VIC ausführen
**
** d7: Rasterzeilenzähler
** a4: Zeiger auf VIC-Register
** a5: Zeiger auf das Ziel im Bildschirmspeicher
**

; VBlank: Zähler zurücksetzen
VICVBlank	move.w	#-1,CURRENTRASTER(a4)
		clr.w	VCBASE(a4)

		bsr	CountTODs	;TODs zählen

		subq.w	#1,SkipCounter
		sne	SKIPFRAME(a4)
		bne	Periodic6569
		move.w	SkipLatch,SkipCounter

; Grafik darstellen
		jsr	_RedrawDisplay
		move.l	_CURRENTA5,CURRENTA5(a4)

; CyberDirect: Basisadresse des Bildschirmspeichers holen
		tst.b	IsCyberDirect
		beq	1$
		move.l	_CyberGfxBase,a6
		move.l	_the_rast_port,a0
		move.l	rp_BitMap(a0),a0
		move.l	#CYBRMATTR_DISPADR,d0
		jsr	GetCyberMapAttr(a6)
		move.l	d0,CyberBase
1$
		;fällt durch!

*
* Aktuelle Rasterzeile holen
*

Periodic6569	lea	Registers,a4
		move.w	CURRENTRASTER(a4),d7

*
* Rasterzähler erhöhen (muß hier geschehen, damit bei einem Raster-IRQ
*  der Wert des Rasterzählers mit der IRQ-Zeile übereinstimmt)
*

		addq.w	#1,d7
		move.w	d7,CURRENTRASTER(a4)
		cmp.w	#TotalRasters,d7	;Bildende erreicht?
		beq	VICVBlank

*
* Raster-IRQ auslösen, wenn Vergeichswert erreicht
*

		cmp.w	IRQRASTER(a4),d7	;IRQ-Zeile erreicht?
		bne	NoRasterIRQ
		bsr	DoRasterIRQ
NoRasterIRQ

*
* In Zeile $30 entscheidet das DEN-Bit, ob Bad Lines auftreten dürfen
*

		cmp.w	#$30,d7
		bne	1$
		btst	#4,CTRL1(a4)
		sne	BADLINEENABLE(a4)
1$

*
* Neue Anzahl CPU-Zyklen setzen
*

		move.w	NormalCycles,CyclesLeft

		tst.b	SKIPFRAME(a4)
		bne	VICSkip

*
* Innerhalb des sichtbaren Bereichs?
*

		cmp.w	#FirstDispLine,d7
		blo	VICNop
		cmp.w	#LastDispLine,d7
		bhi	VICNop

*
* Zeiger in Bildschirmspeicher nach a5 holen
*

		move.l	CURRENTA5(a4),a5

*
* VC-Zähler setzen
*

		move.w	VCBASE(a4),VCCOUNT(a4)
		clr.b	BADLINE(a4)

*
* Bei Amiga-Mono in Mono-VIC-Routine verzweigen
*

		cmp.w	#STYP_1BIT,ScreenType
		beq	AmigaMono6569

*
* "Bad Lines"-Videomatrixzugriff:
* 40 Bytes aus Videomatrix und Farb-RAM lesen und zwischenspeichern
*

		tst.b	BADLINEENABLE(a4) ;War das DEN-Bit in Rasterzeile $30 gesetzt?
		beq	NoBadLine

		cmp.w	#FirstDMALine,d7 ;Innerhalb des DMA-Bereiches?
		blo	NoBadLine
		cmp.w	#LastDMALine,d7
		bhi	NoBadLine

		move.b	d7,d0		;Ja, stimmen die unteren Bits
		and.b	#7,d0		;der Rasterzeile mit dem Y-Scroll
		cmp.b	YSCROLL+1(a4),d0 ;überein?
		bne	NoBadLine

IsBadLine	st.b	BADLINE(a4)	;Ja, Bad Line
		move.w	VCCOUNT(a4),d2	;d2: VC Videomatrix-Zähler

		move.l	MATRIXBASE(a4),a0 ;Videomatrixbasis holen
		add.w	d2,a0		;Videomatrixzähler dazunehmen

		move.l	TheColor,a2	;Zeiger auf Farb-RAM holen
		add.w	d2,a2		;Videomatrixzähler dazunehmen

		lea	MatrixLine,a1	;Videomatrix- und Farb-RAM-Zeile lesen
		lea	ColorLine,a3
		movem.l	(a0)+,d0-d6	;Je 40 Bytes kopieren
		movem.l	d0-d6,(a1)
		movem.l	(a2)+,d0-d6
		movem.l	d0-d6,(a3)
		movem.l	(a0)+,d0-d2
		movem.l	d0-d2,28(a1)
		movem.l	(a2)+,d0-d2
		movem.l	d0-d2,28(a3)

		clr.w	RC(a4)		;RC zurücksetzen
		clr.b	DISPLAYOFF(a4)	;Darstellung anschalten

		move.w	BadLineCycles,CyclesLeft ;Andere Anzahl Zyklen
NoBadLine

*
* Oberen und unteren Rahmen handhaben
*

		cmp.w	DYSTOP(a4),d7	;Unteres Ende des Fensters erreicht?
		bne	1$		; -> Rahmen einschalten
		st.b	BORDERON(a4)
		bra	TBBorderDraw

1$		btst	#4,CTRL1(a4)	;Rahmen nur abschalten, wenn DEN-Bit gesetzt
		beq	TBBorderDone
		cmp.w	DYSTART(a4),d7	;Oberes Ende des Fensters erreicht?
		bne	TBBorderDone	; -> Rahmen abschalten
		clr.b	BORDERON(a4)
		bra	TBNoBorder

TBBorderDone	tst.b	BORDERON(a4)	;Rahmen an?
		beq	TBNoBorder

TBBorderDraw	move.l	a5,a0		;Ja, Rahmen malen.
		move.l	BORDERLONG(a4),d0 ;d0.l: Rahmenfarbe
		moveq	#DisplayX/4-1,d1
1$		move.l	d0,(a0)+
		dbra	d1,1$
		bra	VICIncA5	;Sonst nix
TBNoBorder

*
* Inhalt des Fensters: Darstellung eingeschaltet?
*

		lea	Col40XStart(a5),a1
		add.w	XSCROLL(a4),a1	;a1: Ziel in Bildschirmspeicher
		lea	MatrixLine,a2	;a2: Zeichencodes
		lea	ColorLine,a3	;a3: Farbcodes
	IFNE	SPR_DATA_COLL
		lea	GfxCollBuf+Col40XStart,a6
		add.w	XSCROLL(a4),a6	;a6: Grafik-Kollisionspuffer
	ENDC

		tst.b	DISPLAYOFF(a4)	;$3FFF darstellen?
		bne	Show3FFF

		move.l	DisplayProc,a0	;Nein, Routine für entsp. Modus anspringen
		jmp	(a0)

*
* Standard-Text: Zeichendaten holen und darstellen
*

TextStd		add.w	#40,VCCOUNT(a4)	;VC erhöhen (wird nicht verwendet)

		move.l	CHARBASE(a4),a0	;a0: Zeichengeneratorbasis
		add.w	RC(a4),a0	;RC dazunehmen

		move.l	BACK0LONG(a4),d3 ;d3.l: Hintergrundfarbe

		move.l	d3,Col40XStart(a5) ;Hintergrund, wenn X-Scroll>0
		move.l	d3,Col40XStart+4(a5)

; Schleife für 40 Zeichen
		moveq	#39,d1		;d1: Zeichenzähler
		moveq	#0,d0
CharLoop	move.b	(a2)+,d0	;Zeichencode lesen
		move.b	(a0,d0.l*8),d0	;Zeichendaten lesen
		beq	OnlyBack
		move.b	(a3)+,d2	;d2: Zeichenfarbe

; 8 Pixel konvertieren
		add.b	d0,d0
		bcc	11$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	12$
11$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
12$		add.b	d0,d0
		bcc	21$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	22$
21$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
22$		add.b	d0,d0
		bcc	31$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	32$
31$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
32$		add.b	d0,d0
		bcc	41$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	42$
41$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
42$		add.b	d0,d0
		bcc	51$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	52$
51$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
52$		add.b	d0,d0
		bcc	61$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	62$
61$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
62$		add.b	d0,d0
		bcc	71$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	72$
71$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
72$		add.b	d0,d0
		bcc	81$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	82$
81$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
82$		dbra	d1,CharLoop
		bra	DoSprites

; Nur Hintergrund
		CNOP	0,4
OnlyBack	move.l	d3,(a1)+
		move.l	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.l	(a6)+
		clr.l	(a6)+
	ENDC
		addq.w	#1,a3		;Farb-RAM-Byte überspringen
		dbra	d1,CharLoop
		bra	DoSprites

*
* Multicolor-Text: Zeichendaten holen und darstellen
*

TextMulti	add.w	#40,VCCOUNT(a4)	;VC erhöhen (wird nicht verwendet)

		move.l	CHARBASE(a4),a0	;a0: Zeichengeneratorbasis
		add.w	RC(a4),a0	;RC dazunehmen

		move.l	BACK0LONG(a4),d3 ;d3.l: Farbe 0

		move.w	$22(a4),d4	;d4.w: Farbe 1
		move.b	$22(a4),d4

		move.w	$23(a4),d5	;d5.w: Farbe 2
		move.b	$23(a4),d5

		move.l	d3,Col40XStart(a5) ;Hintergrund, wenn X-Scroll>0
		move.l	d3,Col40XStart+4(a5)

; Schleife für 40 Zeichen
		moveq	#39,d1		;d1: Zeichenzähler
		moveq	#0,d0
CharMLoop	move.b	(a2)+,d0	;Zeichencode lesen
		move.b	(a0,d0.l*8),d0	;Zeichendaten lesen
		beq	MOnlyBack
		move.b	(a3)+,d2	;d2: Farbnibble
		bclr	#3,d2		;Standard oder Multi?
		beq	StdInMulti

; Multicolor: 4 Pixel konvertieren
		add.b	d0,d0
		bcc	11$
		add.b	d0,d0
		bcc	12$
		move.b	d2,(a1)+	;11
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
		st.b	(a6)+
	ENDC
		bra	14$
12$		move.w	d5,(a1)+	;10
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
		st.b	(a6)+
	ENDC
		bra	14$
11$
	IFNE	SPR_DATA_COLL
		clr.w	(a6)+
	ENDC
		add.b	d0,d0
		bcc	13$
		move.w	d4,(a1)+	;01
		bra	14$
13$		move.w	d3,(a1)+	;00
14$

		add.b	d0,d0
		bcc	21$
		add.b	d0,d0
		bcc	22$
		move.b	d2,(a1)+	;11
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
		st.b	(a6)+
	ENDC
		bra	24$
22$		move.w	d5,(a1)+	;10
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
		st.b	(a6)+
	ENDC
		bra	24$
21$
	IFNE	SPR_DATA_COLL
		clr.w	(a6)+
	ENDC
		add.b	d0,d0
		bcc	23$
		move.w	d4,(a1)+	;01
		bra	24$
23$		move.w	d3,(a1)+	;00
24$

		add.b	d0,d0
		bcc	31$
		add.b	d0,d0
		bcc	32$
		move.b	d2,(a1)+	;11
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
		st.b	(a6)+
	ENDC
		bra	34$
32$		move.w	d5,(a1)+	;10
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
		st.b	(a6)+
	ENDC
		bra	34$
31$
	IFNE	SPR_DATA_COLL
		clr.w	(a6)+
	ENDC
		add.b	d0,d0
		bcc	33$
		move.w	d4,(a1)+	;01
		bra	34$
33$		move.w	d3,(a1)+	;00
34$

		add.b	d0,d0
		bcc	41$
		add.b	d0,d0
		bcc	42$
		move.b	d2,(a1)+	;11
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
		st.b	(a6)+
	ENDC
		bra	44$
42$		move.w	d5,(a1)+	;10
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
		st.b	(a6)+
	ENDC
		bra	44$
41$
	IFNE	SPR_DATA_COLL
		clr.w	(a6)+
	ENDC
		add.b	d0,d0
		bcc	43$
		move.w	d4,(a1)+	;01
		bra	44$
43$		move.w	d3,(a1)+	;00
44$
		dbra	d1,CharMLoop
		bra	DoSprites

; Standard: 8 Pixel konvertieren
		CNOP	0,4
StdInMulti	add.b	d0,d0
		bcc	11$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	12$
11$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
12$		add.b	d0,d0
		bcc	21$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	22$
21$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
22$		add.b	d0,d0
		bcc	31$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	32$
31$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
32$		add.b	d0,d0
		bcc	41$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	42$
41$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
42$		add.b	d0,d0
		bcc	51$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	52$
51$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
52$		add.b	d0,d0
		bcc	61$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	62$
61$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
62$		add.b	d0,d0
		bcc	71$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	72$
71$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
72$		add.b	d0,d0
		bcc	81$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	82$
81$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
82$		dbra	d1,CharMLoop
		bra	DoSprites

; Nur Hintergrund
		CNOP	0,4
MOnlyBack	move.l	d3,(a1)+
		move.l	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.l	(a6)+
		clr.l	(a6)+
	ENDC
		addq.w	#1,a3		;Farb-RAM-Byte überspringen
		dbra	d1,CharMLoop
		bra	DoSprites

*
* Extended Color Mode: Grafikdaten holen und darstellen
*

TextECM		add.w	#40,VCCOUNT(a4)	;VC erhöhen (wird nicht verwendet)

		move.l	CHARBASE(a4),a0	;a0: Zeichengeneratorbasis
		add.w	RC(a4),a0	;RC dazunehmen

		move.b	$21(a4),d3	;d3: Hintergrund 0
		move.b	$22(a4),d4	;d4: Hintergrund 1
		move.b	$23(a4),d5	;d5: Hintergrund 2

		move.w	LASTBKGD(a4),d0	;Letzter Hintergrund, wenn X-Scroll>0
		move.b	LASTBKGD(a4),d0

		move.w	d0,Col40XStart(a5)
		move.w	d0,Col40XStart+2(a5)
		move.w	d0,Col40XStart+4(a5)
		move.w	d0,Col40XStart+6(a5)

; Schleife für 40 Zeichen
; d7: Aktuelle Hintergrundfarbe
		moveq	#39,d1		;d1: Zeichenzähler
		moveq	#0,d0
CharELoop	move.b	(a2)+,d0	;Zeichencode lesen
		move.b	(a3)+,d2	;d2: Farbnibble
		bclr	#7,d0
		bne	1$
		bclr	#6,d0
		bne	2$
		move.b	d3,d7		;00: Hintergrund 0
		bra	4$
2$		move.b	d4,d7		;01: Hintergrund 1
		bra	4$
1$		bclr	#6,d0
		bne	3$
		move.b	d5,d7		;10: Hintergrund 2
		bra	4$
3$		move.b	$24(a4),d7	;11: Hintergrund 3
4$		move.b	(a0,d0.l*8),d0	;Zeichendaten lesen
		beq	EOnlyBack

; 8 Pixel konvertieren
		add.b	d0,d0
		bcc	11$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	12$
11$		move.b	d7,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
12$		add.b	d0,d0
		bcc	21$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	22$
21$		move.b	d7,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
22$		add.b	d0,d0
		bcc	31$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	32$
31$		move.b	d7,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
32$		add.b	d0,d0
		bcc	41$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	42$
41$		move.b	d7,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
42$		add.b	d0,d0
		bcc	51$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	52$
51$		move.b	d7,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
52$		add.b	d0,d0
		bcc	61$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	62$
61$		move.b	d7,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
62$		add.b	d0,d0
		bcc	71$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	72$
71$		move.b	d7,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
72$		add.b	d0,d0
		bcc	81$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	82$
81$		move.b	d7,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
82$		dbra	d1,CharELoop

		move.b	d7,LASTBKGD(a4)	;Letzte Hintergrundfarbe merken
		move.w	CURRENTRASTER(a4),d7	;d7 wurde zerstört
		bra	DoSprites

; Nur Hintergrund
		CNOP	0,4
EOnlyBack	move.b	d7,(a1)+
		move.b	d7,(a1)+
		move.b	d7,(a1)+
		move.b	d7,(a1)+
		move.b	d7,(a1)+
		move.b	d7,(a1)+
		move.b	d7,(a1)+
		move.b	d7,(a1)+
	IFNE	SPR_DATA_COLL
		clr.l	(a6)+
		clr.l	(a6)+
	ENDC
		dbra	d1,CharELoop
		move.b	d7,LASTBKGD(a4)	;Letzte Hintergrundfarbe merken
		move.w	CURRENTRASTER(a4),d7	;d7 wurde zerstört
		bra	DoSprites

*
* Standard-BitMap: Grafikdaten holen und darstellen
*

BitMapStd	move.l	BITMAPBASE(a4),a0 ;a0: Bitmap-Basis
		move.w	VCCOUNT(a4),d0	;VC holen
		lsl.w	#3,d0		;*8
		add.w	RC(a4),d0	;RC dazunehmen
		add.w	d0,a0		;und zur Bitmap-Basis dazunehmen

		add.w	#40,VCCOUNT(a4)	;VC erhöhen

		move.w	LASTBKGD(a4),d0	;Letzter Hintergrund, wenn X-Scroll>0
		move.b	LASTBKGD(a4),d0

		move.w	d0,Col40XStart(a5)
		move.w	d0,Col40XStart+2(a5)
		move.w	d0,Col40XStart+4(a5)
		move.w	d0,Col40XStart+6(a5)

; Schleife für 40 Bytes
		moveq	#39,d1		;d1: Zeichenzähler
BitMapLoop	move.b	(a2)+,d2	;Farbe holen
		move.b	d2,d3		;d3: Hintergrundfarbe
		move.b	(a0),d0		;Byte holen
		beq	BOnlyBack
		lsr.b	#4,d2		;d2: Vordergrundfarbe

; 8 Pixel konvertieren
		add.b	d0,d0
		bcc	11$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	12$
11$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
12$		add.b	d0,d0
		bcc	21$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	22$
21$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
22$		add.b	d0,d0
		bcc	31$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	32$
31$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
32$		add.b	d0,d0
		bcc	41$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	42$
41$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
42$		add.b	d0,d0
		bcc	51$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	52$
51$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
52$		add.b	d0,d0
		bcc	61$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	62$
61$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
62$		add.b	d0,d0
		bcc	71$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	72$
71$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
72$		add.b	d0,d0
		bcc	81$
		move.b	d2,(a1)+
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
	ENDC
		bra	82$
81$		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.b	(a6)+
	ENDC
82$		addq.l	#8,a0		;Quellzeiger erhöhen
		dbra	d1,BitMapLoop

		move.b	d3,LASTBKGD(a4)	;Letzte Hintergrundfarbe merken
		bra	DoSprites

; Nur Hintergrund
		CNOP	0,4
BOnlyBack	move.b	d3,(a1)+
		move.b	d3,(a1)+
		move.b	d3,(a1)+
		move.b	d3,(a1)+
		move.b	d3,(a1)+
		move.b	d3,(a1)+
		move.b	d3,(a1)+
		move.b	d3,(a1)+
	IFNE	SPR_DATA_COLL
		clr.l	(a6)+
		clr.l	(a6)+
	ENDC
		addq.l	#8,a0		;Quellzeiger erhöhen
		dbra	d1,BitMapLoop
		move.b	d3,LASTBKGD(a4)	;Letzte Hintergrundfarbe merken
		bra	DoSprites

*
* Multicolor-Bitmap: Grafikdaten holen und darstellen
*

BitMapMulti	move.l	BITMAPBASE(a4),a0 ;a0: Bitmap-Basis
		move.w	VCCOUNT(a4),d0	;VC holen
		lsl.w	#3,d0		;*8
		add.w	RC(a4),d0	;RC dazunehmen
		add.w	d0,a0		;und zur Bitmap-Basis dazunehmen

		add.w	#40,VCCOUNT(a4)	;VC erhöhen

		move.l	BACK0LONG(a4),d5 ;d5.w: Farbe 0

		move.l	d5,Col40XStart(a5) ;Hintergrund, wenn X-Scroll>0
		move.l	d5,Col40XStart+4(a5)

; Schleife für 40 Bytes
		moveq	#39,d1
BitMapMLoop	move.b	(a2)+,d2	;Farbe 1/2 holen
		move.b	(a0),d0		;Byte holen
		beq	BMOnlyBack
		move.b	d2,d3		;d3.b: Farbe 2
		lsl.w	#8,d3
		move.b	d2,d3
		lsr.b	#4,d2		;d2.b: Farbe 1
		move.b	(a3),d4		;d4.b: Farbe 3
		lsl.w	#8,d4
		move.b	(a3)+,d4

; 4 Pixel konvertieren
		add.b	d0,d0
		bcc	11$
		add.b	d0,d0
		bcc	12$
		move.w	d4,(a1)+	;11
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
		st.b	(a6)+
	ENDC
		bra	14$
12$		move.w	d3,(a1)+	;10
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
		st.b	(a6)+
	ENDC
		bra	14$
11$	
	IFNE	SPR_DATA_COLL
		clr.w	(a6)+
	ENDC
		add.b	d0,d0
		bcc	13$
		move.b	d2,(a1)+	;01
		move.b	d2,(a1)+
		bra	14$
13$		move.w	d5,(a1)+	;00
14$

		add.b	d0,d0
		bcc	21$
		add.b	d0,d0
		bcc	22$
		move.w	d4,(a1)+	;11
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
		st.b	(a6)+
	ENDC
		bra	24$
22$		move.w	d3,(a1)+	;10
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
		st.b	(a6)+
	ENDC
		bra	24$
21$	
	IFNE	SPR_DATA_COLL
		clr.w	(a6)+
	ENDC
		add.b	d0,d0
		bcc	23$
		move.b	d2,(a1)+	;01
		move.b	d2,(a1)+
		bra	24$
23$		move.w	d5,(a1)+	;00
24$

		add.b	d0,d0
		bcc	31$
		add.b	d0,d0
		bcc	32$
		move.w	d4,(a1)+	;11
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
		st.b	(a6)+
	ENDC
		bra	34$
32$		move.w	d3,(a1)+	;10
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
		st.b	(a6)+
	ENDC
		bra	34$
31$	
	IFNE	SPR_DATA_COLL
		clr.w	(a6)+
	ENDC
		add.b	d0,d0
		bcc	33$
		move.b	d2,(a1)+	;01
		move.b	d2,(a1)+
		bra	34$
33$		move.w	d5,(a1)+	;00
34$

		add.b	d0,d0
		bcc	41$
		add.b	d0,d0
		bcc	42$
		move.w	d4,(a1)+	;11
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
		st.b	(a6)+
	ENDC
		bra	44$
42$		move.w	d3,(a1)+	;10
	IFNE	SPR_DATA_COLL
		st.b	(a6)+
		st.b	(a6)+
	ENDC
		bra	44$
41$	
	IFNE	SPR_DATA_COLL
		clr.w	(a6)+
	ENDC
		add.b	d0,d0
		bcc	43$
		move.b	d2,(a1)+	;01
		move.b	d2,(a1)+
		bra	44$
43$		move.w	d5,(a1)+	;00
44$
		addq.l	#8,a0		;Quellzeiger erhöhen
		dbra	d1,BitMapMLoop
		bra	DoSprites

; Nur Hintergrund
		CNOP	0,4
BMOnlyBack	move.l	d5,(a1)+
		move.l	d5,(a1)+
	IFNE	SPR_DATA_COLL
		clr.l	(a6)+
		clr.l	(a6)+
	ENDC
		addq.w	#1,a3		;Farb-RAM-Byte überspringen
		addq.l	#8,a0		;Quellzeiger erhöhen
		dbra	d1,BitMapMLoop
		bra	DoSprites

*
* Ungültiger Darstellungsmodus: Schwarzen Bildschirm anzeigen
*

BlackScreen	add.w	#40,VCCOUNT(a4)	;VC erhöhen

		moveq	#39,d0		;40 Zeichen schwarz
1$		clr.l	(a1)+
		clr.l	(a1)+
	IFNE	SPR_DATA_COLL
		clr.l	(a6)+
		clr.l	(a6)+
	ENDC
		dbra	d0,1$
		bra	DoSprites

*
* $3FFF darstellen
*

Show3FFF	move.l	BACK0LONG(a4),d3 ;d3.w: Hintergrundfarbe

		move.l	d3,Col40XStart(a5) ;Hintergrund, wenn X-Scroll>0
		move.l	d3,Col40XStart+4(a5)

		btst	#6,CTRL1(a4)
		bne	11$
		move.w	#$3fff,d0	;Byte bei $3FFF lesen
		bra	12$
11$		move.w	#$39ff,d0	;ECM: Byte bei $39FF lesen
12$		bsr	GetPhysical
		move.b	(a0),d0		;Byte lesen

; 4 Pixel nach d1 konvertieren, 0: Hintergrund, 1: schwarz
		moveq	#0,d1
		add.b	d0,d0
		bcs	1$
		move.b	d3,d1
1$		lsl.w	#8,d1
		add.b	d0,d0
		bcs	2$
		move.b	d3,d1
2$		lsl.l	#8,d1
		add.b	d0,d0
		bcs	3$
		move.b	d3,d1
3$		lsl.l	#8,d1
		add.b	d0,d0
		bcs	4$
		move.b	d3,d1
4$

; 4 Pixel nach d2 konvertieren
		moveq	#0,d2
		add.b	d0,d0
		bcs	5$
		move.b	d3,d2
5$		lsl.w	#8,d2
		add.b	d0,d0
		bcs	6$
		move.b	d3,d2
6$		lsl.l	#8,d2
		add.b	d0,d0
		bcs	7$
		move.b	d3,d2
7$		lsl.l	#8,d2
		add.b	d0,d0
		bcs	8$
		move.b	d3,d2
8$

; Zeile schreiben
		moveq	#39,d0		;d0: Bytezähler
Loop3FFF	move.l	d1,(a1)+
		move.l	d2,(a1)+
	IFNE	SPR_DATA_COLL
		clr.l	(a6)+		;Falsch!!
		clr.l	(a6)+
	ENDC
		dbra	d0,Loop3FFF

*
* Sprites malen?
*

DoSprites	tst.b	SPRITEON(a4)	;Ist überhaupt ein Sprite z.Z. sichtbar?
		beq	DrawLRBorder	;Nein, dann Rahmen
		tst.w	SpritesOn	;Sprite-Darstellung angeschaltet?
		beq	DrawLRBorder

*
* Mindestens ein Sprite ist sichtbar, Sprites malen
*

; Kollisions-Puffer löschen
		lea	SprCollBuf,a0
		moveq	#DisplayX/4-1,d0
1$		clr.l	(a0)+
		dbra	d0,1$

; Sprites malen
		moveq	#0,d4		;Sprite-Grafik Kollisionsflag
		moveq	#0,d5		;Sprite-Sprite Kollisionsflag
		DoSprite 0
		DoSprite 1
		DoSprite 2
		DoSprite 3
		DoSprite 4
		DoSprite 5
		DoSprite 6
		DoSprite 7
		move.w	CURRENTRASTER(a4),d7	;d7 wurde zerstört

; Kollisions-Flags auswerten
		tst.w	Collisions
		beq	DrawLRBorder

		move.b	CLXSPR(a4),d0
		or.b	d5,CLXSPR(a4)	;Bits im Kollisionsregister setzen
		tst.b	d0		;Haben bereits Kollisionen stattgefunden?
		bne	2$
		or.b	#$04,IRQFLAG(a4) ;Nein, IMMC-Bit setzen
		btst	#2,IRQMASK(a4)	;IRQ erlaubt?
		beq	2$
		or.b	#$80,IRQFLAG(a4) ;Ja, IRQ-Bit setzen
		st.b	IntIsVICIRQ	;Und Interrupt auslösen

2$		move.b	CLXBGR(a4),d0
		or.b	d4,CLXBGR(a4)
		tst.b	d0
		bne	DrawLRBorder
		or.b	#$02,IRQFLAG(a4)
		btst	#1,IRQMASK(a4)
		beq	DrawLRBorder
		or.b	#$80,IRQFLAG(a4)
		st.b	IntIsVICIRQ

*
* Linken und rechten Rahmen zeichnen
*

; 40-Spalten-Rahmen
DrawLRBorder	move.l	a5,a0
		move.l	BORDERLONG(a4),d0 ;d0.l: Rahmenfarbe

		move.l	d0,(a0)+	;Links: $00..$1f
		move.l	d0,(a0)+
		move.l	d0,(a0)+
		move.l	d0,(a0)+
		move.l	d0,(a0)+
		move.l	d0,(a0)+
		move.l	d0,(a0)+
		move.l	d0,(a0)+

		lea	Col40XStop-Col40XStart(a0),a0
		move.l	d0,(a0)+	;Rechts: $160..$17f
		move.l	d0,(a0)+
		move.l	d0,(a0)+
		move.l	d0,(a0)+
		move.l	d0,(a0)+
		move.l	d0,(a0)+
		move.l	d0,(a0)+
		move.l	d0,(a0)

; 38-Spalten-Rahmen
		tst.b	IS38COL(a4)
		beq	1$

		lea	Col40XStart(a5),a0
		move.l	d0,(a0)+	;Links: $20..$26
		move.w	d0,(a0)+
		move.b	d0,(a0)

		lea	Col38XStop(a5),a0
		move.b	d0,(a0)+	;Rechts: $157..$15e
		move.l	d0,(a0)+
		move.l	d0,(a0)+
1$		bra	VICIncA5

*
* Bild wird übersprungen, nur Bad-Line-Zyklen berechnen
*

VICSkip		cmp.w	#FirstDMALine,d7 ;Innerhalb des DMA-Bereiches?
		blo	VICNop
		cmp.w	#LastDMALine,d7
		bhi	VICNop

		move.b	d7,d0		;Ja, stimmen die unteren Bits
		and.b	#7,d0		;der Rasterzeile mit dem Y-Scroll
		cmp.b	YSCROLL+1(a4),d0 ;überein?
		bne	VICNop

		move.w	BadLineCycles,CyclesLeft
		bra	VICNop

*
* Bei 8 Bit eine Pixelzeile darstellen
* Zeiger in ChunkyBuf erhöhen
*

VICIncA5	cmp.w	#STYP_8BIT,ScreenType
		bne	VICIncA5Really

		tst.b	IsCyber
		beq	1$
		tst.b	IsCyberDirect
		beq	2$

		moveq	#DisplayX/4-1,d0	;CyberDirect
		lea	ChunkyBuf,a0
		move.l	CyberBase,a1
		move.l	a1,d1
3$		move.l	(a0)+,(a1)+
		dbra	d0,3$
		add.l	CyberXMod,d1
		move.l	d1,CyberBase
		bra	VICIncRC		

2$		move.l	_CyberGfxBase,a6	;Cyber
		lea	CyberHook,a0
		move.l	_the_rast_port,a1
		sub.l	a2,a2
		jsr	DoCDrawMethod(a6)
		bra	VICIncRC

1$		move.l	_GfxBase,a6		;Normal
		move.l	_the_rast_port,a0
		moveq	#0,d0
		move.w	CURRENTRASTER(a4),d1
		sub.w	#FirstDispLine,d1
		move.l	#DisplayX,d2
		lea	ChunkyBuf,a2
		lea	_temp_rp,a1
		JSRLIB	WritePixelLine8
		bra	VICIncRC

CyberHookProc	move.l	(a1),a0		;a0: Adresse des Bildschirmspeichers
		moveq	#0,d0
		move.w	20(a1),d0
		move.w	Registers+CURRENTRASTER,d1
		sub.w	#FirstDispLine,d1
		mulu.w	d1,d0
		add.l	d0,a0
		lea	ChunkyBuf,a1
		moveq	#DisplayX/4-1,d0
1$		move.l	(a1)+,(a0)+
		dbra	d0,1$
		rts

VICIncA5Really	add.l	#DisplayX,CURRENTA5(a4)

*
* RC erhöhen, Darstellung abschalten, wenn gleich 7
* (braucht nur im sichtbaren Bereich zu geschehen)
*

VICIncRC	cmp.w	#7,RC(a4)
		beq	1$
		addq.w	#1,RC(a4)
		bra	2$
1$		st.b	DISPLAYOFF(a4)
		move.w	VCCOUNT(a4),VCBASE(a4)
2$

*
* MCs erhöhen (muß in jeder Rasterzeile geschehen, damit die Sprites
*  auch im Overscan-Bereich korrekt dargestellt werden)
*

; Wenn alle Sprites aus sind, direkt zu CIA-Periodic springen
VICNop		lea	SPRITEON(a4),a3
		move.b	SPREN(a4),d0
		or.b	(a3),d0
		beq	Periodic6526

; MC für jedes Sprite zählen (7..0)
		moveq	#7,d6		;d6: Spritenummer
		lea	M7Y(a4),a1	;a1: Zeiger auf erste Y-Koordinate
		lea	MC7(a4),a2	;a2: Zeiger auf MC

MCLoop		move.b	(a1),d0		;Y-Koordinate
		btst	d6,SPREN(a4)	;Sprite angeschaltet?
		bne	1$
3$		cmp.w	#60,(a2)	;Nein, MC kleiner als 60?
		blo	2$
		bclr	d6,(a3)		;Nein, Sprite nicht mehr darstellen
		bra	5$

1$		cmp.b	d0,d7		;Sprite angeschaltet, Y-Koord. vergleichen
		bne	3$
		clr.w	(a2)		;Gleich, MC zurücksetzen
		bset	d6,(a3)		;Und Sprite ab jetzt darstellen
		bra	5$

2$		btst	d6,MYE(a4)	;MC kleiner als 60, Sprite Y-expandiert?
		beq	4$
		eor.b	d7,d0		;Ja, nur erhöhen, wenn Bit 0
		and.b	#$01,d0		; der Y-Koordinate gleich Bit 0
		bne	5$		; des Rasterzählers ist
4$		addq.w	#3,(a2)		;MC erhöhen
		subq.w	#2,CyclesLeft	;2 Zyklen vom 6510 abziehen

5$		subq.w	#2,a1		;Zeiger auf Y-Koordinate erhöhen
		subq.w	#2,a2		;Zeiger auf MC erhöhen
		dbra	d6,MCLoop

; Zu CIA-Periodic springen
		bra	Periodic6526


**
** Raster-IRQ auslösen
**

DoRasterIRQ	lea	Registers,a0
		or.b	#$01,IRQFLAG(a0)	;IRST-Bit setzen
		btst	#0,IRQMASK(a0)		;Raster-IRQ erlaubt?
		beq	1$
		or.b	#$80,IRQFLAG(a0)	;Ja, IRQ-Bit setzen
		st.b	IntIsVICIRQ		;Und Interrupt auslösen
1$		rts


**
** Ein Sprite zeichnen
** d0.l: Spritedaten
** d1.w: X-Koordinate
** d2.b: Spritefarbe
** d3  : (Temp.)
** d4.b: Kollisionsergebnis Sprite-Hintergrund
** d5.b: Kollisionsergebnis Sprite-Sprite
** d6  : (Pixelzähler)
** d7.b: Sprite-Bit (1,2,4, ...)
** a1  : Ziel im Bildschirmspeicher
** a2  : Ziel im Kollisionspuffer
** a3  : Zeiger auf Grafik-Kollisionspuffer
**

		CNOP	0,4
; Standard-Sprite: 3 Byte mit je 8 Pixeln konvertieren
DrawSprStd	cmp.w	#DisplayX-24,d1	;Sprite horizontal sichtbar?
		bhs	DSSRts

		moveq	#0,d6		;Pixelzähler
DSSLoop		add.l	d0,d0		;Pixel gesetzt?
		bcc	DSSNext

	IFNE	SPR_DATA_COLL
		tst.b	(a3,d6.l)	;Ist hier schon Grafik?
		beq	1$
		or.b	d7,d4		;Ja, Kollision erkannt
1$
	ENDC
		move.b	(a2,d6.l),d1	;Ist schon ein Sprite da?
		bne	DSSDont

		move.b	d2,(a1,d6.l)	;Nein, Punkt setzen
		move.b	d7,(a2,d6.l)
		bra	DSSNext

DSSDont		or.b	d1,d5		;Ja, Kollision erkannt zwischen bestehendem
		or.b	d7,d5		; und aktuellem Sprite

DSSNext		addq.w	#1,d6
		cmp.w	#24,d6
		bne	DSSLoop
DSSRts		rts

		CNOP	0,4
; X-expandiertes Standard-Sprite: 3 Byte mit je 8 Pixeln konvertieren
DrawSprStdExp	cmp.w	#DisplayX-48,d1
		bhs	DSSERts

		moveq	#0,d6
DSSELoop	add.l	d0,d0
		bcc	DSSENext

	IFNE	SPR_DATA_COLL
		tst.b	(a3,d6.l)
		beq	1$
		or.b	d7,d4
1$
	ENDC
		move.b	(a2,d6.l),d1
		bne	DSSEDont1st

		move.b	d2,(a1,d6.l)
		move.b	d7,(a2,d6.l)
		bra	DSSETest2nd

DSSEDont1st	or.b	d1,d5
		or.b	d7,d5

DSSETest2nd
	IFNE	SPR_DATA_COLL
		tst.b	1(a3,d6.l)
		beq	1$
		or.b	d7,d4
1$
	ENDC
		move.b	1(a2,d6.l),d1
		bne	DSSEDont2nd

		move.b	d2,1(a1,d6.l)
		move.b	d7,1(a2,d6.l)
		bra	DSSENext

DSSEDont2nd	or.b	d1,d5
		or.b	d7,d5

DSSENext	addq.w	#2,d6
		cmp.w	#48,d6
		bne	DSSELoop
DSSERts		rts

		CNOP	0,4
; Multicolor-Sprite: 3 Byte mit je 4 Pixeln konvertieren
DrawSprMulti	cmp.w	#DisplayX-24,d1
		bhs	DSMRts

		moveq	#0,d6
DSMLoop		add.l	d0,d0		;Farbe des Pixels bestimmen
		bcc	DSMFirstIs0
		add.l	d0,d0
		bcc	DSMDraw10
		move.b	$26(a4),d3	;11
		bra	DSMDraw
DSMDraw10	move.b	d2,d3		;10
		bra	DSMDraw
DSMFirstIs0	add.l	d0,d0
		bcc	DSMNext
		move.b	$25(a4),d3	;01

DSMDraw
	IFNE	SPR_DATA_COLL
		tst.b	(a3,d6.l)
		beq	1$
		or.b	d7,d4
1$
	ENDC
		move.b	(a2,d6.l),d1
		bne	DSMDont1st

		move.b	d3,(a1,d6.l)
		move.b	d7,(a2,d6.l)
		bra	DSMTest2nd

DSMDont1st	or.b	d1,d5
		or.b	d7,d5

DSMTest2nd
	IFNE	SPR_DATA_COLL
		tst.b	1(a3,d6.l)
		beq	1$
		or.b	d7,d4
1$
	ENDC
		move.b	1(a2,d6.l),d1
		bne	DSMDont2nd

		move.b	d3,1(a1,d6.l)
		move.b	d7,1(a2,d6.l)
		bra	DSMNext

DSMDont2nd	or.b	d1,d5
		or.b	d7,d5

DSMNext		addq.w	#2,d6
		cmp.w	#24,d6
		bne	DSMLoop
DSMRts		rts

		CNOP	0,4
; X-expandiertes Multicolor-Sprite: 3 Byte mit je 4 Pixeln konvertieren
DrawSprMultiExp	cmp.w	#DisplayX-48,d1
		bhs	DSMERts

		moveq	#0,d6
DSMELoop	add.l	d0,d0
		bcc	DSMEFirstIs0
		add.l	d0,d0
		bcc	DSMEDraw10
		move.b	$26(a4),d3	;11
		bra	DSMEDraw
DSMEDraw10	move.b	d2,d3		;10
		bra	DSMEDraw
DSMEFirstIs0	add.l	d0,d0
		bcc	DSMENext
		move.b	$25(a4),d3	;01

DSMEDraw
	IFNE	SPR_DATA_COLL
		tst.b	(a3,d6.l)
		beq	1$
		or.b	d7,d4
1$
	ENDC
		move.b	(a2,d6.l),d1
		bne	DSMEDont1st

		move.b	d3,(a1,d6.l)
		move.b	d7,(a2,d6.l)
		bra	DSMETest2nd

DSMEDont1st	or.b	d1,d5
		or.b	d7,d5

DSMETest2nd
	IFNE	SPR_DATA_COLL
		tst.b	1(a3,d6.l)
		beq	1$
		or.b	d7,d4
1$
	ENDC
		move.b	1(a2,d6.l),d1
		bne	DSMEDont2nd

		move.b	d3,1(a1,d6.l)
		move.b	d7,1(a2,d6.l)
		bra	DSMETest3rd

DSMEDont2nd	or.b	d1,d5
		or.b	d7,d5

DSMETest3rd
	IFNE	SPR_DATA_COLL
		tst.b	2(a3,d6.l)
		beq	1$
		or.b	d7,d4
1$
	ENDC
		move.b	2(a2,d6.l),d1
		bne	DSMEDont3rd

		move.b	d3,2(a1,d6.l)
		move.b	d7,2(a2,d6.l)
		bra	DSMETest4th

DSMEDont3rd	or.b	d1,d5
		or.b	d7,d5

DSMETest4th
	IFNE	SPR_DATA_COLL
		tst.b	3(a3,d6.l)
		beq	1$
		or.b	d7,d4
1$
	ENDC
		move.b	3(a2,d6.l),d1
		bne	DSMEDont4th

		move.b	d3,3(a1,d6.l)
		move.b	d7,3(a2,d6.l)
		bra	DSMENext

DSMEDont4th	or.b	d1,d5
		or.b	d7,d5

DSMENext	addq.w	#4,d6
		cmp.w	#48,d6
		bne	DSMELoop
DSMERts		rts

		CNOP	0,4
; Standard-Sprite im Hintergrund: 3 Byte mit je 8 Pixeln konvertieren
DrawBackStd	cmp.w	#DisplayX-24,d1	;Sprite horizontal sichtbar?
		bhs	DBSRts

		moveq	#0,d6		;Pixelzähler
DBSLoop		add.l	d0,d0		;Pixel gesetzt?
		bcc	DBSNext

	IFNE	SPR_DATA_COLL
		tst.b	(a3,d6.l)	;Ist hier schon Grafik?
		beq	1$
		or.b	d7,d4		;Ja, Kollision erkannt
		move.b	(a2,d6.l),d1	;Ist schon ein Sprite da?
		beq	DBSNext
		or.b	d1,d5		;Ja, Kollision erkannt
		or.b	d7,d5
		bra	DBSNext		;Sprite nicht zeichnen
1$
	ENDC
		move.b	(a2,d6.l),d1	;Ja, ist schon ein Sprite da?
		bne	DBSDont

		move.b	d2,(a1,d6.l)	;Nein, Punkt setzen
		move.b	d7,(a2,d6.l)
		bra	DBSNext

DBSDont		or.b	d1,d5		;Ja, Kollision erkannt zwischen bestehendem
		or.b	d7,d5		; und aktuellem Sprite

DBSNext		addq.w	#1,d6
		cmp.w	#24,d6
		bne	DBSLoop
DBSRts		rts

		CNOP	0,4
; X-expandiertes Standard-Sprite im Hintergrund: 3 Byte mit je 8 Pixeln konvertieren
DrawBackStdExp	cmp.w	#DisplayX-48,d1
		bhs	DBSERts

		moveq	#0,d6
DBSELoop	add.l	d0,d0
		bcc	DBSENext

	IFNE	SPR_DATA_COLL
		tst.b	(a3,d6.l)
		beq	1$
		or.b	d7,d4
		move.b	(a2,d6.l),d1
		beq	DBSETest2nd
		or.b	d1,d5
		or.b	d7,d5
		bra	DBSETest2nd
1$
	ENDC
		move.b	(a2,d6.l),d1
		bne	DBSEDont1st

		move.b	d2,(a1,d6.l)
		move.b	d7,(a2,d6.l)
		bra	DBSETest2nd

DBSEDont1st	or.b	d1,d5
		or.b	d7,d5

DBSETest2nd
	IFNE	SPR_DATA_COLL
		tst.b	1(a3,d6.l)
		beq	1$
		or.b	d7,d4
		move.b	1(a2,d6.l),d1
		beq	DBSENext
		or.b	d1,d5
		or.b	d7,d5
		bra	DBSENext
1$
	ENDC
		move.b	1(a2,d6.l),d1
		bne	DBSEDont2nd

		move.b	d2,1(a1,d6.l)
		move.b	d7,1(a2,d6.l)
		bra	DBSENext

DBSEDont2nd	or.b	d1,d5
		or.b	d7,d5

DBSENext	addq.w	#2,d6
		cmp.w	#48,d6
		bne	DBSELoop
DBSERts		rts

		CNOP	0,4
; Multicolor-Sprite im Hintergrund: 3 Byte mit je 4 Pixeln konvertieren
DrawBackMulti	cmp.w	#DisplayX-24,d1
		bhs	DBMRts

		moveq	#0,d6
DBMLoop		add.l	d0,d0		;Farbe des Pixels bestimmen
		bcc	DBMFirstIs0
		add.l	d0,d0
		bcc	DBMDraw10
		move.b	$26(a4),d3	;11
		bra	DBMDraw
DBMDraw10	move.b	d2,d3		;10
		bra	DBMDraw
DBMFirstIs0	add.l	d0,d0
		bcc	DBMNext
		move.b	$25(a4),d3	;01

DBMDraw
	IFNE	SPR_DATA_COLL
		tst.b	(a3,d6.l)
		beq	1$
		or.b	d7,d4
		move.b	(a2,d6.l),d1
		beq	DBMTest2nd
		or.b	d1,d5
		or.b	d7,d5
		bra	DBMTest2nd
1$
	ENDC
		move.b	(a2,d6.l),d1
		bne	DBMDont1st

		move.b	d3,(a1,d6.l)
		move.b	d7,(a2,d6.l)
		bra	DBMTest2nd

DBMDont1st	or.b	d1,d5
		or.b	d7,d5

DBMTest2nd
	IFNE	SPR_DATA_COLL
		tst.b	1(a3,d6.l)
		beq	1$
		or.b	d7,d4
		move.b	1(a2,d6.l),d1
		beq	DBMNext
		or.b	d1,d5
		or.b	d7,d5
		bra	DBMNext
1$
	ENDC
		move.b	1(a2,d6.l),d1
		bne	DBMDont2nd

		move.b	d3,1(a1,d6.l)
		move.b	d7,1(a2,d6.l)
		bra	DBMNext

DBMDont2nd	or.b	d1,d5
		or.b	d7,d5

DBMNext		addq.w	#2,d6
		cmp.w	#24,d6
		bne	DBMLoop
DBMRts		rts

		CNOP	0,4
; X-expandiertes Multicolor-Sprite im Hintergrund: 3 Byte mit je 4 Pixeln konvertieren
DrawBackMultiExp cmp.w	#DisplayX-48,d1
		bhs	DBMERts

		moveq	#0,d6
DBMELoop	add.l	d0,d0
		bcc	DBMEFirstIs0
		add.l	d0,d0
		bcc	DBMEDraw10
		move.b	$26(a4),d3	;11
		bra	DBMEDraw
DBMEDraw10	move.b	d2,d3		;10
		bra	DBMEDraw
DBMEFirstIs0	add.l	d0,d0
		bcc	DBMENext
		move.b	$25(a4),d3	;01

DBMEDraw
	IFNE	SPR_DATA_COLL
		tst.b	(a3,d6.l)
		beq	1$
		or.b	d7,d4
		move.b	(a2,d6.l),d1
		beq	DBMETest2nd
		or.b	d1,d5
		or.b	d7,d5
		bra	DBMETest2nd
1$
	ENDC
		move.b	(a2,d6.l),d1
		bne	DBMEDont1st

		move.b	d3,(a1,d6.l)
		move.b	d7,(a2,d6.l)
		bra	DBMETest2nd

DBMEDont1st	or.b	d1,d5
		or.b	d7,d5

DBMETest2nd
	IFNE	SPR_DATA_COLL
		tst.b	1(a3,d6.l)
		beq	1$
		or.b	d7,d4
		move.b	1(a2,d6.l),d1
		beq	DBMETest3rd
		or.b	d1,d5
		or.b	d7,d5
		bra	DBMETest3rd
1$
	ENDC
		move.b	1(a2,d6.l),d1
		bne	DBMEDont2nd

		move.b	d3,1(a1,d6.l)
		move.b	d7,1(a2,d6.l)
		bra	DBMETest3rd

DBMEDont2nd	or.b	d1,d5
		or.b	d7,d5

DBMETest3rd
	IFNE	SPR_DATA_COLL
		tst.b	2(a3,d6.l)
		beq	1$
		or.b	d7,d4
		move.b	2(a2,d6.l),d1
		beq	DBMETest4th
		or.b	d1,d5
		or.b	d7,d5
		bra	DBMETest4th
1$
	ENDC
		move.b	2(a2,d6.l),d1
		bne	DBMEDont3rd

		move.b	d3,2(a1,d6.l)
		move.b	d7,2(a2,d6.l)
		bra	DBMETest4th

DBMEDont3rd	or.b	d1,d5
		or.b	d7,d5

DBMETest4th
	IFNE	SPR_DATA_COLL
		tst.b	3(a3,d6.l)
		beq	1$
		or.b	d7,d4
		move.b	3(a2,d6.l),d1
		beq	DBMENext
		or.b	d1,d5
		or.b	d7,d5
		bra	DBMENext
1$
	ENDC
		move.b	3(a2,d6.l),d1
		bne	DBMEDont4th

		move.b	d3,3(a1,d6.l)
		move.b	d7,3(a2,d6.l)
		bra	DBMENext

DBMEDont4th	or.b	d1,d5
		or.b	d7,d5

DBMENext	addq.w	#4,d6
		cmp.w	#48,d6
		bne	DBMELoop
DBMERts		rts


**
** Amiga-Mono-Routinen einbinden
**

		INCLUDE	"6569mono.i"


**
** Konstanten
**

; Tabelle der Display-Routinen (jeweils für Farbe und Monochrom)
		CNOP	0,4
DispProcTab	dc.l	TextStd
		dc.l	TextMulti
		dc.l	BitMapStd
		dc.l	BitMapMulti
		dc.l	TextECM
		dc.l	BlackScreen
		dc.l	BlackScreen
		dc.l	BlackScreen

MonoDispProcTab	dc.l	FTextStd
		dc.l	FTextStd
		dc.l	FBitMapStd
		dc.l	FBitMapStd
		dc.l	FTextStd
		dc.l	FBlackScreen
		dc.l	FBlackScreen
		dc.l	FBlackScreen

; Tabelle der Sprite-Display-Routinen
SpriteProcTab	dc.l	DrawSprStd
		dc.l	DrawSprStdExp
		dc.l	DrawSprMulti
		dc.l	DrawSprMultiExp
		dc.l	DrawBackStd
		dc.l	DrawBackStdExp
		dc.l	DrawBackMulti
		dc.l	DrawBackMultiExp

; Hook für DoCDrawMethod
CyberHook	dc.l	0,0
		dc.l	CyberHookProc
		dc.l	0
		dc.l	0


**
** Datenbereich
**

; Variablen
		CNOP	0,4
DisplayProc	dc.l	0	;Zeiger auf die Display-Routine (Text/Bitmap etc.)

Sprite0Proc	dc.l	0	;Zeiger auf Display-Routinen für die einzelnen Sprites
Sprite1Proc	dc.l	0
Sprite2Proc	dc.l	0
Sprite3Proc	dc.l	0
Sprite4Proc	dc.l	0
Sprite5Proc	dc.l	0
Sprite6Proc	dc.l	0
Sprite7Proc	dc.l	0

DisplayID	dc.l	0	;Prefs: DisplayID des Screens
ScreenType	dc.w	0	;Prefs: Typ der Screen-Ansteuerung
NormalCycles	dc.w	0	;Prefs: Anzahl 6510-Zyklen pro Rasterzeile
BadLineCycles	dc.w	0	;Prefs: Anzahl 6510-Zyklen in einer Bad Line
SpritesOn	dc.w	0	;Prefs: Sprites-Darstellung angeschaltet
Collisions	dc.w	0	;Prefs: Sprite-Kollisionen angeschaltet
Overscan	dc.w	0	;Prefs: Overscan-Typ für Amiga-Modi
DirectVideo	dc.w	0	;Prefs: Direkter Grafikspeicherzugriff bei 8 Bit erlaubt

SkipCounter	dc.w	1
		XDEF	_SkipLatch
_SkipLatch
SkipLatch	dc.w	0	;Prefs: Nur jedes nte Bild darstellen

		XDEF	_LimitSpeed
_LimitSpeed
LimitSpeed	dc.w	0	;Prefs: Geschwindigkeit auf 100% beschränken

IsCyber		dc.b	0	;#0: DoCDrawMethod kann statt WritePixelLine8 benutzt werden
IsCyberDirect	dc.b	0	;#0: Direkter Bildschirmspeicherzugriff erlaubt
		CNOP	0,4
CyberBase	dc.l	0	;Basisadresse des Bildschirmspeichers
CyberXMod	dc.l	0	;Modulo des Bildschirmspeichers

		CNOP	0,4
Registers	ds.b	VICRegLength	;VIC-Register
MatrixLine	ds.b	40	;Eine Bildschirmzeile
ColorLine	ds.b	40	;Eine Farb-RAM-Zeile


**
** Nicht initialisierte Daten
**

		SECTION	"BSS",BSS
		XDEF	_ChunkyBuf
_ChunkyBuf
ChunkyBuf	ds.b	DisplayX*DisplayY ;Puffer für die Chunky-Bitmap

SprCollBuf	ds.b	DisplayX	;Puffer für Sprite-Sprite-Kollisionen
	IFNE	SPR_DATA_COLL
GfxCollBuf	ds.b	DisplayX	;Puffer für Sprite-Grafik-Kollisionen und Priorität
	ENDC

		XDEF	_CURRENTA5
_CURRENTA5	ds.l	1		;Kommunikation mit _RedrawDisplay

		END
