{File name: Process.mc
Last edited by Jim Frandeen September 29, 1981 9:26 AM: Fix CancelBR at MREAbort+1.
Last edited by Jim 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.WH2, 7];
Set[L2.DQ2, 4];
Set[L2.NQ1, 6];
Set[L2.NQ0, 3]; {also QRead}
Set[L2.NQ3, 8];
Set[L2.RS3, 9];
Set[L2.LP1, 0A];
Set[L2.AS0, 0B];
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.DQ0, 7]; {3 MOD 4; also QRead}
Set[L2.AAS1, 9];
Set[L2.SP2, 0A];
Set[L2.NQ4, 4];
Set[L2.FS0, 5];
Set[L2.MW2, 6]; {also PFetch, QRead}
Set[L2.PSS0, 2];
Set[L2.PSS1, 8];
Set[L2.SP1, 1]; {1 MOD 4; paired with L2.ASS0}
Set[L2.AAS0, 3]; {3 MOD 4; contains SP1}
Set[L2.LP3, 0B];
Set[L2.FS1, 0C];

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

{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;
{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;

{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];
}

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

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

{
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];
}

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:
G ← UvQ2, 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},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];
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:
PC ← uPSB, GOTO[SaveProcess],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:
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;

Rx ← uWP, BRANCH[NoInt, Interruptx],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
*****************************************************************************}
FreeState:Map ← Q ← [rhPC, PDA.state or T], L2←L2.FS1{PWRets},c1;
T ← TOS, CALL[PWrite3],c2;
T ← MD, L2←L2.FS0{PWRets}, LOOPHOLE[mdok],c3, at[L2.FS1,10,PWRets];

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

{*****************************************************************************
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];
Interruptx:
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;

Map ← UvQ1 ← [rhG, Q], BRANCH[Int, CheckTime],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 uFaultPram0 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
*****************************************************************************}
CheckTime:TT ← LShift1 uTickCount, XDisp,c2;
uTickCount ← TT, BRANCH[Scan, NoScan, 0B],c3;

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

Scan:
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:
uTickCount ← L xor ~L, 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:
TT ← rhTT ← MD, XDirtyDisp,c3;
QR:
MAR ← [rhTT, G + 0], BRANCH[QRMpFx, QRMpOk, 1],c1;
QRMpOk:
Q ← uPMask, L2Disp,c2;
T ← MD, XLDisp, RET[QRRets],c3;
QRMpFx:
Noop,c2;
Xbus ← TT LRot0, XwdDisp,c3;
Map ← [rhG, G], DISP2[QRFlgFx],c1;
QRFlgFx:
MDR ← TT or 10, GOTO[QRx],c2, at[0,4,QRFlgFx];
MDR ← TT or 10, GOTO[QRx],c2, at[1,4,QRFlgFx];
T ← qWriteProtect, L2←L2.Fault, GOTO[PRestart],c2, at[2,4,QRFlgFx];
T ← qPageFault, L2←L2.Fault, GOTO[PRestart],c2, at[3,4,QRFlgFx];
QRx:
Xbus ← 2, 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:
TT ← MD, rhTT ← MD, XDirtyDisp,c3;
QW:
MAR ← [rhTT, G + 0], BRANCH[QWMpFx, QWMpOk, 1], L2Disp,c1;
QWMpOk:
MDR ← T, RET[QWRets],c2;
QWMpFx:
CANCELBR[$,0F], c2;
Xbus ← TT LRot0, XwdDisp, c3;
Map ← [rhG, G], DISP2[QWFlgFx],c1;
QWFlgFx:
MDR ← TT or 0A0, GOTO[QWx],c2, at[0,4,QWFlgFx];
MDR ← TT or 0A0, GOTO[QWx],c2, at[1,4,QWFlgFx];
T ← qWriteProtect, L2←L2.Fault, GOTO[PRestart],c2, at[2,4,QWFlgFx];
T ← qPageFault, L2←L2.Fault, GOTO[PRestart],c2, at[3,4,QWFlgFx];
QWx:
Xbus ← 2, XDisp, GOTO[QW],c3;

{END}