;processa.sr - Lampson&Metcalfe Process Primitives - ALTOASM

;**some of this was cut out by Factory because dup in BFSML.A

;External links

	.bext GetStackPointer,PCBTemplate,ProcessSave
	.bext Block,DisableInterrupts,EnableInterrupts
	.bext EndProcessInit,CurrentPCB,WakeUpBits
	.bext GetProcessNumber,Noop,TruePredicate,FalsePredicate
	.bext CLoad

	.srel
GetStackPointer: .GetStackPointer
PCBTemplate: .PCBTemplate
ProcessSave: .ProcessSave
Block: .Block
WakeUpBits: .WakeUpBits
CLoad: .CLoad	;Just to find it, no use yet
EndProcessInit: .EndProcessInit
GetProcessNumber: .GetProcessNumber

Noop:		.Noop
TruePredicate:	.TruePredicate
FalsePredicate:	.FalsePredicate

CurrentPCB:	.PCBTemplate	;Template is PCB for main
	.nrel

	callswat=77400 ;Trap to SWAT




;Template for process control block
;Must be consistent with definitions in PROCESS.BC
;Used to store state of "main process"

.PCBTemplate:
PCB:

	;Dummy frame at base of process's stack
DummyF: 0 ;pointer to self, by EndProcessInit
	0 ;To be filled in with SWAT-1

	;Interrupts come here directly for context switch
Save3: sta 3 Previous3
JSRProcessSave: jsr@ AdrProcessSave

	;State of machine at time of (last) interrupt
Base:
Saved0:	0
Saved1: 0
Saved2: 0
Saved3: 0
SavedCarry: 0
SavedPC: 0
SavedStackMinimum: 0
SavedInterruptsActive: 0

PreviousPCBPointer: 0	;PCB of interrupted process
Previous3: 0		;Used during context switch only
Previous2: 0

AdrProcessSave: 0	;Address of shared context-switching code
StackLow: 0		;Lowest value reached by stack (unused)
ProcessNumber: 0	;0-14 are interrupt processes
State: 0		;0 running, 1 suspended, 2 blocked
PCBPointer: 0		;Holds pointer to this PCB
LinkPointer: 0		;For stringing PCB's together

.PCBTemplateEnd:

PCBSize=.PCBTemplateEnd-.PCBTemplate




;ProcessSave - saved machine state in PCB off ac 3

InterruptPC: 500	;PC stashed here at interrupt time
InterruptsActive: 453	;1 if interrupt can happen
WakeUpsWaiting: 452	;1 means interrupt pending
StckMin=335		;Address of word holding stack minimum
AdrCurrentPCB: CurrentPCB ;Pointer to static

.ProcessSave:

	;Finish saving state of previously running process
	sta 2 Previous2-Base,3	;Tuck his 2 for now
	lda 2 @AdrCurrentPCB	;Get his PCB
	mov 2 2 snr		;PCB must be non-zero
	callswat
	sta 2 PreviousPCBPointer-Base,3	;Tell whom to resume
	sta 0 Saved0-PCB,2	;Tuck his 0 in his PCB
	sta 1 Saved1-PCB,2
	lda 0 Previous3-Base,3	;Get back his 3
	sta 0 Saved3-PCB,2	;Put in his PCB
	lda 0 Previous2-Base,3	;Get back his 2
	sta 0 Saved2-PCB,2
	movl 0 0 ;Carry
	sta 0 SavedCarry-PCB,2	;His carry
	lda 0 @InterruptPC
	sta 0 SavedPC-PCB,2	;His PC
	lda 0 StckMin		;Current stack minimum
	sta 0 SavedStackMinimum-PCB,2
	lda 1 @InterruptsActive
	sta 1 SavedInterruptsActive-PCB,2
	lda 0 State-PCB,2	;Get his state, better be running
	mov 0 0 szr		;0 is running
	callswat
	subzl 0 0		;make a 1
	sta 0 State-PCB,2	;mark suspended
	lda 0 PCBPointer-Base,3 ;PCB for new process




	;Load context of process, PCB in ac0
	;Restriction of interrupts in ac1
	;Interrupts off
.CLoad:	mov 0 3 snr		;Check and move to index
	callswat		;Swat if restoring with zero PCB
	lda 0 State-PCB,3	;Get state of new process
	mov 0 0 snr		;better not be running
	callswat
	sub 0 0			;make a 0
	sta 0 State-PCB,3	;mark running
	sta 3 @AdrCurrentPCB	;New guy now
	lda 0 SavedInterruptsActive-PCB,3
	and 1 0			;Allow only if already allowed
	sta 0 @InterruptsActive
	lda 0 SavedStackMinimum-PCB,3
	sta 0 StckMin
	lda 0 SavedPC-PCB,3
	sta 0 @InterruptPC
	lda 0 SavedCarry-PCB,3
	movr 0 0
	lda 0 Saved0-PCB,3
	lda 1 Saved1-PCB,3
	lda 2 Saved2-PCB,3
	lda 3 Saved3-PCB,3
	bri	;start us up with interrupts on now

;Block - Give processor up, done running
.Block:

	;Store state required to unBlock at next WAKEUP
	inc 3 1			;Point at where to wakeup
	lda 3 @AdrCurrentPCB	;Find out who we are
	mov 3 3 snr		;Check
	callswat
	lda 0 PreviousPCBPointer-PCB,3 ;Whom to start
	dir			;Disable interrupts
	sta 1 SavedPC-PCB,3	;Just save PC and AC2
	sta 2 Saved2-PCB,3
	adc 1 1			;all interrupts previous ok now
	lda 2 Block2		;This process now blocked
	sta 2 State-PCB,3	;Mark us blocked
	jmp .CLoad

Block2:	2	;State of a blocked process




;GetStackPointer - Returns current stack pointer
.GetStackPointer: mov 2 0 ;return as value
	jmp 1,3 ;return

;EndProcessInit - Leave process context after initialization
;One arg is initial code pointer for process
.EndProcessInit:

	;Get back to main context, fix up dummy to itself
	lda 2 0,2 ;Point at PCB dummy frame
	sta 0 SavedPC-PCB,2 ;stash intial PC in PCB
	lda 1 SavedStackMinimum-PCB,2 ;Saved by BeginProcessInit
	lda 0 StckMin
	sta 1 StckMin
	sta 0 SavedStackMinimum-PCB,2 ;Ready to run
	lda 0 0,2 ;Get initializers original frame
	sta 2 0,2 ;Dummy frame should really point to itself
	mov 0 2 ;Now running over original
	jmp 1,3 ;return




;WakeUpBits - Or bits into WakeUps waiting
;One arg is bit pattern to be ORed (usually only 1 on)
.WakeUpBits:

	dir	;no interrupts just now
	lda 1 @WakeUpsWaiting
	com 0 0	;inclusive or
	and 0 1
	adc 0 1
	sta 1 @WakeUpsWaiting
	eir	;interrupts ok now
	jmp 1,3	;return

;GetProcessNumber - Returns process number
;-1 means no PCB so no process number
;If an arg, use as PCB instead of current
.GetProcessNumber:

	sta 3 1,2	;stash return pc
	lda 3 0,3	;number of args
	mov 3 3 szr	;skip if none, if use current
	mov 0 3 skp	;assume 1 arg, PCB in ac0
	lda 3 @AdrCurrentPCB
	mov 3 3 snr
	adc 0 0 skp	;no pcb, return -1
	lda 0 ProcessNumber-PCB,3
	lda 3 1,2	;restore return pc
	jmp 1,3

;Noop - Just returns, does nothing
.Noop:	jmp 1,3

;TruePredicate - Just returns true
.TruePredicate:
	adc 0 0		;-1
	jmp 1,3		;return

;FalsePredicate - Just returns false
.FalsePredicate:
	sub 0 0		;0
	jmp 1,3		;return





; miscellaneous machine code

; frame
	callersFrame=0
	savedPC=1
	temp=2
	extraArguments=3

; machine code for messing with frames

	.srel
Null:	pNull
	.bext CoCall,CallFrame,GotoFrame,CoReturn,Null

	.nrel
pNull:	jmp 1,3




	.srel
prototypeStream: .prototypeStream
	.bext prototypeStream

	.nrel
; this must agree with the ST declaration
	.bext SYSERR
.prototypeStream: 0
	Null		; open
	Null		; close
	SYSERR		; gets
	SYSERR		; puts
	Null		; reset
	SYSERR		; putback
	SYSERR		; error
	FalsePredicate	; endof
	FalsePredicate	; stateof
	0
	0
	0
	0
	0


	.end