*
* SD64evd.asm - ShapeShifter external video driver for PiccoloSD64
*
* $VER: SD64evd.asm 1.0 (20.05.96)
*
* By Francesco Doro (fdoro@gpnet.it)
*

	incdir	"INCLUDE_I:"
		
	INCLUDE	"exec/types.i"
	INCLUDE	"exec/macros.i"
	INCLUDE	"exec/memory.i"
	INCLUDE	"intuition/intuition.i"
	INCLUDE	"utility/tagitem.i"
	INCLUDE	"exec/alerts.i"
	INCLUDE	"shapeextvideo.i"

*
* Definition of our private context structure for storing local variables
*

 STRUCTURE	MyContext,0
	APTR	conIntBase
	APTR	conGfxBase
	APTR	conDOSBase
	APTR	conExpBase

	APTR	conScreen	;The screen
	APTR	conViewPort	;The screen's ViewPort
	APTR	conBitMap	;The screen's RastPort

	APTR	conVirtualMem	;Buffer base in SD64 memory
	APTR	conDisplayMem	;Display base in SD64 memory
	APTR	conBLTSource	;Source start address for blitter
	APTR	conSD64reg	;Base of SD64 registers
	WORD	con4Meg		;Flag for 4 meg boards
	WORD	conBLTWidth	;Width of the blit
	WORD	conBLTHeight	;Height of the blit

	WORD	conVideoMode	;Video mode (VMODE_*)

 LABEL	MyContext_SIZEOF

*
* This is the driver header
*

		EVHEADER DriverTags

*
* The header tags that describe the driver and provide pointers to
* the driver's routines
*

DriverTags	dc.l	SHEV_Level,1		;Interface level 1
		dc.l	SHEV_Version,1
		dc.l	SHEV_Revision,0
		dc.l	SHEV_Name,DriverName
		dc.l	SHEV_ID,DriverID
		dc.l	SHEV_Author,DriverAuthor

		dc.l	SHEV_OpenScreen,MyOpenScreen
		dc.l	SHEV_CloseScreen,MyCloseScreen
		dc.l	SHEV_Refresh,Refresh
		dc.l	TAG_END,0

DriverName	dc.b	"PiccoloSD64 24 bit Driver",0
		CNOP	0,4
DriverID	dc.b	"$VER: SD64evd 1.0 by Francesco Doro (20.05.96)",13,10,0
		CNOP	0,4
DriverAuthor	dc.b	"Francesco Doro (fdoro@gpnet.it)",0
		CNOP	0,4


*****************
**   REFRESH   **
*****************
* a2: Context pointer (never NULL)

* Since the SD64 pixel format is RGBX while Mac's one is XRGB
* we only have to do a copy from offset #1 of the Mac's display memory
* to offset #0 of the real display memory. This is difficult to do for CPU
* but easy for the blitter, since it doesn't care about odd or even address.
* Sorry for multitasking and vblank disabled; must be sure nothing accesses
* video memory during the blit.

Refresh
		movem.l	d2-d7/a2-a6,-(sp)
		move.l	4,a6
		jsr	-132(a6)		;Forbid
		move.w	$dff01c,d0
		andi.w	#$0020,d0
		ori.w	#$8000,d0
		move.w	d0,-(a7)
		move.w	#$0020,$dff09a		;disable vblank irq

		move.l	conSD64reg(a2),a0

		move.w	#$1f1e,$3c4(a0)		;MCLK
		move.w	#$3104,$3ce(a0)		;reset blitter

		move.w	conBLTWidth(a2),d0	;source pitch
		move.w	#$2600,d1
		move.b	d0,d1
		move.w	d1,$3ce(a0)
		move.b	#$27,d0
		ror.w	#8,d0
		move.w	d0,$3ce(a0)

		move.w	conBLTWidth(a2),d0	;dest pitch
		move.w	#$2400,d1
		move.b	d0,d1
		move.w	d1,$3ce(a0)
		move.b	#$25,d0
		ror.w	#8,d0
		move.w	d0,$3ce(a0)

		move.w	conBLTWidth(a2),d0	;width
		subq.w	#1,d0
		move.w	#$2000,d1
		move.b	d0,d1
		move.w	d1,$3ce(a0)
		move.b	#$21,d0
		ror.w	#8,d0
		move.w	d0,$3ce(a0)

		move.w	conBLTHeight(a2),d0	;height
		subq.w	#1,d0
		move.w	#$2200,d1
		move.b	d0,d1
		move.w	d1,$3ce(a0)
		move.b	#$23,d0
		ror.w	#8,d0
		move.w	d0,$3ce(a0)

		move.l	#0,d0			;dest address
		move.w	#$2800,d1
		move.b	d0,d1
		move.w	d1,$3ce(a0)
		move.b	#$29,d0
		ror.w	#8,d0
		move.w	d0,$3ce(a0)
		swap	d0
		move.w	#$2a00,d1
		move.b	d0,d1
		move.w	d1,$3ce(a0)

		move.l	conBLTSource(a2),d0	;source address
		move.w	#$2c00,d1
		move.b	d0,d1
		move.w	d1,$3ce(a0)
		move.b	#$2d,d0
		ror.w	#8,d0
		move.w	d0,$3ce(a0)
		swap	d0
		move.w	#$2e00,d1
		move.b	d0,d1
		move.w	d1,$3ce(a0)

		move.w	#$3000,$3ce(a0)		;BLT mode
		move.w	#$2f00,$3ce(a0)		;write mask
		move.w	#$320d,$3ce(a0)		;BLT operation (copy from source)
		move.w	#$3102,$3ce(a0)		;go!

		move.b	#$31,$3ce(a0)		;We must wait until
waitblt		nop				;blitter finish, no good
		nop				;to access video memory
		nop				;during a blit
		nop
		btst	#3,$3cf(a0)
		bne.s	waitblt

		move.w	(a7)+,$dff09a
		move.l	4,a6
		jsr	-138(a6)		;Permit
		movem.l	(sp)+,d2-d7/a2-a6
		moveq	#0,d0
		rts


*
* The OpenScreen routine
* a0: Taglist with input parameters
* a1: Taglist with output parameters
* a6: Base of utility.library
*

MyOpenScreen	movem.l	d2-d7/a2-a6,-(sp)
		move.l	a0,a4			;a4: Input taglist
		move.l	a1,a5			;a5: Output taglist
		move.l	a6,d7			;d7: UtilityBase


; Allocate memory for context

		move.l	4,a6
		move.l	#MyContext_SIZEOF,d0
		move.l	#$00010001,d1
		jsr	-684(a6)		:AllocVec
		tst.l	d0
		beq	OpenFailed1
		move.l	d0,a2			;a2: Context


; Open intuition.library

		move.l	4,a6
		lea	IntName(pc),a1
		moveq	#37,d0
		jsr	-552(a6)		;OpenLibrary
		move.l	d0,conIntBase(a2)
		beq	OpenFailed2


; Open graphics.library

		move.l	4,a6
		lea	GfxName(pc),a1
		moveq	#37,d0
		jsr	-552(a6)		;OpenLibrary
		move.l	d0,conGfxBase(a2)
		beq	OpenFailed3


; Open dos.library

		move.l	4,a6
		lea	DOSName(pc),a1
		moveq	#37,d0
		jsr	-552(a6)		;OpenLibrary
		move.l	d0,conDOSBase(a2)
		beq	OpenFailed4


; Open expansion.library

		move.l	4,a6
		lea	ExpName(pc),a1
		moveq	#0,d0
		jsr	-552(a6)		;OpenLibrary
		move.l	d0,conExpBase(a2)
		beq	OpenFailed12


; Check board and get video memory address

		move.l	conExpBase(a2),a6
		suba.l	a0,a0
		move.l	#$893,d0
		moveq	#10,d1
		jsr	-72(a6)			;FindConfigDev
		tst.l	d0
		beq	OpenFailed13
		move.l	d0,a0
		move.l	$20(a0),d0
		move.l	d0,conDisplayMem(a2)
		beq	OpenFailed13
		addi.l	#$100000,d0
		move.l	d0,conVirtualMem(a2)
		move.l	#$100000,conBLTSource(a2)
		move.w	#0,con4Meg(a2)
		move.l	$24(a0),d0
		cmpi.l	#$01000000,d0		;is the size 4 Meg?
		bne.s	findreg
		move.w	#1,con4Meg(a2)

findreg		move.l	conExpBase(a2),a6
		suba.l	a0,a0
		move.l	#$893,d0
		moveq	#11,d1
		jsr	-72(a6)			;FindConfigDev
		tst.l	d0
		beq	OpenFailed13
		move.l	d0,a0
		move.l	$20(a0),d0
		move.l	d0,conSD64reg(a2)
		beq	OpenFailed13


; Verify whether really this is a 4 meg SD64

		tst.w	con4Meg(a2)
		beq.s	no4
		movea.l	conDisplayMem(a2),a0
		move.l	a0,a1
		adda.l	#$200000,a1
		move.l	#$ff,d0
		moveq	#0,d1
chk.1		move.l	d0,(a0)+
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		move.l	d1,(A1)+
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		addq.l	#1,d1
		dbra	d0,chk.1
		movea.l	conDisplayMem(a2),a0
		move.l	a0,a1
		adda.l	#$200000,a1
		move.l	#$ff,d0
		moveq	#0,d1
chk.2		cmp.l	(a0)+,d0
		bne.s	chk.3
		cmp.l	(a1)+,d1
		bne.s	chk.3
		addq.l	#1,d1
		dbra	d0,chk.2
		bra.s	chk.4

chk.3		move.w	#0,con4Meg(a2)
chk.4		tst.w	con4Meg(a2)
		beq.s	no4
		addi.l	#$100000,conVirtualMem(a2)
		addi.l	#$100000,conBLTSource(a2)
no4		addq.l	#1,conBLTSource(a2)


; Store context pointer in output taglist

		move.l	d7,a6
		move.l	a5,a0
		move.l	#SHEV_Context,d0
		jsr	-30(a6)		;FindTagItem
		move.l	d0,a0
		move.l	a2,ti_Data(a0)



; Get video mode and set the refresh type and screen depth accordingly
; This driver only supports VMODE_24BIT

		move.l	d7,a6
		move.l	a4,a0
		move.l	#SHEV_VideoMode,d0
		jsr	-36(a6)		;GetTagData
		move.w	d0,conVideoMode(a2)
		cmp.l	#VMODE_24BIT,d0
		bne	OpenFailed5
		move.l	a5,a0
		move.l	#SHEV_RefreshType,d0
		jsr	-30(a6)		;FindTagItem
		tst.l	d0
		beq	OpenFailed6
		move.l	d0,a1
		move.l	#RTYPE_CUSTOM,ti_Data(a1)
		move.l	#24,ScrDepth


; Extract screen parameters from input taglist

		move.l	d7,a6
		move.l	a4,a0
		move.l	#SHEV_ScreenX,d0
		moveq	#0,d1
		jsr	-36(a6)		;GetTagData
		move.l	d0,ScrWidth
		move.l	d0,-(a7)
		lsl.l	#2,d0
		move.w	d0,conBLTWidth(a2)

		move.l	a4,a0
		move.l	#SHEV_ScreenY,d0
		moveq	#0,d1
		jsr	-36(a6)		;GetTagData
		move.l	d0,ScrHeight
		move.w	d0,conBLTHeight(a2)
		move.l	d0,d1
		move.l	(a7)+,d0
		swap	d0
		move.w	d1,d0

		cmpi.l	#$02000180,d0
		beq.s	s512x384
		cmpi.l	#$024001b0,d0
		beq.s	s576x432
		cmpi.l	#$02800190,d0
		beq.s	s640x400
		cmpi.l	#$028001e0,d0
		beq.s	s640x480
		cmpi.l	#$03000240,d0
		beq.s	s768x576
		cmpi.l	#$03200258,d0
		beq.s	s800x600
		cmpi.l	#$03400270,d0
		beq.s	s832x624

		bra	OpenFailed7

s512x384
		bra.s	okscr

s576x432
		bra.s	okscr

s640x400
		bra.s	okscr

s640x480
		tst.w	con4Meg(a2)
		beq	OpenFailed8
		bra.s	okscr

s768x576
		tst.w	con4Meg(a2)
		beq	OpenFailed8
		bra.s	okscr

s800x600
		tst.w	con4Meg(a2)
		beq	OpenFailed8
		bra.s	okscr

s832x624
		tst.w	con4Meg(a2)
		beq	OpenFailed8
		bra.s	okscr

		nop
okscr		move.l	a4,a0
		move.l	#SHEV_DisplayID,d0
		moveq	#0,d1
		jsr	-36(a6)		;GetTagData
		move.l	d0,ScrDisplayID

		move.l	a4,a0
		move.l	#SHEV_OverscanType,d0
		moveq	#OSCAN_TEXT,d1
		jsr	-36(a6)		;GetTagData
		move.l	d0,ScrOverscan


; Open the screen and store pointer in output taglist

		move.l	conIntBase(a2),a6
		sub.l	a0,a0
		lea	ScreenTags,a1
		jsr	-612(a6)	;OpenScreenTagList
		move.l	d0,a3		;a3: Screen
		move.l	d0,conScreen(a2)
		beq	OpenFailed9

ScreenOpened	move.l	d7,a6
		move.l	a5,a0
		move.l	#SHEV_Screen,d0
		jsr	-30(a6)		;FindTagItem
		move.l	d0,a0
		move.l	a3,ti_Data(a0)


; Extract our private data

		lea	sc_ViewPort(a3),a0
		move.l	a0,conViewPort(a2)
		lea	sc_RastPort(a3),a0
		move.l	rp_BitMap(a0),conBitMap(a2)


; Extract all the other data that the caller wants

		move.l	d7,a6
		move.l	a5,a0
		move.l	#SHEV_ScreenBase,d0
		jsr	-30(a6)		;FindTagItem
		tst.l	d0
		beq	OpenFailed10
		move.l	d0,a1
		move.l	conVirtualMem(a2),ti_Data(a1)

		move.l	d7,a6
		move.l	a5,a0
		move.l	#SHEV_BytesPerRow,d0
		jsr	-30(a6)		;FindTagItem
		tst.l	d0
		beq	OpenFailed11
		move.l	d0,a1
		moveq	#0,d0
		move.w	conBLTWidth(a2),d0
		move.l	d0,ti_Data(a1)


; Everything is OK

		movem.l	(sp)+,d2-d7/a2-a6
		moveq	#0,d0
		rts

; An error occurred

OpenFailed	movem.l	(sp)+,d2-d7/a2-a6
		moveq	#-1,d0
		rts

OpenFailed1
		bra.s	OpenFailed

OpenFailed2
		bra.s	OpenFailed

OpenFailed3
		bra.s	OpenFailed

OpenFailed4
		bra.s	OpenFailed

OpenFailed5
		lea	err5(pc),a0
		bra.s	doerr

OpenFailed6
		lea	err6(pc),a0
		bra.s	doerr

OpenFailed7
		lea	err7(pc),a0
		bra.s	doerr

OpenFailed8
		lea	err8(pc),a0
		bra.s	doerr

OpenFailed9
		lea	err9(pc),a0
		bra.s	doerr

OpenFailed10
		lea	err10(pc),a0
		bra.s	doerr

OpenFailed11
		lea	err11(pc),a0
		bra.s	doerr

OpenFailed12
		lea	err12(pc),a0
		bra.s	doerr

OpenFailed13
		lea	err13(pc),a0
		bra.s	doerr


; Show error message

		nop
doerr		bsr.s	doreq
		bra	OpenFailed

doreq		movem.l	d0-a6,-(a7)
		move.l	conIntBase(a2),a6
		lea	easyreq(pc),a1
		move.l	a0,es_TextFormat(a1)
		suba.l	a0,a0
		suba.l	a2,a2
		suba.l	a3,a3
		jsr	-588(a6)	;EasyRequestArgs
		movem.l	(a7)+,d0-a6
		rts


*
* The CloseScreen routine
* a0: Taglist with input parameters
* a1: Taglist with output parameters
* a2: Context pointer (never NULL)
* a6: Base of utility.library
*

MyCloseScreen
		movem.l	d2-d7/a2-a6,-(sp)

; Close the screen

		move.l	conScreen(a2),d0
		beq.s	NoScreen
		move.l	d0,a0
		move.l	conIntBase(a2),a6
		jsr	-66(a6)		;CloseScreen
NoScreen


; Close dos.library
		move.l	conDOSBase(a2),d0
		beq.s	nodos
		move.l	d0,a1
		move.l	4,a6
		jsr	-414(a6)	;CloseLibrary
nodos

; Close graphics.library
		move.l	conGfxBase(a2),d0
		beq.s	nogfx
		move.l	d0,a1
		move.l	4,a6
		jsr	-414(a6)	;CloseLibrary
nogfx

; Close intuition.library
		move.l	conIntBase(a2),d0
		beq.s	noint
		move.l	d0,a1
		move.l	4,a6
		jsr	-414(a6)	;CloseLibrary
noint

; Close expansion.library
		move.l	conExpBase(a2),d0
		beq.s	noexp
		move.l	d0,a1
		move.l	4,a6
		jsr	-414(a6)	;CloseLibrary
noexp

; Free context
		move.l	4,a6
		move.l	a2,a1
		jsr	-690(a6)	;FreeVec

CloseDone	movem.l	(sp)+,d2-d7/a2-a6
		moveq	#0,d0
		rts


; Library names

UtilityName	dc.b	"utility.library",0
IntName		dc.b	"intuition.library",0
GfxName		dc.b	"graphics.library",0
DOSName		dc.b	"dos.library",0
ExpName		dc.b	"expansion.library",0

; The name of our screen

ScreenName	dc.b	"ShapeShifter Screen",0
		CNOP	0,4

; Taglist for OpenScreen()

ScreenTags	dc.l	SA_Depth
ScrDepth	dc.l	0
		dc.l	SA_Width
ScrWidth	dc.l	0
		dc.l	SA_Height
ScrHeight	dc.l	0
		dc.l	SA_DisplayID
ScrDisplayID	dc.l	0
		dc.l	SA_Overscan
ScrOverscan	dc.l	0
		dc.l	SA_Quiet,-1
		dc.l	SA_Exclusive,-1
		dc.l	SA_Title,ScreenName
		dc.l	TAG_END,0


; Bad news...

easyreq		dc.l	EasyStruct_SIZEOF
		dc.l	0
		dc.l	er1
		dc.l	0
		dc.l	er2

er1		dc.b	"SD64evd Problem:",0
er2		dc.b	"Bye!",0

err1
err2
err3
err4
err5		dc.b	"You must set color depth 24 bit",0
err6		dc.b	"Can't find TagItem RefreshType",0
err7		dc.b	"This driver supports only these Screen Modes:",$a,$a
		dc.b	"512 x 384 x 24 bit",$a
		dc.b	"576 x 432 x 24 bit",$a
		dc.b	"640 x 400 x 24 bit",$a
		dc.b	"640 x 480 x 24 bit (only with 4 Meg SD64)",$a
		dc.b	"768 x 576 x 24 bit (only with 4 Meg SD64)",$a
		dc.b	"800 x 600 x 24 bit (only with 4 Meg SD64)",$a
		dc.b	"832 x 624 x 24 bit (only with 4 Meg SD64)",0
err8		dc.b	"This Screen Mode requires 4 Meg SD64",0
err9		dc.b	"OpenScreen failed",0
err10		dc.b	"Can't find TagItem ScreenBase",0
err11		dc.b	"Can't find TagItem BytesPerRow",0
err12		dc.b	"Can't open expansion.library",$a
		dc.b	"Are you sure you are using an Amiga?",0
err13		dc.b	"You don't have a PiccoloSD64",$a
		dc.b	"or your board has some problems",0


		END
