{File name:  Process.mc

bj		18-Jan-88 23:44:16 fix comments at PEnd:, comment out MesaIntBr's
bj		 7-Jan-88 16:20:50 temporarily put back in stackerr checking code.
Trow		 9-Nov-87 21:15:03 Add interrupt check at Enqueue, Reschedule.
Trow		 9-Nov-87 20:22:51 Eliminate uTickCount at Scan.
Trow		 9-Nov-87 17:22:10 Split memory reference at FreeState.
BJackson	 9-Nov-87 14:37:28 quick fix for interrupts.
Trow		 5-Nov-87  0:15:49 Fix interrupt at IdleLoop.
Trow		22-Oct-87 21:56:08 Change XwdDisp to XdwDisp.
BJackson	22-Oct-87  3:29:43 use "map.rd" instead of "30".
Trow		13-Oct-87 15:27:07 Reverse targets 1 and 2 of XwdDisp.
Fiala 15-May-86 19:15:45 Fixes for 4MB storage in map.  Noted following problems for future:
	1) QRead tested XDirtyDisp and proceeded only if flags were ok for a write but did
	   a read and set map flags only for a read.
	2) QWrite formerly or'ed 0A0 into the map flags instead of 0B0 like all other writes;
	   I changed it to be 30 for the new format, like all other writes.
	***Note Kiku also has these bugs (if bugs).
Frandeen September 29, 1981  9:26 AM: Fix CancelBR at MREAbort+1. 
Frandeen August 20, 1981  2:20 PM: Fix for new assembler. 
Sandman March 26, 1981  10:43 AM to fix timing restrictions
Sandman March 26, 1981  3:53 PM Change Wait to check condition.abortable
Created: February 13, 1981  1:12 PM,
Description: Dandelion Process Microcode,
Author: Sandman,
}

{*****************************************************************************
Definitions
*****************************************************************************}

{Xfer defs}
Set[xtPSwitch, 0];
Set[L2.RSStashr,09];

Set[L2.Pop0Incr1or2, 0  {00xx}]; {also in Jump.mc} 

{Offsets and Magic locations}
Set[PSB.link, 0];
Set[PSB.link.vector, 1];
Set[PSB.flags, 1];
Set[PSB.flags.waiting, 2];
Set[PSB.context, 2];
Set[PSB.timeout, 3];
Set[Condition.wakeup, 1];
Set[Condition.abortable, 2];
Set[Monitor.lock, 1];
Set[FaultQueue.condition, 1];
Set[PDAHi, 1];
Set[PDA.ready, 0];
Set[PDA.count, 1];
Set[PDA.timeout, 2];
Set[PDA.state, 10'b];
Set[PDA.interrupt, 20'b];
Set[PDA.lastCV, 36'b];
Set[PDA.fault, 60'b];
Set[PSBSize, 4];
Set[StartPsbM4, 74'b];

{
uPFlags holds opcode dispatch values and general flags.  Its encoding:
	Bit    Meaning
	8	    0: no Requeue, 1: Requeue occured
	9	    Interrupt
	10	    Process Trap
	11	    PCValid
	12-15  Opcode dispatch
}

{Flag values}
Set[pME, 0];
Set[pMR, 1];
Set[pMX, 2];
Set[pMW, 9];
Set[pNC, 4];
Set[pBC, 5];
Set[pREQ, 8];
Set[pInt, 47]; Set[pIntLoc, 7];  {Also in Dandelion.df}
Set[pIdle, 77]; {pIdle MOD 16 = pInt MOD 16 = pIntLoc}
Set[pFault, 3];
Set[pFaultPC, 0D3];
Set[pFaultNoPC, 0E3];
Set[pTrap, 20];

Set[cPCInvalid, 10];
Set[cRequeueFlag, 80];

Set[L3.Normal, 0];
Set[L3.Interrupt, 1];
Set[L3.Fault, 3];

Set[L0.SrcOK, 0];
Set[L0.SrcNull, 1];

Set[L2.Fault, 1];
Set[L2.Trap, 0];  { Same as L2.MRE4}

{PRead Returns}
Set[L2.LP0,	0];
Set[L2.MRE3,	1];
Set[L2.DQ2,	4];
Set[L2.NQ1,	6];
Set[L2.WH2,	7];
Set[L2.NQ3,	8];
Set[L2.RS3,	9];
Set[L2.LP1,	0A];
Set[L2.AS0,	0B];
Set[L2.NQ0,	0C]; {also QRead}
Set[L2.LP2,	0D];
Set[L2.TS0,	0E];
Set[L2.TS2,	0F];

{PMRead Returns}
Set[L2.WH0, 0]; {0 MOD 2}
Set[L2.RS0, 2]; {also PFetch}
Set[L2.DQ1, 3]; {3 MOD 4}
Set[L2.EM2, 4]; {0 MOD 2; also NQRets}
Set[L2.CQ3, 5];
Set[L2.CQ2, 6]; {0 MOD 2}
Set[L2.CQ1, 7]; {3 MOD 4}

{PFetch Returns}
Set[L2.RS0, 2]; {also PMRead}
Set[L2.RS2, 0]; {0 MOD 2}
Set[L2.SP0, 1];
Set[L2.EF0, 3];
Set[L2.LP5, 4];
Set[L2.DQ5, 5];
Set[L2.MW2, 6]; {also PWrite, QRead}

{PWrite Returns}
Set[L2.WH1,	0];
Set[L2.SP1,	1]; {1 MOD 4; paired with L2.ASS0}
Set[L2.PSS0,	2];
Set[L2.AAS0,	3]; {3 MOD 4; contains SP1}
Set[L2.NQ4,	4];
Set[L2.FS0,	5];
Set[L2.MW2,	6]; {also PFetch, QRead}
Set[L2.DQ0,	7]; {3 MOD 4; also QRead}
Set[L2.AAS1,	9];
Set[L2.PSS1,	8];
Set[L2.SP2,	0A];
Set[L2.LP3,	0B];
Set[L2.FS1,	0C];

{QRead Returns}
Set[L2.MRE4,	0]; {Same as L2.Trap}
Set[L2.CQ0,	1];
Set[L2.MRE0,	2];
Set[L2.ME0,	4]; {also QWrite}
Set[L2.EM0,	5];
Set[L2.MW2,	6]; {also PFetch, PWrite}
Set[L2.DQ0,	7]; {3 MOD 4; also PWrite}
Set[L2.BC0,	8];
Set[L2.RQ0,	9];
Set[L2.F0,	0A];
Set[L2.NQ0,	0C]; {also PRead}

{QWrite Returns}
Set[L2.ME0, 4]; {also QRead}
Set[L2.MRE1, 1]; {also PRead}
Set[L2.DQ4, 2]; {0 MOD 2; DQm; paired with DQl}
{DQl has 3}
Set[L2.NQ2, 0];
Set[L2.MW3, 5]; {1 MOD 2}
Set[L2.EM1, 7]; {3 MOD 4}
Set[L2.INT2, 8];
Set[L2.CQ4, 9]; {1 MOD 2}
Set[L2.NQ8, 0A];

{Requeue Returns}
Set[rhT.PT, 0]; {Must be zero}
Set[rhT.BCast, 1];
Set[rhT.IntNN, 2];
Set[rhT.TS, 3];
{4 contains EMa}
Set[rhT.EM, 5]; {paired with EMa}
Set[rhT.Fault, 6];
Set[rhT.FaultNN, 7];


{*****************************************************************************
Opcodes
*****************************************************************************}

@ME:	Rx ← pME, push, GOTO[Check1],	c1, opcode[1];

@MR:	Rx ← pMR, push, GOTO[Check2],	c1, opcode[2];

@MW:	Rx ← pMW,						c1, opcode[3];
MWx:	TT ← ErrnIBnStkp, push, XDisp,				c2;
{bj}	STK ← TOS, pop, DISP4[Test2, 8],			c3;
{	STK ← TOS, pop, BRANCH[Short2of2, Long2of2, 0D],	c3;	}

@MD:	Rx ← pMX, push, GOTO[Check1],	c1, opcode[4];

@NC:	Rx ← pNC, push, GOTO[Check1],	c1, opcode[5];

@BC:	Rx ← pBC, push, GOTO[Check1],	c1, opcode[6];

@REQ:	Rx ← pREQ, GOTO[MWx],	c1, opcode[7];

Check1:	TT ← ErrnIBnStkp, XDisp,	c2;
{	rhT ← 0, STK ← TOS, BRANCH[Long1of1, Short1of1, 0E],	c3;

Long1of1:	T ← STK, pop, GOTO[Got1],	c1;
Short1of1:	T ← UvMDS, GOTO[Got1],	c1;
}
{bj}	rhT ← 0, STK ← TOS, DISP4[Test1, 8],	c3;

Test1:	T ← sStackError, L2←L2.TRAPStashr, GOTO[BadStack],	c1, at[ 8,10,Test1];
	T ← sStackError, L2←L2.TRAPStashr, GOTO[BadStack],	c1, at[ 9,10,Test1];
	T ← sStackError, L2←L2.TRAPStashr, GOTO[BadStack],	c1, at[0A,10,Test1];
	T ← sStackError, L2←L2.TRAPStashr, GOTO[BadStack],	c1, at[0B,10,Test1];
	T ← STK, pop, GOTO[Got1],				c1, at[0C,10,Test1];
	T ← UvMDS, GOTO[Got1],					c1, at[0D,10,Test1];
	T ← sStackError, L2←L2.TRAPStashr, GOTO[BadStack],	c1, at[0E,10,Test1];
	T ← sStackError, L2←L2.TRAPStashr, GOTO[BadStack],	c1, at[0F,10,Test1];
{bj}

Got1:	UvQ1Hi ← T,	c2;
	T ← STK, pop,	c3;

	UvQ1 ← T, pop, GOTO[SaveRegs],	c1;

{bj}
BadStack: TT ← UvPCpage, L1←0, GOTO[StashPC0],	c2;

Check2:	TT ← ErrnIBnStkp, XDisp,	c2;
	rhT ← 0, STK ← TOS, DISP4[Test2, 8],	c3;

Test2:	T ← sStackError, L2←L2.TRAPStashr, GOTO[BadStack],	c1, at[ 8,10,Test2];
	T ← sStackError, L2←L2.TRAPStashr, GOTO[BadStack],	c1, at[ 9,10,Test2];
	T ← STK, pop, GOTO[Got2],				c1, at[0A,10,Test2];
	T ← sStackError, L2←L2.TRAPStashr, GOTO[BadStack],	c1, at[0B,10,Test2];
	T ← UvMDS, GOTO[Got2],					c1, at[0C,10,Test2];
	T ← sStackError, L2←L2.TRAPStashr, GOTO[BadStack],	c1, at[0D,10,Test2];
	T ← sStackError, L2←L2.TRAPStashr, GOTO[BadStack],	c1, at[0E,10,Test2];
	T ← sStackError, L2←L2.TRAPStashr, GOTO[BadStack],	c1, at[0F,10,Test2];
{bj}

{
Check2:	TT ← ErrnIBnStkp, XDisp,	c2;
	rhT ← 0, STK ← TOS, BRANCH[Short2of2, Long2of2, 0D],	c3;

Long2of2:	T ← STK, pop, GOTO[Got2],	c1;
Short2of2:	T ← UvMDS, GOTO[Got2],	c1;
}

Got2:	UvQ2Hi ← T,	c2;
	T ← STK, pop,	c3;

	UvQ2 ← T,	c1;
	uStkDepth ← TT, YDisp, c2;
	rhT ← 0, BRANCH[Short1of2, Long1of2, 0D],	c3;
Long1of2:	T ← STK, pop, GOTO[Got1],	c1;
Short1of2:	T ← UvMDS, GOTO[Got1],	c1;

SaveRegs:	UrL ← L,	c2;
	UrG ← G, G ← rhG,	c3;

	UrGHi ← G,	c1;
	UrPC ← PC, PC ← rhPC,	c2;
	UrPCHi ← PC,	c3;

	L0←L0.SrcOK, G ← PDA.lastCV{for interrupts},	c1;
	uPFlags ← Rx, YDisp, L3←L3.Normal,	c2;
	rhPC ← PDAHi, DISP3[Enter],	c3;

PRestart:	uFaultParm0 ← G,	c3;

	TOS ← ~uStkDepth,	c1;
	stackP ← TOS, TOS ← pFault,	c2;
	TT ← uPFlags, XDisp,	c3;

	G ← rhG, L2Disp, BRANCH[PFa, PFb, 7],	c1;
PFa:	uFaultParm1 ← G, pop, BRANCH[PTrap, PFault],	c2;
PFb:	uFaultParm1 ← G, BRANCH[PTrap, PFault],	c2;
PTrap:	uPFlags ← Rx, GOTO[PTail1],	c3;
PFault:	uPFlags ← TOS, GOTO[Fault],	c3;

{*****************************************************************************
Monitor Entry opcode
    Entry:
	UvQ1Hi,,UvQ1 hold virtual address of monitor lock to be entered
    Exit:
*****************************************************************************}
Enter:	uStkDepth ← TT, L2←L2.ME0{QRRets, QWRets},	c1, at[pME,10,Enter];
	G ← UvQ1, CALL[Q1Read3],	c2;

	Map ← UvQ2 ← [rhG, G], push, BRANCH[MEUnLocked, MELocked, 2],	c1, at[L2.ME0,10,QRRets];

MEUnLocked:
	T ← T or Monitor.lock, push, CALL[QWrite3],	c2;
	TOS ← 1,	c3, at[L2.ME0,10,QWRets];

	STK ← TOS, pop, GOTO[PTail2]{L not used},	c1;

MELocked:	PC ← uPSB, pop,	c2;
EnterFailed:
	L ← UvQ1Hi, L2←L2.EF0{PFRets},	c3;

	Map ← Q ← [rhPC, PC+PSB.link],	c1;
	rhG ← PDAHi, G ← PDA.ready, CALL[PFetch3],	c2;
	Rx ← MD or Rx,	c3, at[L2.EF0,10,PFRets];

	MAR ← [rhTT, PC+PSB.link],	c1;
	MDR ← Rx or u8000, L2←L2.DQ0{QRRets},	c2;
CallDQ:	UvQ2Hi ← L, CALL[QRead1],	c3;

{*****************************************************************************
Monitor ReEnter opcode 
    Entry:
	UvQ1Hi,,UvQ1 hold virtual address of monitor lock to be entered
	UvQ2Hi,,UvQ2 hold virtual address of condition variable just left
    Exit:
*****************************************************************************}
ReEnter:	uStkDepth ← TT, L2←L2.MRE0{QRRets},	c1, at[pMR,10,Enter];
	G ← UvQ1, CALL[Q1Read3],	c2;

	PC ← uPSB, BRANCH[MREUnLocked, MRELocked, 2],	c1, at[L2.MRE0,10,QRRets];

MRELocked:	UvQ2 ← G, GOTO[EnterFailed],	c2;

MREUnLocked:
	G ← UvQ2,	c2;
	rhG ← UvQ2Hi,	c3;

	Map ← [rhG, G], L2←L2.CQ0{QRRets},	c1;
	TOS ← T, CALL[QRead3],	c2;
	PC ← uPSB,	c3, at[pMR,10,CQRets];

	Map ← Q ← [rhPC, PC or PSB.flags], L2←L2.MRE3{PRRets},	c1;
	Rx ← uPMask, CALL[PRead3],	c2;

	MAR ← [rhTT, PC+PSB.flags], L2←L2.MRE4{QRRets},	c1, at[L2.MRE3,10,PRRets];
	MDR ← Ybus ← T and ~Rx, YDisp, CANCELBR[$,0],	c2;
AbortNotOK:	rhG ← UvQ1Hi, BRANCH[MRENoAbort, MREAbort, 0E],	c3;

MRENoAbort:	Map ← [rhG, G], L2←L2.MRE1{QWRets},	c1; {write locked monitor}
	T ← TOS or Monitor.lock, push, CALL[QWrite3],	c2;
	TOS ← 1, push,	c3, at[L2.MRE1,10,QWRets];

	STK ← TOS, pop, GOTO[PTail2]{L not used},	c1;

MREAbort:	Rx ← pTrap, CALL[Q2Read2],	c1;

	[] ← T and Condition.abortable, NZeroBr, CANCELBR[$,3],	c1, at[L2.MRE4,10,QRRets];
	G ← UvQ1, BRANCH[AbortNotOK, PRestart],	c2;


{*****************************************************************************
Monitor Exit and Depart opcode 
    Entry:
	UvQ1Hi,,UvQ1 hold virtual address of monitor lock to be exited
    Exit:
*****************************************************************************}
Depart:	uStkDepth ← TT, L2←L2.EM0{QRRets},	c1, at[pMX,10,Enter];
	G ← UvQ1, CALL[Q1Read3],	c2;

MXDExit:	L ← UrL, GOTO[PTail2],	c1;


{*****************************************************************************
Exit Monitor Subroutine 
   Entry:
	rhG,,G hold virtual address of monitor lock to be exited
	T has monitor lock
    Exit:
*****************************************************************************}
ExitMonitor:
	Map ← [rhG, G], L2←L2.EM1{QWRets}, CANCELBR[$,3],	c1, at[L2.EM0,10,QRRets];
	T ← T and ~Monitor.lock, CALL[QWrite3],	c2;
	T ← T and Q, ZeroBr, rhT ← rhT.EM{NQRets},	c3, at[L2.EM1,10,QWRets];

	Map ← Q ← [rhPC, T+PSB.link], L2←L2.EM2{PMRets}, BRANCH[EMa, EMb],	c1;
EMa:	UvQ2 ← PDA.ready, CALL[PMRead3],	c2;

	L ← PDAHi,	c1, at[L2.EM2,10,PMRRets];
	PC ← T, L2←L2.DQ0{QRRets}, CALL[CallDQ],	c2;

EMb:	Xbus ← uPFlags, XLDisp,	c2, at[rhT.EM,10,NQRets];
	PC ← uPSB, BRANCH[MXDExit, MWExit, 2],	c3;


{*****************************************************************************
Monitor Exit and Wait opcode 
    Entry:
	UvQ1Hi,,UvQ1 hold virtual address of monitor lock to be exited
	UvQ2Hi,,UvQ2 hold virtual address of condition on which to wait
	TOS holds timeout value
    Exit:
*****************************************************************************}
Wait:	uTicks ← TOS, L2←L2.CQ0{QRRets}, CALL[CleanSecond],	c1, at[pMW,10,Enter];

	rhG ← UvQ1Hi,	c3, at[pMW,10,CQRets];

	Rx ← UvQ2,	c1;
	UvQTemp ← Rx,	c2;
	Rx ← UvQ2Hi,	c3;

	Map ← [rhG, G], L2←L2.EM0{QRRets},	c1;
	UvQTempHi ← Rx, CALL[QRead3],	c2;

MWExit:	rhG ← G ← UvQTempHi,	c1;
	UvQ2Hi ← G,	c2;
	G ← UvQTemp, L2←L2.MW2{QRRets, PFRets, PWRets},	c3;

	Map ← UvQ2 ← [rhG, G], CALL[QRead2],	c1;

	Map ← Q ← [rhPC, PC or PSB.flags], CANCELBR[PFetch2,3],	c1, at[L2.MW2,10,QRRets];
	TOS ← MD, XLDisp,	c3, at[L2.MW2,10,PFRets];

	[] ← T and Condition.abortable, ZeroBr, BRANCH[MWa, MWb, 2],	c1;
MWa:	Rx ← uPTC, CANCELBR[MWd, 1],	c2;
MWb:	Rx ← uPTC, BRANCH[MWc, MWd],	c2;
MWc:	GOTO[PTail1],	c3;
MWd:	Xbus ← T LRot0, XLDisp,	c3;

	TT ← uTicks, ZeroBr, BRANCH[MWNoWW, MWWW, 2],	c1;
MWNoWW:	rhG ← PDAHi, G ← PDA.ready, BRANCH[MWMakeTime, MWHaveTime],	c2;
MWHaveTime:
	Xbus ← 0, XDisp, GOTO[MWWriteTime],	c3;
MWMakeTime:
	TT ← TT + Rx, ZeroBr,	c3;

MWWriteTime:
	Map ← Q ← [rhPC, PC or PSB.timeout], BRANCH[MWTimeOK, MWIncTime],	c1;
MWTimeOK:	T ← TT, rhT ← rhT.PT{NQRets}, CALL[PWrite3],	c2;
MWIncTime:	T ← 0 + 0 + 1, rhT ← rhT.PT{NQRets}, CALL[PWrite3],	c2;
	T ← TOS or PSB.flags.waiting, L2←L2.DQ0{QRRets, PWRets},	c3, at[L2.MW2,10,PWRets];

	Map ← Q ← [rhPC, PC or PSB.flags], CALL[PWrite2];
	CALL[QRead1],	c3, at[L2.DQ0,10,PWRets];

MWWW:	L2←L2.MW3{QWRets}, CANCELBR[$,1],	c2;
	T ← T and ~Condition.wakeup, CALL[QWrite1],	c3;

	GOTO[PTail1],	c3, at[L2.MW3,10,QWRets];


{*****************************************************************************
Notify opcode 
    Entry:
	UvQ1Hi,,UvQ1 hold virtual address of condition to be notified
    Exit:
*****************************************************************************}
Notify:	uStkDepth ← TT, L2←L2.CQ0{QRRets}, CALL[CleanFirst],	c1, at[pNC,10,Enter];

	T ← T and Q, ZeroBr, L2←L2.WH0{PMRRets},	c3, at[pNC,10,CQRets];

	Map ← Q ← [rhPC, T+PSB.link], BRANCH[DoNotify, NoNotify],	c1;
DoNotify:	L ← PDAHi, CALL[PMRead3],	c2;
NoNotify:	TT ← uPFlags, GOTO[PTail3], {L not used}	c2;


{*****************************************************************************
Broadcast opcode 
    Entry:
	UvQ1Hi,,UvQ1 hold virtual address of condition to be broadcast
    Exit:
*****************************************************************************}
BCast:	uStkDepth ← TT, L2←L2.CQ0{QRRets}, CALL[CleanFirst],	c1, at[pBC,10,Enter];

BCe:	rhT ← rhT.BCast{NQRets}, T ← T and Q, ZeroBr,	c3, at[pBC,10,CQRets];

BCd:	Map ← Q ← [rhPC, T+PSB.link], L2←L2.WH0{PMRRets}, BRANCH[BCa, BCb],	c1;
BCa:	L ← PDAHi, CALL[PMRead3],	c2;
BCb:	rhT ← 0, GOTO[PTail0],	c2;

BCc:	G ← UvQ1, L2←L2.BC0{QRRets},	c2, at[rhT.BCast,10,NQRets];
	rhG ← UvQ1Hi, CALL[QRead1],	c3;

	CANCELBR[$,3],	c1, at[L2.BC0,10,QRRets];
	GOTO[BCe],	c2;


{*****************************************************************************
WakeHead subroutine 
    Entry:	rhG, G contains virtual address of condition to wake
	T contains queue.tail.link
	L has PDAHi
    Exit:
*****************************************************************************}
WakeHead:	Map ← Q ← [rhPC, T or PSB.timeout], L2←L2.WH1{PWRets},	c1, at[L2.WH0,10,PMRRets];
	T ← 0, UvQ2 ← PDA.ready, CALL[PWrite3],	c2;
	PC ← Q - PSB.timeout, L2←L2.WH2{PRRets},	c3, at[L2.WH1,10,PWRets];

	Map ← Q ← [rhPC, PC or PSB.flags], CALL[PRead2],	c1;

	MAR ← [rhTT, PC+PSB.flags],	c1, at[L2.WH2,10,PRRets];
	MDR ← T and ~PSB.flags.waiting, L2←L2.DQ0{QRRets}, CANCELBR[CallDQ,0],	c2;


{*****************************************************************************
Requeue opcode 
    Entry:
	UvQ1Hi,,UvQ1 hold virtual address of source queue
	UvQ2Hi,,UvQ2 hold virtual address of destination queue
	TOS has process
    Exit:
*****************************************************************************}
Requeue:	PC ← TOS, L2←L2.RQ0{QRRets}, CALL[Q2Read2],	c1, at[pREQ,10,Enter];

	G ← UvQ1, L2←L2.DQ0{QRRets}, CANCELBR[$,3],	c1, at[L2.RQ0,10,QRRets];
	rhG ← UvQ1Hi, [] ← G or UvQ1Hi, ZeroBr,	c2;
	L0←L0.SrcOK, BRANCH[QRead1, RQa],	c3;

RQa:	Map ← Q ← [rhPC, PC+PSB.link], L2←L2.DQ1{PMRRets}, GOTO[DQx],	c1;


{*****************************************************************************
Dequeue subroutine: 
    Entry:
	rhT # 0 => src = NIL
	UvQ1Hi,,UvQ1 has src
	PC has process
    Exit:
	Returns to NQ

    Register Usage
	PC = process
	T = temp
	TOS = prev
	Rx has queue
	UvLPhigh has psb.link
*****************************************************************************}
Dequeue:	Map ← Q ← [rhPC, PC+PSB.link], L2←L2.DQ1{PMRRets}, CANCELBR[$, 3],	c1, at[L2.DQ0,10,QRRets];
DQx:	Rx ← T, CALL[PMRead3],	c2; {Fetch[@psb.link]}

	TOS ← uPFlags,	c1, at[L2.DQ1,10,PMRRets];
	TOS ← TOS or cRequeueFlag,	c2;
	uPFlags ← TOS, L0Disp,	c3;

	[] ← T - PC, ZeroBr, BRANCH[DQa, DQb]	c1;

DQa:	TOS ← 0, uPsbLink ← T, BRANCH[DQc, DQd],	c2;{src#NIL}
DQb:	TOS ← 0, uPsbLink ← T, BRANCH[DQe, DQf],	c2;{src=NIL}

DQc:	TOS ← Rx and uPMask2, GOTO[DQg],	c3;{link.next#psb}
DQd:	T ← Rx and uPMask2, GOTO[DQj],	c3;{link.next=psb}

DQe:	TOS ← PC, GOTO[DQg],	c3;{link.next#psb}
DQf:	GOTO[DQk],	c3;{link.next=psb}

DQg:	Map ← Q ← [rhPC, TOS+PSB.link], L2←L2.DQ2{PRRets},	c1;
DQgh:	TOS ← Q, CALL[PRead3],	c2;

	Q ← T and uPMask,	c1, at[L2.DQ2,10,PRRets];
	[] ← Q - PC, ZeroBr,	c2;
	T ← T and ~uPMask, BRANCH[DQh, DQi],	c3;

DQh:	Map ← Q ← [rhPC, Q+PSB.link], L2←L2.DQ2{PRRets}, GOTO[DQgh],	c1;

DQi:	MAR ← [rhTT, TOS+PSB.link],	c1;
	MDR ← T or uPsbLink, L0Disp,	c2;
	T ← Rx and uPMask2, BRANCH[DQj, DQk],	c3;

DQj:	[] ← T - PC, ZeroBr,	c1;
	T ← Rx and ~uPMask2, BRANCH[DQm, DQl],	c2;
DQl:	T ← TOS or T, L2←L2.DQ4{QWRets},	c3;

	Map ← [rhG, G], CALL[QWrite2],	c1;	

DQk:	Map ← Q ← [rhPC, PC or PSB.flags], L2←L2.DQ5{PFRets},	c1;
	T ← ~uPMask, CALL[PFetch3],	c2;
	T ← MD and T,	c3, at[L2.DQ5,10,PFRets];

	MAR ← [rhTT, PC+PSB.flags],	c1;
	MDR ← T or uPsbLink, CANCELBR[$,0],	c2;
DQm:
{db}	G ← UvQ2, {MesaIntBr,}{bj} GOTO[Enqueue],	c3, at[L2.DQ4,10,QWRets];


{*****************************************************************************
Enqueue subroutine: 
    Entry:
	UvQ2Hi,,UvQ2 has dst
	PC has process
	rhT has return
    Exit:
    Register Usage
	L has process.priority
	T = temp
	TOS = prev
	Rx = queue, prev
*****************************************************************************}
Enqueue:
	Map ← Q ← [rhPC, PC+PSB.link], L2←L2.NQ0{QRRets, PRRets},
		BRANCH[$, EnqueueInt],					c1;
	Rx ← uPPMask, CALL[PRead3],	c2;

	UreturnPC ← T,	c1, at[L2.NQ0,10,PRRets];
	L ← T and uPPMask, CALL[Q2Read3],	c2;

	Q ← T and uPMask, ZeroBr, CANCELBR[$,3],	c1, at[L2.NQ0,10,QRRets];
	T ← T and ~uPMask, BRANCH[NQb, NQc],	c2;

NQc:	T ←  T or PC, L2←L2.NQ8{QWRets},	c3;

	Map ← [rhG, G],	c1;
	Q ← ~uPMask, CALL[QWrite3],	c2;
	T ← Q and UreturnPC, L2←L2.NQ4{PWRets},	c3, at[L2.NQ8,10,QWRets];

	Map ← Q ← [rhPC, PC+PSB.link],	c1;
	T ← T or PC, CALL[PWrite3],	c2;

NQb:	TOS ← Q, uTemp ← T, L2←L2.NQ1{PRRets},	c3;

	Map ← Q ← [rhPC, TOS+PSB.link],	c1;
	uPsbLink ← T or PC, CALL[PRead3],	c2;

	Rx ← T and Rx, Ufsi ← T,	c1, at[L2.NQ1,10,PRRets];
	[] ← Rx - L, CarryBr, L2←L2.NQ3{PRRets},	c2;
NQi:	Rx ← T and uPMask, BRANCH[NQd, NQe],	c3;

NQe:	Map ← [rhG, G], L2←L2.NQ2{QWRets},	c1;
	T ← uPsbLink, CALL[QWrite3],	c2;
	Q ← ~uPMask, GOTO[NQg],	c3, at[L2.NQ2,10,QWRets];

NQd:	Map ← Q ← [rhPC, Rx+PSB.link], CALL[PRead2],	c1;

	TT ← T and uPPMask,	c1, at[L2.NQ3,10,PRRets];
	[] ← L - TT - 1, CarryBr,	c2;
	Q ← ~uPMask, BRANCH[NQf, NQg],	c3;

NQf:	TOS ← Rx,	c1;
	Ufsi ← T, GOTO[NQi],	c2;

NQg:	Map ← [rhPC, PC+PSB.link],	c1;
	T ← Q and UreturnPC,	c2;
	TT ← rhTT ← MD,	c3;

	MAR ← [rhTT, PC+PSB.link],	c1;
	MDR ← T or Rx,	c2;
	T ← Q and Ufsi, L2←L2.NQ4{PWRets},	c3;

	Map ← Q ← [rhPC, TOS+PSB.link],	c1;
	T ← T or PC, CALL[PWrite3],	c2;
	Xbus ← rhT, XDisp,	c3, at[L2.NQ4,10,PWRets];

NQRet:	L ← UrL, DISP2[NQRets],	c1;


{*****************************************************************************
Reschedule 
    Entry:
	uPFlags.0: reSchedulePending BOOLEAN
	uPFlags.1..3: 0: Opcode, 2: Trap, 4: Interrupt, 7: Idle,
		5: Fault, 6: FaultNoPC
    Exit:
    Register Usage
*****************************************************************************}

PTail0:	Noop,	c3;

PTail1:	L ← UrL,	c1;
PTail2:	TT ← uPFlags,	c2, at[rhT.PT,10,NQRets];
PTail3:	G ← UrG, L0←L0.JRemap,	c3;

	rhG ← UrGHi,	c1;
	PC ← UrPC, L2←L2.RSStashr{StashRets}, 	c2;
	rhRx ← TT LRot12, XDisp,	c3;

PTNormal:
	DISP4[PEnd],							c1;

PEnd:
	PC ← PC + PC16, IBDisp, GOTO[SimpleEnd],			c2, at[0,10];
	{***not possible,						c2, at[1,10,PEnd];}
	T ← sProcessTrap, GOTO[Trapc3],					c2, at[2,10,PEnd];
	{***not possible,						c2, at[3,10,PEnd];}
	[] ← PC - 1, PgCrOvDisp, push, L1←L1r.Refill, GOTO[IntRet],	c2, at[4,10,PEnd];
	{***not possible to have fault but no requeue,			c2, at[5,10,PEnd];}
	{***not possible to have fault but no requeue,			c2, at[6,10,PEnd];}
	GOTO[SPIdle], {was in idle loop}				c2, at[7,10,PEnd];
	TT ← UvPCpage, L1 ← 1, GOTO[StashPC1],				c2, at[8,10,PEnd];
	{***not possible,						c2, at[9,10,PEnd];}
	T ← sProcessTrap, GOTO[Trapc3],					c2, at[0A,10,PEnd];
	{***not possible,						c2, at[0B,10,PEnd];}
	[] ← PC - 1, PgCrOvDisp, push, L1←L1r.Refill, GOTO[IntRet],	c2, at[0C,10,PEnd];
	TT ← UvPCpage, L1 ← 0, GOTO[StashPC0],				c2, at[0D,10,PEnd];
{db}	{MesaIntBr,}{bj} GOTO[Reschedule],					c2, at[0E,10,PEnd];
	GOTO[SPIdle], {was in idle loop}				c2, at[0F,10,PEnd];

SimpleEnd:	rhPC ← UrPCHi, DISPNI[OpTable],	c3;

Reschedule:
{db}	PC ← uPSB, BRANCH[SaveProcess, RescheduleInt],			c3, at[L2.RSStashr,10,StashRets];

IntRet:	TOS ← STK, pop, BRANCH[PCPageOK, IncPage, 1],	c3;
PCPageOK:	Xbus ← rhRx, XDisp, Q ← 0, L2←L2.Pop0Incr1or2,	c1;
PageOKx:	TT ← UvPCpage, BRANCH[FastEasy, SlowEasy, 7],	c2;
FastEasy:	rhTT ← UvChigh, GOTO[RReMap],	c3;
SlowEasy:	Q ← UvC, L1←0,	c3;
	L2←L2.RSStashr{StashRets}, GOTO[StashPCa1],	c1;

IncPage:	Rx ← LRot1 ErrnIBnStkp,	c1;
	Xbus ← Rx LRot0, XwdDisp,	c2;
	TT ← UvPCpage, DISP2[IBState],	c3;

IBState:
	Xbus ← rhRx, XDisp, Q ← 0, L2←L2.Pop0Incr1or2, GOTO[PageOKx],	c1, at[0,4,IBState];
	Xbus ← rhRx, XDisp, Q ← 0, L2←L2.Pop0Incr1or2, GOTO[PageOKx],	c1, at[1,4,IBState];
	Xbus ← rhRx, XDisp, Q ← 0, L2←L2.Pop0Incr1or2, GOTO[PageOKx],	c1, at[2,4,IBState];
	Xbus ← rhRx, XDisp, Q ← 0, L2←L2.Pop0Incr1or2,			c1, at[3,4,IBState];
	TT ← TT + 0FF + 1, BRANCH[FastEasy, SlowEasy, 7],		c2;


SPIdle:	G ← PDA.lastCV{for interrupts}, L2←L2.RS0{PMRRets, PFRets},	c3, at[L2.SP2,10,PWRets];

SPRet:	Map ← Q ← [rhPC, PDA.ready], CALL[PMRead2],	c1;

	Map ← Q ← [rhPC, T+PSB.link], ZeroBr,	c1, at[L2.RS0,10,PMRRets];
	UreturnPC ← T, BRANCH[PFetch3, BusyWaita],	c2;
	PC ← MD and Q, L2←L2.RS2{PFRets},	c3, at[L2.RS0,10,PFRets];

RSe:
{bj}	
	RegDef[uHelp,	U,	5F];

z1:	[] ← uHelp xor PC, ZeroBr,				,c1;
z2:	BRANCH[z3a, z3b],					,c2;
z3a:	GOTO[z4],							,c3;
z3b:	GOTO[z4],							,c3;

z4:
	Map ← Q ← [rhPC, PC{+PSB.link}], uPSB ← PC, CALL[PFetch2],	c1;
	T ← MD, XLDisp,	c3, at[L2.RS2,10,PFRets];

	uPsbLink ← T, BRANCH[RSa, RSb, 2],	c1;
RSb:	GOTO[RSc],	c2;
RSa:	T ← T and uPPMask,	c2;
	T ← T LRot4, L2←L2.RS3{PRRets},	c3;

	Map ← Q ← [rhPC, PDA.state or T], CALL[PRead2],	c1;

	[] ← T, ZeroBr, L2←L2.RS2{PFRets},	c1, at[L2.RS3,10,PRRets];
	[] ← UreturnPC xor PC, ZeroBr, BRANCH[RSc, RSd],	c2;
RSd:	PC ← uPsbLink and Q, BRANCH[RSe, BusyWaitb],	c3;
RSc:	uPCValid ← 0, L ← 0, CANCELBR[LoadProcess,1],	c3;

BusyWaita:	Noop,	c3;

BusyWaitb:	T ← pIdle,	c1;
	[] ← uWDC, NZeroBr,	c2;
IdleLoop:
	uPFlags ← T, MesaIntBr, BRANCH[$, WakeError],			c3;

{db}	BRANCH[NoInt, IdleInt {InterruptsDaybreak}],			c1;
NoInt:
	GOTO[IdleLoop],							c2;

WakeError:
	T ← sWakeupError, CANCELBR[$, 1],				c1;
	GOTO[TrapGo],							c2;


{*****************************************************************************
SaveProcess subroutine
    Entry:
	L3 has preemption booleon: 0 => FALSE, 1 => TRUE
    Exit:
    Register Usage
*****************************************************************************}
SaveProcess:	Map ← Q ← [rhPC, PC+PSB.link], L2←L2.SP0{PFRets},	c1;
	TOS ← PSB.link.vector, CALL[PFetch3],	c2;
	T ← MD or TOS, L3Disp,	c3, at[L2.SP0,10,PFRets];

	MAR ← [rhTT, PC+PSB.link], BRANCH[SPa, SPb, 2],	c1;
SPa:	MDR ← T and ~PSB.link.vector, GOTO[SPc],	c2;
SPb:	MDR ← T, T ← T and uPPMask,	c2;
	T ← T LRot4, GOTO[AllocAndSave],	c3;

AASRet:	T ← TOS, L2←L2.SP2{PWRets},	c3, at[L2.SP1,10,PWRets];

SPd:	Map ← Q ← [rhPC, PC or PSB.context], CALL[PWrite2],	c1;

SPc:	T ← UvL, L2←L2.SP2{PWRets}, GOTO[SPd],	c3;


{*****************************************************************************
LoadProcess subroutine
    Entry:	Ufsi has state vector of saved process if fault
	L has 0
    Exit:	Returns to EFCHaveLink
    Register Usage
*****************************************************************************}
LoadProcess:
	Map ← Q ← [rhPC, PC or PSB.context], L2←L2.LP0{PRRets},	c1;
	rhT ← xtPSwitch, stackP ← 0, CALL[PRead3],	c2;

	Q ← T + State.word,	c1, at[L2.LP0,10,PRRets];
	Xbus ← uPsbLink, TOS ← T, XLDisp, L2←L2.LP2{PRRets},	c2;
	Rx ← uPsbLink, NegBr, BRANCH[LPa, LPb, 2],	c3;

LPa:	MAR ← [rhTT, PC+PSB.link], BRANCH[LPc, LPd],	c1;
LPd:	MDR ← Rx and ~u8000, push,	c2;
	push,	c3;

	STK ← 0, pop,	c1;
LPc:	TT ← T,	c2;
	Ybus ← TT, YDisp,	c3;

LPe:	Map ← Q ← [rhMDS, TT], UvL ← TT, L0←L0.XFStartRead, DISP4[XferFrame, 0C],	c1;

LPb:	Map ← Q ← [rhPC, Q], CANCELBR[PRead2, 1],	c1;

FSRet:	TOS ← TOS + State.frame, L2←L2.LP5{PFRets},	c3, at[L2.FS0,10,PWRets];

	Map ← Q ← [rhPC, TOS], CALL[PFetch2],	c1;

	TT ← MD, XDisp, GOTO[LPe],	c3, at[L2.LP5,10,PFRets];


{*****************************************************************************
FreeState subroutine
    Entry:	T has priority
	TOS has state
    Exit:
    Register Usage
	T, Q, rhTT, TT, TOS
*****************************************************************************}
{db}
FreeState:
	Map ← Q ← [rhPC, PDA.state or T],				c1;
	Noop,								c2;
	TT ← rhTT ← MD,							c3;

	MAR ← [rhTT, Q + 0],						c1;
	Noop,								c2;
	T ← MD,								c3;

	MAR ← [rhTT, Q + 0],						c1;
	MDR ← TOS,							c2;
	L2 ← L2.FS0 {PWRets},						c3;

	Map ← Q ← [rhPC, TOS],						c1;
	stackP ← uStkDepth, CALL[PWrite3],				c2;
{db}


{*****************************************************************************
AllocAndSave subroutine
    Entry:	T has priority
    Exit:	TOS has state
    Register Usage
	T, Q, rhRx, Rx, TOS, uTemp
*****************************************************************************}
AllocAndSave:
	Map ← Q ← [rhPC, PDA.state or T], L2←L2.AS0{PRRets},	c1;
	uTemp ← Q, CALL[PRead3],	c2;

	Map ← Q ← [rhPC, T],	c1, at[L2.AS0,10,PRRets];
	TOS ← Q,	c2;
	rhRx ← Rx ← MD,	c3;

	MAR ← [rhRx, T+0],	c1;
	T ← uTemp,	c2;
	Rx ← MD,	c3;

	MAR ← [rhTT, T+0],	c1;
	MDR ← Rx, T ← Q + State.word,	c2;
	G ← ~ErrnIBnStkp,	c3;

	Map ← Q ← [rhPC, T], L2←L2.PSS0{PWRets},	c1;
	T ← 0F and G, CALL[PWrite3],	c2;
	[] ← T - cSSm2, CarryBr,	c3, at[L2.PSS0,10,PWRets];

	stackP ← Rx ← T + 2, BRANCH[PSSstore, PSScarry],	c1;
PSScarry:	stackP ← Rx ← cSS,	c2;
	Noop,	c3;

	Noop,	c1;
PSSstore:	Q ← Q - State.word,	c2;
	Q ← Q + Rx, push, L2←L2.PSS1{PWRets},	c3;

PSSloop:	Map ← Q ← [rhPC, Q-1], BRANCH[$,PSSRet],	c1;
	T ← STK, pop, CALL[PWrite3],	c2;
	Rx ← Rx - 1, ZeroBr, GOTO[PSSloop],	c3, at[L2.PSS1,10,PWRets];

PSSRet:	T ← UvL, L3Disp,	c2;
	Q ← TOS + State.frame, L2←L2.SP1{PWRets}, BRANCH[AASa, AASb, 1],	c3;

AASa:	Map ← Q ← [rhPC, Q], CALL[PWrite2],	c1;
AASb:	Map ← Q ← [rhPC, Q], CALL[PWrite2],	c1;

	T ← uFaultParm0, L2←L2.AAS1{PWRets},	c3, at[L2.AAS0,10,PWRets];

	Map ← Q ← [rhPC, Q+1], CALL[PWrite2],	c1;
	T ← uFaultParm1, L2←L2.SP1{PWRets},	c3, at[L2.AAS1,10,PWRets];

	Map ← Q ← [rhPC, Q+1], CALL[PWrite2],	c1;


{*****************************************************************************
PLoadStack subroutine
    Entry:	T has state.word
	TOS has stack pointer
    Exit:	TOS has stack pointer
	T has priority
	Returns to FreeState
    Register Usage
	T, rhTT, TT, Q, Rx, TOS
*****************************************************************************}
PLoadStack:	uStkDepth ← T,	c1, at[L2.LP2,10,PRRets];
	rhTT ← T LRot8,	c2;
	TT ← rhTT,	c3;

	T ← T and 0F,	c1;
	Q ← T - cSSm1, CarryBr,	c2;
	Q ← Q + cSSp1, BRANCH[LPload, LPcarry],	c3;

LPcarry:	Q ← cSS,	c1;
	Noop,	c2;
	Noop,	c3;

LPload:	UBrkByte ← TT, Rx ← Q,	c1;
	Q ← TOS - 1, GOTO[PLPa],	c2;

LPloop:	Map ← Q ← [rhPC, Q+1],	c1;
	G ← uPsbLink,	c2;
	rhTT ← TT ← MD,	c3;

	MAR ← [rhTT, Q+0],	c1;
	Rx ← Rx - 1, ZeroBr,	c2;
PLPa:	T ← MD, STK ← T, push, BRANCH[LPloop, LPdone], LOOPHOLE[mdok],	c3;

LPdone:	STK ← T,	c1;
	T ← G LRot4,	c2;
	T ← T and 7, GOTO[FreeState],	c3;


{*****************************************************************************
Interrupt Handler 
    Entry:
	CALLing sequence has done Rx ← pInt, GOTO[SaveRegs];
    Exit:
    Register Usage
*****************************************************************************}
Interrupt:
	Rx ← uWP,								c1, at[pIntLoc,10,Enter];
{db}	{ClrIntErr}, uWP ← 0, L3←L3.Interrupt,					c2;
CVLoop:
	Rx ← RShift1 Rx, Xbus ← Rx LRot0, XLDisp,				c3;

	uWW ← Rx, NZeroBr, BRANCH[CheckNext, IntThisCV, 2],			c1;

IntThisCV:
	Q ← PDA.interrupt + G, CANCELBR[$,1],					c2;
	[] ← G, rhG ← PDAHi, ZeroBr,						c3;

{db}	Map ← UvQ1 ← [rhG, Q], BRANCH[Int, Scan],				c1;

Int:
	uIntLevel ← G, G ← Q, L2←L2.CQ0{QRRets}, CALL[QRead3],			c2;

	rhT ← rhT.IntNN{NQRets}, Q ← T and Q, ZeroBr,				c3, at[pIntLoc,10,CQRets];

	Map ← Q ← [rhPC, Q+PSB.link], L2←L2.WH0{PRRets}, BRANCH[INTa, INTb],	c1;

INTa:
	L ← PDAHi, L0←L0.SrcOK, CALL[PMRead3], {Do Naked Notify}		c2;

INTb:
	L2←L2.INT2{QWRets},							c2;
	T ← T or 1, CALL[QWrite1],						c3;

INTc:
	G ← uIntLevel,								c3, at[L2.INT2,10,QWRets];

	Rx ← uWW, NZeroBr,							c1;
CheckNext:
	G ← G - 2, BRANCH[IntDone, CVLoop],					c2;

IntDone:
	T ← UrPC, GOTO[PTail1],							c3;
	
IntDidNN:
	GOTO[INTc],								c2, at[rhT.IntNN,10,NQRets];


{*****************************************************************************
Fault Handler 
    Entry:	T has FaultIndex*2
	parameters stored in uFaultParm0 and uFaultParm1
	CALLing sequence has done Rx ← pFault, GOTO[SaveRegs];
    Exit:
    Register Usage
*****************************************************************************}
Fault:	UvQ2 ← T, L3←L3.Fault,	c1, at[pFault,10,Enter];
	rhG ← G ← PDAHi,	c2;
	UvQ2Hi ← G, G ← PDA.ready,	c3;

	PC ← uPSB, L2←L2.DQ0{QRRets},	c1;
	rhT ← rhT.Fault{NQRets},	c2;
	CALL[QRead1],	c3;

	rhT ← rhT.FaultNN{NQRets},	c2, at[rhT.Fault,10,NQRets];
	G ← UvQ2, L2←L2.F0{QRRets},	c3;

	Map ← G ← [rhG, G+FaultQueue.condition],	c1;
	UvQ2 ← PDA.ready, CALL[QRead3],	c2;

	Map ← Q ← [rhPC, T and Q], ZeroBr, CANCELBR[$,3],	c1, at[L2.F0,10,QRRets];
	L ← PDAHi, L2←L2.WH0{PMRRets}, BRANCH[PMRead3, Fb],	c2;
Fb:	PC ← Q or Condition.wakeup,	c3;

	MAR ← [rhTT, G+0],	c1;
	MDR ← PC, T ← uPCValid, NZeroBr,	c2;
Fc:	BRANCH[Fd, Fe],	c3;

Fd:	TT ← pFaultNoPC, GOTO[Ff],	c1;
Fe:	TT ← pFaultPC, GOTO[Ff],	c1;
Ff:	L ← UrL, GOTO[PTail3],	c2;

FaultDidNN:	[] ← uPCValid, NZeroBr, GOTO[Fc],	c2, at[rhT.FaultNN,10,NQRets];


{*****************************************************************************
Check For Timeouts 
    Entry:
    Exit:
    Register Usage
*****************************************************************************}
{db *****
CheckTime:
	TT ← LShift1 uTickCount, XDisp,	c2;
	uTickCount ← TT, BRANCH[Scan, NoScan, 0B],	c3;

NoScan:	T ← UrPC,					c1;
	GOTO[PTail0],					c2;
***** db}

Scan:
	Noop,						c2;
	Noop,						c3;

	T ← uPTC, L0←L0.SrcNull,			c1;
	T ← T + 1,					c2;
	uPTC ← T, L2←L2.TS0{PRRets},			c3;

	Map ← Q ← [rhPC, PDA.count],			c1;
	G ← PDAHi, CALL[PRead3],			c2;

	TT ← T,						c1, at[L2.TS0,10,PRRets];
	PC ← StartPsbM4,				c2;
	UvQ2Hi ← G,					c3;

	UvQ2 ← PDA.ready, GOTO[CheckEndx],		c1;

TSLoop:	Map ← Q ← [rhPC, PC or PSB.timeout], L2←L2.TS2{PRRets},	c1;
	uBLTTemp ← TT, CALL[PRead3],	c2;

	Q ← T, ZeroBr,	c1, at[L2.TS2,10,PRRets];
	[] ← Q xor uPTC, NZeroBr, BRANCH[CanTimeout, NoTimeout],	c2;
CanTimeout:	T ← uBLTTemp, BRANCH[Timeout, CheckEnd],	c3;

Timeout:	MAR ← [rhTT, PC+PSB.flags],	c1;
	CANCELBR[$,0],	c2;
	T ← MD,	c3;

	MAR ← [rhTT, PC+PSB.flags],	c1;
	MDR ← T and ~PSB.flags.waiting, CANCELBR[$,0],	c2;
	rhT ← rhT.TS{NQRets},	c3;

	MAR ← [rhTT, PC+PSB.timeout],	c1;
	MDR ← 0, CANCELBR[$,0],	c2;
	GOTO[Dequeue],	c3;

	GOTO[NoTimeout],	c2, at[rhT.TS,10,NQRets];

NoTimeout:	T ← uBLTTemp, CANCELBR[CheckEnd,1],	c3;

CheckEnd:	TT ← T - 1, ZeroBr,	c1;
CheckEndx:	T ← UrPC, BRANCH[TSNotDone, TSDone],	c2;
TSNotDone:	PC ← PC + PSBSize, GOTO[TSLoop],	c3;

TSDone:
{db
	uTickCount ← L xor ~L, GOTO[PTail1],	c3;
db}

{db}	GOTO[PTail1],					c3;


{*****************************************************************************
CleanupQueue subroutine 
    Entry:
	calling instruction in c1
	L2 holds L2.CQ0{QRRets}
	returns to uPFlags
    Exit:
	T holds condition queue
	G holds UvQ1	
    Register Usage
	PC = process
	T = cleanup or link
	Rx = head of queue
	UreturnPC = condition and ~uPMask
	MUST NOT USE L or TOS
*****************************************************************************}
CleanFirst:	G ← UvQ1, CALL[Q1Read3],	c2;
CleanSecond:
	G ← UvQ2, CALL[Q2Read3],	c2;

	PC ← T and Q, ZeroBr, CANCELBR[$,3],	c1, at[L2.CQ0,10,QRRets];
	T ← T and ~uPMask, BRANCH[CQNE, CQEmpty],	c2;
CQNE:	T ← T and ~Condition.wakeup, L2←L2.CQ1{PMRRets},	c3;

	Map ← Q ← [rhPC, PC or PSB.flags],	c1;
	UreturnPC ← T, CALL[PMRead3],	c2;

	[] ← T, ZeroBr, L2←L2.CQ4{QWRets},	c1, at[L2.CQ1,10,PMRRets];
CQLoop1:	[] ← T - PC, ZeroBr, BRANCH[$, CQClean],	c2;
	[] ← T, ZeroBr, BRANCH[$, CQMakeEmpty],	c3;

	Map ← Q ← [rhPC, T or PSB.flags], L2←L2.CQ2{PMRRets}, BRANCH[$, CQHead],	c1;
	PC ← T, CALL[PMRead3],	c2;

	L2←L2.CQ4{QWRets}, GOTO[CQLoop1],	c1, at[L2.CQ2,10,PMRRets];

CQHead:	Rx ← PC,	c2;
	L2←L2.CQ3{PMRRets},	c3;

CQLoop2:	Map ← Q ← [rhPC, PC], CALL[PMRead2],	c1;

	[] ← T - Rx, ZeroBr, L2←L2.CQ4{QWRets},	c1, at[L2.CQ3,10,PMRRets];
	BRANCH[$, CQFoundTail],	c2;
	PC ← T, L2←L2.CQ3{PMRRets}, GOTO[CQLoop2],	c3;

CQFoundTail:
	T ← UreturnPC or PC, CALL[QWrite1],	c3;

CQMakeEmpty:
	Map ← [rhG, G], CANCELBR[$,1],	c1;
	T ← UreturnPC, CALL[QWrite3],	c2;
CQClean:	T ← PC, CANCELBR[CQRet,1], GOTO[CQRet],	c3;

CQEmpty:	T ← 0, GOTO[CQRet],	c3;
	GOTO[CQRet],	c3, at[L2.CQ4,10,QWRets];

CQRet:	Xbus ← uPFlags, XDisp,	c1;
	G ← UvQ1, DISP4[CQRets],	c2;


{*****************************************************************************
PRead subroutine: 
      Entry:
	c2, c3 => Q has virtual address; Map reference started by caller
	L2 holds return
      Exit State:
	T has memory data
	rhTT, TT, has real address
	Q has uPMask
	returnee executed on c1
*****************************************************************************}
PRead2:	Noop,	c2;
PRead3:	TT ← rhTT ← MD,	c3;
PR:	MAR ← [rhTT, Q + 0],	c1;
	Q ← uPMask, L2Disp,	c2;
	T ← MD, DISP4[PRRets],	c3;


{*****************************************************************************
PMRead subroutine: 
      Entry:
	c2, c3 => Q has virtual address; Map reference started by caller
	L2 holds return
      Exit State:
	T has memory data and uPMask
	rhTT, TT, has real address
	Q has uPMask
	returnee executed on c1
*****************************************************************************}
PMRead2:	Noop,	c2;
PMRead3:	TT ← rhTT ← MD,	c3;
PMR:	MAR ← [rhTT, Q + 0],	c1;
	Q ← uPMask, L2Disp,	c2;
	T ← MD and Q, DISP4[PMRRets],	c3;


{*****************************************************************************
PFetch subroutine: 
      Entry:
	c2, c3 => Q has virtual address; Map reference started by caller
	L2 holds return
      Exit State:
	rhTT, TT, has real address
	Q has uPMask
	memory reference started
	returnee executed on c3
*****************************************************************************}
PFetch2:	Noop,	c2;
PFetch3:	TT ← rhTT ← MD,	c3;
	MAR ← [rhTT, Q + 0], L2Disp,	c1;
	Q ← uPMask, DISP4[PFRets],	c2;


{*****************************************************************************
PWrite subroutine: 
      Entry:
	Q has virtual address
	calling instruction executed on c1 => Map reference started by caller
	T has data to be written
	L2 holds return
      Exit State:
	T has memory data
	rhTT, TT, Q has real address
	returnee executed on c3
*****************************************************************************}
PWrite2:	Noop,	c2;
PWrite3:	TT ← rhTT ← MD,	c3;
PW:	MAR ← [rhTT, Q + 0], L2Disp,	c1;
	MDR ← T, RET[PWRets], c2;


{*****************************************************************************
QRead subroutine: 
      Entry:
	rhG,,G has virtual address
	L2 holds return
      Exit State:
	rhG, G has virtual address
	T has MD and 77777B
	XLDisp pending on MD to save ww bit
	returnee executed on c1
*****************************************************************************}
QRead1:	Map ← [rhG, G],					c1;
QRead2:	Noop,						c2;
QRead3:
{db}	TT ← rhTT ← MD, XdwDisp,			c3;

QR:	MAR ← [rhTT, G + 0], DISP2[QRMpFx],		c1;
QRMpFx:	GOTO[QRMpFx1],					c2, at[0, 4, QRMpFx];
{db}	GOTO[QRMpFx1],					c2, at[1, 4, QRMpFx];
	GOTO[QRMpFx1],					c2, at[3, 4, QRMpFx];
{db}	Q ← uPMask, L2Disp,				c2, at[2, 4, QRMpFx];
	T ← MD, XLDisp, RET[QRRets],			c3;

QRMpFx1:
{db}	Xbus ← TT LRot0, XdwDisp,			c3;

	Map ← [rhG, G], DISP2[QRFlgFx],			c1;
QRFlgFx:
{db}	MDR ← TT or map.referenced, GOTO[QRx],		c2, at[0,4,QRFlgFx];
{db}	MDR ← TT or map.referenced, GOTO[QRx],		c2, at[2,4,QRFlgFx];
{db}	T ← qWriteProtect, L2←L2.Fault, GOTO[PRestart],	c2, at[1,4,QRFlgFx];
	T ← qPageFault, L2←L2.Fault, GOTO[PRestart],	c2, at[3,4,QRFlgFx];
QRx:	Xbus ← rdw.x10, XDisp, GOTO[QR],		c3;


{*****************************************************************************
Q1Read subroutine: 
      Entry:
	UvQ1Hi, UvQ1 has virtual address
	calling instruction executed on c1
	L2 holds return
      Exit State:
	same as QRead
*****************************************************************************}
Q1Read3:	rhG ← UvQ1Hi, GOTO[QRead1],	c3;


{*****************************************************************************
Q2Read subroutine: 
      Entry:
	UvQ2Hi, UvQ2 has virtual address
	calling instruction executed on c1
	L2 holds return
      Exit State:
	same as QRead
*****************************************************************************}
Q2Read2:	G ← UvQ2,	c2;
Q2Read3:	rhG ← UvQ2Hi, GOTO[QRead1],	c3;


{*****************************************************************************
QWrite subroutine: 
      Entry:
	rhG, G has virtual address
	L2 holds return
	T has data to be written
      Exit State:
	rhG, G has virtual address
	returnee executed on c3
*****************************************************************************}
QWrite1:
	Map ← [rhG, G],					c1;
QWrite2:
	Noop,						c2;
QWrite3:
{db}	TT ← MD, rhTT ← MD, XdwDisp,			c3;

QW:	MAR ← [rhTT, G + 0], DISP2[QWMpFx], L2Disp,	c1;
QWMpFx:	CANCELBR[QWMpFx1,0F],				c2, at[0, 4, QWMpFx];
{db}	CANCELBR[QWMpFx1,0F],				c2, at[1, 4, QWMpFx];
	CANCELBR[QWMpFx1,0F],				c2, at[3, 4, QWMpFx];
QWMpOk:
{db}	MDR ← T, RET[QWRets],				c2, at[2, 4, QWMpFx];

QWMpFx1:
{db}	Xbus ← TT LRot0, XdwDisp,			c3;

	Map ← [rhG, G], DISP2[QWFlgFx],			c1;
QWFlgFx:
{bj}	MDR ← TT or map.rd, GOTO[QWx],			c2, at[0,4,QWFlgFx];
{db}	MDR ← TT or map.rd, GOTO[QWx],			c2, at[2,4,QWFlgFx];
{db}	T ← qWriteProtect, L2←L2.Fault, GOTO[PRestart],	c2, at[1,4,QWFlgFx];
	T ← qPageFault, L2←L2.Fault, GOTO[PRestart],	c2, at[3,4,QWFlgFx];
QWx:	Xbus ← rdw.x10, XDisp, GOTO[QW],		c3;