*
* A2410 external video driver for ShapeShifter
* ©1995-1996 Brian King, Fourth Dimension Software
* Support for 68040 MMU ©1995 Christian Bauer
*
		INCLUDE "exec/execbase.i"
		INCLUDE "exec/types.i"
		INCLUDE "exec/macros.i"
		INCLUDE "exec/memory.i"
		INCLUDE "libraries/expansion.i"
		INCLUDE "libraries/configvars.i"
		INCLUDE "intuition/intuition.i"
		INCLUDE "intuition/intuitionbase.i"
		INCLUDE "utility/tagitem.i"
		INCLUDE "exec/alerts.i"
		INCLUDE "shapeextvideo.i"
		
		MACHINE 68020

		SECTION NTRYHUNK,CODE

	XREF	_hst2gsp32,_refresh
	XDEF	_HSTADR, _HSTDATA, _MemCmpCpy

	STRUCTURE	MyContext,0
	APTR	conIntuitionBase
	APTR	conExpansionBase
	APTR	conGfxBase
	APTR	conDosBase
	APTR	conScreen
	APTR	conScreenBuf
	APTR	conDeltaBuf
	APTR	conViewPort
	WORD	conBytesPerRow
	WORD	conDeltaUsed
	LONG    conRGBnum
	STRUCT	conRGBBuf,256*12	; 256 entries * 3 values * 4 bytes each (256*12)
	LONG    conRGBterm
	APTR	conPageTable
	LONG	conScreenSize
	LONG	conScreenRemainder
	APTR	conSemaphore
	WORD	conSegmentSize
	WORD	conScreenPages
	LABEL MyContext_SIZEOF

    EVHEADER DriverTags
DriverTags dc.l SHEV_Level,1
           dc.l SHEV_Version,0
		   dc.l SHEV_Revision,8
		   dc.l SHEV_Name,DriverName
		   dc.l SHEV_ID,DriverID
		   dc.l SHEV_Author,DriverAuthor
		   dc.l SHEV_OpenScreen,A2410_OpenScreen
		   dc.l SHEV_CloseScreen,A2410_CloseScreen
		   dc.l SHEV_Refresh,A2410_Refresh
		   dc.l SHEV_LoadRGB32,A2410_LoadPalette
		   dc.l TAG_END,0

DriverID	dc.b	"\0$VER:A2410 EVD version 0.8 for ShapeShifter3.2a and higher, ©1995-1996 Brian King (15.06.96)",0
			CNOP	0,4
DriverName	dc.b	"ShapeShifter A2410 Driver",0
			CNOP 0,4
DriverAuthor dc.b	"Brian King",0
			CNOP 0,4

*
* OpenScreen stuff
* a0 - input taglist
* a1 - output taglist
* a2 - context ptr
* a6 - utility base
*
A2410_OpenScreen	movem.l d2-d7/a2-a6,-(sp)
				move.l  a0,a4 					; a4 contains input taglist
				move.l  a1,a5 					; a5 contains output taglist
				move.l  a6,_UtilityBase 		; store utility base at _UtilityBase
				move.l  (4).w,_ExecBase 		; store exec base at _ExecBase
				
				move.l _ExecBase,a6
				move.l #MyContext_SIZEOF,d0
				move.l #MEMF_PUBLIC|MEMF_CLEAR,d1
				JSRLIB AllocVec					; AllocVec()
				tst.l  d0						; Check for allocation
				beq    ShutDown
				move.l d0,a2					; a2 has context

				lea    IntuitionName,a1
				moveq  #37,d0
				JSRLIB OpenLibrary				; OpenLibrary() for Intuition
				move.l d0,conIntuitionBase(a2)
				beq    ShutDown

				lea		ExpansionName,a1
				moveq	#37,d0
				JSRLIB	OpenLibrary				; OpenLibrary() for Expansion
				move.l	d0,conExpansionBase(a2)
				beq		ShutDown
				
				JSR		A2410_Present			; returns boolean in d0
				tst.l	d0
				bne		GetA2410adr				; found the A2410
				movem.l d0/a3,-(sp)
				moveq	#0,d0
				lea.l	NoA2410String,a3
				jsr		requester
				movem.l	(sp)+,d0/a3
				bra		ShutDown

GetA2410adr		move.l	d0,a0
				move.l	cd_BoardAddr(a0),d0
				move.l	d0,_HSTADR				; BoardAddr is HSTADDR
				addi.l	#4,d0
				move.l	d0,_HSTDATA				; BoardAddr+4 is HSTDATA
				
				move.l	_ExecBase,a6	
				lea		SemaName,a1
				JSRLIB	Forbid
				JSRLIB	FindSemaphore			; FindSemaphore("A2410_SEMAPHORE")
				JSRLIB	Permit
				tst.l	d0
				bne		OpenGfx
				movem.l d0/a3,-(sp)
				moveq	#0,d0
				lea.l	NoEGSdriver,a3
				jsr		requester
				movem.l (sp)+,d0/a3
				bra		ShutDown
				
OpenGfx			move.l	d0,conSemaphore(a2)
				lea    GfxName,a1
				moveq  #37,d0
				JSRLIB OpenLibrary				; OpenLibrary() for Graphics
				move.l d0,conGfxBase(a2)
				beq    ShutDown
				
				lea    DOSName,a1
				moveq  #37,d0
				JSRLIB OpenLibrary				; OpenLibrary() for DOS
				move.l d0,conDosBase(a2)
				beq    ShutDown
				
				move.l _UtilityBase,a6			; setup a6 with _UtilityBase
				move.l a5,a0					; output taglist to a0
				move.l #SHEV_Context,d0			; find SHEV_Context
				JSRLIB FindTagItem				; FindTagItem()
				move.l d0,a0					; put tag addr in a0
				move.l a2,ti_Data(a0)			; set ti_Data for tag
				
				move.l a5,a0					; output taglist to a0
				move.l #SHEV_RefreshType,d0		; find SHEV_RefreshType
				JSRLIB FindTagItem				; FindTagItem()
				move.l d0,a1					; put tag addr in a1
				move.l #RTYPE_CUSTOM,ti_Data(a1); set ti_Data to RTYPE_CUSTOM
				
				move.l a4,a0					; input taglist to a0
				move.l #SHEV_ScreenX,d0			; get SHEV_ScreenX data
				move.l #800,d1					; default result
				JSRLIB GetTagData				; GetTagData()
				move.l d0,ScrWidth				; store in our ScrWidth area
				
				moveq	#0,d7
				move.w	#32,d7				; d7 - default segment size of 32

				cmp.w	#640,d0
				bne		w800
				move.w	#160,d7				; d7 - segment size of 160
				bra		seg_size

w800			cmp.w	#800,d0
				bne		w512
				move.w	#160,d7				; d7 - segment size of 160
				bra		seg_size

w512			cmp.w	#512,d0
				bne		w832
				move.w	#64,d7				; d7 - segment size of 64
				bra		seg_size
				
w832			cmp.w	#832,d0
				bne		w1024
				move.w	#64,d7				; d7 - segment size of 64
				bra		seg_size
				
w1024			cmp.w	#1024,d0
				bne		seg_size
				move.w	#128,d7				; d7 - segment size of 128

seg_size		move.w	d7,conSegmentSize(a2)

				move.l a4,a0					; input taglist to a0
				move.l #SHEV_ScreenY,d0			; get SHEV_ScreenY data
				move.l #600,d1					; default result
				JSRLIB GetTagData				; GetTagData()
				move.l d0,ScrHeight				; store in our ScrHeight area
				
				move.l a4,a0					; input taglist in a0
				move.l #SHEV_DisplayID,d0		; get SHEV_DisplayID data
				move.l #67112964,d1				; default result
				JSRLIB GetTagData				; Get SHEV_DisplayID
				move.l d0,ScrDisplayID			; store in our ScrDisplayID area

				movem.l	d0/a3,-(sp)				; show information requester
				moveq.l	#3,d0
				move.l	#0,a3
				jsr		requester
				movem.l	(sp)+,d0/a3
				
				move.l	_ExecBase,a6
				move.w	AttnFlags(a6),d0		; d0 contains ExecBase.AttnFlags
				and.w	#$000F,d0
				cmpi.w	#$000F,d0				; check for 040 or higher
				beq		DoMMUstuff
				bra		choice	
				
DoMMUstuff		jsr		MMUSetup

choice			movem.l d0/a3,-(sp)				; get delta-buffer choice
				tst.b	HasMMU
				beq		DeltaDumbOnly
				moveq	#2,d0
				bra		loadchoice
DeltaDumbOnly	moveq	#1,d0
loadchoice		lea.l	ChoiceString,a3
				jsr		requester
				move.w  d0,conDeltaUsed(a2)
				movem.l (sp)+,d0/a3
				
				move.l conIntuitionBase(a2),a6	; setup a6 with IntuitionBase
				sub.l  a0,a0					; clear a0
				lea    ScreenTags,a1			; ScreenTags addr in a1
				JSRLIB OpenScreenTagList		; OpenScreenTagList()
				move.l d0,a3					; a3 contains screen address
				move.l d0,conScreen(a2)			; store screen address in conScreen
				beq    ShutDown					; problem - goto OpenFailed

				moveq.l	#0,d0
				move.w	conDeltaUsed(a2),d0
				cmpi.w	#2,d0					; conDeltaUsed >= 2 only if
												; MMU chosen
				bge		MMUAlloc
				bra		NormalAlloc
				
MMUAlloc		move.l	ScrWidth,d0
				move.l	ScrHeight,d1
				mulu.l	d1,d0
				move.l	d0,conScreenSize(a2)
				
				move.l	d0,d1
				divu.l	PageSize,d0
				move.w	d0,conScreenPages(a2)	; number of pages
				mulu.l	PageSize,d0
				sub.l	d0,d1
				move.l	d1,conScreenRemainder(a2); remaining screen memory bytes (unpaged)
				
				move.l	_ExecBase,a6
				move.l	conScreenSize(a2),d0
				move.l	#MEMF_PUBLIC|MEMF_CLEAR,d1
				jsr		AllocMMU
				move.l	d0,conScreenBuf(a2)
				beq		ARMNoMem
				
				moveq	#0,d0					; Yes, get page table
				move.w	conScreenPages(a2),d0
				lsl.l	#2,d0
				move.l	#MEMF_PUBLIC|MEMF_CLEAR,d1
				JSRLIB	AllocVec
				move.l	d0,conPageTable(a2)
				beq		ARMNoMem
				
				move.l	d0,a1
				move.l	conScreenBuf(a2),d6
				move.w	conScreenPages(a2),d7
				subq.w	#1,d7
2$				move.l	d6,d0
				jsr		GetMMUPage
				addq.l	#3,a0
				move.l	a0,(a1)+
				add.l	PageSize,d6
				dbra	d7,2$

				moveq.l	#0,d0
				move.w	conDeltaUsed(a2),d0
				cmpi.w	#3,d0					; conDeltaUsed = 3 only if
												; MMU chosen
				beq		CheckDeltaBuf
				bra		NoDeltaBuf
				
ARMNoMem		moveq	#-1,d0
				bra		ShutDown
				
NormalAlloc		move.l _ExecBase,a6				; setup a6 with _ExecBase
				move.l ScrWidth,d0				; width in d0
				move.l ScrHeight,d1				; height in d1
				mulu.w d0,d1					; get # bytes
				move.l d1,d0
				move.l d1,conScreenSize(a2)		; store in conScreenSize
				move.l #MEMF_PUBLIC|MEMF_CLEAR,d1	; type of mem
				JSRLIB AllocVec					; AllocVec()
				tst.l  d0
				beq    ShutDown
				move.l d0,conScreenBuf(a2)

				moveq.l	#0,d0
				move.l	d0,conPageTable(a2);	; clear PageTable value

CheckDeltaBuf	move.w	conDeltaUsed(a2),d0
				beq		NoDeltaBuf
				move.l	conScreenSize(a2),d0
				move.l	#MEMF_PUBLIC|MEMF_CLEAR,d1
				JSRLIB	AllocVec
				tst.l	d0
				beq		ShutDown
				move.l d0,conDeltaBuf(a2)		; conDeltaBuf has addr
				bra		ScreenTag

NoDeltaBuf		move.l	#0,conDeltaBuf(a2)		; put 0 into conDeltaBuf
				move.l	ScrWidth,d0
				move.w	d0,conSegmentSize(a2)	; set segment size = full scan-line
				
ScreenTag		move.l _UtilityBase,a6			; setup a6 with _UtilityBase
				move.l a5,a0					; output taglist in a0
				move.l #SHEV_Screen,d0			; SHEV_Screen tag in d0
				JSRLIB FindTagItem				; FindTagItem()
				move.l d0,a0					; Result in a0
				move.l conScreen(a2),ti_Data(a0); Store screen address in 
												; ti_Data
				
				move.l conDosBase(a2),a6		; setup a6 with DosBase
				moveq  #15,d1
				JSRLIB Delay					; Delay(15)
				
				lea    sc_ViewPort(a3),a0		; get ViewPort of screen into a0
				move.l a0,conViewPort(a2)		; store ViewPort address in conViewPort

				move.l _UtilityBase,a6
				move.l a5,a0					; output taglist in a0
				move.l #SHEV_ScreenBase,d0		; find SHEV_ScreenBase
				JSRLIB FindTagItem				; FindTagItem()
				tst.l  d0
				beq    ShutDown
				move.l d0,a0
				move.l conScreenBuf(a2),ti_Data(a0)

				move.l #16777216,conRGBnum(a2)	; set up colour-table
				move.l #0,conRGBterm(a2)

				move.l a5,a0					; output taglist in a0
				move.l #SHEV_BytesPerRow,d0		; find SHEV_BytesPerRow
				JSRLIB FindTagItem				; FindTagItem()
				tst.l  d0
				beq    ShutDown
				move.l d0,a1
				move.l ScrWidth,d0
				move.w d0,conBytesPerRow(a2)
				move.l d0,ti_Data(a1)

				movem.l (sp)+,d2-d7/a2-a6
				moveq   #0,d0
				rts
*
* The CloseScreen routine
* a0 - input taglist
* a1 - output taglist
* a2 - context pointer
* a6 - utility.library base
*
A2410_CloseScreen	movem.l	d2-d7/a2-a6,-(sp)
ShutDown		move.l	conScreen(a2),d0
				beq		10$
				move.l	d0,a0
				move.l	conIntuitionBase(a2),a6
				JSRLIB	CloseScreen
10$
				move.l	_ExecBase,a6
				move.l	conDosBase(a2),d0
				beq		20$
				move.l	d0,a1
				JSRLIB	CloseLibrary
20$
				move.l	conGfxBase(a2),d0
				beq		30$
				move.l	d0,a1
				JSRLIB	CloseLibrary
30$
				move.l	conExpansionBase(a2),d0
				beq		35$
				move.l	d0,a1
				JSRLIB	CloseLibrary
35$				
				move.l	conIntuitionBase(a2),d0
				beq		40$
				move.l	d0,a1
				JSRLIB	CloseLibrary
40$
				move.l	conScreenBuf(a2),d0
				beq		FreeDeltaBuf
				move.l	d0,a1
				tst.b	HasMMU
				beq		ScreenFreeVec
				
				move.l	conScreenSize(a2),d0
				JSRLIB	FreeMem
				bra		FreeDeltaBuf
ScreenFreeVec	JSRLIB	FreeVec

FreeDeltaBuf
				move.l	conDeltaBuf(a2),d0
				beq		60$
				move.l	d0,a1
				JSRLIB	FreeVec				
60$
				move.l	conPageTable(a2),d0
				beq		70$
				move.l	d0,a1
				JSRLIB	FreeVec
70$
				move.l	a2,a1
				JSRLIB	FreeVec
				
				movem.l	(sp)+,d2-d7/a2-a6
				moveq	#-1,d0
				rts
				
*
* The Palette routine
* a0 - input taglist
* a1 - output taglist
* a2 - context pointer
* a6 - utility.library base
*
A2410_LoadPalette	movem.l	d2-d7/a2-a6,-(sp)
				move.l  #SHEV_ColorTable,d0
				moveq	#0,d1
				JSRLIB	GetTagData
				move.l	d0,a0 				; a0 is the Mac's colour table
				
				lea		conRGBBuf(a2),a1	; a1 is our colour table
				move.l	#255,d1				; 256 entries
Start			move.l	(a0)+,(a1)+
				move.l	(a0)+,(a1)+
				move.l	(a0)+,(a1)+
				dbra	d1,Start
				
				move.l  conGfxBase(a2),a6	; set up gfxbase for JSRLIB
				move.l  conViewPort(a2),a0  ; set up a0 with viewport ptr
				lea     conRGBnum(a2),a1    ; set up a1 with colour table
				JSRLIB  LoadRGB32           ; call LoadRGB32()

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

*
* The Refresh routine
* Set-up:
* a0 - semaphore adress
* a1 - scratch
* a2 - context pointer
* a3 - scratch
* a4 - scratch
* a5 - scratch
* a6 - library pointer (either Exec or Intuition)
* d7 - offset for delta refresh
* d6 - loop for delta refresh
* d5 - height loop count
* d4 - intermediate count
* d3 - y-coord
*
A2410_Refresh	movem.l	d2-d7/a2-a6,-(sp)

				moveq.l	#0,d0
				move.w	conDeltaUsed(a2),d0
				cmpi.w	#2,d0
				blt		NoMMUrefreshing
				jsr		A2410MMURefresh
				movem.l	(sp)+,d2-d7/a2-a6
				moveq	#0,d0
				rts

NoMMUrefreshing	move.l	conSemaphore(a2),a0	; Set-up a0 with semaphore
				move.l	_ExecBase,a6
				JSRLIB	ObtainSemaphore

				moveq	#0,d6
				move.l	ScrHeight,d5		; d5 - height loop
				sub.l	#1,d5
				moveq	#0,d4				; d4 - intermed. count
				moveq	#0,d3				; d3 - y-coord

yloop			cmp.b	#45,d4				; check if intermed. < 45
				bge		obtlock				; 
				add.b	#1,d4				; increment intermed.
				bra		active

obtlock			moveq	#0,d4				; clear intermed
				JSRLIB	ObtainSemaphore
				
active			move.l	a0,a3				; back up semaphore from a0 to a3

prepare			move.l	ScrWidth,d6
				move.l	d6,d7
				moveq	#0,d2
				move.w	conSegmentSize(a2),d2
				cmp.l	d2,d6
				beq		scanline
				divu	d2,d6				; d6 = width / segment_size
				move.w	d6,d0
				moveq	#0,d6				; clear remainder if any
				move.w	d0,d6
				subq	#1,d6				; prepare d6 for dbra
				moveq	#1,d0				; d0 as 1 indicates delta-refresh
				bra		gsppitch

scanline		moveq	#0,d0				; d0 as 0 indicates no delta refresh
				
gsppitch		move.l	#$2000,d1			; put gsp-pitch into d1
				mulu.w	d3,d7				; d7 contains y-coord * (width in bytes)
				mulu.w	d3,d1				; d1 contains y-coord * (gsp-pitch)
				move.l	d2,a5				; put segment-size in a5
				sub.l	a5,d7				; prepare hst offset properly
				rol.l	#3,d2				; prepare gsp offset properly
				sub.l	d2,d1
				cmp.l	#0,d0
				beq		nodelta
				
delta2			add.l	a5,d7				; d7 contains offset for host
				add.l	d2,d1				; d1 contains offset for gsp
				move.l	conScreenBuf(a2),a0	; a0 is src-addr
				move.l	conDeltaBuf(a2),a1	; a1 is dst-addr
				add.l	d7,a0
				add.l	d7,a1				; add offset to base src/dst addresses
				jsr		_MemCmpCpy			; do comparison (and copying if needed)
				tst.b	d0					; any differences?
				beq		deltaloop			; no, go to delta_loop
				move.l	#$FE000000,a1		; yes, base gsp-addr is 0xfe000000
				add.l	d1,a1				; add gsp-offset to base
				
				movem.l	d0/d6,-(sp)
				move.l	a5,d6				; d6 is width (a5 had segment size)
				move.l	a1,d0				; d0 is dest-addr
				jsr		_hst2gsp32
				movem.l	(sp)+,d0/d6
				
deltaloop		dbra	d6,delta2
				bra		finish

nodelta			add.l	a5,d7				; d7 contains offset for host
				add.l	d2,d1				; d1 contains offset for gsp
				move.l	conScreenBuf(a2),a0 ; a0 is src-addr
				add.l	d7,a0
				move.l	#$FE000000,a1		; base gsp-addr is 0xfe000000
				add.l	d1,a1				; add gsp-offset to base
				
				movem.l	d0/d6,-(sp)
				move.l	a5,d6				; d6 is width (a5 had segment size, full scan-line)
				move.l	a1,d0				; d0 is dest-addr
				jsr		_hst2gsp32
				movem.l	(sp)+,d0/d6
				
finish			move.l	a3,a0				; restore semaphore to a0 from a3
				cmp.b	#45,d4				; d4 - intermed. count
				bne		loop
				JSRLIB	ReleaseSemaphore
				
loop			add.w	#1,d3
				dbra	d5,yloop
				
				cmp.b	#45,d4
				bge		exit
				JSRLIB	ReleaseSemaphore

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

*
* A2410_Present()
* A2 - context pointer
* D0 - result
*
A2410_Present	move.l	conExpansionBase(a2),a6
				move.l	#0,a0
				move.l	#1030,d0
				move.l	#0,d1
				JSRLIB	FindConfigDev
				rts
*
* MemCmpCpy()
* d0 - return code - 1 means difference, 0 means no changes
* a5 - width in bytes
* a0 - source address
* a1 - destin address
*
_MemCmpCpy		movem.l	d2/a0/a1,-(sp)
				move.l	a5,d2
				ror.l	#2,d2				; divide by 4
				subq	#1,d2
				moveq	#0,d0				; return code
.start2			cmpm.l	(a0)+,(a1)+
				bne		.copy2
				dbra	d2,.start2
				bra		.finish2
.copy2			moveq	#1,d0				; return code
				move.l	-4(a0),-4(a1)
				dbra	d2,.copymore
				bra		.finish2
.copymore		move.l	(a0)+,(a1)+
				dbra	d2,.copymore
.finish2		movem.l	(sp)+,d2/a0/a1
				rts

*
* requester
* d0 - type of requester
* a3 - pointer to string
*
requester		movem.l	a0-a3/a6,-(sp)
				lea.l	ReqStruct,a1
				move.l	#EasyStruct_SIZEOF,es_StructSize(a1)
				move.l	#0,es_Flags(a1)
				lea.l	RequesterString,a0
				move.l	a0,es_Title(a1)
				cmp.l	#0,d0
				bne		ChoiceReq
ErrorReq		lea.l	ErrorString,a0
				move.l	a0,es_TextFormat(a1)
				lea.l	OKPrompt,a0
				move.l	a0,es_GadgetFormat(a1)
				bra		makereq
ChoiceReq		cmp.l	#1,d0
				bne		ChoiceReqMMU
				lea.l	ParameterString,a0
				move.l	a0,es_TextFormat(a1)
				lea.l	DeltaDumbPrompt,a0
				move.l	a0,es_GadgetFormat(a1)
				bra		makereq
ChoiceReqMMU	cmp.l	#2,d0
				bne		ShareReq
				lea.l	ParameterString,a0
				move.l	a0,es_TextFormat(a1)
				lea.l	DeltaDumbMMU,a0
				move.l	a0,es_GadgetFormat(a1)
				bra		makereq
ShareReq		cmp.l	#3,d0
				bne		exitreq
				lea.l	AboutString,a0
				move.l	a0,es_TextFormat(a1)
				lea.l	OKPrompt,a0
				move.l	a0,es_GadgetFormat(a1)
makereq			move.l	conIntuitionBase(a2),a6
				move.l	a3,ArgList
				lea.l	ArgList,a3
				move.l	#0,a0
				; a1 is the requester
				move.l	#0,a2
				; a3 is the arg list
				moveq	#0,d0
				JSRLIB	EasyRequestArgs
exitreq			movem.l	(sp)+,a0-a3/a6
				rts

	MACHINE 68040
	PMMU
	
*
* MMUSetup
* Once you know that an 040 is present, need to setup some things
*

MMUSetup		movem.l	d0-d7/a0-a6,-(sp)
				lea		GetMMUProc,a5		;Read SRP and TC
				JSRLIB	Supervisor
				btst	#15,d1				;MMU active?
				beq		MMUDone
				btst	#14,d1				;Yes, 4K pages?
				bne		MMUIs8K

MMUIs4K			bfclr	d0{23:9}
				move.l	d0,MMURoot
				move.l	#$1000,d0
				move.l	d0,PageSize
				subq.l	#1,d0
				move.l	d0,PageOffsetMask
				not.l	d0
				move.l	d0,PageIndexMask
				st.b	HasMMU
				bra		MMUDone
			
MMUIs8K			bfclr	d0{23:9}
				move.l	d0,MMURoot
				move.l	#$2000,d0
				move.l	d0,PageSize
				subq.l	#1,d0
				move.l	d0,PageOffsetMask
				not.l	d0
				move.l	d0,PageIndexMask
				st.b	HasMMU
				movem.l	d0/a3,-(sp)
				moveq	#0,d0
				lea.l	NoA2410String,a3
				jsr		requester
				movem.l	(sp)+,d0/a3
				st.b	MMUHas8KPages
			
MMUDone			movem.l	(sp)+,d0-d7/a0-a6
				rts

GetMMUProc		movec	srp,d0
				movec	tc,d1
				rte

*
* GetMMUPage
*
GetMMUPage		move.l	MMURoot,a0
				bfextu	d0{0:7},d1
				move.l	(a0,d1.l*4),d1
				bfclr	d1{23:9}
				move.l	d1,a0
				bfextu	d0{7:7},d1
				move.l	(a0,d1.l*4),d1
				clr.b	d1
				move.l	d1,a0
				bfextu	d0{14:6},d1
				lea		(a0,d1.l*4),a0
				rts
			
*
* A2410MMURefresh
*
A2410MMURefresh	jsr		FlushMMU
				moveq	#0,d0
				move.w  conDeltaUsed(a2),d0		;d0: delta-buffer status
				move.l	conDeltaBuf(a2),d1		;d1: delta-buffer address
				move.l	ScrWidth,d6				;d6: screen width
				move.l	conSemaphore(a2),a0		;a0: Semaphore for A2410 driver
				move.l	conScreenBuf(a2),a4		;a4: Pointer to Mac gfx memory
				move.l	conPageTable(a2),a5		;a5: Pointer to page table
				move.l	_ExecBase,a6			;a6: ExecBase
				moveq	#0,d7
				move.w	conScreenPages(a2),d7	;
				subq.w	#1,d7					;d7: counter for MMU pages
1$				move.l	(a5)+,a3				;a5: page table entry
				bclr	#4,(a3)
				beq		2$

;Refresh one page here

				JSRLIB	ObtainSemaphore
				movem.l	d0-d7/a0-a6,-(sp)
				move.l	a4,a0					; a0: Screen base
				move.l	PageSize,a1				; a1: amount to blit
				move.w	conScreenPages(a2),a2	; a2: number of pages
				jsr		_refresh
				movem.l	(sp)+,d0-d7/a0-a6
				JSRLIB	ReleaseSemaphore
				
2$				dbra	d7,1$

;Refresh remainder here
				JSRLIB	ObtainSemaphore
				movem.l	d0-d7/a0-a6,-(sp)
				moveq	#0,d7					; page number
				move.l	a4,a0					; a0: screen base
				move.l	PageSize,a1				; a1: amount to blit
				move.w	conScreenPages(a2),a2	; a2: number of pages
				adda.w	#1,a2					; one extra page...
				jsr		_refresh
				movem.l	(sp)+,d0-d7/a0-a6
				JSRLIB	ReleaseSemaphore
				rts
			
FlushMMU		movem.l	a5-a6,-(sp)
				move.l	_ExecBase,a6
				lea		FlushMMUProc,a5
				JSRLIB	Supervisor
				movem.l	(sp)+,a5-a6
				rts
			
FlushMMUProc	cpusha	dc
				pflusha
				rte
				
*
* Allocate memory on MMU page boundary
* d0: Number of bytes
* d1: Memory Type
*
AllocMMU		movem.l d6-d7/a4,-(sp)
				move.l	_ExecBase,a6
				move.l	d0,d7				;d7: Original Size
				add.l	PageOffsetMask,d0
				move.l	d0,d6				;d6: Increase Size
				JSRLIB	AllocMem			;Memory type already in d1
				tst.l	d0
				beq		1$
				move.l	d0,a4				;a4: Pointer to larger block
				
				JSRLIB	Forbid
				
				move.l	a4,a1				;Memory reserved, free it
				move.l	d6,d0
				JSRLIB	FreeMem
				
				move.l	a4,d0				;Align address to page boundary
				add.l	PageOffsetMask,d0
				and.l	PageIndexMask,d0
				move.l	d0,a4
				
				move.l	d0,a1				;Reallocate just the needed part
				move.l	d7,d0
				JSRLIB	AllocAbs
				
				JSRLIB	Permit
				move.l	a4,d0
1$				movem.l	(sp)+,d6-d7/a4
				rts

	MACHINE 68020
	
*
* Constants
*
UtilityName		dc.b	"utility.library",0
IntuitionName	dc.b	"intuition.library",0
ExpansionName	dc.b	"expansion.library",0
GfxName			dc.b	"graphics.library",0
DOSName			dc.b	"dos.library",0
ScreenName		dc.b	"ShapeShifter Screen (A2410 EVD)",0
SemaName		dc.b	"A2410_SEMAPHORE",0
ChoiceString	dc.b	"Pick your refresh-type:",0
NoA2410String	dc.b	"No A2410 card found!",0
NoEGSdriver		dc.b	"The EGS-A2410 driver is not running!",0
RequesterString	dc.b	"A2410 EVD for ShapeShifter",0
DeltaDumbPrompt	dc.b	"Delta|Dumb",0
DeltaDumbMMU	dc.b	"Delta|MMU|Delta+MMU|Dumb",0
ParameterString	dc.b	"%s",0
AboutString		dc.b	"A2410 External Video Driver 0.8\n"
				dc.b	"for ShapeShifter 3.2a or higher.\n"
				dc.b	"©1995-1996 Brian King.  Portions\n"
				dc.b	"©1995 Christian Bauer.\n",0
OKPrompt		dc.b	"OK",0
				CNOP	0,4
ErrorString		dc.b	"Error: %s",0
				CNOP	0,4

*
* Data Section
*
		SECTION "DATA",DATA

ScreenTags	dc.l	SA_Depth
ScrDepth    dc.l    1
			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_Quiet,-1
			dc.l	SA_Title,ScreenName
			dc.l	TAG_END,0
ArgList		dc.l	0
			dc.l	0

		SECTION "BSS",BSS
_ExecBase		ds.l	1
_UtilityBase	ds.l	1
_HSTADR			ds.l	1
_HSTDATA		ds.l	1
MMURoot			ds.l	1
PageOffsetMask	ds.l	1
PageIndexMask	ds.l	1
PageSize		ds.l	1
HasMMU			ds.b	1
MMUHas8KPages	ds.b	1
padding			ds.b	2
ReqStruct		ds.b	EasyStruct_SIZEOF
