|*****************************************************************************
|
|   NAME
|
|	void Dispatch (
|
|   SYNOPSIS
|	void)
|
|   FUNCTION
|	This function switches between the task in SysBase->ThisTask and
|	the first task in the ready list. Is must be called from supervisor
|	mode with all registers set to the values of the underlying user
|	context and sp pointing to the normal exception frame (just as if
|	it was a routine in one of the interrupt vectors).
|
|	SysBase->IDNestCnt is moved to and from the task structures and
|	the interrupt control is prepared accordingly. The routines in
|	task->tc_Launch and task->tc_Switch are called if necessary and
|	a task exception for the new task is raised if TF_EXCEPT is set.
|
|	If the ready list is empty this function waits (with interrupts
|	enabled) until a task is willing to run.
|
|   INPUTS
|
|   RESULT
|
|   NOTES
|	If the current task (when calling this function) is not part of
|	one of the two task lists it gets lost.
|
|	This function is for internal exec use only.
|
|	This function is processor dependant.
|
|   EXAMPLE
|
|   BUGS
|	This function currently doesn't read *(struct ExecBase **)4 to get
|	SysBase and thus works only from Switch(). But it makes it usable
|	for link libraries.
|
|   SEE ALSO
|
|   INTERNALS
|	For the task lists the following conditions must always be true as
|	long as SysBase->IDNestCnt>=0. Changes are legal with interrupts
|	Disable()d only:
|
|	* A task is in state TS_WAIT if and only if it is part of the waiting
|	  list.
|	* It is in state TS_READY if and only if it is part of the ready list.
|	* SysBase->ThisTask always points to a legal task structure.
|	* In normal user context SysBase->ThisTask->tc_State is TS_RUN.
|	  There are two possible exceptions from this rule:
|	  * In supervisor mode when bit 15 of SysBase->AttnResched is set
|	    (dispatch pending bit).
|	    This ends by calling Dispatch() before falling down to user context.
|	  * In exec code. This ends by calling Switch() before going back to
|	    user code.
|	* The task in SysBase->ThisTask is one of the ready tasks with the
|	  highest priority (round robin). There's an exception from this rule,
|	  too:
|	  * If dispatching is disabled and bit 7 of SysBase->AttnResched is set
|	    (switch pending bit) it is allowed to have a running task with a
|	    lower priority as a waiting one. This ends by calling Switch() as
|	    soon as the dispatcher is reactivated.
|	* The ready list is sorted by priority.
|
|   HISTORY
|
|******************************************************************************
	.globl	_Dispatch_68000
_Dispatch_68000:
	movel	a5,sp@-
	movel	usp,a5
	movel	sp@+,a5@-
	movew	sp@+,a5@-
	movel	sp@+,a5@-
	moveml	d0-d7/a0-a4/a6,a5@-
|	 movel	 4,a6
	movew	#0x2700,sr		    | disable interrupts
	movel	a6@(0x114:W),a2             | SysBase->ThisTask
	movel	a5,a2@(0x36)                | ThisTask->tc_SPReg
	btst	#6,a2@(0xe)                 | TB_SWITCH
	jeq	noswch
	movel	a2@(0x82),a5
	jsr	a5@
noswch: moveb	a6@(0x126),a2@(0x10)        | store SysBase->IDNestCnt
	moveb	#-1,a6@(0x126)              | set interrupt control
	movew	#0xc000,0xdff09a
	leal	a6@(0x196:W),a0             | &SysBase->TaskReady
loop:	movel	a0@,a2			    | ->lh_Head
	movel	a2@,d0			    | ->ln_Succ()
	jeq	ready
	stop	#0x2000 		    | wait for interrupts
	movew	#0x2700,sr		    | disable interrupts
	jra	loop
ready:	movel	d0,a1			    | remove first node
	movel	a1,a0@
	movel	a0,a1@(4:W)
	movel	a2,a6@(0x114:W)             | store it into SysBase->ThisTask
	moveb	a2@(0x10),a6@(0x126)        | restore SysBase->IDNestCnt
	jpl	nodis
	movew	#0x4000,0xdff09a	    | set interrupt control
nodis:	btst	#7,a2@(0xe)                 | TB_LAUNCH
	jeq	nolnch
	movel	a2@(0x86),a5
	jsr	a5@
nolnch: movel	a2@(0x36),a5                | get ThisTask->tc_SPReg
	btst	#5,a2@(0xe)                 | TF_EXCEPT set?
	jeq	noexc
	bclr	#5,a2@(0xe)
	movel	a5@(14*4),d0                | swap returnaddress
	movel	a5@(14*4+6),a5@(14*4)       | and stored a5
	movel	d0,a5@(14*4+6)
	movew	#0x4000,0xdff09a	    | mini-disable
	movel	a5,usp			    | prepare going to user mode
	movel	exloop,sp@-
	clrw	sp@-
	rte
exloop: movel	a2@(0x1e),d0                | get signals causing the exception
	andl	a2@(0x1a),d0
	jeq	excend			    | none?
	eorl	d0,a2@(0x1e)                | disable them
	movel	a2@(0x26),a1                | tc_ExceptData
	movel	a2@(0x2a),a0                | tc_ExceptCode
	movew	#0xc000,0xdff09a	    | mini-enable
	jsr	a0@
	movew	#0x4000,0xdff09a
	orl	d0,a2@(0x1e)                | reenable signals
	jra	exloop			    | look again
excend: movew	#0xc000,0xdff09a	    | OK, we're done.
	moveml	sp@+,d0-d7/a0-a4/a6
	movel	sp@+,a5
	movew	sp@+,ccr
	rts
noexc:	movew	#0x2000,sr		    | enable interrupts
	moveml	a5@+,d0-d7/a0-a4/a6
	movel	a5@+,sp@-
	movew	a5@+,sp@-
	movel	a5@+,sp@-
	movel	a5,usp
	movel	sp@+,a5
	rte
