:TITLE[MesaP--Alto.mode.only]; *Last edited: 19 January 1981 by Fiala *Process Microcode; *PSB format MC[CleanUpOffset,1]; MC[TimeOffset,2]; MC[FlagsOffset,3]; MC[FrameOffset,4]; MC[Priority,7]; MC[WaitingOnCV,10]; MC[AbortPending,40]; MC[TimeoutAllowed,100]; MC[EnterFailed,100000]; MC[SizePSB,5]; *Monitor Lock format MC[LockBit,100000]; *Condition Variable format MC[WWBit,100000]; *Constants MC[CleanQueue1,0]; MC[CleanQueue2,1]; MC[NegInfinity,100000]; MC[CVBase,40]; MC[TimerBit,20]; MC[TimeLocation,344]; *Dispatch bas address Set[ProcessDisp,LShift[prPage,10]]; %PRFlags holds opcode dispatch values and general flags. Its interpretation is: bit 0 0 => Clean Queue 1 1 => Clean Queue 2 bit 10 0 => Requeue not done 1 => Requeue done bits 16,17 0 => Notify 1 => Broadcast 2 => Naked Notify 3 => not used bits 12-15 Opcode Dispatch All flag constants except NakedNotifyFlags are cycled right 1 in order to set bit 0 if necessary. % *Flag values MC[MEFlags, 0]; * Dispatch to 0 SET[MEloc, 0]; MC[MREFlags, 21]; * Dispatch to 2, Clean Queue 2 SET[MREloc, 2]; MC[MXWFlags, 51]; * Dispatch to 5, Clean Queue 2 SET[MXWloc, 5]; MC[MXDFlags, 61]; * Dispatch to 6, Clean Queue 2 SET[MXDloc, 6]; MC[NOTIFYFlags, 100]; * Dispatch to 10, Clean Queue 1, Notify MC[BCASTFlags, 102]; * Dispatch to 10, Clean Queue 1, Broadcast SET[WakeHeadloc, 10]; MC[REQFlags, 130]; * Dispatch to 13 SET[REQloc, 13]; MC[NakedNotifyFlags, 2]; * Clean Queue 1, Naked Notify, not cycled MC[RequeueOccured, 200]; *Requeue occured, not cycled @ME: PRFlags _ MEFlags, Goto[CheckLong1], Opcode[1]; *Monitor Lock @MRE: PRFlags _ MREFlags, Goto[CheckLong2], Opcode[2]; *CV, Lock @MXW: PRFlags _ MXWFlags, Opcode[3]; *Time, CV, Lock MXWx: T _ Stack&-1; Process _ T, Goto[CheckLong2]; @MXD: PRFlags _ MXDFlags, Goto[CheckLong1], Opcode[4]; *Monitor Lock @NOTIFY: PRFlags _ NOTIFYFlags, Goto[CheckLong1], Opcode[5]; *CV @BCAST: PRFlags _ BCASTFlags, Goto[CheckLong1], Opcode[6]; *CV @REQUEUE: PRFlags _ REQFlags, Goto[MXWx], Opcode[7]; *Process, Q1, Q2 ***Should use MDShi literally here rather than fixing it up in a way that ***makes the LH and RH .ne.; also should start with LH[MDShi] if going to ***do the fixup as shown. FixQueue2: T _ Queue2hi _ (Lsh[Queue2hi,10]) + T + 1; Queue2hi _ (FixVA[Queue2hi]) or T; T _ Stack&-1; TtoQueue2: Queue2 _ T, Return; CheckLong2: T _ 373C; *StkP value for two long pointer operands (4). T _ (NStkP) xor T; *Check for stack size of 4. T _ RHMask[MDShi], DblGoto[Short2,Long2,ALU#0]; CheckLong1: T _ 375C; *StkP value for one long pointer operand (2). T _ (NStkP) xor T; *Check for stack size of 2. T _ RHMask[MDShi], DblGoto[Short1,Long1,ALU#0]; Short2: Queue2hi _ T, Call[FixQueue2]; T _ RHMask[MDShi], Goto[Short1]; Long2: T _ Stack&-1; Queue2hi _ T, Call[FixQueue2]; T _ Stack&-1, Goto[Short1]; Long1: T _ Stack&-1; Short1: Queue1Hi _ T; T _ Stack&-1, Task; Queue1 _ T; LU _ (Queue1hi) or T; T _ Queue1hi, Skip[ALU=0]; T _ Queue1hi _ (Lsh[Queue1hi,10]) + T + 1; Queue1hi _ (FixVA[Queue1hi]) or T; LoadPage[prPage]; *Process dispatch Dispatch[PRFlags,11,4], GotoP[.+1]; OnPage[prPage]; PRFlags _ Rcy[PRFlags,1], Disp[MEnter]; ************************************************************************* * Monitor Enter; * * Input * Queue1 Base register pointing at monitor queue * * Temps * MQ process handle * * Constants * CurrentPSB 21B, address of CurrentPSB * LockBit 100000B, lock bit of Monitor Lock * ************************************************************************* MEnter: T _ CurrentPSB, Call[Queue1ToMQ], At[ProcessDisp,MEloc]; LU _ MQ, Skip[R<0]; PFetch1[PBase,Process], Goto[MREnterFailed]; *Locked MQ _ (MQ) and not (LockBit), Call[MQToQueue1]; MRENoAbort: Stack&+1 _ 1C; * even location PrTail: LoadPage[opPage0]; Goto[P4Tail]; ************************************************************************* * Monitor ReEnter; * * Input * Queue1 Base register pointing at monitor queue * Queue2 Base register pointing at condition queue * * Temps * PBase Base register of PSBs * Process process handle * RTemp1 temp * * Constants * LockBit 100000B, lock bit of Monitor Lock * CleanUpOffset 1, offset of cleanup link in PSB * FlagsOffset 3, offset of flags and priority in PSB * CurrentPSB 21B, address of CurrentPSB * sProcessTrap 17B, offset of sProcessTrap in SD * ************************************************************************* MREnter: T _ CurrentPSB, Call[Queue1ToMQ], At[ProcessDisp, MREloc]; Call[PBaseToProcess]; LU _ MQ, Goto[MREnterFailed,R>=0]; * ignore ww bit UseCTask, Call[CleanUpQueue]; * Clean up Queue1 MQ _ (MQ) and not (LockBit), Call[MQToQueue1]; T _ (Process) + (CleanUpOffset), Call[ZeroToPBase]; T _ (Process) + (FlagsOffset), Call[PBaseToRTemp1]; LU _ (RTemp1) and (AbortPending); Goto[MRENoAbort,ALU=0]; T _ sProcessTrap; PRTrap: LoadPage[opPage3]; GotoP[kfcr]; MREnterFailed: T _ Queue1hi; Queue2hi _ T, LoadPage[opPage0]; T _ Queue1, Call[TtoQueue2]; T _ (MDShi) or (1C), Call[ReadyInQueue1]; T _ (Process) + (FlagsOffset), Call[PBaseToRTemp1]; RTemp1 _ (RTemp1) or (EnterFailed), Call[RTemp1ToPBase]; Goto[RequeueOp]; ************************************************************************* * Monitor Exit and Depart; * * Input * Queue1 Base register pointing at monitor queue * ************************************************************************* MXDepart: UseCTask, Call[ExitMon], At[ProcessDisp, MXDloc]; LU _ (PRFlags) and (200C), Goto[ReSchedule]; ************************************************************************* * Exit Monitor; * * Input * Queue1 Base register pointing at monitor queue * * Temps * PBase Base register of PSBs * MQ process handle * Process process handle * EMLink Return link * * Constants * LockBit 100000B, lock bit of Monitor Lock * ************************************************************************* ExitMon: T _ APCTask&APC, Call[Queue1ToMQ]; EMLink _ T; T _ MQ _ (MQ) and not (LockBit); Goto[EMUnlock,ALU=0]; PFetch1[PBase, Process], Call[ReadyInQueue2]; UseCTask, Call[RequeueSub]; PFetch1[Queue1,MQ,0]; EMUnlock: MQ _ (MQ) or (LockBit); PStore1[Queue1,MQ,0]; APCTask&APC _ EMLink, Goto[PRRet]; ************************************************************************* * Monitor Exit and Wait; * * Input * Queue2 Base register pointing at condition queue * Queue1 Base register pointing at monitor queue * Process Timeout value * * Temps * PBase Base register of PSBs * MQ process handle * PRTime holds timeout value * RTemp1 process handle * * Constants * WWBit 100000B, ww bit of Condition * LockBit 100000B, lock bit of Monitor Lock * CleanUpOffset 1, offset of cleanup link in PSB * TimeOffset 2, offset of flags and priority in PSB * FlagsOffset 3, offset of flags and priority in PSB * WaitingOnCV 10B, WaitingOnCV bit of PSB * AbortPending 40B, AbortPending bit of PSB * TimeoutAllowed 100B, TimeoutAllowed bit of PSB * CurrentPSB 21B, address of CurrentPSB * TimeLocation 344B, address of Timeout time in Memory * ************************************************************************* MXWait: T _ Process, At[ProcessDisp,MXWloc]; PRTime _ T, UseCTask, Call[CleanUpQueue]; T _ QTemp, Call[SwapQTempAndQ2]; UseCTask, Call[ExitMon]; T _ CurrentPSB, Call[PBaseToProcess]; T _ (Process) + (FlagsOffset), Call[PBaseToRTemp1]; LU _ (RTemp1) and (AbortPending); Goto[MXWReSched,ALU#0]; PFetch1[QTemp,MQ,0]; MQ _ (MQ) and not (WWBit), Goto[MXWOntoCV,R>=0]; PStore1[QTemp,MQ,0], Call[PRRet]; LU _ (PRFlags) and (200C), Goto[ReSchedule]; MXWOntoCV: LU _ PRTime; RTemp1 _ (RTemp1) or (WaitingOnCV), Goto[MXWHaveTime,ALU=0]; T _ TimeLocation; PFetch1[PBase,CurrentTime]; T _ CurrentTime; PRTime _ (PRTime) + T; Goto[MXWHaveTimex,ALU#0]; PRTime _ (PRTime) + 1; MXWHaveTime: nop; MXWHaveTimex: T _ (MDShi) or (1C), Call[ReadyInQueue1]; T _ QTemp, Call[SwapQTempAndQ2]; T _ (Process) + (FlagsOffset), Call[RTemp1ToPBase]; UseCTask, Call[RequeueSub]; T _ (Process) + (TimeOffset); PStore1[PBase,PRTime]; MXWReSched: LU _ (PRFlags) and (200C), Goto[ReSchedule]; SwapQTempAndQ2: MNBR _ Queue2, Queue2 _ T, NoRegILockOK; T _ MNBR; QTemp _ T; T _ QTemphi; MNBR _ Queue2hi, Queue2hi _ T, NoRegILockOK; T _ MNBR; QTemphi _ T, Return; ************************************************************************* * Notify Broadcast; * * Input * Queue1 Base register of queue to be notified * * Temps * PBase Base register of PSBs * MQ process handle * RTemp1 process handle * Process process handle * PRTime Did something * PRFlags flags * * Constants * WWBit 100000B, ww bit of Condition * NegInfinity 100000B * FlagsOffset 3, offset of cleanup link in PSB * WaitingOnCV 10B, WaitingOnCV bit in PSB * ************************************************************************* WakeHead: UseCTask, Call[CleanUpQueue], At[ProcessDisp,WakeHeadloc]; WHLoop: Call[Queue1ToMQ]; MQ _ T _ (MQ) and not (WWBit); PRTime _ Zero, Skip[ALU#0]; LU _ LdF[PRFlags,16,1], Goto[WHExit]; PFetch1[PBase,Process], Call[ReadyInQueue2]; T _ (Process) + (FlagsOffset), Call[PBaseToRTemp1]; RTemp1 _ (RTemp1) and not (WaitingOnCV), Call[RTemp1ToPBase]; PRTime _ (PRTime) + 1, UseCTask, Call[RequeueSub]; LU _ LdF[PRFlags,16,1], Skip[R Even]; Goto[WHLoop]; WHExit: LU _ (PRFlags) and (200C), Goto[ReSchedule,ALU=0]; LU _ PRTime, Skip[R Odd]; MQ _ WWBit, Call[MQToQueue1]; IntLevel _ (IntLevel) + 1, LoadPage[opPage0]; Goto[CheckCV]; ************************************************************************* * Requeue; * * calling instruction must include UseCTask * * Input * Queue1 Base register pointing at queue * Queue2 Base register pointing at queue * Process process handle * * Output * ReSched BOOLEAN * * Temps * PBase Base register of PSBs * Prev process handle * RTemp Process.link until insert, then Process.priority * RTemp1 process handle, priority * MQ process handle, priority * RLink Return address * * Constants * CleanUpOffset 1, offset of cleanup link in PSB * FlagsOffset 3, offset of flags and priority in PSB * Priority 7, priority bits * RequeueOccured 200B * ************************************************************************* RequeueOp: UseCTask, Call[RequeueSub], At[ProcessDisp,REQloc]; LU _ (PRFlags) and (200C), Goto[ReSchedule]; RequeueSub: T _ APCTask&APC; RLink _ T; T _ Process, Call[PBaseToRTemp]; LU _ (RTemp) - T; LU _ Queue1hi, Skip[ALU#0]; *only one process Prev _ Zero, Goto[RQFixCV]; Prev _ T, Skip[ALU=0]; *Queue1 NIL, T = Process PFetch1[Queue1,Prev,0]; T _ Prev; RQLoop1x: Prev _ T, Call[PBaseToRTemp1]; T _ RTemp1; LU _ (Process) - T; Goto[RQLoop1x,ALU#0]; T _ Prev; Call[RTempToPBase]; *RTemp has Process.link RQFixCV:LU _ Queue1hi; T _ (Process) + (CleanUpOffset), Skip[ALU#0]; PStore1[PBase,RTemp], Goto[RQInsrt]; RQHaveQ1: PFetch1[Queue1,RTemp1,0]; T _ Process, Call[PRRet]; LU _ (RTemp1) - T; Skip[ALU#0]; PStore1[Queue1,Prev,0], Call[PRRet]; RQInsrt:PFetch1[Queue2,Prev,0], Call[PRRet]; LU _ Prev; T _ Process, Goto[RQNilPP,ALU=0]; T _ (Process) + (FlagsOffset), Call[PBaseToRTemp]; T _ (Prev) + (FlagsOffset), Call[PBaseToRTemp1]; T _ LdF[RTemp,15,3]; *priority LU _ (LdF[RTemp1,15,3]) - T, Call[RQLp2S]; RQLoop2:T _ (RTemp1) + (FlagsOffset); PFetch1[PBase,MQ]; T _ LdF[RTemp,15,3]; LU _ (LdF[MQ,15,3]) - T; T _ RTemp1, Skip[ALU<0]; Prev _ T, Goto[PBaseToRTemp1]; RQInsrtHere: T _ Process, Call[RTemp1ToPBase]; T _ Prev, Call[ProcessToPBase]; RQRet: T _ (Process) + (TimeOffset), Call[ZeroToPBase]; APCTask&APC _ RLink; PRFlags _ (PRFlags) or (RequeueOccured), Return; RQNilPP:PStore1[PBase,Process]; PStore1[Queue2,Process,0], Goto[RQRet]; RQLp2S: T _ Prev, Goto[PBaseToRTemp1,ALU<0]; PFetch1[PBase,RTemp1]; PStore1[Queue2,Process,0], Goto[RQinsrtHere]; ************************************************************************* * CleanUpQueue; * this routine cleans up a queue which may possibly * have been left in a mess by Requeue. * * calling instruction must include UseCTask * * Input * PRFlags even => clean Queue1, odd => clean Queue2 * * Temps * PBase Base register of PSBs * RTemp process handle * RTemp1 process handle * MNBR process handle * RLink Return address * * Constants * WWBit 100000B, ww bit of Condition * CleanUpOffset 1, offset of cleanup link in PSB * ************************************************************************* CleanUpQueue: T _ APCTask&APC; RLink _ T, Call[CQueueToRTemp]; * get pointer to tail RTemp _ (RTemp) and not (WWBit); * ignore ww bit T _ (RTemp) + (CleanUpOffset), Goto[CURet,ALU=0]; PFetch1[PBase,RTemp1], Call[PRRet]; * get head of queue LU _ T _ RTemp1; LU _ (RTemp) - T, Skip[ALU#0]; APCTask&APC _ RLink, Goto[PRRet]; RTemp _ T, Skip[ALU#0]; CUEmpty: RTemp _ Zero, Goto[CUFixCV]; CULoop: T _ (RTemp) + (CleanUpOffset), Call[PBaseToRTemp1]; *get head of queue LU _ T _ RTemp1; LU _ (RTemp) - T, Skip[ALU=0]; RTemp _ T, DblGoto[CUEmpty,CULoop,ALU=0]; T _ MNBR _ RTemp; CULoop2: RTemp _ T, Call[PBaseToRTemp1]; T _ RTemp1; LU _ (MNBR) - T; CUFixCV:LU _ PRFlags, Goto[CULoop2,ALU#0]; APCTask&APC _ RLink, Skip[ALU<0]; PStore1[Queue1,RTemp,0], Return; PStore1[Queue2,RTemp,0], Return; CURet: APCTask&APC _ RLink, Goto[PRRet]; CQueueToRTemp: LU _ PRFlags, Skip[R<0]; PFetch1[Queue1,RTemp,0], Return; PFetch1[Queue2,RTemp,0], Return; ************************************************************************* * ReSchedule; * * Input * lu (PRFlags) and (200C) * * Temps * PBase Base register of PSBs * RTemp process handle * RTemp1 process handle * MNBR process handle * RLink Return address * * Constants * EnterFailed 100000B, EnterFailed bit of PSB * CleanUpOffset 1, offset of cleanup link in PSB * FlagsOffset 3, offset of priority and flags in PSB * FrameOffset 4, offset of frame in PSB * CleanUpOffset 1, offset of cleanup link in PSB * Priority 7, priority bits in PSB * StkPOffset 10B, offset of stack pointer in state vector * DestOffset 11B, offset of dest in state vector * CurrentPSB 21B, Current process * ReadyQ 22B, Ready queue * CurrentState 23B, Current state * ************************************************************************* ReSchedule: T _ CurrentState, Goto[PrTail,ALU=0]; Nop; IntReSch: LoadPage[opPage3]; PFetch1[PBase,xfTemp], CallP[SavePCInFrame]; LoadPage[xfPage1]; UseCTask, CallP[SaveState]; T _ CurrentPSB, Call[PBaseToRTemp1]; *RTemp1 _ currentPSB T _ (RTemp1) + (FrameOffset); PStore1[PBase,LOCAL]; IdleIntRS: T _ ReadyQ; PFetch1[PBase,RTemp1], Call[PRRet]; LU _ T _ RTemp1; LU _ xfWDC, Goto[NoneReady,ALU=0]; PFetch1[PBase,Process]; *Process _ readylist.link *Setup for new process T _ (Process) + (FlagsOffset), Call[PBaseToRTemp1]; RTemp _ xfAV; T _ (RTemp) + (FirstStateVector), Call[PBaseToRTemp]; T _ LdF[RTemp1,15,3], Task; *Priority xfTemp _ T; xfTemp _ (Lsh[xfTemp,2]) + T; T _ (Lsh[xfTemp,1]) + T; *13b*priority RTemp _ (RTemp) + T; RTemp1 _ (RTemp1) and not (EnterFailed), Goto[NoEnterFailed,R>=0]; T _ (Process) + (FlagsOffset), Call[RTemp1ToPBase]; T _ RTemp, Call[ZeroToPBase]; * stack[0] _ 0; RTemp1 _ 1C; * stkp _ 1 T _ (RTemp) + (StkPOffset), Call[RTemp1ToPBase]; NoEnterFailed: T _ (Process) + (FrameOffset); PFetch1[PBase,RTemp1]; T _ (RTemp) + (DestOffset), Call[RTemp1ToPBase]; T _ CurrentPSB, Call[ProcessToPBase]; * currentPSB _ process T _ CurrentState, Call[RTempToPBase]; T _ RTemp, LoadPage[xfPage1]; xfTemp _ T, GotoP[LoadStateNF]; NoneReady: T _ sWakeupError, Goto[PRTrap,ALU#0]; IntType _ T _ Zero; *PC backup amount, StkP value for MIPend Call[IdleLoop]; IdleLoop: Goto[MIPend,IntPending]; PRRet: Return; *Get here with StkP in T (0 if from IdleLoop), PC backup amount in IntType. MIPend: RTemp1 _ IP[RSImage]C; *Clear IntPending StkP _ RTemp1, RTemp1 _ T, NoRegILockOK; T _ Stack _ (Stack) and not (IntPendingBit); StkP _ RTemp1, RS232 _ T; T _ IntType; *back up the PC T _ (PCFreg) - T, Goto[NoBackup,ALU=0]; *When PCF is 10b, BitBlt has done PC_PC+4, PCF_0, so PCF-1 can be negative; *In this situation we have to do PC_PC-4 and PCF_7. The code below also *allows MIPend to be called by opcodes longer than 1 byte (CSUM). RTemp1 _ T, Goto[BackNoOvf,ALU>=0]; PCB _ (PCB) - (4C); PFetch4[PCB,IBuf,0]; BackNoOvf: PCF _ RTemp1; NoBackup: LU _ xfWDC; *Check (NWW#0 & xfWDC=0) T _ NWW, Skip[ALU=0]; Return; NWW _ Zero, Skip[ALU#0]; NWW _ T, Return; :IF[CacheLocals]; ************************** *We are going to cause the interrupt; refill cache in case BitBlt interrupt PFetch4[LOCAL,LocalCache0,4], Task; ***Should task here when CacheLocals=0*** :ENDIF; ************************************ PRFlags _ Zero; WW _ T, LoadPage[opPage0]; *Promote NWW into WW LU _ LdF[WW,13,1], Goto[Interrupt]; PBaseToProcess: PFetch1[PBase,Process], Return; ProcessToPBase: PStore1[PBase,Process], Return; PBaseToRTemp: PFetch1[PBase,RTemp], Return; RTempToPBase: PStore1[PBase,RTemp], Return; PBaseToRTemp1: PFetch1[PBase,RTemp1], Goto[PRRet]; RTemp1ToPBase: PStore1[PBase,RTemp1], Goto[PRRet]; Queue1ToMQ: PFetch1[Queue1,MQ,0], Goto[PRRet]; MQToQueue1: PStore1[Queue1,MQ,0], Goto[PRRet]; ZeroToPBase: PStore1[PBase,RMZero], Return; ReadyInQueue1: Queue1hi _ T; Queue1 _ ReadyQ, Return; ReadyInQueue2: T _ (MDShi) or (1c); Queue2hi _ T; Queue2 _ ReadyQ, Return; ************************************************************************* * Interrupt Processing; * * Input * WW Wakeups Waiting register * TickCount number of ticks until scaning PSBs required * CurrentTime current time * * Temps * IntLevel pointer to CV array elements * IntType even => idle loop interrupt * ITemp temp * ITemp1 temp * * Constants * WWBit 100000B, ww bit of Condition * TimeOffset 2, offset of time in PSB * FlagsOffset 3, offset of flags and priority in PSB * WaitingOnCV 10B, WaitingOnCV bit of PSB * NakedNotifyFlags * ************************************************************************* OnPage[opPage0]; Interrupt: WW _ (WW) and not (TimerBit), Goto[TimerInterrupt,ALU#0]; IntLevel _ CVBase; CheckCV:Call[.+1]; WW _ Rsh[WW,1], Goto[IntThisCV,R Odd]; Goto[IntDone,ALU=0]; *load page for done IntLevel _ (IntLevel) + 1, Return; IntThisCV: T _ IntLevel, Call[IntPBaseToQueue1]; LU _ Queue1; T _ (MDShi) or (1C), Skip[ALU#0]; *T _ ReadyQueuehi IntLevel _ (IntLevel) + 1, Goto[CheckCV]; Queue1hi _ T, LoadPage[prPage]; PRFlags _ (PRFlags) or (NakedNotifyFlags), Goto[WakeHead]; IntDone: LU _ IntType, LoadPage[prPage]; *Load page for done T _ CurrentState, DblGotoP[IntReSch,IdleIntRS,ALU#0]; TimerInterrupt: TickCount _ (TickCount) - 1; IntLevel _ CVBase, Goto[CheckCV,ALU#0]; ITemp _ xfAV; T _ ITemp _ (ITemp) + (FirstProcess), Call[IntPBaseToProcess]; T _ (ITemp) + 1; PFetch1[PBase,ITemp1]; T _ TimeLocation, Call[IntPBaseToCurrentTime]; CurrentTime _ (CurrentTime) + 1, Call[IntCurrentTimeToPBase]; Nop; TLoop: T _ (Process) + (TimeOffset); *Can't have call before this PFetch1[PBase,ITemp], Call[P4Ret]; LU _ T _ ITemp; LU _ (CurrentTime) - T, Goto[CheckEnd,ALU=0]; T _ (MDShi) or (1C), Skip[ALU=0]; Goto[CheckEnd]; *Timeout Queue2 _ ReadyQ; Queue1Hi _ Zero; Queue2Hi _ T, LoadPage[prPage]; *Make Queue2 the ReadyQueue UseCTask, Call[RequeueSub]; T _ (Process) + (FlagsOffset), Call[IntPBaseToQueue1]; Queue1 _ (Queue1) and not (WaitingOnCV); PStore1[PBase,Queue1]; CheckEnd: T _ Process _ (Process) + (SizePSB); LU _ (ITemp1) - T; TickCount _ 3C, Goto[TLoop,ALU>=0]; Goto[CheckCV]; IntPBaseToProcess: PFetch1[PBase,Process], Goto[P4Ret]; IntPBaseToQueue1: PFetch1[PBase,Queue1], Goto[P4Ret]; IntPBaseToCurrentTime: PFetch1[PBase,CurrentTime], Goto[P4Ret]; IntCurrentTimeToPBase: PStore1[PBase,CurrentTime], Goto[P4Ret]; P4Ret: Return; :END[MesaP];