; Context.asm -- CONTEXT -- Assembly Code
; Copyright Xerox Corporation 1979

;	Last modified November 4, 1977  5:24 PM

	.ent CallContextList
	.ent Block
	.ent Yield
	.ent CtxCaller
	.ent CtxRunning
	.ent CtxSwitch

; Offsets into CTX structure:
	CTXNext=0
	CTXStack=1
	CTXStackMin=2

; Bcpl runtime information
	StkMin=335


	.srel

CallContextList: .CallContextList
Block:		.Block
Yield:		.Block		; Yield same as Block initially
CtxCaller:	0
CtxRunning:	dummyCtx
CtxSwitch:	0		; Used by ContextSched

	.nrel

; CallContextList(ctx)
; Successively resumes each context on the list starting at ctx
; until it executes Block().  Returns after the last context on
; the list has blocked.

.CallContextList:
	sta 3 1 2		; Save return in normal spot
	lda 1 @lvCtxCaller	; Save CtxCaller in frame
	sta 1 2 2
	lda 1 @lvCtxRunning	; Save CtxRunning in frame
	sta 1 3 2
	lda 1 StkMin		; Save StkMin below frame (yes, this is safe!)
	sta 1 -1 2
	sta 2 @lvCtxCaller	; Establish new CtxCaller frame
	jmp nxtCtx		; Go resume first context

; Here when the resumed context executes Block()
.Block:	inc 3 3			; Generate real return address
	sta 3 1 2		; Save in canonical spot
block1:	lda 3 @lvCtxRunning	; Get current context
	sta 2 CTXStack 3	; Save our stack pointer
	lda 1 StkMin		; Save our StkMin
	sta 1 CTXStackMin 3
	lda 0 CTXNext 3		; Find next context to try

; Here to resume next context on list
nxtCtx:	mov 0 3 snr
	 jmp donCtx		; No more on list to run
	sta 3 @lvCtxRunning	; Record context about to be run
	lda 1 CTXStackMin 3
	sta 1 StkMin		; Stack bounds
runCtx:	sta 3 @lvCtxSwitch	; Note that contexts have switched
	lda 2 CTXStack 3	; Get the stack to run it in
	jsr @1 2		; And return from its Block().
	 1			; On first call, arg is context
	jmp block1		; If he returns, call him again

; Here when no more contexts on list
donCtx:	lda 2 @lvCtxCaller	; Get stack for CallContextList
	snz 2 2
	 jmp notCtx		; Block called outside of context
	lda 0 -1 2		; Restore previous StkMin
	sta 0 StkMin
	lda 0 3 2		; Restore previous CtxRunning
	sta 0 @lvCtxRunning
	lda 0 2 2		; Restore previous CtxCaller
	sta 0 @lvCtxCaller
	lda 3 1 2
	jmp 1 3			; Return from CallContextList

; What happens if Block() is called outside of any context
notCtx:	lda 3 @lvCtxRunning	; Just re-run the dummy context
	jmp runCtx

lvCtxCaller:	CtxCaller
lvCtxRunning:	CtxRunning
lvCtxSwitch:	CtxSwitch

dummyCtx: 0		; The dummy context has "next" of zero
	.blk 2		; Clobbered by Stack and StackMin 

	.end