{File name: Process.mc
Description: Dandelion Process Microcode,
Author: JGS
Created: February 13, 1981 1:12 PM,
AHL/JPM, 6-Jan-87 8:16:32 Changes for MDS relief.
JPM, 14-Nov-86 12:48:39 Add incrementing of uIdleCount* in IdleLoop for performance study.
JPM, 11-Jul-86 9:46:32 Hard-wire address of SaveRegs.
AEF/JAC 7-Aug-85 15:24:53 Four's a charm - Fix up interrupt handling again
AEF/JAC 17-Jul-85 18:02:17 Fix up interrupt handling again
JPM, 11-Feb-85 14:26:49 Separate stackP ← and push by one instr. (at PSSc & LPe).
JGS/JPM, 9-Jan-85 10:12:25 Fix interrupt handling.
JGS, 12-Dec-84 16:12:13 Restore rhPC on PInt path.
JPM, 11-Oct-84 14:09:49 Change PIntReschedule to set L2 in different instruction (to fix alloc error).
JPM, 9-Oct-84 16:23:36 Simplify return from interrupt.
JPM, 19-Sep-84 16:22:19 Remove uTickCount (not needed for Daybreak programmed timeout).
JPM, 11-Sep-84 12:12:44 Fix BRANCH mask after XWtOKDisp.
DEG 1-Sep-84 19:44:17 add copyright notice.
JPM, 1-Jun-84 16:35:42, Replace XDirtyDisp by XWtOKDisp, reorder XwdDisp destinations, use map flag constants.
HGM, 28-Nov-83 7:04:41, Check MesaInt at LoadProcess
HGM, 27-Sep-83 20:58:54, Merge In Dicentra fixes
Check MesaInt at SaveProcess+Enqueue (Long SDLC path)
Check MesaInt in Process Timeout Scan
Turn off MInt from IdleLoop (to catch lost interrupts)
FreeState used MDR←, ←MD quirk.
Deleted several LOOPHOLE[mdok]s (1 left)
Patched IdleLoop for Dicentra Interrupts
RXJ 30-Aug-83 9:03:43 new instruction set
AXD 5-Aug-83 16:04:37 new instruction set
JGS February 24, 1982 add Set Process Priority inst, bum 1 uinst
JGS January 18, 1982 12:30 PM fix ibempty, pccross, interrupt, no switch
JGS 8-Dec-81 20:54:29 Correct PC/Stack fixup on faults
JGS November 17, 1981 10:34 AM New instruction set
JGS March 26, 1981 10:43 AM to fix timing restrictions
JGS March 26, 1981 3:53 PM Change Wait to check condition.abortable
}
{ Copyright (C) 1981, 1982, 1983, 1984, 1985, 1986 by Xerox Corporation. All rights reserved.}
{*****************************************************************************
Definitions
*****************************************************************************}
Set[L2.Pop0IncrX, 0 {00xx}]; {also in Jump.mc}
{Offsets and Magic locations}
Set[PSB.link, 0];
Set[PSB.link.preempted, 1];
Set[PSB.link.permanent, 2];
Set[PSB.link.enterfailed, 4];
Set[PSB.flags, 1];
Set[PSB.flags.waiting, 2];
Set[PSB.context, 2];
Set[PSB.timeout, 3];
Set[PSB.mds, 4];
Set[PSB.SIZE, 8];
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.state, 10'b];
Set[PDA.interrupt, 20'b];
Set[PDA.lastCV, 36'b];
Set[PDA.fault, 60'b];
Set[StartPSB, 100'b];
Set[StartPSBMinus1Times2, Lshift[Sub[StartPSB,PSB.SIZE],1]];
{
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, 10]; Set[pMELoc, 0];
Set[pMR, 1];
Set[pMX, 12]; Set[pMXLoc, 2]
Set[pMW, 9];
Set[pNC, 4];
Set[pBC, 5];
Set[pREQ, 8];
Set[pSPP, 0A];
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];{also L2.MR4 in QRead}
MacroDef[PRr, at[#1,10,PRRets]];
MacroDef[PMRr, at[#1,10,PMRRets]];
MacroDef[PFr, at[#1,10,PFRets]];
MacroDef[PWr, at[#1,10,PWRets]];
MacroDef[QRr, at[#1,10,QRRets]];
MacroDef[QWr, at[#1,10,QWRets]];
MacroDef[NQr, at[#1,10,NQRets]];
MacroDef[CQr, at[#1,10,CQRets]];
{PRead Returns}
Set[L2.LP0, 0];
Set[L2.MR3, 1];
Set[L2.NQ0, 2]; {also QRead}
Set[L2.DQ2, 4];
Set[L2.NQ1, 5];
Set[L2.MW2, 6]; {also PFetch, PWrite, QRead}
Set[L2.WH2, 7];
Set[L2.NQ3, 8];
Set[L2.RS3, 9];
Set[L2.LP1, 0A];{also PWRets}
Set[L2.AS0, 0B];
Set[L2.PLS0, 0C];
Set[L2.LP2, 0D];
Set[L2.TS0, 0E];
Set[L2.TS2, 0F];
{PMRead Returns}
Set[L2.WH0, 0]; {0 MOD 2}
Set[L2.RS0, 1]; {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.RS2, 0]; {0 MOD 2}
Set[L2.RS0, 1]; {also PMRead}
Set[L2.SP0, 2]; {2 MOD 4}
Set[L2.SP1, 3]; {3 MOD 4; tied to L2.SP0}
Set[L2.LP5, 4];
Set[L2.DQ5, 5];
Set[L2.MW1, 6]; {also PRead, PWrite, QRead}
Set[L2.TS1, 7];
Set[L2.SPP, 8];
Set[L2.EF0, 9];
Set[L2.LP6, 0A];
{PWrite Returns}
Set[L2.WH1, 0];
Set[L2.DQ0, 7]; {3 MOD 4; also QRead}
Set[L2.AAS1, 9];
Set[L2.LP1, 0A]; {also PRead}
Set[L2.NQ4, 4];
Set[L2.SP2, 5];
Set[L2.MW2, 6]; {also PRead, QRead}
Set[L2.PSS0, 2];
Set[L2.PSS1, 8];
Set[L2.SP3, 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];
Set[L2.FreeState, 0D];{0F, paired with L2.FS0}
Set[L2.FS0, 0F];{0F, paired with FreeState}
{QRead Returns}
Set[L2.ME0, 4]; {also QWrite}
Set[L2.DQ0, 7]; {3 MOD 4; also PWrite}
Set[L2.MR0, 3];
Set[L2.CQ0, 1];
Set[L2.MR4, 0]; {also L2.Trap}
Set[L2.EM0, 5];
Set[L2.MW2, 6]; {also PRead, PWrite}
Set[L2.NQ0, 2]; {also PRead}
Set[L2.BC0, 8];
Set[L2.RQ0, 9];
Set[L2.F0, 0A];
{QWrite Returns}
Set[L2.ME0, 4]; {also QRead}
Set[L2.MR1, 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.NQ8, 6];
Set[L2.EM1, 7]; {3 MOD 4}
Set[L2.INT2, 8];
Set[L2.CQ4, 9]; {1 MOD 2}
{Requeue Returns}
Set[rhT.PT, 0]; {Must be zero}
Set[rhT.BC, 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];
{*****************************************************************************
Monitor Entry
*****************************************************************************}
@ME: T ← STK, push, L2←0, c1, opcode[361'b];
rhTT ← TOS LRot0, STK ← TOS, c2;
MEf: UvQ1Hi ← TOS, pop, c3;
Map ← [rhTT, T], L1←L1.Push, TT ← Monitor.lock, c1;
UvQ2 ← T, L0←L0.ME, c2;
rhRx ← Rx ← MD, XWtOKDisp, pop, c3;
MAR ← [rhRx, T+0], BRANCH[MEa, MEb, 0D], c1, WLMFRet[L0.ME];
MEb: TOS ← 1, L2Disp, c2;
Q ← MD or TT, XLDisp, BRANCH[MEc, MXa], c3;
MEc: MAR ← [rhRx, T+0], BRANCH[MEe, MEd, 2], c1;
MEe: MDR ← Q, IBDisp, c2;
MEg: PC ← PC + PC16, DISPNI[OpTable], c3;
MEa: Q ← T, GOTO[WLMapFix], c2;
MEd: Rx ← pME, pop, GOTO[Long1b], c2;
{*****************************************************************************
Monitor Exit
*****************************************************************************}
@MX: T ← STK, push, L2←1, c1, opcode[362'b];
rhTT ← TOS LRot0, STK ← TOS, GOTO[MEf], c2;
MXa: MAR ← [rhRx, T+0], CANCELBR[$,3], c1;
MDR ← Q and ~Monitor.lock, c2;
[] ← Q and uPMask, ZeroBr, c3;
BRANCH[MXb, MXc], c1;
MXc: PC ← PC + PC16, IBDisp, GOTO[SLa], c2;
MXb: Rx ← pMX, pop, GOTO[Long1b], c2;
{*****************************************************************************
Opcodes
*****************************************************************************}
@MW: Rx ← pMW, GOTO[Long2], c1, at[2,10,ESC0n];
@MR: Rx ← pMR, push, GOTO[Long2], c1, at[3,10,ESC0n];
@NC: Rx ← pNC, push, GOTO[Long1], c1, at[4,10,ESC0n];
@BC: Rx ← pBC, push, GOTO[Long1], c1, at[5,10,ESC0n];
@REQ: Rx ← pREQ, GOTO[Long2], c1, at[6,10,ESC0n];
@SPP: Rx ← pSPP, GOTO[Long1a], c1, at[0F,10,ESC0n];
Long2: T ← STK, pop, L0←0, c2;
UvQ2Hi ← T, L0Disp, GOTO[Long2a], c3;
Long2a: T ← STK, pop, BRANCH[Long2b, Long1a], c1;
Long2b: UvQ2 ← T, c2;
TT ← 2, c3;
uStkDepth ← TT, c1;
Long1: T ← STK, pop, L0←1, c2;
UvQ1Hi ← T, L0Disp, GOTO[Long2a], c3;
Long1a: PC ← PC - 1, pop, c2;
Long1b: UvQ1 ← T c3;
rhT ← rhT.PT, c1;
SaveRegs:
UrL ← L, c2, at[addrSaveRegs];
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, DISP4[Enter], c3;
PRestart:
uFaultParm0 ← G, c3;
stackP ← uStkDepth, c1;
TOS ← pFault, c2;
TT ← uPFlags, XDisp, push, c3;
G ← rhG, L2Disp, push, BRANCH[PFa, PFb, 7], c1;
PFa: uFaultParm1 ← G, BRANCH[PTrap, PFault], c2;
PFb: uFaultParm1 ← G, push, 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 ← 0, c1, at[pMELoc,10,Enter];
PC ← uPSB, c2;
EnterFailed:
L ← UvQ1Hi, L2←L2.EF0{PFRets}, c3;
EFa: Map ← Q ← [rhPC, PC+PSB.link], c1;
rhG ← PDAHi, G ← PDA.ready, CALL[PFetch3], c2;
Rx ← MD, c3, PFr[L2.EF0];
MAR ← [rhTT, PC+PSB.link], c1;
MDR ← Rx or PSB.link.enterfailed, 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: G ← UvQ1, L2←L2.MR0{QRRets}, c1, at[pMR,10,Enter];
CALL[Q1Read3], c2;
PC ← uPSB, BRANCH[MRa, MRb, 2], c1, QRr[L2.MR0];
MRb: UvQ2 ← G, GOTO[EnterFailed], c2;
MRa: G ← UvQ2, c2;
rhG ← UvQ2Hi, c3;
Map ← [rhG, G], L2←L2.CQ0{QRRets}, c1;
TOS ← T, CALL[QRead3], c2;
PC ← uPSB, c3, CQr[pMR];
Map ← Q ← [rhPC, PC or PSB.flags], L2←L2.MR3{PRRets}, c1;
Rx ← uPMask, CALL[PRead3], c2;
MAR ← [rhTT, PC+PSB.flags], L2←L2.MR4{QRRets}, c1, PRr[L2.MR3];
MDR ← Ybus ← T and ~Rx, YDisp, CANCELBR[$,0], c2;
MRe: rhG ← UvQ1Hi, BRANCH[MRc, MRd, 0E], c3;
MRc: Map ← [rhG, G], L2←L2.MR1{QWRets}, c1; {write locked monitor}
T ← TOS or Monitor.lock, push, CALL[QWrite3], c2;
TOS ← 1, push, c3, QWr[L2.MR1];
STK ← TOS, pop, GOTO[PTail2]{L not used}, c1;
MRd: Rx ← pTrap, CALL[Q2Read2], c1;
[] ← T and Condition.abortable, NZeroBr, CANCELBR[$,3], c1, QRr[L2.MR4];
G ← UvQ1, BRANCH[MRe, PRestart], c2;
{*****************************************************************************
Monitor Exit and Depart opcode
Entry:
UvQ1Hi,,UvQ1 hold virtual address of monitor lock to be exited
Exit:
*****************************************************************************}
Depart: G ← UvQ1, L2←L2.EM0{QRRets}, c1, at[pMXLoc,10,Enter];
uStkDepth ← 0, CALL[Q1Read3], c2;
MXx: 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, QRr[L2.EM0];
T ← T and ~Monitor.lock, CALL[QWrite3], c2;
T ← T and Q, ZeroBr, rhT ← rhT.EM{NQRets}, c3, QWr[L2.EM1];
Map ← Q ← [rhPC, T+PSB.link], L2←L2.EM2{PMRets}, BRANCH[EMa, EMb], c1;
EMa: UvQ2 ← PDA.ready, CALL[PMRead3], c2;
L ← PDAHi, c1, PMRr[L2.EM2];
PC ← T, L2←L2.DQ0{QRRets}, CALL[CallDQ], c2;
EMb: Xbus ← uPFlags, XLDisp, c2, NQr[rhT.EM];
PC ← uPSB, BRANCH[MXx, MWa, 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, CQr[pMW];
Rx ← UvQ2, c1;
UvQTemp ← Rx, c2;
Rx ← UvQ2Hi, c3;
Map ← [rhG, G], L2←L2.EM0{QRRets}, c1;
UvQTempHi ← Rx, CALL[QRead3], c2;
MWa: rhG ← G ← UvQTempHi, c1;
UvQ2Hi ← G, c2;
G ← UvQTemp, L2←L2.MW2{QRRets, PFRets}, c3;
Map ← UvQ2 ← [rhG, G], CALL[QRead2], c1;
Map ← Q ← [rhPC, PC or PSB.flags], CANCELBR[PFetch2,3], c1, QRr[L2.MW2];
TOS ← MD, XLDisp, c3, PFr[L2.MW2];
[] ← T and Condition.abortable, ZeroBr, BRANCH[MWb, MWc, 2], c1;
MWb: Rx ← uPTC, CANCELBR[MWe, 1], c2;
MWc: Rx ← uPTC, BRANCH[MWd, MWe], c2;
MWd: GOTO[PTail1], c3;
MWe: Xbus ← T LRot0, XLDisp, c3;
L ← uTicks, ZeroBr, BRANCH[MWNoWW, MWWW, 2], c1;
MWNoWW: G ← PDA.ready, BRANCH[MWMakeTime, MWHaveTime], c2;
MWHaveTime:
Xbus ← 0, XDisp, GOTO[MWWriteTime], c3;
MWMakeTime:
L ← L + Rx, ZeroBr, c3;
MWWriteTime:
MAR ← [rhTT, PC + PSB.timeout], BRANCH[MWOK, MWInc], c1;
MWOK: MDR ← L, T ← 0+0+1, rhT←rhT.PT, CANCELBR[MWf,0], c2;
MWInc: MDR ← T ← 0+0+1, rhT←rhT.PT, CANCELBR[MWf,0], c2;
MWf: UvQ1Hi ← T, L2←L2.DQ0{QRRets}, c3;
MAR ← [rhTT, PC + PSB.flags], c1;
MDR ← TOS or PSB.flags.waiting, CANCELBR[Q1Read3,0], c2;
MWWW: L2←L2.MW3{QWRets}, CANCELBR[$,1], c2;
T ← T and ~Condition.wakeup, CALL[QWrite1], c3;
GOTO[PTail1], c3, QWr[L2.MW3];
{*****************************************************************************
Notify opcode
Entry:
UvQ1Hi,,UvQ1 hold virtual address of condition to be notified
Exit:
*****************************************************************************}
Notify: uStkDepth ← 0, L2←L2.CQ0{QRRets}, CALL[CleanFirst], c1, at[pNC,10,Enter];
T ← T and Q, ZeroBr, L2←L2.WH0{PMRRets}, c3, CQr[pNC];
Map ← Q ← [rhPC, T+PSB.link], BRANCH[NCa, NCb], c1;
NCa: L ← PDAHi, CALL[PMRead3], c2;
NCb: TT ← uPFlags, GOTO[PTail3], {L not used} c2;
{*****************************************************************************
Broadcast opcode
Entry:
UvQ1Hi,,UvQ1 hold virtual address of condition to be broadcast
Exit:
*****************************************************************************}
BCast: uStkDepth ← 0, L2←L2.CQ0{QRRets}, CALL[CleanFirst], c1, at[pBC,10,Enter];
BCe: rhT ← rhT.BC{NQRets}, T ← T and Q, ZeroBr, c3, CQr[pBC];
BCd: Map ← Q ← [rhPC, T+PSB.link], L2←L2.WH0{PMRRets}, BRANCH[BCa, BCb], c1;
BCa: L ← PDAHi, CALL[PMRead3], c2;
BCb: rhT ← rhT.PT, GOTO[MWd], c2;
BCc: G ← UvQ1, L2←L2.BC0{QRRets}, c2, NQr[rhT.BC];
rhG ← UvQ1Hi, CALL[QRead1], c3;
CANCELBR[$,3], c1, QRr[L2.BC0];
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, PMRr[L2.WH0];
T ← 0, UvQ2 ← PDA.ready, CALL[PWrite3], c2;
PC ← Q - PSB.timeout, L2←L2.WH2{PRRets}, c3, PWr[L2.WH1];
Map ← Q ← [rhPC, PC or PSB.flags], CALL[PRead2], c1;
MAR ← [rhTT, PC+PSB.flags], c1, PRr[L2.WH2];
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, QRr[L2.RQ0];
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;
{*****************************************************************************
Set Process Priority opcode
Entry:
TOS has priority
Exit:
*****************************************************************************}
SetPP: TOS ← LRot1 TOS and 7, L2←L2.SPP{PFRets}, c1, at[pSPP,10,Enter];
Rx ← ~uPPMask, c2;
PC ← uPSB, GOTO[EFa], c3;
Rx ← Rx and MD, c3, PFr[L2.SPP];
UvQ2 ← PDA.ready, c1;
L ← PDAHi, c2;
TOS ← TOS LRot12, c3;
MAR ← [rhTT, PC+PSB.link], c1;
MDR ← TOS or Rx, L2←L2.DQ0{QRRets}, GOTO[CallDQ], c2;
{*****************************************************************************
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, QRr[L2.DQ0];
DQx: Rx ← T, CALL[PMRead3], c2;
TOS ← uPFlags, c1, PMRr[L2.DQ1];
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, PRr[L2.DQ2];
[] ← 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, PFr[L2.DQ5];
MAR ← [rhTT, PC+PSB.flags], c1;
MDR ← T or uPsbLink, CANCELBR[$,0], c2;
DQm: G ← UvQ2, MesaIntBr, GOTO[Enqueue], c3, QWr[L2.DQ4];
{*****************************************************************************
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, PRr[L2.NQ0];
L ← T and uPPMask, CALL[Q2Read3], c2;
Q ← T and uPMask, ZeroBr, CANCELBR[$,3], c1, QRr[L2.NQ0];
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, QWr[L2.NQ8];
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, uT ← T, c1, PRr[L2.NQ1];
[] ← 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, QWr[L2.NQ2];
NQd: Map ← Q ← [rhPC, Rx+PSB.link], CALL[PRead2], c1;
TT ← T and uPPMask, c1, PRr[L2.NQ3];
[] ← L - TT - 1, CarryBr, c2;
Q ← ~uPMask, BRANCH[NQf, NQg], c3;
NQf: TOS ← Rx, c1;
uT ← 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 uT, L2←L2.NQ4{PWRets}, c3;
Map ← Q ← [rhPC, TOS+PSB.link], c1;
T ← T or PC, CALL[PWrite3], c2;
Xbus ← rhT, XDisp, c3, PWr[L2.NQ4];
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
*****************************************************************************}
PTail1: L ← UrL, c1;
PTail2: TT ← uPFlags, c2, NQr[rhT.PT];
PTail3: G ← UrG, L0←L0.JRemap, c3;
rhG ← UrGHi, c1;
PC ← UrPC, L2←L2.RSSpc, c2;
rhRx ← TT LRot12, XDisp, c3;
PTNormal:
TT ← UvPCpage, DISP4[PEnd], c1;
PEnd: PC ← PC + 1, IBDisp, GOTO[PDispNI], c2, at[0,10];
PC ← PC + PC16, IBDisp, GOTO[PDispNI], c2, at[1,10,PEnd];
T ← sProcessTrap, GOTO[Trapc3], c2, at[2,10,PEnd];
{not possible, c2, at[3,10,PEnd];}
Q ← PC and 0FF, L1 ← L1.Refill, GOTO[PInt], 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];
L1 ← 2, GOTO[StashPC2], c2, at[8,10,PEnd];
L1 ← 1, GOTO[StashPC1], 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, GOTO[PIntRS], c2, at[0C,10,PEnd];
L1 ← 0, GOTO[StashPC0], c2, at[0D,10,PEnd];
MesaIntBr, GOTO[Reschedule], c2, at[0E,10,PEnd];
GOTO[SPIdle], {was in idle loop} c2, at[0F,10,PEnd];
PDispNI:
rhPC ← UrPCHi, DISPNI[OpTable], c3;
Reschedule:
PC ← uPSB, L3Disp, BRANCH[SaveProcess, RescheduleInt], c3, SPCr[L2.RSSpc];
PInt: [] ← Q and ~1, ZeroBr, L2 ← L2.Pop0IncrX, c3;
Xbus ← uPCCross, XRefBr, T ← Q, BRANCH[PInta, PIntb], c1;
PInta: rhTT ← UvChigh, BRANCH[PIntc, PIntd], c2;
PIntc: GOTO[RReMap], c3;
PIntd: Q ← Q - r0100, GOTO[RReMap], c3;
PIntb: [] ← Q, ZeroBr, BRANCH[PIntf, PInte], c2;
PInte: rhTT ← UvChigh, CANCELBR[RReMap, 1], c3;
PIntf: Rx ← 30, BRANCH[pcLowEquals1, $], c3;
Ybus ← ~ErrnIBnStkp and Rx, ZeroBr, c1;
PInti: rhTT ← UvChigh, BRANCH[PIntg, PInth], c2;
PIntg: GOTO[RReMap], c3;
PInth: TT ← TT + 0FF + 1, GOTO[RReMap], c3;
pcLowEquals1:
GOTO[PInti], c1;
PIntRS: Xbus ← uPCCross, XRefBr, BRANCH[PIRSa, PIRSb, 1], c3;
PIRSa: TOS ← STK, pop, CANCELBR[PIRSc,1], c1;
PIRSc: L1 ← 0, GOTO[StashPC0], c2;
PIRSb: TOS ← STK, pop, BRANCH[PIRSd, PIRSc], c1;
PIRSd: TT ← 30, c2;
Ybus ← ~ErrnIBnStkp and TT, ZeroBr, c3;
TT ← UvPCpage, BRANCH[PIRSe, PIRSf], c1;
PIRSe: L1 ← 0, GOTO[StashPC0], c2;
PIRSf: TT ← TT + 0FF + 1, L1 ← 0, GOTO[StashPC0], c2;
SPIdle: G ← PDA.lastCV{for interrupts}, L2←L2.RS0{PMRRets, PFRets}, c3;
SPRet: Map ← Q ← [rhPC, PDA.ready], CALL[PMRead2], c1;
Map ← Q ← [rhPC, T+PSB.link], ZeroBr, c1, PMRr[L2.RS0];
UreturnPC ← T, BRANCH[PFetch3, BusyWaita], c2;
PC ← MD and Q, L2←L2.RS2{PFRets}, c3, PFr[L2.RS0];
PRSe: Map ← Q ← [rhPC, PC{+PSB.link}], uPSB ← PC, CALL[PFetch2], c1;
T ← MD, XDisp, c3, PFr[L2.RS2];
uPsbLink ← T, L1 ← 0C, DISP4[PRSa, 0C], c1;
PRSa: T ← RRot1 T and uPPMask, GOTO[PRSb], c2, at[0C,10,PRSa];
GOTO[PRSc], c2, at[0D,10,PRSa];
GOTO[PRSc], c2, at[0E,10,PRSa];
GOTO[PRSc], c2, at[0F,10,PRSa];
PRSb: 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, PRr[L2.RS3];
[] ← UreturnPC xor PC, ZeroBr, BRANCH[PRSc, PRSd], c2;
PRSc: uGFI ← 0 {disable SameG in Xfer}, MesaIntBr, CANCELBR[LoadProcess,1], c3;
PRSd: PC ← uPsbLink and Q, BRANCH[PRSe, BusyWaitb], c3;
BusyWaita: Noop, c3;
BusyWaitb: T ← pIdle, c1;
uPFlags ← T, c2;
IdleLoop: Q ← uIdleCountHigh, MesaIntBr, c3;
T ← uIdleCountLow, BRANCH[NoInt, IdleInt {InterruptsDaybreak}], c1;
NoInt: T ← T + 1, CarryBr, BRANCH[$, WakeError], c2;
uIdleCountLow ← T, MesaIntBr, BRANCH[IdleCheck, $], c3;
Q ← Q + 1, BRANCH[NoInt, IdleInt], c1;
IdleCheck: [] ← uWDC, NZeroBr, BRANCH[NoInt, IdleInt], c1;
WakeError: uIdleCountHigh ← Q, CANCELBR[$, 1], c3;
T ← sRescheduleError, 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], BRANCH[SPa,SPb,2], L2←L2.SP0{PFRets}, c1;
SPa: TOS ← ~PSB.link.preempted, CALL[PFetch3], c2;
SPb: TOS ← PSB.link.preempted, CALL[PFetch3], c2;
T ← MD and TOS, XDisp, GOTO[SPd], c3, PFr[L2.SP0];
T ← MD or TOS, XDisp, GOTO[SPc], c3, PFr[L2.SP1];
SPc: MAR ← [rhTT, PC+PSB.context], BRANCH[SPe, SPf, 0D], c1;
SPe: TT ← RRot1 T and uPPMask, CANCELBR[$,0], c2;
TT ← TT LRot4, GOTO[AllocSV], c3;
SPf: G ← ~ErrnIBnStkp, CANCELBR[$,0], L2←1, c2;
TOS ← MD, uPsbLink ← T, GOTO[DSKg], c3;
SPd: MAR ← [rhTT, PC+PSB.context], BRANCH[SPi, SPh, 0D], c1;
SPh: uPsbLink ← T, CANCELBR[$,0], c2;
TOS ← MD, c3;
GOTO[PSSe], c1;
SPi: MDR ← UvL, CANCELBR[$,0], c2;
uPsbLink ← T, GOTO[SPj], c3;
PSSRet: T ← TOS, L2←L2.SP2{PWRets}, c3, PWr[L2.SP3];
SPg: Map ← Q ← [rhPC, PC or PSB.context], CALL[PWrite2], c1;
Noop, c3, PWr[L2.SP2];
SPj: MAR ← [rhTT, PC+PSB.link], c1;
MDR ← uPsbLink, GOTO[SPIdle], c2;
{*****************************************************************************
AllocAndSave subroutine
Entry: T has priority
Exit: TOS has state
Register Usage
T, Q, rhRx, Rx, TOS, uTemp
*****************************************************************************}
AllocSV:
Map ← Q ← [rhPC, PDA.state or TT], L2←L2.AS0{PRRets}, c1;
uTemp ← Q, c2;
rhTT ← TT ← MD, uPsbLink ← T, CALL[PR], c3;
Map ← Q ← [rhPC, T], c1, PRr[L2.AS0];
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, c2;
G ← ~ErrnIBnStkp, L2←1, GOTO[DSKg], c3;
PSSf: G ← 0F and G, c1;
T ← G or T, c2;
Q ← State.word, L2←L2.PSS0{PWRets}, c3;
Map ← Q ← [rhPC, TOS + Q], CALL[PWrite2], c1;
T ← G + 4, NibCarryBr, c3, PWr[L2.PSS0];
Q ← Q - State.word, BRANCH[PSSa, PSSb], c1;
PSSa: stackP ← G ← G + 2, GOTO[PSSc], c2;
PSSb: stackP ← G ← 0E, GOTO[PSSc], c2;
PSSc: Q ← Q + G, L2←L2.PSS1, c3;
Map ← Q ← [rhPC, Q - 1], push, c1;
PSSd: T ← STK, pop, CALL[PWrite3], c2;
G ← G - 1, ZeroBr, c3, PWr[L2.PSS1];
Map ← Q ← [rhPC, Q - 1], BRANCH[PSSd, PSSe], c1;
PSSe: T ← UvL, L3Disp, c2;
Q ← TOS+State.frame, L2←L2.SP3{PWRets}, BRANCH[AASa, AASb, 1], c3;
AASa: Map ← Q ← [rhPC, Q], CALL[PWrite2], pop, c1;
AASb: Map ← Q ← [rhPC, Q], CALL[PWrite2], pop, c1;
T ← uFaultParm0, L2←L2.AAS1{PWRets}, c3, PWr[L2.AAS0];
Map ← Q ← [rhPC, Q+1], CALL[PWrite2], c1;
T ← uFaultParm1, L2←L2.SP3{PWRets}, c3, PWr[L2.AAS1];
Map ← Q ← [rhPC, Q+1], CALL[PWrite2], c1;
{*****************************************************************************
LoadProcess subroutine
Entry: L has 0
Exit: Returns to EFCHaveLink
Register Usage
*****************************************************************************}
LoadProcess:
Map ← Q ← [rhPC, PC or PSB.context], BRANCH[$, LoadProcessInt], c1;
uPCValid ← 0, L ← 0, c2;
rhTT ← TT ← MD, c3;
MAR ← [rhTT, Q + 0], c1;
L1Disp, Q ← ~PSB.link.preempted, c2;
TOS ← MD, DISP4[LPa, 0C], c3;
LPa: T ← uPsbLink, XDisp, GOTO[LPb], c1, at[0C,10,LPa];
MAR ← [rhTT, PC], GOTO[PLS], c1, at[0D,10,LPa];
MAR ← [rhTT, PC], GOTO[PLS], c1, at[0E,10,LPa];
MAR ← [rhTT, PC], GOTO[PLS], c1, at[0F,10,LPa];
LPb: stackP ← 0, rhT ← xtPSwitch, BRANCH[LPd, LPe, 0B], c2;
LPd: T ← TOS, GOTO[LPf], c3;
LPe: T ← T and ~PSB.link.enterfailed, c3;
Map ← Q ← [rhPC, PC or PSB.link], push, L2←L2.LP1{PW}, c1;
TT ← 0, push, c2;
TT ← rhTT ← MD, STK ← TT, pop, CALL[PW], c3;
T ← TOS, GOTO[LPf], c3, PWr[L2.LP1];
LPx: TOS ← TOS + State.frame, L2←L2.LP6{PFets}, c3, PWr[L2.FS0];
Map ← Q ← [rhPC, TOS], CALL[PFetch2], c1;
T ← MD, c3, PFr[L2.LP6];
LPf: Map ← Q ← [rhPC, PC or PSB.mds], L2←L2.LP5{PF}, c1;
UvL ← T, CALL[PFetch3], c2;
rhMDS ← TOS ← MD, LOOPHOLE[mdok], c3, PFr[L2.LP5];
UvMDS ← Q ← TOS, c1;
Rx ← XferType.pSwitch, L1←L1.Xfer, c2;
uXferType ← Rx, GOTO[XFER], c3;
{*****************************************************************************
PLoadStack subroutine
Entry: T has state.word
TOS has stack pointer
Exit: TOS has state pointer
G has priority
Returns to FreeState
Register Usage
T, rhTT, TT, Q, Rx, TOS
*****************************************************************************}
PLS: MDR ← uPsbLink and Q, CANCELBR[$,0], c2;
Q ← State.word, c3;
Map ← Q ← [rhPC, TOS + Q], L2←L2.PLS0{PR}, c1;
stackP ← 0, rhT ← xtPSwitch, CALL[PRead3], c2;
TT ← T LRot8, STK ← T, push, c1, PRr[L2.PLS0];
TT ← TT and 0FF, c2;
T ← T + 4, NibCarryBr, c3;
UBrkByte ← TT, BRANCH[PLSa, PLSb], c1;
PLSa: T ← T and 0F, GOTO[PLSc], c2;
PLSb: T ← 10, GOTO[PLSc], c2;
PLSc: Rx ← T - 2, c3;
Map ← Q ← [rhPC, TOS], c1;
PLSf: G ← RRot1 uPsbLink, c2;
rhTT ← TT ← MD, c3;
MAR ← [rhTT, Q+0], c1;
Rx ← Rx - 1, ZeroBr, c2;
T ← MD, STK ← T, push, BRANCH[PLSd, PLSe], c3;
PLSd: Map ← Q ← [rhPC, Q+1], GOTO[PLSf], c1;
PLSe: STK ← T, L1Disp, c1;
stackP ← uBlock0, BRANCH[FreeState, LPx, 0D], c2;
{*****************************************************************************
FreeState subroutine
*****************************************************************************}
FreeState:
T ← G LRot4, c3;
Map ← Q ← [rhPC, PDA.state], c1;
Rx ← T and 7, c2;
TT ← rhTT ← MD, c3;
MAR ← [rhTT, Q + Rx], c1;
CANCELBR[$,0], c2;
T ← MD, c3;
MAR ← [rhTT, Q + Rx], c1;
MDR ← TOS, CANCELBR[$,0], c2;
L2←L2.FS0{PWRets}, c3;
Map ← Q ← [rhPC, TOS], CALL[PWrite2], c1;
{*****************************************************************************
Interrupt Handler
Entry:
CALLing sequence has done Rx ← pInt, GOTO[SaveRegs];
Exit:
Register Usage
*****************************************************************************}
Interrupt: Rx ← uWP, c1, at[pIntLoc,10,Enter];
Interruptx: 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, Scan], c1;
Int: uIntLevel ← G, G ← Q, L2←L2.CQ0{QRRets}, CALL[QRead3], c2;
rhT ← rhT.IntNN{NQRets}, Q ← T and Q, ZeroBr, c3, CQr[pIntLoc];
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, QWr[L2.INT2];
Rx ← uWW, NZeroBr, c1;
CheckNext: G ← G - 2, BRANCH[IntDone, CVLoop], c2;
IntDone: GOTO[PTail1], c3;
IntDidNN: GOTO[INTc], c2, NQr[rhT.IntNN];
{*****************************************************************************
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;
rhPC ← PDAHi, CALL[QRead1], c3;
rhT ← rhT.FaultNN{NQRets}, c2, NQr[rhT.Fault];
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, QRr[L2.F0];
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: uGFI ← 0 {disable SameG in Xfer}, 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, NQr[rhT.FaultNN];
{*****************************************************************************
Check For Timeouts
Entry:
Exit:
Register Usage
*****************************************************************************}
Scan: L ← uPTC, L0←L0.SrcNull, c2;
L ← L + 1, L2←L2.TS0{PRRets}, c3;
Map ← Q ← [rhPC, PDA.count], c1;
PC ← StartPSB, c2;
TT ← rhTT ← MD, uPTC ← L, CALL[PR], c3;
T ← T LRot4, c1, PRr[L2.TS0];
L ← T + StartPSBMinus1Times2, c2;
TSe: uStkDepth ← L, L2←L2.TS2{PRRets}, c3;
Map ← Q ← [rhPC, PC or PSB.timeout],CALL[PRead2], c1;
Q ← T, ZeroBr, c1, PRr[L2.TS2];
[] ← Q xor uPTC, NZeroBr, BRANCH[TSa, TSb], c2;
TSa: Q ← PC + PC, MesaIntBr, BRANCH[TSc, TSd], c3;
{Kick this one}
TSc: MAR ← [rhTT, PC+PSB.timeout], CANCELBR[$, 1] c1;
MDR ← 0, rhT ← rhT.TS{NQRets}, CANCELBR[$,0], c2;
G ← PDAHi, L2←L2.TS1{PFRets}, c3;
MAR ← [rhTT, PC + PSB.flags], c1;
CANCELBR[$,0], c2;
T ← MD, UvQ2Hi ← G, c3;
MAR ← [rhTT, PC + PSB.flags], c1;
MDR ← T and ~PSB.flags.waiting, CANCELBR[$,0], c2;
UvQ2 ← PDA.ready, GOTO[Dequeue], c3;
L ← uStkDepth, c2, NQr[rhT.TS];
TSb: Q ← PC + PC, MesaIntBr, CANCELBR[TSd, 1], c3;
{ScanInt smashes lots of registers...}
TSd: [] ← Q xor uStkDepth, ZeroBr, BRANCH[$, ScanInt{InterruptsDaybreak}], c1;
PC ← PC + PSB.SIZE, BRANCH[TSe, TSf], c2;
TSf: Rx ← uWP, NZeroBr, c3;
G ← PDA.lastCV, BRANCH[$, Interruptx], c1;
Noop, c2;
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, rhPC ← PDAHi, CANCELBR[$,3], c1, QRr[L2.CQ0];
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, PMRr[L2.CQ1];
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, PMRr[L2.CQ2];
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, PMRr[L2.CQ3];
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, QWr[L2.CQ4];
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, XWtOKDisp, c3;
QR: MAR ← [rhTT, G + 0], BRANCH[QRMpFx, QRMpOk, 0D], 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 map.referenced, GOTO[QRx], c2, at[0,4,QRFlgFx];
T ← qWriteProtect, L2←L2.Fault, GOTO[PRestart], c2, at[1,4,QRFlgFx];
MDR ← TT or map.referenced, GOTO[QRx], 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, XWtOKDisp, c3;
QW: MAR ← [rhTT, G + 0], BRANCH[QWMpFx, QWMpOk, 0D], 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 map.rd, GOTO[QWx], c2, at[0,4,QWFlgFx];
T ← qWriteProtect, L2←L2.Fault, GOTO[PRestart], c2, at[1,4,QWFlgFx];
MDR ← TT or map.rd, GOTO[QWx], 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}