{Process.mc, HGM, 4-Nov-84 3:00:50 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 File name: Process.mc Description: Dandelion Process Microcode, Author: Sandman, Created: February 13, 1981 1:12 PM, Johnsson 30-Aug-83 9:03:43 new instruction set Daniels 5-Aug-83 16:04:37 new instruction set Sandman February 24, 1982 add Set Process Priority inst, bum 1 uinst Sandman January 18, 1982 12:30 PM fix ibempty, pccross, interrupt, no switch Sandman 8-Dec-81 20:54:29 Correct PC/Stack fixup on faults Sandman November 17, 1981 10:34 AM New instruction set Sandman March 26, 1981 10:43 AM to fix timing restrictions Sandman March 26, 1981 3:53 PM Change Wait to check condition.abortable } {***************************************************************************** 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, XDirtyDisp, pop, c3; MAR ← [rhRx, T+0], BRANCH[MEa, MEb, 1], 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; 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]}; [] ← PC - 1, PgCrOvDisp, push, 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, L1←L1.Refill, GOTO[PInt], 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: TOS ← STK, pop, BRANCH[PInta, PIntb, 1], c3; PInta: Xbus ← rhRx, XDisp, Q ← 0, L2←L2.Pop0IncrX, c1; PIntc: T ← PC, BRANCH[PIntd, PInte, 7], c2; PIntd: rhTT ← UvChigh, GOTO[RReMap], c3; PInte: Q ← UvC, L1←0, c3; L2←L2.RSSpc, GOTO[StashPCa1], c1; PIntb: TT ← 30, c1; Ybus ← ~ErrnIBnStkp and TT, ZeroBr, c2; TT ← UvPCpage, BRANCH[PIntf, PIntg], c3; PIntf: Xbus ← rhRx, XDisp, Q ← 0, L2←L2.Pop0IncrX, GOTO[PIntc], c1; PIntg: TT ← TT + 0FF + 1, c1; push, GOTO[PInt], 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: MesaIntBr, CANCELBR[LoadProcess,1], c3; PRSd: PC ← uPsbLink and Q, BRANCH[PRSe, BusyWaitb], c3; BusyWaita: Noop, c3; BusyWaitb: T ← pIdle, c1; [] ← uWDC, NZeroBr, c2; IdleLoop: uPFlags ← T, MesaIntBr, BRANCH[$, WakeError], c3; IdleLoopBranch: Rx ← uWP, BRANCH[NoInt, IdleInt {InterruptsDicentra}], c1; NoInt: GOTO[IdleLoop], c2; WakeError: T ← sRescheduleError, 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], 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, push, L2←L2.PSS1, c3; PSSg: Map ← Q ← [rhPC, Q - 1], BRANCH[PSSd, PSSe], c1; PSSd: T ← STK, pop, CALL[PWrite3], c2; G ← G - 1, ZeroBr, GOTO[PSSg], c3, PWr[L2.PSS1]; 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, push, c3; Map ← Q ← [rhPC, PC or PSB.link], push, L2←L2.LP1{PW}, c1; STK ← 0, pop, CALL[PWrite3], c2; 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, CheckTime], 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: 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 *****************************************************************************} CheckTime: TT ← LShift1 uTickCount, XDisp, c2; uTickCount ← TT, BRANCH[Scan, PTail1, 0B], c3; Scan: L ← uPTC, L0←L0.SrcNull, c1; L ← L + 1, c2; uPTC ← L, L2←L2.TS0{PRRets}, c3; Map ← Q ← [rhPC, PDA.count], c1; PC ← StartPSB, CALL[PRead3], c2; 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{InterruptsDicentra}], c1; PC ← PC + PSB.SIZE, BRANCH[TSe, TSf], c2; TSf: uTickCount ← L xor ~L, c3; [] ← uWP, NZeroBr, c1; G ← PDA.lastCV, BRANCH[$, IntDuringScan], c2; GOTO[PTail1], c3; IntDuringScan: GOTO[Interrupt], 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, 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}