; ContextSched.asm -- Simple time-slicing scheduler for contexts
; Copyright Xerox Corporation 1979


.ent SchedInterrupt
.ent SchedYield
.ent SchedFinish
.ent schedSavedUFP
.ent schedMask

.bext Block
.bext CtxSwitch
.bext lvUserFinishProc

.srel

SchedInterrupt: .SchedInterrupt
SchedYield: .SchedYield
SchedFinish: .SchedFinish
schedSavedUFP: 0
schedMask: 0

.nrel


; Yield()
; Same as Block() except that if the current context has not yet
; run for a full time slice (17 ms), Yield returns immediately
; at a cost of only 3 instructions.
; This procedure is plugged into the Yield procedure's static
; by InitContextSched.

.SchedYield:
	lda 0 @lvCtxSwitch	; Time slice expired?
	sz 0 0
	 jmp 1 3		; No, continue this context
	lda 0 @lvBlock		; Yes, run other contexts
	sta 0 1 2
	jmp @1 2


; Interrupt routine executed every 17 ms to update the CtxSwitch
; flag.  The flag is handled in the following way:
; When contexts are actually switched (by Block or Yield),
; the Context package sets CtxSwitch to some value other than
; 0 or -1.  At the next 17 ms interrupt, CtxSwitch is set to -1
; as an indication that a time slice has begun.  If CtxSwitch
; is still -1 at the next 17 ms interrupt, then we know the
; current context has run for between 17 and 34 ms, so it is
; time to switch to another context.  This is signalled by setting
; CtxSwitch to 0, which tells Yield to do a Block next time it
; is called rather than returning immediately.

.SchedInterrupt:
	sta 0 save0
	lda 0 @lvCtxSwitch	; Get context switch flag
	mov# 0 0 snr		; Switch already requested?
	 jmp .+4		; Yes, done
	com 0 0 szr		; Any switch in last slice?
	 adc 0 0		; Yes, request switch after next
	sta 0 @lvCtxSwitch	; Update the flag
	lda 0 save0
	bri

lvCtxSwitch: CtxSwitch
lvBlock: Block
save0:	0

; User finish procedure -- turns off scheduler interrupt

.SchedFinish:
	sta 3 1 2
	lda 0 @lvSchedMask
	com 0 0
	lda 1 @lvDisplayInterrupt
	and 0 1
	sta 1 @lvDisplayInterrupt
	lda 1 @lvActive
	and 0 1
	sta 1 @lvActive
	lda 0 @lvSchedSavedUFP
	lda 3 @lvLvUserFinishProc
	sta 0 0 3
	lda 3 1 2
	jmp 1 3

lvSchedMask: schedMask
lvDisplayInterrupt: 421
lvActive: 453
lvSchedSavedUFP: schedSavedUFP
lvLvUserFinishProc: lvUserFinishProc

	.end