*
* 6569SC.asm - Einzelzyklus-VIC-Emulation
*
* Copyright (C) 1995-1996 by Christian Bauer
*

*
* Anmerkungen:
* ------------
*
* Registerbelegung:
* d5: Index in MatrixLine
* d6: Schleifenzähler
* d7: Von 6510-Emulation benutzt
* a3: Zeiger in ChunkyBuf zum Schreiben der Grafikdaten
* a4: Zeiger für Near-Adressierung
* a5: Zeiger in C64-RAM, Offset 32K (für Adressierung mit Vorzeichen)
* a6: Von 6510-Emulation benutzt
*
* Es wird ein 6569R5 emuliert.
*
* Inkompatibilitäten:
*  - Farbe der $ff-Bytes, die gelesen werden, wenn BA low und AEC high ist,
*    stimmt nicht
*  - Änderungen in der Rahmen-/Hintergrundfarbe werden 7 Pixel zu
*    spät sichtbar
*  - Der Zugriff auf die Sprite-Daten beachtet BA nicht
*  - Keine Sprite-Darstellung
*  - Keine Sprite-Kollisionen
*

DEBUG_DETAIL	SET 0

DE00_COMPATIBLE	SET 1

		MACHINE	68020

		INCLUDE	"exec/types.i"
		INCLUDE	"exec/macros.i"
		INCLUDE	"debug.i"

		XREF	_SysBase	;Main.asm
		XREF	_GfxBase

		NREF	TheChar		;6510SC.asm
		NREF	TheColor
		NREF	IntIsIRQ
		NREF	IntIsVICIRQ
		NREF	FirstIRQCycle
		NREF	BALow
	IFNE	DEBUG_DETAIL
		NREF	DEBUGON
	ENDC

		XREF	CountTODs	;6526SC.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	TriggerLightpen
		XDEF	Main6569
		XDEF	ReadFrom6569
		XDEF	WriteTo6569
	IFNE	DE00_COMPATIBLE
		XDEF	LastVICByte
	ENDC
		XDEF	CycleCounter

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

		NEAR	a4,-2

		SECTION	"text",CODE

		FAR


**
** Definitionen
**

; Registerbelegung
INDEX		EQUR	d5	;Index in Matrixzeile
BUFFER		EQUR	a3	;Zeiger in ChunkyBuf zum Schreiben der Grafikdaten
RAMPTR		EQUR	a5	;Zeiger in C64-RAM

; Gesamtzahl Rasterzeilen
TotalLines	= 312

; Anfang und Ende des DMA-Bereiches
FirstDMALine	= $30
LastDMALine	= $f7

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

; Größe der Anzeige
DisplayX	= (5+40+4)*8	;40 Zeichen, 9*8 Pixel Rahmen
DisplayY	= TotalLines
;DisplayY	= 272

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


**
** Emulation vorbereiten
**

*
* Register/Tabellen vorbereiten
*

Init6569	lea	MemReadTab,a0		;Alle mit RAM vorbelegen
		move.w	#256-1,d0
11$		move.l	#ReadByteRAM,(a0)+
		dbra	d0,11$

		lea	MemReadTab+16*4,a0	;Char-ROM bei $1000..$1fff
		moveq	#15,d0
12$		move.l	#ReadByteChar,(a0)+
		dbra	d0,12$

		lea	MemReadTab+144*4,a0	;Char-ROM bei $9000..$9fff
		moveq	#15,d0
13$		move.l	#ReadByteChar,(a0)+
		dbra	d0,13$

		move.w	#7,RC
		clr.w	VCBASE
		clr.w	VCCOUNT
		move.w	#63,MC0
		move.w	#63,MC1
		move.w	#63,MC2
		move.w	#63,MC3
		move.w	#63,MC4
		move.w	#63,MC5
		move.w	#63,MC6
		move.w	#63,MC7
		clr.w	CIAVABASE
		move.w	#TotalLines-1,RASTERY
		move.w	#1,SkipCounter
		move.w	#Row24YStart,DYSTART
		move.w	#Row24YStop,DYSTOP
		clr.w	DISPROCIDX
		rts


*
* Screen und Fenster öffnen
* d0=0: Alles OK
* d0=1: Fehler beim Screen-Ö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
		rts


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

_GetVICDump	move.l	4(sp),a1

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

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

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

		addq.l	#1,a1
		move.w	IRQRASTERY,(a1)+
		move.w	VCCOUNT,(a1)+
		move.w	VCBASE,(a1)+
		move.b	RC+1,(a1)+
		move.b	SPRDMAON,(a1)+

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

		tst.b	DISPLAYSTATE
		seq.b	(a1)+
		seq.b	(a1)+
		tst.b	BADLINE
		sne.b	(a1)+
		sne.b	(a1)+
		tst.b	BADLINEENABLE
		sne.b	(a1)+
		sne.b	(a1)+

		move.w	CIAVABASE,d1
		move.w	d1,(a1)+
		move.w	MATRIXBASE,d0
		or.w	d1,d0
		move.w	d0,(a1)+
		move.w	CHARBASE,d0
		or.w	d1,d0
		move.w	d0,(a1)+
		move.w	BITMAPBASE,d0
		or.w	d1,d0
		move.w	d0,(a1)+

		move.l	d2,-(sp)
		lea	SPRPTR,a0
		moveq	#7,d2
2$		move.w	(a0)+,d0
		or.w	d1,d0
		move.w	d0,(a1)+
		dbra	d2,2$
		move.l	(sp)+,d2
		rts


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

ChangedVA	clr.w	d1		;VABase speichern
		move.b	d0,d1
		ror.w	#2,d1
		move.w	d1,CIAVABASE
		rts


**
** CIA-A PB4 hat einen Übergang 1->0 gemacht, evtl. Lightpen triggern
**

TriggerLightpen	tst.b	LPTRIGGERED	;Lightpen in diesem Frame schon getriggert?
		bne	1$

		st.b	LPTRIGGERED	;Nein, Flag setzen

		move.w	RASTERX,d0	;Und Lightpen-Register mit den aktuellen Koordinaten füllen
		lsr.w	#1,d0
		move.b	d0,LPX
		move.b	RASTERY+1,LPY

		or.b	#$08,IRQFLAG	;ILP-Bit setzen
		btst	#3,IRQMASK	;LP-IRQ erlaubt?
		beq	1$
		or.b	#$80,IRQFLAG	;Ja, IRQ-Bit setzen
		tst.w	IntIsIRQ	;IRQ schon ausgelöst?
		bne	2$
		move.l	CycleCounter,FirstIRQCycle ;Nein, Zyklus merken
2$		st.b	IntIsVICIRQ	; und Interrupt auslösen
1$		rts


**
** Aus einem VIC-Register lesen
** d0.w: Registernummer ($00-$3f)
** Rückgabe: d0.b: Byte
**

		NEAR

ReadFrom6569	move.l	(ReadTab,pc,d0.w*4),a0
		jmp	(a0)

		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	(VICREGS,d0.w),d0
		rts

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

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

RdRASTER	move.w	RASTERY,d0		;Rasterzähler lesen (nur die unteren 8 Bit sind wichtig)
		rts

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

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

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

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

RdCLXSPR	move.b	CLXSPR,d0		;Lesen und löschen
		clr.b	CLXSPR
		rts

RdCLXBGR	move.b	CLXBGR,d0		;Lesen und löschen
		clr.b	CLXBGR
		rts

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

RdUndef		moveq.b	#-1,d0			;Nicht existierendes Register
		rts


**
** In ein VIC-Register schreiben
** d0.w: Registernummer ($00-$3f)
** d1.b: Byte
**

WriteTo6569	move.l	(WriteTab,pc,d0.w*4),a0
		jmp	(a0)

		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	WrMYE
		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	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	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,(VICREGS,d0.w)
WrUndef		rts

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

WrSprXMSB	move.b	d1,MX8
		lea	SPRX7,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

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

		move.b	d1,d0		;MSB der IRQ-Rasterzeile
		lsr.b	#7,d0
		move.b	d0,IRQRASTERY

		btst	#3,d1		;24/25 Zeilen
		beq	2$
		move.w	#Row25YStart,DYSTART
		move.w	#Row25YStop,DYSTOP
		bra	3$
2$		move.w	#Row24YStart,DYSTART
		move.w	#Row24YStop,DYSTOP
3$
		move.w	RASTERY,d0	;d0: RASTERY
		cmp.w	#$30,d0		;In Rasterzeile $30 entscheidet das DEN-Bit,
		bne	5$		; ob Bad Lines erlaubt sind
		btst	#4,d1
		beq	5$
		st.b	BADLINEENABLE
5$
		tst.b	BADLINEENABLE	;Bad Lines erlaubt?
		beq	1$
		cmp.w	#FirstDMALine,d0 ;Ja, dann Bad Line Condition prüfen
		blo	1$
		cmp.w	#LastDMALine,d0
		bhi	1$
		and.w	#$07,d0
		cmp.w	YSCROLL,d0
		seq	BADLINE
		bra	SetDispProc	;Anzeigemodus in Index konvertieren
1$		clr.b	BADLINE
		bra	SetDispProc	;Anzeigemodus in Index konvertieren

WrRASTER	move.b	d1,IRQRASTERY+1
		rts

WrCTRL2		move.b	d1,CTRL2

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

		btst	#3,d1		;38/40 Zeilen
		seq.b	IS38COL
		;fällt durch

SetDispProc	moveq	#0,d0		;ECM, BMM und MCM holen
		move.b	CTRL1,d0
		and.b	#$60,d0
		move.b	CTRL2,d1
		and.b	#$10,d1
		or.b	d1,d0
		lsr.b	#4,d0
		move.w	d0,DISPROCIDX	;Anzeigemodus als Index
		rts

WrMYE		move.b	d1,MYE
		not.b	d1
		or.b	d1,SPREXPY
		rts

WrVBASE		move.b	d1,VBASE

		move.b	d1,d0		;Videomatrixbasis berechnen
		and.w	#$00f0,d0
		lsl.w	#6,d0
		move.w	d0,MATRIXBASE

		move.b	d1,d0		;Zeichengeneratorbasis berechnen
		and.w	#$000e,d0
		ror.w	#6,d0
		move.w	d0,CHARBASE

		move.b	d1,d0		;Bitmapbasis berechnen
		and.w	#$0008,d0
		ror.w	#6,d0
		move.w	d0,BITMAPBASE
		rts

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

		move.b	d1,d0		;Erlaubter IRQ noch gesetzt?
		and.b	IRQMASK,d0
		beq	1$
		or.b	#$80,d1		;Ja, Master-Bit setzen
		move.b	d1,IRQFLAG
		rts
1$		clr.b	IntIsVICIRQ	;Nein, Interrupt zurücknehmen
		move.b	d1,IRQFLAG
		rts

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

		and.b	IRQFLAG,d1	;Gesetzter IRQ jetzt erlaubt?
		beq	1$
		or.b	#$80,IRQFLAG	;Ja, Master-Bit setzen
		tst.w	IntIsIRQ	;IRQ schon ausgelöst?
		bne	2$
		move.l	CycleCounter,FirstIRQCycle ;Nein, Zyklus merken
2$		st.b	IntIsVICIRQ	; und Interrupt auslösen
		rts
1$		clr.b	IntIsVICIRQ	;Nein, Interrupt zurücknehmen
		and.b	#$7f,IRQFLAG	;Master-Bit löschen
		rts

WrMDP		move.b	d1,MDP
		bra	SetSpriteProcs

WrMMC		move.b	d1,MMC
		bra	SetSpriteProcs

WrMXE		move.b	d1,MXE

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

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

WrBorder	move.b	d1,EC
		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
		rts


**
** Byte vom VIC aus lesen
**

; Normaler Zugriff
; -> d0.w: Adresse ($0000..$3fff)
; <- d0.b: Byte
VICRead		MACRO
		bsr	VICReadIt
		ENDM

VICReadIt	or.w	CIAVABASE,d0
		move.w	d0,d1
		lsr.w	#8,d1
		move.l	(MemReadTab,d1.w*4),a0
		jmp	(a0)

ReadByteRAM	move.b	(RAMPTR,d0.w),d0
	IFNE	DE00_COMPATIBLE
		move.b	d0,LastVICByte
	ENDC
		rts

ReadByteChar	and.w	#$0fff,d0
		move.l	TheChar,a0
		move.b	(a0,d0.w),d0
	IFNE	DE00_COMPATIBLE
		move.b	d0,LastVICByte
	ENDC
		rts


**
** Hauptschleife für VIC
**

*
* Makros
*

; BA low setzen
SetBALow	MACRO
		tst.b	BALow		;War BA schon low?
		bne	\@1$
		move.l	CycleCounter,FirstBACycle ;Nein, Zyklus merken
		st.b	BALow		;Und BA low setzen
\@1$
		ENDM

; Bei Bad Line die Anzeige anschalten
; Muß synchron mit der positiven Flanke von Phi0 aufgerufen werden
DisplayIfBadLine MACRO
		tst.b	BADLINE		;Bad Line?
		beq	\@1$
		st.b	DISPLAYSTATE	;Ja, Anzeige ein
\@1$
		ENDM

; Bei Bad Line den Matrixzugriff und die Anzeige anschalten
; Muß synchron mit der positiven Flanke von Phi0 aufgerufen werden
FetchIfBadLine	MACRO
		tst.b	BADLINE		;Bad Line?
		beq	\@1$
		st.b	DISPLAYSTATE	;Ja, Anzeige ein
		SetBALow
\@1$
		ENDM

; Bei Bad Line den Matrixzugriff und die Anzeige anschalten und den RC zurücksetzen
; Muß synchron mit der positiven Flanke von Phi0 aufgerufen werden
RCIfBadLine	MACRO
		tst.b	BADLINE		;Bad Line?
		beq	\@1$
		st.b	DISPLAYSTATE	;Ja, Anzeige ein
		clr.w	RC		; und RC zurücksetzen
		SetBALow
\@1$
		ENDM

; "Leerer" Zugriff
IdleAccess	MACRO
	IFNE	DE00_COMPATIBLE
		move.w	#$3fff,d0
		VICRead
	ENDC
		ENDM

; Refreshzugriff
RefreshAccess	MACRO
	IFNE	DE00_COMPATIBLE
		move.w	#$3f00,d0
		move.b	REFCNT,d0
		VICRead
		subq.b	#1,REFCNT
	ENDC
		ENDM

; Videomatrixzugriff
;  INDEX: Index in Matrixzeile
MatrixAccess	MACRO
		tst.b	BALow
		beq	\@1$

		move.l	CycleCounter,d1	;Wenn BA noch keine 3 Takte low ist, $ff lesen
		sub.l	FirstBACycle,d1
		moveq	#3,d2
		cmp.l	d2,d1
		blo	\@2$

		move.w	VCCOUNT,d0	;BA war 3 Takte low, zugreifen
		and.w	#$03ff,d0
		or.w	MATRIXBASE,d0
		or.w	CIAVABASE,d0
		move.w	d0,d1
		move.w	d0,d2
		lsr.w	#8,d1
		move.l	(MemReadTab,d1.w*4),a0
		jsr	(a0)
		move.b	d0,(MatrixLine,INDEX.l*2)

		and.w	#$03ff,d2	;Farb-RAM lesen
		move.l	TheColor,a0
		move.b	(a0,d2.w),(MatrixLine+1,INDEX.l*2)
		bra	\@1$

\@2$		move.w	#-1,(MatrixLine,INDEX.l*2) ;BA low, AEC high (Farbnibble stimmt nicht)
\@1$
		ENDM

; Grafikzugriff
;  INDEX: Index in Matrixzeile
GraphicsAccess	MACRO
		tst.b	DISPLAYSTATE	;Anzeige ein?
		beq	Fetch3FFF\@

		btst	#5,CTRL1	;Ja, Bitmap-Modus?
		bne	FetchBitmap\@

		moveq	#0,d0		;Nein, Textmodus
		move.b	(MatrixLine,INDEX.l*2),d0
		lsl.w	#3,d0
		or.w	CHARBASE,d0
		bra	FetchDoIt\@

FetchBitmap\@	move.w	VCCOUNT,d0	;Bitmap-Modus
		and.w	#$03ff,d0
		lsl.w	#3,d0
		or.w	BITMAPBASE,d0
		bra	FetchDoIt\@

Fetch3FFF\@	move.w	#$3fff,d0	;Anzeige aus, $3fff darstellen
		or.w	CIAVABASE,d0

		btst	#6,CTRL1
		beq	\@1$
		and.w	#$f9ff,d0
\@1$
		move.w	d0,d1
		lsr.w	#8,d1
		move.l	(MemReadTab,d1.w*4),a0
		jsr	(a0)
		bra	FetchStore\@

FetchDoIt\@	or.w	RC,d0
		or.w	CIAVABASE,d0

		btst	#6,CTRL1
		beq	\@1$
		and.w	#$f9ff,d0
\@1$
		move.w	d0,d1
		lsr.w	#8,d1
		move.l	(MemReadTab,d1.w*4),a0
		jsr	(a0)
		addq.w	#1,VCCOUNT
		move.w	(MatrixLine,INDEX.l*2),CHARDATA ;Zeichen/Farbe für Anzeigestufe
		addq.b	#1,INDEX
FetchStore\@	move.b	d0,GFXDATA	;Grafikbyte für Anzeigestufe merken
		ENDM

; Darstellung des Rahmens (8 Pixel)
; BUFFER: Zeiger in ChunkyBuf, wird um 8 erhöht
DrawBorder	MACRO
		tst.b	BORDERON
		beq	\@1$
		move.l	BORDERLONG,d0	;Rahmen an, malen
		move.l	d0,(BUFFER)+
		move.l	d0,(BUFFER)+
		bra	\@2$
\@1$		addq.l	#8,BUFFER
\@2$
		ENDM

; Sprite-DMA einschalten, wenn nötig
CheckSpriteDMA	MACRO
		lea	M7Y,a0		;a0: Zeiger auf Y-Koordinate
		lea	MC7BASE,a1	;a1: Zeiger auf Spritedatenzähler-Zwischenspeicher
		moveq	#7,d0		;d0: Schleifenzähler
		move.w	RASTERY,d1	;d1: Aktuelle Rasterzeile
		move.b	SPRDMAON,d2	;d2: Puffer für SPRDMAON
		move.b	SPREN,d3	;d3: SPREN (VIC-Register)
\@2$		btst	d0,d3		;SPREN-Bit gesetzt?
		beq	\@1$
		cmp.b	(a0),d1		;Ja, Y-Koordinate = RASTERY?
		bne	\@1$
		bset	d0,d2		;Ja, DMA ein
		clr.w	(a1)		; und Datenzähler löschen
		btst	d0,MYE
		beq	\@1$
		bclr	d0,SPREXPY
\@1$		subq.l	#2,a0
		subq.l	#2,a1
		dbra	d0,\@2$
		move.b	d2,SPRDMAON
		ENDM

; Sprite-Darstellung einschalten, wenn nötig
CheckSpriteDisp	MACRO
		lea	M7Y,a0		;a0: Zeiger auf Y-Koordinate
		moveq	#7,d0		;d0: Schleifenzähler
		move.w	RASTERY,d1	;d1: Aktuelle Rasterzeile
		move.b	SPRDISPON,d2	;d2: Puffer für SPRDISPON
		move.b	SPRDMAON,d3	;d3: SPRDMAON
\@2$		btst	d0,d3		;Sprite-DMA eingeschaltet?
		beq	\@1$
		cmp.b	(a0),d1		;Ja, Y-Koordinate = RASTERY?
		bne	\@1$
		bset	d0,d2		;Ja, Darstellung ein
\@1$		subq.l	#2,a0
		subq.l	#2,a1
		dbra	d0,\@2$
		move.b	d2,SPRDISPON
		ENDM

; Zugriff auf Sprite-Datenzeiger
SprPtrAccess	MACRO	;Spritenummer
		move.w	MATRIXBASE,d0
		or.w	#$03f8+\1,d0
		VICRead
		moveq	#0,d1
		move.b	d0,d1
		lsl.w	#6,d1
		move.w	d1,SPRPTR+(\1*2)
		ENDM

; Zugriff auf Sprite-Daten, Spritezähler erhöhen
SprDataAccess	MACRO	;Spritenummer, Byte-Nummer (0..2)
		btst	#\1,SPRDMAON
		beq	\@1$
		move.w	MC\1,d0
		and.w	#63,d0
		or.w	SPRPTR+(\1*2),d0
		VICRead
		move.b	d0,SPR\1DATA+\2
		addq.w	#1,MC\1
	IFEQ	\2-1
		bra	\@2$
	ENDC
\@1$
	IFEQ	\2-1			;Im zweiten Zyklus Idle-Zugriff machen, wenn Sprite-DMA ausgeschaltet
		IdleAccess
\@2$
	ENDC
		ENDM

; Y-Expansions-Flipflop invertieren, wenn Bit in MYE gesetzt
CheckMYE	MACRO	;Spritenummer
		btst	#\1,MYE
		beq	\@4$
		bchg	#\1,SPREXPY
\@4$
		ENDM

; MCBASE um 2 erhöhen, falls Expansions-Flipflop gesetzt
McbaseInc2	MACRO	;Spritenummer
		btst	#\1,SPREXPY
		beq	\@1$
		addq.w	#2,MC\1BASE
\@1$
		ENDM

; MCBASE um 1 erhöhen, falls Expansions-Flipflop gesetzt und testen, ob
;  Sprite-DMA und -Darstellung abgeschaltet werden kann
CheckSprOff	MACRO
		btst	#\1,SPREXPY
		beq	\@2$
		addq.w	#1,MC\1BASE
\@2$		move.w	MC\1BASE,d0
		and.w	#63,d0
		cmp.w	#63,d0
		bne	\@1$
		bclr	#\1,SPRDMAON
\@1$
		ENDM

; Sprite darstellen
DrawSprite	MACRO	;Nummer
		btst	#\1,SPRDISPON	;Wird das Sprite dargestellt?
		beq	\@1$

		move.l	SPR\1DATA,d0	;d0: Spritedaten
		move.w	SPRX\1,d1	;d1: X-Koordinate
		move.b	M\1C,d2		;d2: Spritefarbe
		move.l	Sprite\1Proc,a0
		jsr	(a0)
		btst	#\1,SPRDMAON	;DMA aus?
		bne	\@1$
		bclr	#\1,SPRDISPON	;Ja, dann Sprite abschalten
\@1$
		ENDM


*
* Hauptschleife
*

Main6569	

; Zyklus 1: Spritezeiger 3 holen, Rasterzähler erhöhen,
;  Raster-IRQ auslösen, auf Bad Line prüfen.
;  BA rücksetzen, falls Sprite 3 und 4 aus. Daten von Sprite 3 lesen
VIC.1		SprPtrAccess 3
		SprDataAccess 3,0

		cmp.w	#STYP_8BIT,ScreenType ;Bei 8 Bit wird nur ein Zeilenpuffer verwendet
		bne	4$
		lea	ChunkyBuf,BUFFER
		move.l	a6,-(sp)
		move.l	_GfxBase,a6
		move.l	_the_rast_port,a0
		moveq	#0,d0
		move.w	RASTERY,d1
		move.l	#DisplayX,d2
		move.l	BUFFER,a2
		lea	_temp_rp,a1
		JSRLIB	WritePixelLine8
		move.l	(sp)+,a6
4$
		cmp.w	#TotalLines-1,RASTERY ;War das die letzte Rasterzeile?
		seq	VBLANKING
		beq	3$

		addq.w	#1,RASTERY	;Nein, Rasterzähler erhöhen
		move.w	RASTERY,d6
		cmp.w	IRQRASTERY,d6	;IRQ-Zeile erreicht?
		bne	1$

		bsr	DoRasterIRQ	;Ja, auslösen
1$
		cmp.w	#$30,d6		;In Rasterzeile $30 entscheidet das DEN-Bit,
		bne	2$		; ob Bad Lines erlaubt sind
		btst	#4,CTRL1
		sne	BADLINEENABLE
2$
		clr.b	BADLINE
		tst.b	BADLINEENABLE	;DMA erlaubt?
		beq	3$
		cmp.w	#FirstDMALine,d6 ;Ja, dann Bad Line Condition prüfen
		blo	3$
		cmp.w	#LastDMALine,d6
		bhi	3$
		move.w	d6,d0
		and.w	#$07,d0
		cmp.w	YSCROLL,d0
		bne	3$
		st.b	BADLINE
3$
		DisplayIfBadLine
		addq.w	#8,RASTERX

		move.b	SPRDMAON,d0
		and.b	#$18,d0
		bne	6$
		clr.b	BALow

6$		bsr	Periodic6526	;CIA und 6510 ausführen

; Zyklus 2: BA für Sprite 5 setzen. Daten von Sprite 3 lesen
VIC.2		tst.b	VBLANKING	;VBlank im letzten Zyklus?
		beq	2$
		bsr	TheVBlank	;Ja

2$		SprDataAccess 3,1
		SprDataAccess 3,2
		DisplayIfBadLine
		addq.w	#8,RASTERX

		btst	#5,SPRDMAON
		beq	1$
		SetBALow

1$		bsr	Periodic6526

; Zyklus 3: Spritezeiger 4 holen. BA rücksetzen, falls Sprite 4 und 5 aus.
;  Daten von Sprite 4 lesen
VIC.3		SprPtrAccess 4
		SprDataAccess 4,0
		DisplayIfBadLine
		addq.w	#8,RASTERX

		move.b	SPRDMAON,d0
		and.b	#$30,d0
		bne	1$
		clr.b	BALow

1$		bsr	Periodic6526

; Zyklus 4: BA für Sprite 6 setzen. Daten von Sprite 4 lesen
VIC.4		SprDataAccess 4,1
		SprDataAccess 4,2
		DisplayIfBadLine
		addq.w	#8,RASTERX

		btst	#6,SPRDMAON
		beq	1$
		SetBALow

1$		bsr	Periodic6526

; Zyklus 5: Spritezeiger 5 holen. BA rücksetzen, falls Sprite 5 und 6 aus.
;  Daten von Sprite 5 lesen
VIC.5		SprPtrAccess 5
		SprDataAccess 5,0
		DisplayIfBadLine
		addq.w	#8,RASTERX

		move.b	SPRDMAON,d0
		and.b	#$60,d0
		bne	1$
		clr.b	BALow

1$		bsr	Periodic6526

; Zyklus 6: BA für Sprite 7 setzen. Daten von Sprite 5 lesen
VIC.6		SprDataAccess 5,1
		SprDataAccess 5,2
		DisplayIfBadLine
		addq.w	#8,RASTERX

		btst	#7,SPRDMAON
		beq	1$
		SetBALow

1$		bsr	Periodic6526

; Zyklus 7: Spritezeiger 6 holen. BA rücksetzen, falls Sprite 6 und 7 aus.
;  Daten von Sprite 6 lesen
VIC.7		SprPtrAccess 6
		SprDataAccess 6,0
		DisplayIfBadLine
		addq.w	#8,RASTERX

		move.b	SPRDMAON,d0
		and.b	#$c0,d0
		bne	1$
		clr.b	BALow

1$		bsr	Periodic6526

; Zyklus 8: Daten von Sprite 6 lesen
VIC.8		SprDataAccess 6,1
		SprDataAccess 6,2
		DisplayIfBadLine
		addq.w	#8,RASTERX

		bsr	Periodic6526

; Zyklus 9: Spritezeiger 7 holen. BA rücksetzen, falls Sprite 7 aus.
;  Daten von Sprite 7 lesen
VIC.9		SprPtrAccess 7
		SprDataAccess 7,0
		DisplayIfBadLine
		addq.w	#8,RASTERX

		btst	#7,SPRDMAON
		bne	1$
		clr.b	BALow

1$		bsr	Periodic6526

; Zyklus 10: Daten von Sprite 7 lesen
VIC.10		SprDataAccess 7,1
		SprDataAccess 7,2
		DisplayIfBadLine
		addq.w	#8,RASTERX

		bsr	Periodic6526

; Zyklus 11: Refresh, BA rücksetzen
VIC.11		RefreshAccess
		DisplayIfBadLine
		addq.w	#8,RASTERX

		clr.b	BALow

		bsr	Periodic6526

; Zyklus 12: Refresh. Bei Bad Line den Matrixzugriff anschalten.
;  Ab hier beginnt die Grafikdarstellung
VIC.12		bsr	DrawBackground
		DrawBorder
		RefreshAccess
		FetchIfBadLine
		addq.w	#8,RASTERX

		bsr	Periodic6526

; Zyklus 13: Refresh. Bei Bad Line den Matrixzugriff anschalten.
;  RASTERX zurücksetzen
VIC.13		bsr	DrawBackground
		DrawBorder
		RefreshAccess
		FetchIfBadLine
		move.w	#4,RASTERX

		bsr	Periodic6526

; Zyklus 14: Refresh. VCBASE->VCCOUNT. Bei Bad Line den Matrixzugriff
;  anschalten und den RC zurücksetzen
VIC.14		bsr	DrawBackground
		DrawBorder
		RefreshAccess
		RCIfBadLine
		addq.w	#8,RASTERX

		move.w	VCBASE,VCCOUNT

		bsr	Periodic6526

; Zyklus 15: Refresh und Matrixzugriff. MCBASE um 2 erhöhen
VIC.15		bsr	DrawBackground
		DrawBorder
		RefreshAccess
		FetchIfBadLine
		addq.w	#8,RASTERX

		McbaseInc2 0
		McbaseInc2 1
		McbaseInc2 2
		McbaseInc2 3
		McbaseInc2 4
		McbaseInc2 5
		McbaseInc2 6
		McbaseInc2 7

		moveq	#0,INDEX	;Index in Matrixzeile
		MatrixAccess

		bsr	Periodic6526

; Zyklus 16: Grafikzugriff und Matrixzugriff. MCBASE um 1 erhöhen und testen,
;  ob Sprite-DMA abgeschaltet werden kann
VIC.16		bsr	DrawBackground
		DrawBorder
		GraphicsAccess
		FetchIfBadLine		;Muß nach GraphicsAccess stehen,
					; damit bei einem STA $D011 im
					; Zyklus zuvor noch kein Grafikzugriff
					; gemacht wird
		addq.w	#8,RASTERX

		CheckSprOff 0
		CheckSprOff 1
		CheckSprOff 2
		CheckSprOff 3
		CheckSprOff 4
		CheckSprOff 5
		CheckSprOff 6
		CheckSprOff 7

		MatrixAccess

		bsr	Periodic6526

; Zyklus 17: Grafikzugriff und Matrixzugriff, im 40-Spalten-Modus
;  Rahmen abschalten. Ab hier beginnt die Darstellung des Textfensters
VIC.17		tst.b	IS38COL
		bne	1$

		move.w	RASTERY,d6
		cmp.w	DYSTOP,d6
		bne	2$
		st.b	UDBORDERON
		bra	1$

2$		btst	#4,CTRL1
		beq	3$
		cmp.w	DYSTART,d6
		bne	3$
		clr.b	UDBORDERON
		bra	4$

3$		tst.b	UDBORDERON
		bne	1$
4$		clr.b	BORDERON
1$
		bsr	DrawBackground	;Verhindert Grafikmüll, falls XSCROLL>0
		bsr	DrawGraphics
		DrawBorder
		GraphicsAccess
		FetchIfBadLine
		addq.w	#8,RASTERX
		MatrixAccess

		bsr	Periodic6526

; Zyklus 18..54: Grafikzugriff und Matrixzugriff, im 38-Spalten-Modus
;  Rahmen abschalten
VIC.18		tst.b	IS38COL
		beq	1$

		move.w	RASTERY,d6
		cmp.w	DYSTOP,d6
		bne	2$
		st.b	UDBORDERON
		bra	1$

2$		btst	#4,CTRL1
		beq	3$
		cmp.w	DYSTART,d6
		bne	3$
		clr.b	UDBORDERON
		bra	4$

3$		tst.b	UDBORDERON
		bne	1$
4$		clr.b	BORDERON
1$
		moveq	#54-18,d6
VIC.Loop	bsr	DrawGraphics
		DrawBorder
		GraphicsAccess
		FetchIfBadLine
		addq.w	#8,RASTERX
		MatrixAccess
		move.b	CHARDATA,LASTCHARDATA	;Letztes Zeichen merken

		bsr	Periodic6526
		dbra	d6,VIC.Loop

; Zyklus 55: Letzter Grafikzugriff, Matrixzugriff abschalten.
;   Sprite-DMA anschalten, wenn Y-Koordinate richtig und SPEN-Bit gesetzt
;   (für alle Sprites). Sprite-Y-Expansion handhaben. BA für Sprite 0 setzen
VIC.55		bsr	DrawGraphics
		DrawBorder
		GraphicsAccess
		DisplayIfBadLine
		addq.w	#8,RASTERX

		CheckMYE 0
		CheckMYE 1
		CheckMYE 2
		CheckMYE 3
		CheckMYE 4
		CheckMYE 5
		CheckMYE 6
		CheckMYE 7

		CheckSpriteDMA

		btst	#0,SPRDMAON	;Sprite 0 an?
		bne	3$
		clr.b	BALow		;Nein, BA high
		bra	4$
3$		SetBALow		;Sonst BA low

4$		bsr	Periodic6526

; Zyklus 56: Im 38-Spalten-Modus Rahmen anschalten. Sprite-DMA anschalten,
;   wenn Y-Koordinate richtig und SPEN-Bit gesetzt (für alle Sprites).
;   BA für Sprite 0 setzen. Nach diesem Zyklus endet die Darstellung des
;   Textfensters
VIC.56		tst.b	IS38COL
		beq	1$
		st.b	BORDERON
1$
		bsr	DrawGraphics
		DrawBorder
		IdleAccess
		DisplayIfBadLine
		addq.w	#8,RASTERX
		CheckSpriteDMA

		bsr	Periodic6526

; Zyklus 57: Im 40-Spalten-Modus Rahmen anschalten, BA für Sprite 1 setzen,
;  Sprites malen
VIC.57		tst.b	IS38COL
		bne	1$
		st.b	BORDERON
1$
		tst.b	SPRDISPON	;Ist überhaupt ein Sprite z.Z. sichtbar?
		beq	3$
		tst.w	SpritesOn
		beq	3$
		DrawSprite 7
		DrawSprite 6
		DrawSprite 5
		DrawSprite 4
		DrawSprite 3
		DrawSprite 2
		DrawSprite 1
		DrawSprite 0
3$
		bsr	DrawBackground
		DrawBorder
		IdleAccess
		DisplayIfBadLine
		addq.w	#8,RASTERX

		btst	#1,SPRDMAON
		beq	2$
		SetBALow

2$		bsr	Periodic6526

; Zyklus 58: Spritezeiger 0 holen. Prüfen, ob RC=7. Wenn ja, Display
;  ausschalten und VCCOUNT->VCBASE machen. Wenn das Display an ist, den
;  RC erhöhen (bei einer Bad Line ist das Display immer an). Daten von
;  Sprite 0 lesen. MCBASE->MC machen
VIC.58		bsr	DrawBackground
		DrawBorder

		move.w	MC0BASE,MC0
		move.w	MC1BASE,MC1
		move.w	MC2BASE,MC2
		move.w	MC3BASE,MC3
		move.w	MC4BASE,MC4
		move.w	MC5BASE,MC5
		move.w	MC6BASE,MC6
		move.w	MC7BASE,MC7

		CheckSpriteDisp

		SprPtrAccess 0
		SprDataAccess 0,0

		cmp.w	#7,RC
		bne	1$
		move.w	VCCOUNT,VCBASE
		clr.b	DISPLAYSTATE

1$		tst.b	BADLINE
		bne	2$
		tst.b	DISPLAYSTATE
		beq	3$

2$		st.b	DISPLAYSTATE	;Dies erübrigt DisplayIfBadLine
		addq.w	#1,RC
		and.w	#7,RC

3$		addq.w	#8,RASTERX

		bsr	Periodic6526

; Zyklus 59: BA für Sprite 2 setzen. Daten von Sprite 0 lesen
VIC.59		bsr	DrawBackground
		DrawBorder
		SprDataAccess 0,1
		SprDataAccess 0,2
		DisplayIfBadLine
		addq.w	#8,RASTERX

		btst	#2,SPRDMAON
		beq	1$
		SetBALow

1$		bsr	Periodic6526

; Zyklus 60: Spritezeiger 1 holen. Nach diesem Zyklus endet
;  die Grafikdarstellung. BA rücksetzen, falls Sprite 1 und 2 aus.
;  Daten von Sprite 1 lesen
VIC.60		bsr	DrawBackground
		DrawBorder
		SprPtrAccess 1
		SprDataAccess 1,0
		DisplayIfBadLine
		addq.w	#8,RASTERX

		move.b	SPRDMAON,d0
		and.b	#$06,d0
		bne	1$
		clr.b	BALow

1$		bsr	Periodic6526

; Zyklus 61: BA für Sprite 3 setzen. Daten von Sprite 1 lesen
VIC.61		SprDataAccess 1,1
		SprDataAccess 1,2
		DisplayIfBadLine
		addq.w	#8,RASTERX

		btst	#3,SPRDMAON
		beq	1$
		SetBALow

1$		bsr	Periodic6526

; Zyklus 62: Spritezeiger 2 holen. BA rücksetzen, falls Sprite 2 und 3 aus.
;  Daten von Sprite 2 lesen
VIC.62		SprPtrAccess 2
		SprDataAccess 2,0
		DisplayIfBadLine
		addq.w	#8,RASTERX

		move.b	SPRDMAON,d0
		and.b	#$0c,d0
		bne	1$
		clr.b	BALow

1$		bsr	Periodic6526

; Zyklus 63: BA für Sprite 4 setzen. Daten von Sprite 2 lesen
VIC.63		SprDataAccess 2,1
		SprDataAccess 2,2
		DisplayIfBadLine
		addq.w	#8,RASTERX

		move.w	RASTERY,d6
		cmp.w	DYSTOP,d6
		bne	2$
		st.b	UDBORDERON
		bra	3$
2$		btst	#4,CTRL1
		beq	3$
		cmp.w	DYSTART,d6
		bne	3$
		clr.b	UDBORDERON
3$
		btst	#4,SPRDMAON
		beq	1$
		SetBALow

1$		bsr	Periodic6526
		bra	Main6569


*
* Darstellung der Grafik (8 Pixel)
* BUFFER: Zeiger in ChunkyBuf, darf nicht verändert werden
*

DrawGraphics	move.l	BUFFER,a0
		move.b	GFXDATA,d0
		add.w	XSCROLL,a0

		tst.b	UDBORDERON
		bne	DrNothing

		tst.b	DISPLAYSTATE
		beq	Dr3FFF

		move.w	DISPROCIDX,d1
		move.l	(GfxJmpTab,d1.w*4),a1
		jmp	(a1)

		CNOP	0,4
GfxJmpTab	dc.l	DrText
		dc.l	DrTextMulti
		dc.l	DrBitMap
		dc.l	DrBitMapMulti
		dc.l	DrTextECM
		dc.l	DrInvalid
		dc.l	DrInvalid
		dc.l	DrInvalid

Dr3FFF		move.b	B0C,d2		;Hintergrund
		moveq	#0,d3		;Vordergrund schwarz
		bra	DrawStd

DrTextECM	moveq	#0,d2
		move.b	CHARDATA,d2
		lsr.b	#6,d2
		move.b	(B0C,d2.l),d2	;Hintergrund
		move.b	COLDATA,d3	;Vordergrund
		bra	DrawStd

DrBitMap	move.b	CHARDATA,d2	;Hintergrund
		move.b	d2,d3
		lsr.b	#4,d3		;Vordergrund
		bra	DrawStd

DrText		move.b	B0C,d2		;Hintergrund
		move.b	COLDATA,d3	;Vordergrund

DrawStd		add.b	d0,d0		;Standard-Daten anzeigen
		bcc	11$
		move.b	d3,(a0)+
		bra	12$
11$		move.b	d2,(a0)+
12$
		add.b	d0,d0
		bcc	21$
		move.b	d3,(a0)+
		bra	22$
21$		move.b	d2,(a0)+
22$
		add.b	d0,d0
		bcc	31$
		move.b	d3,(a0)+
		bra	32$
31$		move.b	d2,(a0)+
32$
		add.b	d0,d0
		bcc	41$
		move.b	d3,(a0)+
		bra	42$
41$		move.b	d2,(a0)+
42$
		add.b	d0,d0
		bcc	51$
		move.b	d3,(a0)+
		bra	52$
51$		move.b	d2,(a0)+
52$
		add.b	d0,d0
		bcc	61$
		move.b	d3,(a0)+
		bra	62$
61$		move.b	d2,(a0)+
62$
		add.b	d0,d0
		bcc	71$
		move.b	d3,(a0)+
		bra	72$
71$		move.b	d2,(a0)+
72$
		add.b	d0,d0
		bcc	81$
		move.b	d3,(a0)+
		bra	82$
81$		move.b	d2,(a0)+
82$		rts

DrBitMapMulti	move.b	CHARDATA,d2
		move.b	d2,d3		;10
		lsr.b	#4,d2		;01
		move.b	COLDATA,d4	;11
		bra	DrawMulti

DrTextMulti	move.b	COLDATA,d4	;11
		bclr	#3,d4		;Bit 3 gelöscht -> Standard-Text
		beq	DrText
		move.b	B1C,d2		;01
		move.b	B2C,d3		;10

DrawMulti	move.b	B0C,d1
		add.b	d0,d0		;Multicolor-Daten anzeigen
		bcc	11$
		add.b	d0,d0
		bcc	12$
		move.b	d4,(a0)+	;11
		move.b	d4,(a0)+
		bra	14$
12$		move.b	d3,(a0)+	;10
		move.b	d3,(a0)+
		bra	14$
11$		add.b	d0,d0
		bcc	13$
		move.b	d2,(a0)+	;01
		move.b	d2,(a0)+
		bra	14$
13$		move.b	d1,(a0)+	;00
		move.b	d1,(a0)+
14$
		add.b	d0,d0
		bcc	21$
		add.b	d0,d0
		bcc	22$
		move.b	d4,(a0)+	;11
		move.b	d4,(a0)+
		bra	24$
22$		move.b	d3,(a0)+	;10
		move.b	d3,(a0)+
		bra	24$
21$		add.b	d0,d0
		bcc	23$
		move.b	d2,(a0)+	;01
		move.b	d2,(a0)+
		bra	24$
23$		move.b	d1,(a0)+	;00
		move.b	d1,(a0)+
24$
		add.b	d0,d0
		bcc	31$
		add.b	d0,d0
		bcc	32$
		move.b	d4,(a0)+	;11
		move.b	d4,(a0)+
		bra	34$
32$		move.b	d3,(a0)+	;10
		move.b	d3,(a0)+
		bra	34$
31$		add.b	d0,d0
		bcc	33$
		move.b	d2,(a0)+	;01
		move.b	d2,(a0)+
		bra	34$
33$		move.b	d1,(a0)+	;00
		move.b	d1,(a0)+
34$
		add.b	d0,d0
		bcc	41$
		add.b	d0,d0
		bcc	42$
		move.b	d4,(a0)+	;11
		move.b	d4,(a0)+
		bra	44$
42$		move.b	d3,(a0)+	;10
		move.b	d3,(a0)+
		bra	44$
41$		add.b	d0,d0
		bcc	43$
		move.b	d2,(a0)+	;01
		move.b	d2,(a0)+
		bra	44$
43$		move.b	d1,(a0)+	;00
		move.b	d1,(a0)+
44$		rts

DrInvalid	clr.l	(a0)+
		clr.l	(a0)
		rts


*
* Darstellung der Hintergrundfarbe (8 Pixel)
* BUFFER: Zeiger in ChunkyBuf, darf nicht verändert werden
*

DrawBackground	move.l	BUFFER,a0
DrNothing	move.b	B0C,d0

		move.w	DISPROCIDX,d1
		move.l	(BackJmpTab,d1.w*4),a1
		jmp	(a1)

BackJmpTab	dc.l	BackDoIt
		dc.l	BackDoIt
		dc.l	BackBitMap
		dc.l	BackDoIt
		dc.l	BackECM
		dc.l	BackBlack
		dc.l	BackBlack
		dc.l	BackBlack

BackECM		moveq	#0,d0
		move.b	LASTCHARDATA,d0	;Letztes Zeichen
		move.b	(B0C,d0.l),d0
		bra	BackDoIt

BackBlack	moveq	#0,d0
		bra	BackDoIt

BackBitMap	move.b	LASTCHARDATA,d0	;Letztes Zeichen

BackDoIt	move.b	d0,(a0)+
		move.b	d0,(a0)+
		move.b	d0,(a0)+
		move.b	d0,(a0)+
		move.b	d0,(a0)+
		move.b	d0,(a0)+
		move.b	d0,(a0)+
		move.b	d0,(a0)
		rts


*
* VBlank
*

; Zähler zurücksetzen
TheVBlank	moveq	#0,d6		;Rasterzähler auf Null
		clr.w	RASTERY
		clr.w	VCBASE
		lea	ChunkyBuf,BUFFER
		st.b	REFCNT		;Refreshzähler zurücksetzen
		clr.b	LPTRIGGERED	;Lightpen wieder freigeben

		bsr	CountTODs	;TODs zählen

		subq.w	#1,SkipCounter	;Bild überspringen?
		bne	1$
		move.w	SkipLatch,SkipCounter

; Grafik darstellen
		jsr	_RedrawDisplay

1$		tst.w	IRQRASTERY	;IRQ in Zeile 0?
		bne	10$
		bra	DoRasterIRQ	;Ja, IRQ auslösen
10$		rts


*
* Raster-IRQ auslösen
*

DoRasterIRQ	or.b	#$01,IRQFLAG	;Ja, IRST-Bit setzen
		btst	#0,IRQMASK	;Raster-IRQ erlaubt?
		beq	2$
		or.b	#$80,IRQFLAG	;Ja, IRQ-Bit setzen
		tst.w	IntIsIRQ	;IRQ schon ausgelöst?
		bne	1$
		move.l	CycleCounter,FirstIRQCycle ;Nein, Zyklus merken
1$		st.b	IntIsVICIRQ	; und Interrupt auslösen
2$		rts


*
* Ein Sprite zeichnen
* d0.l: Spritedaten
* d1.w: X-Koordinate
* d2.b: Spritefarbe
*

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

		lea	ChunkyBuf+16,a0
		add.w	d1,a0

		moveq	#0,d1		;Pixelzähler
DSSLoop		add.l	d0,d0		;Pixel gesetzt?
		bcc	DSSNext
		move.b	d2,(a0)

DSSNext		addq.l	#1,a0
		addq.w	#1,d1
		cmp.w	#24,d1
		bne	DSSLoop
DSSRts		rts

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

		lea	ChunkyBuf+16,a0
		add.w	d1,a0

		moveq	#0,d1		;Pixelzähler
DSSELoop	add.l	d0,d0		;Pixel gesetzt?
		bcc	DSSENext
		move.b	d2,(a0)
		move.b	d2,1(a0)

DSSENext	addq.l	#2,a0
		addq.w	#2,d1
		cmp.w	#48,d1
		bne	DSSELoop
DSSERts		rts

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

		lea	ChunkyBuf+16,a0
		add.w	d1,a0

		moveq	#0,d1		;Pixelzähler
DSMLoop		add.l	d0,d0
		bcc	DSMFirstIs0
		add.l	d0,d0
		bcc	DSMDraw10
		move.b	MM1,(a0)	;11
		move.b	MM1,1(a0)
		bra	DSMNext
DSMDraw10	move.b	d2,(a0)		;10
		move.b	d2,1(a0)
		bra	DSMNext
DSMFirstIs0	add.l	d0,d0
		bcc	DSMNext
		move.b	MM0,(a0)	;01
		move.b	MM0,1(a0)

DSMNext		addq.l	#2,a0
		addq.w	#2,d1
		cmp.w	#24,d1
		bne	DSMLoop
DSMRts		rts

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

		lea	ChunkyBuf+16,a0
		add.w	d1,a0

		moveq	#0,d1		;Pixelzähler
DSMELoop	add.l	d0,d0
		bcc	DSMEFirstIs0
		add.l	d0,d0
		bcc	DSMEDraw10
		move.b	MM1,(a0)	;11
		move.b	MM1,1(a0)
		move.b	MM1,2(a0)
		move.b	MM1,3(a0)
		bra	DSMENext
DSMEDraw10	move.b	d2,(a0)		;10
		move.b	d2,1(a0)
		move.b	d2,2(a0)
		move.b	d2,3(a0)
		bra	DSMENext
DSMEFirstIs0	add.l	d0,d0
		bcc	DSMENext
		move.b	MM0,(a0)	;01
		move.b	MM0,1(a0)
		move.b	MM0,2(a0)
		move.b	MM0,3(a0)

DSMENext	addq.l	#4,a0
		addq.w	#4,d1
		cmp.w	#48,d1
		bne	DSMELoop
DSMERts		rts


**
** Datenbereich
**

; Grafikpuffer
		SECTION	"BSS",BSS
		XDEF	_ChunkyBuf
_ChunkyBuf
ChunkyBuf	ds.b	DisplayX*DisplayY


		SECTION	"__MERGED",BSS

DisplayID	ds.l	1	;Prefs: DisplayID des Screens
ScreenType	ds.w	1	;Prefs: Typ der Screen-Ansteuerung
NormalCycles	ds.w	1	;Unbenutzt
BadLineCycles	ds.w	1	;Unbenutzt
SpritesOn	ds.w	1	;Prefs: Sprite-Darstelung angeschaltet
Collisions	ds.w	1	;Prefs: Sprite-Kollisionen angeschaltet
Overscan	ds.w	1	;Prefs: Overscan-Typ für Amiga-Modi
DirectVideo	ds.w	1	;Unbenutzt

SkipCounter	ds.w	1
		XDEF	_SkipLatch
_SkipLatch
SkipLatch	ds.w	1	;Prefs: Nur jedes nte Bild darstellen
		XDEF	_LimitSpeed
_LimitSpeed
LimitSpeed	ds.w	1	;Prefs: Speed Limiter

; VIC-Register
VICREGS
		ds.b	1	;Sprite-Positionen, X-Werte unbenutzt,
M0Y		ds.b	1	; stattdessen SPRX*
		ds.b	1
M1Y		ds.b	1
		ds.b	1
M2Y		ds.b	1
		ds.b	1
M3Y		ds.b	1
		ds.b	1
M4Y		ds.b	1
		ds.b	1
M5Y		ds.b	1
		ds.b	1
M6Y		ds.b	1
		ds.b	1
M7Y		ds.b	1
MX8		ds.b	1	;MSBs der X-Positionen
CTRL1		ds.b	1	;Steuerreg. 1
		ds.b	1	;Rasterzeile, ersetzt durch 16-Bit RASTERY
LPX		ds.b	1	;Lightpen X
LPY		ds.b	1	;Lightpen Y
SPREN		ds.b	1	;Sprite eingeschaltet?
CTRL2		ds.b	1	;Steuerreg. 2
MYE		ds.b	1	;Sprite-Y-Expansion
VBASE		ds.b	1	;Basisadressen
IRQFLAG		ds.b	1	;Interruptreg.
IRQMASK		ds.b	1
MDP		ds.b	1	;Sprite-Priorität
MMC		ds.b	1	;Sprite-Multicolor
MXE		ds.b	1	;Sprite-X-Expansion
CLXSPR		ds.b	1	;Kollisionsreg.
CLXBGR		ds.b	1
EC		ds.b	1	;Rahmenfarbe
B0C		ds.b	1	;Hintergrundfarbe 0
B1C		ds.b	1	;Hintergrundfarbe 1
B2C		ds.b	1	;Hintergrundfarbe 2
B3C		ds.b	1	;Hintergrundfarbe 3
MM0		ds.b	1	;Sprite-Multicolorfarbe 0
MM1		ds.b	1	;Sprite-Multicolorfarbe 1
M0C		ds.b	1	;Farbe Sprite 0
M1C		ds.b	1	;Farbe Sprite 1
M2C		ds.b	1	;Farbe Sprite 2
M3C		ds.b	1	;Farbe Sprite 3
M4C		ds.b	1	;Farbe Sprite 4
M5C		ds.b	1	;Farbe Sprite 5
M6C		ds.b	1	;Farbe Sprite 6
M7C		ds.b	1	;Farbe Sprite 7

		CNOP	0,4
RASTERX		ds.w	1	;Aktuelle X-Position des Rasterstrahls (für Lightpen)
RASTERY		ds.w	1	;Aktuelle Rasterzeile
IRQRASTERY	ds.w	1	;Rasterzeile, bei der ein IRQ ausgelöst wird
RC		ds.w	1	;Rasterzähler RC
VCBASE		ds.w	1	;VC-Zwischenspeicher
VCCOUNT		ds.w	1	;VC-Zähler
MC0		ds.w	1	;Spritedatenzähler 0
MC1		ds.w	1	;Spritedatenzähler 1
MC2		ds.w	1	;Spritedatenzähler 2
MC3		ds.w	1	;Spritedatenzähler 3
MC4		ds.w	1	;Spritedatenzähler 4
MC5		ds.w	1	;Spritedatenzähler 5
MC6		ds.w	1	;Spritedatenzähler 6
MC7		ds.w	1	;Spritedatenzähler 7
MC0BASE		ds.w	1	;MC-Zwischenspeicher
MC1BASE		ds.w	1
MC2BASE		ds.w	1
MC3BASE		ds.w	1
MC4BASE		ds.w	1
MC5BASE		ds.w	1
MC6BASE		ds.w	1
MC7BASE		ds.w	1
SPRX0		ds.w	1	;16-Bit Sprite-X-Koordinaten
SPRX1		ds.w	1
SPRX2		ds.w	1
SPRX3		ds.w	1
SPRX4		ds.w	1
SPRX5		ds.w	1
SPRX6		ds.w	1
SPRX7		ds.w	1
DYSTART		ds.w	1	;Aktuelle Werte des Randbereichs
DYSTOP		ds.w	1	; (für Rahmenstufe)
XSCROLL		ds.w	1	;X-Scroll-Wert
YSCROLL		ds.w	1	;Y-Scroll-Wert

CIAVABASE	ds.w	1	;16-Bit Basisadresse durch CIA-VA14/15
				;xx00000000000000
MATRIXBASE	ds.w	1	;16-Bit Videomatrixbasis
				;00xxxx0000000000
CHARBASE	ds.w	1	;16-Bit Zeichengeneratorbasis
				;00xxx00000000000
BITMAPBASE	ds.w	1	;16-Bit Bitmapbasis
				;00x0000000000000
SPRPTR		ds.w	8	;Sprite-Datenzeiger
				;00xxxxxxxx000000

BADLINE		ds.b	1	;Flag: Bad-Line-Zustand
DISPLAYSTATE	ds.b	1	;Flag: Display-Zustand
BADLINEENABLE	ds.b	1	;Flag: Bad Line erlaubt (DEN)
BORDERON	ds.b	1	;Flag: Rahmen an (Haupt-Rahmenflipflop)
UDBORDERON	ds.b	1	;Flag: Oberer/unterer Rahmen an (vertikales Rahmenflipflop)
IS38COL		ds.b	1	;Flag: 38 Spalten
VBLANKING	ds.b	1	;Flag: In Zyklus 2 VBlank
LPTRIGGERED	ds.b	1	;Flag: Lightpen wurde in diesem Frame schon getriggert
SPRDMAON	ds.b	1	;8 Flags: Sprite-DMA angeschaltet
SPRDISPON	ds.b	1	;8 Flags: Sprite-Anzeige angeschaltet
SPREXPY		ds.b	1	;8 Flags: MC->MCBASE machen
REFCNT		ds.b	1	;Refreshzähler

	IFNE	DE00_COMPATIBLE
LastVICByte	ds.b	1	;Zuletzt vom VIC gelesenes Byte
				; (für $DE00-Kompatibilität)
	ENDC

		CNOP	0,4
DISPROCIDX	ds.w	1	;Anzeigestufe: Index des Darstellungsmodus
CHARDATA	ds.b	1	;Character-Byte im "Schieberegister"
COLDATA		ds.b	1	;Farbnybble im "Schieberegister"
GFXDATA		ds.b	1	;Grafikdaten im "Schieberegister"
LASTCHARDATA	ds.b	1	;Letztes Character-Byte einer Zeile

		CNOP	0,4
SPR0DATA	ds.b	4	;Spritedaten 0
SPR1DATA	ds.b	4	;Spritedaten 1
SPR2DATA	ds.b	4	;Spritedaten 2
SPR3DATA	ds.b	4	;Spritedaten 3
SPR4DATA	ds.b	4	;Spritedaten 4
SPR5DATA	ds.b	4	;Spritedaten 5
SPR6DATA	ds.b	4	;Spritedaten 6
SPR7DATA	ds.b	4	;Spritedaten 7

		CNOP	0,4
BORDERLONG	ds.l	1	;Rahmenfarbe als Langwort
CycleCounter	ds.l	1	;Zyklenzähler
FirstBACycle	ds.l	1	;Zyklus, an dem BA zuletzt auf low ging

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

; Sprungtabelle für Speicherzugriff: Ein Eintrag pro Seite
MemReadTab	ds.l	256

; Interner Videomatrix-Puffer
MatrixLine	ds.b	80	;Jeweils 1 Byte Zeichen, 1 Byte Farbe

		XDEF	_CURRENTA5
_CURRENTA5	ds.l	1	;Unbenutzt

		END
