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