TITLE[MesaP--Pilot.or.Alto.Mode];

* Process Microcode;

*PSB format
MC[CleanUpOffset, 1];
MC[TimeOffset, 2];
MC[FlagsOffset, 3];
MC[FrameOffset, 4];
MC[Priority, 7];
MC[WaitingOnCV, 10];
MC[AbortPending, 40];
MC[TimeoutAllowed, 100];
MC[EnterFailed, 100000];
MC[SizePSB, 5];

*Monitor Lock format
MC[LockBit, 100000];

*Condition Variable format
MC[WWBit, 100000];

*  Constants
MC[CleanQueue1, 0];
MC[CleanQueue2, 1];
MC[NegInfinity, 100000];
MC[CVBase, 40];
MC[TimerBit, 20];
MC[TimeLocation, 344];

*Dispatch bas address
SET[ProcessDisp, LSHIFT[prPage,10]];

%PRFlags holds opcode dispatch values and general flags.  Its interpretation is:

  bit 0		0 => Clean Queue 1
		1 => Clean Queue 2

  bit 10	0 => Requeue not done
		1 => Requeue done

  bits 16,17	0 => Notify
		1 => Broadcast
		2 => Naked Notify
		3 => not used

  bits 12-15	Opcode Dispatch

All flag constants except NakedNotifyFlags are cycled right 1 in order
to set bit 0 if necessary.
%

*Flag values
MC[MEFlags, 0];			* Dispatch to 0
SET[MEloc, 0];
MC[MREFlags, 21];		* Dispatch to 2, Clean Queue 2
SET[MREloc, 2];
MC[MXWFlags, 51];		* Dispatch to 5, Clean Queue 2
SET[MXWloc, 5];
MC[MXDFlags, 61];		* Dispatch to 6, Clean Queue 2
SET[MXDloc, 6];
MC[NOTIFYFlags, 100];		* Dispatch to 10, Clean Queue 1, Notify
MC[BCASTFlags, 102];		* Dispatch to 10, Clean Queue 1, Broadcast
SET[WakeHeadloc, 10];
MC[REQFlags, 130];		* Dispatch to 13
SET[REQloc, 13];
MC[NakedNotifyFlags, 2];	* Clean Queue 1, Naked Notify, not cycled
MC[RequeueOccured, 200];	* Requeue occured, not cycled

	ONPAGE[opPage0];

*ME
@ME:	GOTO[CheckLong1], PRFlags ← (MEFlags), opcode[1];	* Monitor Lock

*MRE
@MRE:	GOTO[CheckLong2], PRFlags ← (MREFlags), opcode[2];	* CV, Lock

*MXW
@MXW:	PRFlags ← (MXWFlags) , opcode[3];			* Time, CV, Lock
MXWx:	T ← Stack&-1;	
	GOTO[CheckLong2], Process ← T;

*MXD
@MXD:	GOTO[CheckLong1], PRFlags ← (MXDFlags), opcode[4];	* Monitor Lock

*NOTIFY
@NOTIFY:
	GOTO[CheckLong1], PRFlags ← (NOTIFYFlags), opcode[5];	* CV

*BCAST
@BCAST:	GOTO[CheckLong1], PRFlags ← (BCASTFlags), opcode[6];	* CV

*REQUEUE
@REQUEUE:
	PRFlags ← (REQFlags), goto[MXWx], opcode[7];		* Process, Q1, Q2

CheckLong2:
	T ← (373c); * Stkp value for two long pointer operands (4).
	T ← (nStkp) XOR (T);	* Check for stack size of 4.
	T ← RHMask[MDShi], dblgoto[Short2, Long2, ALU#0];

CheckLong1:
	T ← (375c);	* Stkp value for one long pointer operand (2).
	T ← (nStkp) XOR (T); 	 * Check for stack size of 2.
	T ← RHMask[MDShi], dblgoto[Short1, Long1, ALU#0];

Short2:	Queue2hi ← T, call[FixQueue2];
	T ← RHMask[MDShi], goto[Short1];

Long2:	T ← Stack&-1;
	Queue2hi ← T, call[FixQueue2];
	T ← Stack&-1, goto[Short1];

Long1:	T ← Stack&-1;
Short1:	Queue1Hi ← T, goto[FixQueue1];

FixQueue2:
	T ← Queue2hi ← (lsh[Queue2hi,10]) + (T) + 1;
	Queue2hi ← (fixVA[Queue2hi]) or (T);
	T ← Stack&-1;
	Queue2 ← T, return;

FixQueue1:
	T ← Stack&-1, TASK;
	Queue1 ← T;
	lu ← (Queue1hi) OR (T);
	T ← Queue1hi, skip[alu = 0];
	  T ← Queue1hi ← (lsh[Queue1hi,10]) + (T) + 1;
	Queue1hi ← (fixVA[Queue1hi]) or (T), goto[ProcessOps];


ProcessOps:
	LoadPage[prPage];
	Dispatch[PRFlags, 11, 4], gotop[ProcessDispatch];

	OnPage[prPage];

ProcessDispatch:
	PRFlags ← RCY[PRFlags, 1], Disp[MEnter];

*************************************************************************
*	Monitor Enter;
*
*		Input
*	Queue1		Base register pointing at monitor queue
*
*		Temps
*	MQ		process handle
*
*		Constants
*	CurrentPSB	21B, address of CurrentPSB
*	LockBit		100000B, lock bit of Monitor Lock
*
*************************************************************************
MEnter:	T ← (CurrentPSB), call[Queue1ToMQ], AT[ProcessDisp, MEloc];
	lu ← MQ, goto[MELocked, R >= 0];
	MQ ← (MQ) AND NOT (LockBit), call[MQToQueue1];
MRENoAbort:
	Stack&+1 ← 1C;	* even location
PrTail:	LoadPage[opPage0];
	goto[P4Tail];

MELocked:
	PFetch1[PBase, Process], goto[MREnterFailed];


*************************************************************************
*	Monitor ReEnter;
*
*		Input
*	Queue1		Base register pointing at monitor queue
*	Queue2		Base register pointing at condition queue
*
*		Temps
*	PBase		Base register of PSBs
*	Process		process handle
*	RTemp1		temp
*
*		Constants
*	LockBit		100000B, lock bit of Monitor Lock
*	CleanUpOffset	1, offset of cleanup link in PSB
*	FlagsOffset	3, offset of flags and priority in PSB
*	CurrentPSB	21B, address of CurrentPSB
*	sProcessTrap	17B, offset of sProcessTrap in SD
*
*************************************************************************


MREnter:
	T ← (CurrentPSB), call[Queue1ToMQ], AT[ProcessDisp, MREloc];
	call[PBaseToProcess];
	lu ← MQ, goto[MREnterFailed, R >= 0];		* ignore ww bit
	UseCTask, call[CleanUpQueue];			* Clean up Queue1
	MQ ← (MQ) AND NOT (LockBit), call[MQToQueue1];
	T ← (Process) + (CleanUpOffset), call[ZeroToPBase];
	T ← (Process) + (FlagsOffset), call[PBaseToRTemp1];
	lu ← (RTemp1) AND (AbortPending);
	goto[MRENoAbort, alu = 0];
	T ← (sProcessTrap);
PRTrap:	LoadPage[opPage3];
	gotop[kfcr];

MREnterFailed:
	T ← Queue1;
	Queue2 ← T, TASK;
	T ← Queue1hi;
	Queue2hi ← T;
	T ← (MDShi) or (1c), call[ReadyInQueue1];
	T ← (Process) + (FlagsOffset), call[PBaseToRTemp1];
	RTemp1 ← (RTemp1) OR (EnterFailed), call[RTemp1ToPBase];
	goto[RequeueOp];

*************************************************************************
*	Monitor Exit and Depart;
*
*		Input
*	Queue1		Base register pointing at  monitor queue
*
*************************************************************************
MXDepart:
	UseCTask, call[ExitMon], AT[ProcessDisp, MXDloc];
	T ← PRFlags, goto[ReSchedule];

*************************************************************************
*	Exit Monitor;
*
*		Input
*	Queue1		Base register pointing at  monitor queue
*
*		Temps
*	PBase		Base register of PSBs
*	MQ		process handle
*	Process		process handle
*	EMLink		return link
*
*		Constants
*	LockBit		100000B, lock bit of Monitor Lock
*
*************************************************************************
ExitMon:
	T ← APC&APCTask, call[Queue1ToMQ];
	EMLink ← T;
	T ← MQ ← (MQ) AND NOT (LockBit);
	goto[EMUnlock, alu = 0];
	PFetch1[PBase, Process], call[ReadyInQueue2];
	UseCTask, call[RequeueSub];
	call[Queue1ToMQ];		* Requeue may have changed MQ
	goto[EMUnlock];
EMUnlock:
	MQ ← (MQ) OR (LockBit);
	PStore1[Queue1, MQ, 0], call[PRRet];
	APC&APCTask ← EMLink, goto[PRRet];

*************************************************************************
*	Monitor Exit and Wait;
*
*		Input
*	Queue2		Base register pointing at condition queue
*	Queue1		Base register pointing at monitor queue
*	Process		Timeout value
*
*		Temps
*	PBase		Base register of PSBs
*	MQ		process handle
*	PRTime		holds timeout value
*	RTemp1		process handle
*
*		Constants
*	WWBit		100000B, ww bit of Condition
*	LockBit		100000B, lock bit of Monitor Lock
*	CleanUpOffset	1, offset of cleanup link in PSB
*	TimeOffset	2, offset of flags and priority in PSB
*	FlagsOffset	3, offset of flags and priority in PSB
*	WaitingOnCV	10B, WaitingOnCV bit of PSB
*	AbortPending	40B, AbortPending bit of PSB
*	TimeoutAllowed	100B, TimeoutAllowed bit of PSB
*	CurrentPSB	21B, address of CurrentPSB
*	TimeLocation	344B, address of Timeout time in Memory
*
*************************************************************************
MXWait:	T ← Process, AT[ProcessDisp, MXWloc];
	PRTime ← T, UseCTask, call[CleanUpQueue];
	T ← QTemp, call[SwapQTempAndQ2];
	UseCTask, call[ExitMon];
	T ← (CurrentPSB), call[PBaseToProcess];
	T ← (Process) + (FlagsOffset), call[PBaseToRTemp1];
	lu ← (RTemp1) AND (AbortPending);
	goto[MXWAbort, alu # 0];
	PFetch1[QTemp, MQ, 0];
	call[PRRet];
	MQ ← (MQ) AND NOT (WWBit), goto[MXWOntoCV, R >= 0];
	PStore1[QTemp, MQ, 0], call[PRRet];
	T ← PRFlags, goto[ReSchedule];
MXWOntoCV:
	lu ← PRTime;
	RTemp1 ← (RTemp1) OR (WaitingOnCV), goto[MXWHaveTime, alu = 0];
	T ← (TimeLocation), call[PBaseToCurrentTime];
	T ← CurrentTime;
	PRTime ← (PRTime) + (T);
	goto[MXWHaveTimex, alu # 0];
	PRTime ← (PRTime) + 1;
MXWHaveTime:
	nop;
MXWHaveTimex:
	T ← (MDShi) or (1c), call[ReadyInQueue1];
	T ← QTemp, call[SwapQTempAndQ2];
	T ← (Process) + (FlagsOffset), call[RTemp1ToPBase];
	UseCTask, call[RequeueSub];
	T ← (Process) + (TimeOffset), call[PRTimeToPBase];
	T ← PRFlags, goto[ReSchedule];

MXWAbort:
	T ← PRFlags, goto[ReSchedule];

SwapQTempAndQ2:
	MNBR ← Queue2, Queue2 ← T, NoRegILockOK;
	T ← MNBR;
	QTemp ← T;
	T ← QTemphi;
	MNBR ← Queue2hi, Queue2hi ← T, NoRegILockOK;
	T ← MNBR;
	QTemphi ← T, return;

*************************************************************************
*	Notify Broadcast;
*
*		Input
*	Queue1		Base register of queue to be notified
*
*		Temps
*	PBase		Base register of PSBs
*	MQ		process handle
*	RTemp1		process handle
*	Process		process handle
*	PRTime		Did something
*	PRFlags		flags
*
*		Constants
*	WWBit		100000B, ww bit of Condition
*	NegInfinity	100000B
*	FlagsOffset	3, offset of cleanup link in PSB
*	WaitingOnCV	10B, WaitingOnCV bit in PSB
*
*************************************************************************
WakeHead:
	UseCTask, call[CleanUpQueue], AT[ProcessDisp, WakeHeadloc];
WHLoop:
	PRTime ← (Zero), call[Queue1ToMQ];
	MQ ← T ← (MQ) AND NOT (WWBit);
	lu ← LDF[PRFlags, 16, 1], goto[WHExit, alu = 0];
	T ← MQ, call[PBaseToProcess];
	PRTime ← (1c), call[ReadyInQueue2];
	T ← (Process) + (FlagsOffset), call[PBaseToRTemp1];
	RTemp1 ← (RTemp1) AND NOT (WaitingOnCV), call[RTemp1ToPBase];
	UseCTask, call[RequeueSub];
	lu ← PRFlags, goto[WHLoopx, R odd];
	lu ← LDF[PRFlags, 16, 1], goto[WHExit];
WHLoopx:
	goto[WHLoop];
WHExit:	T ← PRFlags, goto[ReSchedule, alu = 0];
	lu ← PRTime, dblgoto[SetWWBit, NakedNotified, R even];
SetWWBit:
	MQ ← (WWBit), call[MQToQueue1];		* even location
NakedNotified:
	IntLevel ← (IntLevel) + 1, LoadPage[OpPage0];	* odd location
	goto[CheckCV];

*************************************************************************
*	Requeue;
*
*	calling instruction must include UseCTask
*
*		Input
*	Queue1		Base register pointing at queue
*	Queue2		Base register pointing at queue
*	Process		process handle
*
*		Output
*	ReSched		BOOLEAN
*
*		Temps
*	PBase		Base register of PSBs
*	Prev		process handle
*	RTemp		Process.link until insert, then Process.priority
*	RTemp1		process handle, priority
*	RTemp2		process handle, priority
*	RLink		return address
*
*		Constants
*	CleanUpOffset	1, offset of cleanup link in PSB
*	FlagsOffset	3, offset of flags and priority in PSB
*	Priority	7, priority bits
*	RequeueOccured	200B
*
*************************************************************************
RequeueOp:
	UseCTask, call[RequeueSub], AT[ProcessDisp, REQloc];
	T ← PRFlags, goto[ReSchedule];

RequeueSub:
	T ← APC&APCTask;
	RLink ← T;
	T ← Process, call[PBaseToRTemp];
	lu ← (RTemp) - (T);
	lu ← Queue1hi, goto[RQGotPP, alu = 0];	* only one process
	goto[RQLoop1, alu = 0];			* Queue1 NIL, T = Process
	PFetch1[Queue1, Prev, 0], call[PRRet];
	T ← Prev, goto[RQLoop1x];
RQLoop1:
	Prev ← T;
RQLoop1x:
	Prev ← T, call[PBaseToRTemp1];
	T ← RTemp1;
	lu ← (Process) - T;
	goto[RQLoop1x, alu # 0];
	T ← Prev;
	call[RTempToPBase];	* RTemp has Process.link
RQFixCV:
	lu ← Queue1hi;
	T ← (Process) + (CleanUpOffset), goto[RQHaveQ1, alu # 0];
	PStore1[PBase, RTemp];
	call[PRRet];
	goto[RQInsrt];
RQGotPP:
	T ← Prev ← (Zero), goto[RQFixCV];
RQHaveQ1:
	PFetch1[Queue1, RTemp1, 0];
	T ← Process, call[PRRet];
	lu ← (RTemp1) - (T);
	goto[RQInsrt, alu # 0];
	PStore1[Queue1, Prev, 0];
	call[PRRet];
	goto[RQInsrt];
RQInsrt:
	PFetch1[Queue2, Prev, 0], call[PRRet];
	lu ← Prev;
	T ← Process, goto[RQNilPP, alu = 0];
	T ← (Process) + (FlagsOffset), call[PBaseToRTemp];
	T ← (Prev) + (FlagsOffset), call[PBaseToRTemp1];
	RTemp ← (RTemp) AND (Priority);
	T ← (RTemp1) AND (Priority);
	lu ← (RTemp) - T - 1;
	T ← Prev, goto[RQFixQ2, alu < 0];
	goto[RQLoop2];
RQLoop2:
	Prev ← T, call[PBaseToRTemp1];
	T ← (RTemp1) + (FlagsOffset), call[PBaseToRTemp2];
	T ← (RTemp2) AND (Priority);
	lu ← (RTemp) - T - 1;
	T ← RTemp1, dblgoto[RQInsrtHere, RQLoop2, alu >= 0];
RQFixQ2:
	PStore1[Queue2, Process, 0], call[PRRet];
RQInsrtHere:
	T ← Prev;
	call[PBaseToRTemp1];
	T ← Process, call[RTemp1ToPBase];
	T ← Prev, call[ProcessToPBase];
RQRet:	T ← (Process) + (TimeOffset), call[ZeroToPBase];
	APC&APCTask ← RLink;
	PRFlags ← (PRFlags) OR (RequeueOccured), return;
RQNilPP:
	T ← Process;
	call[ProcessToPBase];
	PStore1[Queue2, Process, 0], goto[RQRet];

*************************************************************************
*	CleanUpQueue;
*	  this routine cleans up a queue which may possibly
*	  have been left in a mess by Requeue.
*
*	calling instruction must include UseCTask
*
*		Input
*	PRFlags		even => clean Queue1, odd => clean Queue2
*
*		Temps
*	PBase		Base register of PSBs
*	RTemp		process handle
*	RTemp1		process handle
*	MNBR		process handle
*	RLink		return address
*
*		Constants
*	WWBit		100000B, ww bit of Condition
*	CleanUpOffset	1, offset of cleanup link in PSB
*
*************************************************************************
CleanUpQueue:
	T ← APC&APCTask;
	RLink ← T, call[CQueueToRTemp];			* get pointer to tail
	RTemp ← (RTemp) AND NOT (WWBit);		* ignore ww bit
	T ← (RTemp) + (CleanUpOffset), goto[CURet, alu = 0];
	Pfetch1[PBase,RTemp1], call[PRRet];		* get head of queue
	lu ← T ← RTemp1;
	lu ← (RTemp) - (T), goto[CURetx, alu=0];
	RTemp ← T, goto[CUEmpty, alu = 0];
CULoop:	T ← (RTemp) + (CleanUpOffset), call[PBaseToRTemp1];	* get head of queue
	lu ← T ← RTemp1;
	lu ← (RTemp) - (T), goto[CUFoundHead, alu=0];
	goto[CUEmptyx, alu = 0];
	RTemp ← T, goto[CULoop];
CUEmpty:
	RTemp ← (Zero), goto[CUFixCV];
CUEmptyx:
	RTemp ← (Zero), goto[CUFixCV];
CUFoundHead:
	T ← MNBR ← RTemp;
CULoop2:
	RTemp ← T, call[PBaseToRTemp1];
	T ← RTemp1;
	lu ← (MNBR) - (T);
	goto[CULoop2, alu # 0];
	nop;
CUFixCV:
	call[RTempToCQueue];
CURet:	APC&APCTask ← RLink, goto[PRRet];
CURetx:	APC&APCTask ← RLink, goto[PRRet];

CQueueToRTemp:
	lu ← PRFlags, DBLGoto[Queue1ToRTemp, Queue2ToRTemp, R >= 0];
RTempToCQueue:
	lu ← PRFlags, DBLGoto[RTempToQueue1, RTempToQueue2, R >= 0];

*************************************************************************
*	ReSchedule;
*
*		Input
*	T		contains PRFlags
*
*		Temps
*	PBase		Base register of PSBs
*	RTemp		process handle
*	RTemp1		process handle
*	MNBR		process handle
*	RLink		return address
*
*		Constants
*	EnterFailed	100000B, EnterFailed bit of PSB
*	CleanUpOffset	1, offset of cleanup link in PSB
*	FlagsOffset	3, offset of priority and flags in PSB
*	FrameOffset	4, offset of frame in PSB
*	CleanUpOffset	1, offset of cleanup link in PSB
*	Priority	7, priority bits in PSB
*	StkPOffset	10B, offset of stack pointer in state vector
*	DestOffset	11B, offset of dest in state vector
*	CurrentPSB	21B, Current process
*	ReadyQ		22B, Ready queue
*	CurrentState	23B, Current state
*
*************************************************************************


ReSchedule:
	goto[PrTail, NoH2Bit8];
	nop;
IntReSch:
	T ← (CurrentState), call[PBaseToRTemp];
	LoadPage[OpPage3];
	callp[SavePCInFrame];
	T ← RTemp, LoadPage[xfPage1];
	xfTemp ← T, UseCTask, callp[SaveState];
	T ← (CurrentPSB), call[PBaseToRTemp1];	* RTemp1 ← currentPSB
	T ← (RTemp1) + (FrameOffset), call[LocalToPBase];
IdleIntRS:
	T ← (ReadyQ);
	call[PBaseToRTemp1];
	lu ← T ← RTemp1;
	lu ← xfWDC, goto[NoneReady, alu = 0];
	call[PBaseToProcess];			* Process ← readylist.link

* setup for new process
	T ← (Process) + (FlagsOffset), call[PBaseToRTemp1];
	RTemp ← (xfAV);
	T ← (RTemp) + (FirstStateVector), call[PBaseToRTemp];
	MNBR ← RTemp1, TASK;
	RTemp1 ← T ← (RTemp1) AND (Priority);
	RTemp1 ← (LSH[RTemp1, 2]) + (T);
	T ← (LSH[RTemp1, 1]) + (T), TASK;
	RTemp ← (RTemp) + (T);

	T ← MNBR, goto[NoEnterFailed, R >= 0];
	RTemp1 ← T;
	RTemp1 ← (RTemp1) AND NOT (EnterFailed);
	T ← (Process) + (FlagsOffset), call[RTemp1ToPBase];
	T ← RTemp, call[ZeroToPBase];		* stack[0] ← 0;
	RTemp1 ← 1c;				* stkp ← 1
	T ← (RTemp) + (StkPOffset), call[RTemp1ToPBase];
NoEnterFailed:
	T ← (Process) + (FrameOffset);
	call[PBaseToRTemp1];
	T ← (RTemp) + (DestOffset), call[RTemp1ToPBase];
	T ← (CurrentPSB), call[ProcessToPBase];		* currentPSB ← process
	T ← (CurrentState), call[RTempToPBase];
	T ← RTemp, LoadPage[xfPage1];
	xfTemp ← T, gotop[LoadStateNF];

NoneReady:
	T ← (sWakeupError), goto[PRTrap, alu # 0];
	IntType ← T ← (Zero); *PC backup amount, Stkp value for MIPend
	call[IdleLoop];
IdleLoop:
	goto[MIPend, IntPending];
PRRet:	return;

*Get here with Stkp in T (0 if from IdleLoop), PC backup amount in IntType.
MIPend:
	RTEMP1 ← pRSImage; *Clear IntPending
	Stkp ← RTEMP1, RTEMP1 ← T, NoRegILockOK;
	T ← Stack ← (Stack) and not (IntPendingBit);
	Stkp ← RTEMP1, RS232 ← T;

	T ← IntType; *back up the PC
	T ← (PCFreg) - T, goto[NoBackup,ALU=0];
	xfTemp ← T;
	PCF ← xfTemp;

NoBackup:	T ← NWW; *Check (NWW#0 & xfWDC=0)
	lu ← xfWDC, skip[ALU#0];
	return;
	skip[ALU=0];
	return;

*We are going to cause the interrupt
	PFetch4[LOCAL,LocalCache0,4]; *refill cache in case the interrupt came from BitBlt
	PRFlags ← 0c;
	NWW ← (Zero);
	WW ← T, LoadPage[OpPage0]; *Promote NWW into WW
	lu ← LDF[WW, 13, 1], goto[Interrupt];

PBaseToProcess:
	PFetch1[PBase, Process], return;
ProcessToPBase:
	PStore1[PBase, Process], return;

PBaseToRTemp:
	PFetch1[PBase, RTemp], return;
RTempToPBase:
	PStore1[PBase, RTemp], return;
PBaseToRTemp1:
	PFetch1[PBase, RTemp1], goto[PRRet];
RTemp1ToPBase:
	PStore1[PBase, RTemp1], goto[PRRet];

PBaseToRTemp2:
	PFetch1[PBase, RTemp2], return;

Queue1ToRTemp:
	PFetch1[Queue1,RTemp,0], return;
RTempToQueue1:
	PStore1[Queue1,RTemp,0], return;

Queue2ToRTemp:
	PFetch1[Queue2,RTemp,0], return;
RTempToQueue2:
	PStore1[Queue2,RTemp,0], return;

Queue1ToMQ:
	PFetch1[Queue1,MQ,0], goto[PRRet];
MQToQueue1:
	PStore1[Queue1,MQ,0], goto[PRRet];

PRTimeToPBase:
	PStore1[PBase, PRTime], return;
ZeroToPBase:
	PStore1[PBase, RZero], return;
LocalToPBase:
	PStore1[PBase, Local], return;

PBaseToCurrentTime:
	PFetch1[PBase, CurrentTime], return;

ReadyInQueue1:
	Queue1hi ← T;
	Queue1 ← (ReadyQ), return;

ReadyInQueue2:
	T ← (MDShi) or (1c);
	Queue2hi ← T;
	Queue2 ← (ReadyQ), return;

*************************************************************************
*	Interrupt Processing;
*
*		Input
*	WW		Wakeups Waiting register
*	TickCount	number of ticks until scaning PSBs required
*	CurrentTime	current time
*
*		Temps
*	IntLevel	pointer to CV array elements
*	IntType		even => idle loop interrupt
*	ITemp		temp
*	ITemp1		temp
*
*		Constants
*	WWBit		100000B, ww bit of Condition
*	TimeOffset	2, offset of time in PSB
*	FlagsOffset	3, offset of flags and priority in PSB
*	WaitingOnCV	10B, WaitingOnCV bit of PSB
*	NakedNotifyFlags
*
*************************************************************************
* Interrupt Processing

	onpage[OpPage0];

Interrupt:
	WW ← (WW) AND NOT (TimerBit), goto[TimerInterrupt, alu # 0];
	IntLevel ← (CVBase);
CheckCV:
	call[ThisCV];
ThisCV:	WW ← RSH[WW, 1], goto[IntThisCV, R odd];
	goto[IntDone, alu = 0];	* load page for done
	IntLevel ← (IntLevel) + 1, return;
	
IntThisCV:
	T ← IntLevel, Call[IntPBaseToQueue1];
	lu ← Queue1;
	T ← (MDShi) or (1c), goto[DoNothing, alu = 0]; *T ← ReadyQueuehi
	Queue1hi ← T, LoadPage[prPage];
	PRFlags ← (PRFlags) OR (NakedNotifyFlags), goto[WakeHead];

DoNothing:
	IntLevel ← (IntLevel) + 1, goto[CheckCV];

IntDone:
	LoadPage[prPage];	* load page for done
	lu ← IntType, dblgotop[IntReSch, IdleIntRS, R odd];

TimerInterrupt:
	TickCount ← (TickCount) - 1;
	IntLevel ← (CVBase), skip[alu = 0];
	  goto[CheckCV];
	ITemp ← (xfAV);
	T ← ITemp ← (ITemp) + (FirstProcess), call[IntPBaseToProcess];
	T ← (ITemp) + 1;
	PFetch1[PBase, ITemp1];
	T ← TimeLocation, call[IntPBaseToCurrentTime];
	CurrentTime ← (CurrentTime) + 1, call[IntCurrentTimeToPBase];
	nop;
TLoop:	T ← (Process) + (TimeOffset);	* can't have call before this
	PFetch1[PBase, ITemp], call[P4Ret];
	lu ← T ← ITemp;
	lu ← (CurrentTime) - (T), goto[CanTimeout, alu # 0];
CheckEnd:
	T ← Process ← (Process) + (SizePSB);
	lu ← (ITemp1) - (T);
	TickCount ← (3c), goto[TLoop, alu >= 0];
	goto[CheckCV];
CanTimeout:
	goto[TimeOut, alu = 0];
	goto[CheckEnd];
Timeout:
	Queue2 ← (ReadyQ);
	Queue1Hi ← (Zero);
	T ← (MDShi) or (1c);
	LoadPage[prPage]; *Make Queue2 the ReadyQueue
	Queue2Hi ← T, UseCTask, call[RequeueSub];
	T ← (Process) + (FlagsOffset), call[IntPBaseToQueue1];
	Queue1 ← (Queue1) AND NOT (WaitingOnCV);
	PStore1[PBase, Queue1], call[P4Ret];
	goto[CheckEnd];

IntPBaseToProcess:
	PFetch1[PBase, Process], goto[P4Ret];
IntPBaseToQueue1:
	PFetch1[PBase, Queue1], goto[P4Ret];

IntPBaseToCurrentTime:
	PFetch1[PBase, CurrentTime], goto[P4Ret];
IntCurrentTimeToPBase:
	PStore1[PBase, CurrentTime], goto[P4Ret];

:END[MesaP];