*****************************************************************************
*
*	pickeeper.asm -- written by Ray Lambert for Theta Systems, Inc.
*
*	Copyright 1991 Commodore Business Machines, Inc.
*
*****************************************************************************


		INCLUDE		"keeper.i"
		INCLUDE		"libraries/dos.i"
		INCLUDE		"graphics/gfx_equ.i"
		INCLUDE		"graphics/gfxbase.i"
		INCLUDE		"graphics/gfx.i"
		INCLUDE		"graphics/view.i"
		INCLUDE		"exec/tasks.i"
		INCLUDE		"exec/memory.i"
		INCLUDE		"hardware/custom.i"
		INCLUDE		"hardware/dmabits.i"
		INCLUDE		"intuition/intuition_equ.i"


STKSIZE		EQU		4096


DISPLAY_ON	MACRO
		move.w		#DMAF_SETCLR|DMAF_RASTER,CHIPBASE+dmacon
		ENDM

SPRITES_ON	MACRO
		move.w		#DMAF_SETCLR|DMAF_SPRITE,CHIPBASE+dmacon
		ENDM

SPRITES_OFF	MACRO
		move.w		#DMAF_SPRITE,CHIPBASE+dmacon
		ENDM



		SECTION		text,code


		FUNCTION	_keeper,0,d2/a3/a4/a6
		ARGUMENTS
		ARG		_APTR,view
		ARG		_APTR,memlist

* allocate memory for task
		lea		tcbmem,a0
		jsrsys		AllocEntry
		bclr.l		#31,d0			; if this bit is set
		bne		fail			; the alloc. failed

* get pointers to newly allocated stack and TCB
* register usage
* d2 = allocated memlist
* a5 = argument pointer (stack frame)
* a4 = code ptr (initPC)
* a3 = TCB
* a2 = stack
		move.l		d0,d2			; save memlist in d2
		move.l		d0,a1
		add.l		#ML_ME,a1		; ptr to 1st ME
		move.l		ME_ADDR(a1),a2		; get pointer to stack
		add.l		#ME_SIZE,a1		; get ptr to 2nd ME
		move.l		ME_ADDR(a1),a3		; get pointer to TCB
		add.l		#ME_SIZE,a1		; get ptr to 3rd ME
		move.l		ME_ADDR(a1),a4		; get pointer to code

* initialize stack and TCB stuff
* TCB node...
		move.b		#NT_TASK,LN_TYPE(a3)	; store node type
		move.b		#5,LN_PRI(a3)		; store node priority
		move.l		a2,LN_NAME(a3)		; store name in TCB node
* task name...
		lea		name,a1			; ptr to original name
		move.l		#endname-name-1,d0	; length of name (-1 for dbra)
1$		move.b		(a1)+,(a2)+		; copy all bytes (including 0)
		dbra		d0,1$			;  to stack bottom
* TCB stack info...
		move.l		a2,a0			; calc SPUPPER
		add.l		#STKSIZE,a0
		move.l		a0,TC_SPUPPER(a3)	; store SPUPPER in TCB
* push data we pass to new task
		move.l		view(a5),-(a0)		; push View ptr and
		move.l		_GfxBase,-(a0)		;  gfxbase and 
		move.l		_IntuitionBase,-(a0)	;  intuitionbase on task's stack
* more TCB stack info...
		move.l		a0,TC_SPREG(a3)		; store SP in TCB
		move.l		a2,d0
		addq.l		#3,d0			; round SPLOWER up
		and.l		#~3,d0			; stack = ((stack+3)&~3)
		move.l		d0,TC_SPLOWER(a3)	; store SPLOWER in TCB

* initialize TCB mem list...
		lea		TC_MEMENTRY(a3),a0	; ptr to mem list
		NEWLIST		a0
		move.l		d2,a1			; our mem list
		jsrlib		AddHead
		lea		TC_MEMENTRY(a3),a0	; ptr to mem list
		move.l		memlist(a5),a1		; caller's mem list
		jsrlib		AddHead

* copy task code...
		move.l		a4,a1			; new segment
		lea		keeper_task,a0		; original code
		move.l		#kt_end-keeper_task-1,d0; size of segment (-1 for dbra)
2$		move.b		(a0)+,(a1)+		; copy code segment
		dbra		d0,2$

* add the task...
		move.l		a3,a1			; TCB
		move.l		a4,a2			; initPC
		move.l		#0,a3			; finalPC (0)
		jsrlib		AddTask

		moveq		#1,d0
		bra		99$
fail
		moveq		#0,d0
99$
		RETURN		_keeper


***********************************************************************
*	   This is the code for the task we detach and spawn
***********************************************************************
		CNOP		0,4
keeper_task
		XDEF		keeper_task	; for debugging reference
		ARGUMENTS
		ARG		_APTR,ibase
		ARG		_APTR,gfxbase
		ARG		_APTR,view
		LOCAL_STACK
*		AUTO		_APTR,oldview

* use a5 for stack frame pointer
		link		a5,#-SFSIZE

* show our view
		move.l		gfxbase(a5),a6
*		move.l		gb_ActiView(a6),oldview(a5); save the old view
9$		move.l		view(a5),a1
		jsrlib		LoadView

* blank the mousey (turn sprite DMA off) and ensure that display DMA is on
10$		jsrlib		WaitTOF		; wait till vertical blank
		SPRITES_OFF
		DISPLAY_ON

* wait until it's time to remove our view
1$		move.l		#29,d7		; wait for 1/2 second (30-1)
		move.l		gfxbase(a5),a6
2$		jsrlib		WaitTOF
		dbra		d7,2$
		move.l		gb_ActiView(a6),d0; check if the ActiView has changed
		beq		9$		; reload our view if this is NULL
		cmp.l		view(a5),d0
		bne		4$		; new view is now visible
		moveq		#0,d0		; check if a CTRL-C has arrived
		moveq		#0,d1
		jsrsys		SetSignal
		and.l		#SIGBREAKF_CTRL_C,d0
		beq		1$		; no CTRL-C

* remove our view by restoring Intuition's unless our View is no longer active
3$		move.l		gfxbase(a5),a6
		move.l		gb_ActiView(a6),d0
		beq		8$
		cmp.l		view(a5),d0
		bne		4$		; our View is no longer active
8$		move.l		ibase(a5),a6
		jsrlib		ViewAddress	; get Intuition's View
		move.l		gfxbase(a5),a6
		tst.l		d0		; did we get it?
		beq		9$		; Intuition's View unavailable
		move.l		d0,a1
		jsrlib		LoadView	; load Intuition's View

* unblank the mousey (turn sprite DMA back on)
4$		jsrlib		WaitTOF		; wait till vertical blank
		SPRITES_ON

* free stuff used by our view
		move.l		view(a5),a2
		move.l		v_LOFCprList(a2),a0
		cmp.l		#0,a0
		beq		5$
		jsrlib		FreeCprList
5$		move.l		v_SHFCprList(a2),a0
		cmp.l		#0,a0
		beq		6$
		jsrlib		FreeCprList
6$		move.l		v_ViewPort(a2),a2
		move.l		vp_ColorMap(a2),a0
		cmp.l		#0,a0
		beq		7$
		jsrlib		FreeColorMap
7$		move.l		a2,a0
		jsrlib		FreeVPortCopLists

* close graphics.library
		move.l		a6,a1
		jsrsys		CloseLibrary
* close intuition.library
		move.l		ibase(a5),a1
		jsrlib		CloseLibrary

* task dies... all MemList-allocated memory gets freed automagically :)
* for now this includes the following structures:
*	View, ViewPort, RasInfo, BitMap
* as well as all of the bitplanes used by the BitMap
* (and of the course the MemList structure itself)
		unlk		a5
		moveq		#0,d0
		rts
kt_end



		SECTION		data,data

* mem list to get memory for task stuff
tcbmem		ds.b		LN_SIZE
		dc.w		3
* #1 task stack (and name)
		dc.l		MEMF_PUBLIC|MEMF_CLEAR
		dc.l		STKSIZE+(endname-name)
* #2 Task structure
		dc.l		MEMF_PUBLIC|MEMF_CLEAR
		dc.l		TC_SIZE
* #3 task code segment
		dc.l		MEMF_PUBLIC|MEMF_CLEAR
		dc.l		(kt_end-keeper_task)

* name of our task
name		dc.b		"PicKeeper",0
endname

		END
