TITLE[MesaP--Pilot.or.Alto.Mode]; * 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 ONPAGE[opPage0]; *ME @ME: GOTO[CheckLong1], PRFlags ← (MEFlags), opcode[1]; * Monitor Lock *MRE @MRE: GOTO[CheckLong2], PRFlags ← (MREFlags), opcode[2]; * CV, Lock *MXW @MXW: PRFlags ← (MXWFlags) , opcode[3]; * Time, CV, Lock MXWx: T ← Stack&-1; GOTO[CheckLong2], Process ← T; *MXD @MXD: GOTO[CheckLong1], PRFlags ← (MXDFlags), opcode[4]; * Monitor Lock *NOTIFY @NOTIFY: GOTO[CheckLong1], PRFlags ← (NOTIFYFlags), opcode[5]; * CV *BCAST @BCAST: GOTO[CheckLong1], PRFlags ← (BCASTFlags), opcode[6]; * CV *REQUEUE @REQUEUE: PRFlags ← (REQFlags), goto[MXWx], opcode[7]; * Process, Q1, Q2 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, goto[FixQueue1]; FixQueue2: T ← Queue2hi ← (lsh[Queue2hi,10]) + (T) + 1; Queue2hi ← (fixVA[Queue2hi]) or (T); T ← Stack&-1; Queue2 ← T, return; FixQueue1: 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), goto[ProcessOps]; ProcessOps: LoadPage[prPage]; Dispatch[PRFlags, 11, 4], gotop[ProcessDispatch]; OnPage[prPage]; ProcessDispatch: 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, goto[MELocked, R >= 0]; MQ ← (MQ) AND NOT (LockBit), call[MQToQueue1]; MRENoAbort: Stack&+1 ← 1C; * even location PrTail: LoadPage[opPage0]; goto[P4Tail]; MELocked: PFetch1[PBase, Process], goto[MREnterFailed]; ************************************************************************* * 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 ← Queue1; Queue2 ← T, TASK; T ← Queue1hi; Queue2hi ← T; 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]; T ← PRFlags, 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 ← APC&APCTask, call[Queue1ToMQ]; EMLink ← T; T ← MQ ← (MQ) AND NOT (LockBit); goto[EMUnlock, alu = 0]; PFetch1[PBase, Process], call[ReadyInQueue2]; UseCTask, call[RequeueSub]; call[Queue1ToMQ]; * Requeue may have changed MQ goto[EMUnlock]; EMUnlock: MQ ← (MQ) OR (LockBit); PStore1[Queue1, MQ, 0], call[PRRet]; APC&APCTask ← 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[MXWAbort, alu # 0]; PFetch1[QTemp, MQ, 0]; call[PRRet]; MQ ← (MQ) AND NOT (WWBit), goto[MXWOntoCV, R >= 0]; PStore1[QTemp, MQ, 0], call[PRRet]; T ← PRFlags, goto[ReSchedule]; MXWOntoCV: lu ← PRTime; RTemp1 ← (RTemp1) OR (WaitingOnCV), goto[MXWHaveTime, alu = 0]; T ← (TimeLocation), call[PBaseToCurrentTime]; 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), call[PRTimeToPBase]; T ← PRFlags, goto[ReSchedule]; MXWAbort: T ← PRFlags, 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: PRTime ← (Zero), call[Queue1ToMQ]; MQ ← T ← (MQ) AND NOT (WWBit); lu ← LDF[PRFlags, 16, 1], goto[WHExit, alu = 0]; T ← MQ, call[PBaseToProcess]; PRTime ← (1c), call[ReadyInQueue2]; T ← (Process) + (FlagsOffset), call[PBaseToRTemp1]; RTemp1 ← (RTemp1) AND NOT (WaitingOnCV), call[RTemp1ToPBase]; UseCTask, call[RequeueSub]; lu ← PRFlags, goto[WHLoopx, R odd]; lu ← LDF[PRFlags, 16, 1], goto[WHExit]; WHLoopx: goto[WHLoop]; WHExit: T ← PRFlags, goto[ReSchedule, alu = 0]; lu ← PRTime, dblgoto[SetWWBit, NakedNotified, R even]; SetWWBit: MQ ← (WWBit), call[MQToQueue1]; * even location NakedNotified: IntLevel ← (IntLevel) + 1, LoadPage[OpPage0]; * odd location 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 * RTemp2 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]; T ← PRFlags, goto[ReSchedule]; RequeueSub: T ← APC&APCTask; RLink ← T; T ← Process, call[PBaseToRTemp]; lu ← (RTemp) - (T); lu ← Queue1hi, goto[RQGotPP, alu = 0]; * only one process goto[RQLoop1, alu = 0]; * Queue1 NIL, T = Process PFetch1[Queue1, Prev, 0], call[PRRet]; T ← Prev, goto[RQLoop1x]; RQLoop1: Prev ← T; 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), goto[RQHaveQ1, alu # 0]; PStore1[PBase, RTemp]; call[PRRet]; goto[RQInsrt]; RQGotPP: T ← Prev ← (Zero), goto[RQFixCV]; RQHaveQ1: PFetch1[Queue1, RTemp1, 0]; T ← Process, call[PRRet]; lu ← (RTemp1) - (T); goto[RQInsrt, alu # 0]; PStore1[Queue1, Prev, 0]; call[PRRet]; goto[RQInsrt]; 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]; RTemp ← (RTemp) AND (Priority); T ← (RTemp1) AND (Priority); lu ← (RTemp) - T - 1; T ← Prev, goto[RQFixQ2, alu < 0]; goto[RQLoop2]; RQLoop2: Prev ← T, call[PBaseToRTemp1]; T ← (RTemp1) + (FlagsOffset), call[PBaseToRTemp2]; T ← (RTemp2) AND (Priority); lu ← (RTemp) - T - 1; T ← RTemp1, dblgoto[RQInsrtHere, RQLoop2, alu >= 0]; RQFixQ2: PStore1[Queue2, Process, 0], call[PRRet]; RQInsrtHere: T ← Prev; call[PBaseToRTemp1]; T ← Process, call[RTemp1ToPBase]; T ← Prev, call[ProcessToPBase]; RQRet: T ← (Process) + (TimeOffset), call[ZeroToPBase]; APC&APCTask ← RLink; PRFlags ← (PRFlags) OR (RequeueOccured), return; RQNilPP: T ← Process; call[ProcessToPBase]; PStore1[Queue2, Process, 0], goto[RQRet]; ************************************************************************* * 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 ← APC&APCTask; 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), goto[CURetx, alu=0]; RTemp ← T, goto[CUEmpty, alu = 0]; CULoop: T ← (RTemp) + (CleanUpOffset), call[PBaseToRTemp1]; * get head of queue lu ← T ← RTemp1; lu ← (RTemp) - (T), goto[CUFoundHead, alu=0]; goto[CUEmptyx, alu = 0]; RTemp ← T, goto[CULoop]; CUEmpty: RTemp ← (Zero), goto[CUFixCV]; CUEmptyx: RTemp ← (Zero), goto[CUFixCV]; CUFoundHead: T ← MNBR ← RTemp; CULoop2: RTemp ← T, call[PBaseToRTemp1]; T ← RTemp1; lu ← (MNBR) - (T); goto[CULoop2, alu # 0]; nop; CUFixCV: call[RTempToCQueue]; CURet: APC&APCTask ← RLink, goto[PRRet]; CURetx: APC&APCTask ← RLink, goto[PRRet]; CQueueToRTemp: lu ← PRFlags, DBLGoto[Queue1ToRTemp, Queue2ToRTemp, R >= 0]; RTempToCQueue: lu ← PRFlags, DBLGoto[RTempToQueue1, RTempToQueue2, R >= 0]; ************************************************************************* * ReSchedule; * * Input * T contains PRFlags * * 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: goto[PrTail, NoH2Bit8]; nop; IntReSch: T ← (CurrentState), call[PBaseToRTemp]; LoadPage[OpPage3]; callp[SavePCInFrame]; T ← RTemp, LoadPage[xfPage1]; xfTemp ← T, UseCTask, callp[SaveState]; T ← (CurrentPSB), call[PBaseToRTemp1]; * RTemp1 ← currentPSB T ← (RTemp1) + (FrameOffset), call[LocalToPBase]; IdleIntRS: T ← (ReadyQ); call[PBaseToRTemp1]; lu ← T ← RTemp1; lu ← xfWDC, goto[NoneReady, alu = 0]; call[PBaseToProcess]; * Process ← readylist.link * setup for new process T ← (Process) + (FlagsOffset), call[PBaseToRTemp1]; RTemp ← (xfAV); T ← (RTemp) + (FirstStateVector), call[PBaseToRTemp]; MNBR ← RTemp1, TASK; RTemp1 ← T ← (RTemp1) AND (Priority); RTemp1 ← (LSH[RTemp1, 2]) + (T); T ← (LSH[RTemp1, 1]) + (T), TASK; RTemp ← (RTemp) + (T); T ← MNBR, goto[NoEnterFailed, R >= 0]; RTemp1 ← T; RTemp1 ← (RTemp1) AND NOT (EnterFailed); 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); call[PBaseToRTemp1]; 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 ← pRSImage; *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]; xfTemp ← T; PCF ← xfTemp; NoBackup: T ← NWW; *Check (NWW#0 & xfWDC=0) lu ← xfWDC, skip[ALU#0]; return; skip[ALU=0]; return; *We are going to cause the interrupt PFetch4[LOCAL,LocalCache0,4]; *refill cache in case the interrupt came from BitBlt PRFlags ← 0c; NWW ← (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]; PBaseToRTemp2: PFetch1[PBase, RTemp2], return; Queue1ToRTemp: PFetch1[Queue1,RTemp,0], return; RTempToQueue1: PStore1[Queue1,RTemp,0], return; Queue2ToRTemp: PFetch1[Queue2,RTemp,0], return; RTempToQueue2: PStore1[Queue2,RTemp,0], return; Queue1ToMQ: PFetch1[Queue1,MQ,0], goto[PRRet]; MQToQueue1: PStore1[Queue1,MQ,0], goto[PRRet]; PRTimeToPBase: PStore1[PBase, PRTime], return; ZeroToPBase: PStore1[PBase, RZero], return; LocalToPBase: PStore1[PBase, Local], return; PBaseToCurrentTime: PFetch1[PBase, CurrentTime], 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 * ************************************************************************* * Interrupt Processing onpage[OpPage0]; Interrupt: WW ← (WW) AND NOT (TimerBit), goto[TimerInterrupt, alu # 0]; IntLevel ← (CVBase); CheckCV: call[ThisCV]; ThisCV: 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), goto[DoNothing, alu = 0]; *T ← ReadyQueuehi Queue1hi ← T, LoadPage[prPage]; PRFlags ← (PRFlags) OR (NakedNotifyFlags), goto[WakeHead]; DoNothing: IntLevel ← (IntLevel) + 1, goto[CheckCV]; IntDone: LoadPage[prPage]; * load page for done lu ← IntType, dblgotop[IntReSch, IdleIntRS, R odd]; TimerInterrupt: TickCount ← (TickCount) - 1; IntLevel ← (CVBase), skip[alu = 0]; goto[CheckCV]; 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[CanTimeout, alu # 0]; CheckEnd: T ← Process ← (Process) + (SizePSB); lu ← (ITemp1) - (T); TickCount ← (3c), goto[TLoop, alu >= 0]; goto[CheckCV]; CanTimeout: goto[TimeOut, alu = 0]; goto[CheckEnd]; Timeout: Queue2 ← (ReadyQ); Queue1Hi ← (Zero); T ← (MDShi) or (1c); LoadPage[prPage]; *Make Queue2 the ReadyQueue Queue2Hi ← T, UseCTask, call[RequeueSub]; T ← (Process) + (FlagsOffset), call[IntPBaseToQueue1]; Queue1 ← (Queue1) AND NOT (WaitingOnCV); PStore1[PBase, Queue1], call[P4Ret]; goto[CheckEnd]; IntPBaseToProcess: PFetch1[PBase, Process], goto[P4Ret]; IntPBaseToQueue1: PFetch1[PBase, Queue1], goto[P4Ret]; IntPBaseToCurrentTime: PFetch1[PBase, CurrentTime], goto[P4Ret]; IntCurrentTimeToPBase: PStore1[PBase, CurrentTime], goto[P4Ret]; :END[MesaP];