:TITLE[MesaP--Alto.mode.only];	*Last edited: 19 January 1981 by Fiala

*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

@ME:	PRFlags ← MEFlags, Goto[CheckLong1], Opcode[1];		*Monitor Lock

@MRE:	PRFlags ← MREFlags, Goto[CheckLong2], Opcode[2];	*CV, Lock

@MXW:	PRFlags ← MXWFlags, Opcode[3];				*Time, CV, Lock
MXWx:	T ← Stack&-1;	
	Process ← T, Goto[CheckLong2];

@MXD:	PRFlags ← MXDFlags, Goto[CheckLong1], Opcode[4];	*Monitor Lock

@NOTIFY:
	PRFlags ← NOTIFYFlags, Goto[CheckLong1], Opcode[5];	*CV

@BCAST:	PRFlags ← BCASTFlags, Goto[CheckLong1], Opcode[6];	*CV

@REQUEUE:
	PRFlags ← REQFlags, Goto[MXWx], Opcode[7];		*Process, Q1, Q2

***Should use MDShi literally here rather than fixing it up in a way that
***makes the LH and RH .ne.; also should start with LH[MDShi] if going to
***do the fixup as shown.
FixQueue2:
	T ← Queue2hi ← (Lsh[Queue2hi,10]) + T + 1;
	Queue2hi ← (FixVA[Queue2hi]) or T;
	T ← Stack&-1;
TtoQueue2:
	Queue2 ← T, Return;

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;
	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;
	LoadPage[prPage];
*Process dispatch
	Dispatch[PRFlags,11,4], GotoP[.+1];
OnPage[prPage];
	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, Skip[R<0];
	  PFetch1[PBase,Process], Goto[MREnterFailed];	*Locked
	MQ ← (MQ) and not (LockBit), Call[MQToQueue1];
MRENoAbort:
	Stack&+1 ← 1C;	* even location
PrTail:	LoadPage[opPage0];
	Goto[P4Tail];


*************************************************************************
*	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 ← Queue1hi;
	Queue2hi ← T, LoadPage[opPage0];
	T ← Queue1, Call[TtoQueue2];
	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];
	LU ← (PRFlags) and (200C), 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 ← APCTask&APC, Call[Queue1ToMQ];
	EMLink ← T;
	T ← MQ ← (MQ) and not (LockBit);
	Goto[EMUnlock,ALU=0];
	PFetch1[PBase, Process], Call[ReadyInQueue2];
	UseCTask, Call[RequeueSub];
	PFetch1[Queue1,MQ,0];
EMUnlock:
	MQ ← (MQ) or (LockBit);
	PStore1[Queue1,MQ,0];
	APCTask&APC ← 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[MXWReSched,ALU#0];
	PFetch1[QTemp,MQ,0];
	MQ ← (MQ) and not (WWBit), Goto[MXWOntoCV,R>=0];
	PStore1[QTemp,MQ,0], Call[PRRet];
	LU ← (PRFlags) and (200C), Goto[ReSchedule];

MXWOntoCV:
	LU ← PRTime;
	RTemp1 ← (RTemp1) or (WaitingOnCV), Goto[MXWHaveTime,ALU=0];
	T ← TimeLocation;
	PFetch1[PBase,CurrentTime];
	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);
	PStore1[PBase,PRTime];
MXWReSched:
	LU ← (PRFlags) and (200C), 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:
	Call[Queue1ToMQ];
	MQ ← T ← (MQ) and not (WWBit);
	PRTime ← Zero, Skip[ALU#0];
	  LU ← LdF[PRFlags,16,1], Goto[WHExit];
	PFetch1[PBase,Process], Call[ReadyInQueue2];
	T ← (Process) + (FlagsOffset), Call[PBaseToRTemp1];
	RTemp1 ← (RTemp1) and not (WaitingOnCV), Call[RTemp1ToPBase];
	PRTime ← (PRTime) + 1, UseCTask, Call[RequeueSub];
	LU ← LdF[PRFlags,16,1], Skip[R Even];
	  Goto[WHLoop];
WHExit:	LU ← (PRFlags) and (200C), Goto[ReSchedule,ALU=0];
	LU ← PRTime, Skip[R Odd];
	  MQ ← WWBit, Call[MQToQueue1];
	IntLevel ← (IntLevel) + 1, LoadPage[opPage0];
	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
*	MQ		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];
	LU ← (PRFlags) and (200C), Goto[ReSchedule];

RequeueSub:
	T ← APCTask&APC;
	RLink ← T;
	T ← Process, Call[PBaseToRTemp];
	LU ← (RTemp) - T;
	LU ← Queue1hi, Skip[ALU#0];	*only one process
	  Prev ← Zero, Goto[RQFixCV];
	Prev ← T, Skip[ALU=0];		*Queue1 NIL, T = Process
	  PFetch1[Queue1,Prev,0];
	T ← Prev;
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), Skip[ALU#0];
	  PStore1[PBase,RTemp], Goto[RQInsrt];
RQHaveQ1:
	PFetch1[Queue1,RTemp1,0];
	T ← Process, Call[PRRet];
	LU ← (RTemp1) - T;
	Skip[ALU#0];
	  PStore1[Queue1,Prev,0], Call[PRRet];
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];
	T ← LdF[RTemp,15,3];	*priority
	LU ← (LdF[RTemp1,15,3]) - T, Call[RQLp2S];
RQLoop2:T ← (RTemp1) + (FlagsOffset);
	PFetch1[PBase,MQ];
	T ← LdF[RTemp,15,3];
	LU ← (LdF[MQ,15,3]) - T;
	T ← RTemp1, Skip[ALU<0];
	  Prev ← T, Goto[PBaseToRTemp1];
RQInsrtHere:
	T ← Process, Call[RTemp1ToPBase];
	T ← Prev, Call[ProcessToPBase];
RQRet:	T ← (Process) + (TimeOffset), Call[ZeroToPBase];
	APCTask&APC ← RLink;
	PRFlags ← (PRFlags) or (RequeueOccured), Return;

RQNilPP:PStore1[PBase,Process];
	PStore1[Queue2,Process,0], Goto[RQRet];

RQLp2S:	T ← Prev, Goto[PBaseToRTemp1,ALU<0];
	PFetch1[PBase,RTemp1];
	PStore1[Queue2,Process,0], Goto[RQinsrtHere];

*************************************************************************
*	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 ← APCTask&APC;
	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, Skip[ALU#0];
	  APCTask&APC ← RLink, Goto[PRRet];
	RTemp ← T, Skip[ALU#0];
CUEmpty:  RTemp ← Zero, Goto[CUFixCV];
CULoop:	T ← (RTemp) + (CleanUpOffset), Call[PBaseToRTemp1];	*get head of queue
	LU ← T ← RTemp1;
	LU ← (RTemp) - T, Skip[ALU=0];
	  RTemp ← T, DblGoto[CUEmpty,CULoop,ALU=0];
	T ← MNBR ← RTemp;
CULoop2:
	RTemp ← T, Call[PBaseToRTemp1];
	T ← RTemp1;
	LU ← (MNBR) - T;
CUFixCV:LU ← PRFlags, Goto[CULoop2,ALU#0];
	APCTask&APC ← RLink, Skip[ALU<0];
	  PStore1[Queue1,RTemp,0], Return;
	PStore1[Queue2,RTemp,0], Return;

CURet:	APCTask&APC ← RLink, Goto[PRRet];

CQueueToRTemp:
	LU ← PRFlags, Skip[R<0];
	  PFetch1[Queue1,RTemp,0], Return;
	PFetch1[Queue2,RTemp,0], Return;

*************************************************************************
*	ReSchedule;
*
*		Input
*	lu		(PRFlags) and (200C)
*
*		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:
	T ← CurrentState, Goto[PrTail,ALU=0];
	Nop;
IntReSch:
	LoadPage[opPage3];
	PFetch1[PBase,xfTemp], CallP[SavePCInFrame];
	LoadPage[xfPage1];
	UseCTask, CallP[SaveState];
	T ← CurrentPSB, Call[PBaseToRTemp1];	*RTemp1 ← currentPSB
	T ← (RTemp1) + (FrameOffset);
	PStore1[PBase,LOCAL];
IdleIntRS:
	T ← ReadyQ;
	PFetch1[PBase,RTemp1], Call[PRRet];
	LU ← T ← RTemp1;
	LU ← xfWDC, Goto[NoneReady,ALU=0];
	PFetch1[PBase,Process];			*Process ← readylist.link
*Setup for new process
	T ← (Process) + (FlagsOffset), Call[PBaseToRTemp1];
	RTemp ← xfAV;
	T ← (RTemp) + (FirstStateVector), Call[PBaseToRTemp];
	T ← LdF[RTemp1,15,3], Task;	*Priority
	xfTemp ← T;
	xfTemp ← (Lsh[xfTemp,2]) + T;
	T ← (Lsh[xfTemp,1]) + T;	*13b*priority
	RTemp ← (RTemp) + T;
	RTemp1 ← (RTemp1) and not (EnterFailed), Goto[NoEnterFailed,R>=0];
	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);
	PFetch1[PBase,RTemp1];
	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 ← IP[RSImage]C;	*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];
*When PCF is 10b, BitBlt has done PC←PC+4, PCF←0, so PCF-1 can be negative;
*In this situation we have to do PC←PC-4 and PCF←7.  The code below also
*allows MIPend to be called by opcodes longer than 1 byte (CSUM).
	RTemp1 ← T, Goto[BackNoOvf,ALU>=0];
	  PCB ← (PCB) - (4C);
	  PFetch4[PCB,IBuf,0];
BackNoOvf:
	PCF ← RTemp1;
NoBackup:	LU ← xfWDC;	*Check (NWW#0 & xfWDC=0)
	T ← NWW, Skip[ALU=0];
	  Return;
	NWW ← Zero, Skip[ALU#0];
	  NWW ← T, Return;
:IF[CacheLocals]; **************************
*We are going to cause the interrupt; refill cache in case BitBlt interrupt
	PFetch4[LOCAL,LocalCache0,4], Task;
***Should task here when CacheLocals=0***
:ENDIF; ************************************
	PRFlags ← 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];

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

ZeroToPBase:	PStore1[PBase,RMZero], 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
*
*************************************************************************

OnPage[opPage0];

Interrupt:
	WW ← (WW) and not (TimerBit), Goto[TimerInterrupt,ALU#0];
	IntLevel ← CVBase;
CheckCV:Call[.+1];
	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), Skip[ALU#0]; *T ← ReadyQueuehi
	  IntLevel ← (IntLevel) + 1, Goto[CheckCV];
	Queue1hi ← T, LoadPage[prPage];
	PRFlags ← (PRFlags) or (NakedNotifyFlags), Goto[WakeHead];

IntDone:
	LU ← IntType, LoadPage[prPage];	*Load page for done
	T ← CurrentState, DblGotoP[IntReSch,IdleIntRS,ALU#0];

TimerInterrupt:
	TickCount ← (TickCount) - 1;
	IntLevel ← CVBase, Goto[CheckCV,ALU#0];
	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[CheckEnd,ALU=0];
	T ← (MDShi) or (1C), Skip[ALU=0];
	  Goto[CheckEnd];
*Timeout
	Queue2 ← ReadyQ;
	Queue1Hi ← Zero;
	Queue2Hi ← T, LoadPage[prPage];	*Make Queue2 the ReadyQueue
	UseCTask, Call[RequeueSub];
	T ← (Process) + (FlagsOffset), Call[IntPBaseToQueue1];
	Queue1 ← (Queue1) and not (WaitingOnCV);
	PStore1[PBase,Queue1];
CheckEnd:
	T ← Process ← (Process) + (SizePSB);
	LU ← (ITemp1) - T;
	TickCount ← 3C, Goto[TLoop,ALU>=0];
	Goto[CheckCV];

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

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

P4Ret:	Return;

:END[MesaP];