:TITLE[Faults.0mc, July 29, 1983 4:39 PM, van Melle]; * Punt cases, going to Bcpl * SubrCall opcode: AC2 = Subr Number, AC3 = Number of Args @SubrCall: nop, opcode[175]; T ← NextData[IBuf]; * Get Subr # AC2 ← T; T ← NextData[IBuf]; * Get Nargs AC3 ← T, loadpage[pgHStack]; callp[ClrHStk]; lspL2 ← SubrArgArea; * Address the subr arg area lspL3 ← (0c); T ← lsh[AC3, 1]; * Nargs*2 lspTsp ← (lspTsp) - T; lspTsp ← (lspTsp) + (2c); * Point tsp at first arg SubrLp: T ← (Form-2[AllOnes]) + T; * T ← T-2 goto[lspSubr1, alu<0]; * (T = 0 for final iteration) PFetch2[lspTsp, lspL0]; * L0,1 ← TOS call[retLBL]; * (alloc constraint keeps out of prev) PStore2[lspL2, lspL0], goto[SubrLp]; * Arg ← L0,1 lspSubr1: T ← PCFreg; PCB ← (lsh[PCB, 1]) + T; T ← lsh[lspIfuBr, 1]; T ← PCB ← (PCB) - T; * PC = 2*(PCB - Fnheader) + PCF lspPC ← T; * prepare to store it T ← lspTsp, loadpage[pgLisp0]; * was addr of first arg = FX:Next lspNext ← T; * this comes after lspIfuBrHi onpage[pgLisp0]; lspEp ← (lspEp) - (12c); * point at FX PStore4[lspEp, lspIfuBr, 2], goto[SubrMkFree]; * Store fnheader, Next, PC :IF[WindFlg]; * ContextSwitch op. TOS = context # (smallp) @ContextSwitch: T ← Stack&-1, loadpage[pgLisp0], opcode[176]; * context # lu ← (Stack&+1) xor (smallpl); * Verify that it is smallp onpage[pgLisp0]; AC2 ← T, skip[alu=0]; * AC2 ← context# lspUfn ← 176c, goto[ufnLBL]; * If we were switching from kbd context, need interrupts back on EnableInterrupts: NWW ← (NWW) and not (100000c), goto[CxS1, R>=0]; FreezeResult, call[CheckInterrupts]; * interrupts were off, may need to set IntPending nop; * Alloc constraint CxS1: AC3 ← 177400c, goto[NoBackup]; * AC3<0 signals contextswitch * While in Lisp, all interrupt bits are in NWW; don't have to worry about WW. CheckInterrupts: T ← (SStkP&NStkP) xor (377c), skip[alu#0]; return; * no interrupts called for lspLN ← IP[RSImage]c; StkP ← lspLN, lspLN ← T, NoRegILockOK; * => RS232 image register T ← Stack ← (Stack) or (IntPendingBit); * OR in the intpending bit StkP ← lspLN, RS232 ← T, return; * restore stkp, stow RS232 :ELSE; lspUFN ← 176c, goto[ufnLBL], opcode[176]; * punt contextswitch :ENDIF; * Assorted punt cases *** NWW Interrupt, between instructions :IF[WindFlg]; onpage[opPage0]; * From Nww opcode (0) NWWPunt: * -2- Fetch --No args, Never FN AC3 ← 0c; loadpage[pgLisp0]; :ELSE; onpage[pgLisp0]; lspNWWInt: AC3 ← 0c; :ENDIF; AC2 ← (LispExitCodex), goto[CheckforBackup]; onpage[pgFrame3]; *** Stack overflow in function call (Context switch) lspSubovPunt: * -1- Frame --Ac1= # of additional words, Always FN AC3 ← 177400c; * => do context switch loadpage[pgLisp0]; AC2 ← SubovFXP, goto[CheckforBackup]; * Ac2 = Context# onpage[pgLisp0]; *** Stack overflow in push, end of instruction (Context switch) StackFullPunt: * -1- Stack --Ac1= # words, Never FN AC3 ← 177400c; AC2 ← SubovFXP, goto[NoBackup]; *** Stats overflow (Checked in Return, at end of inst) :IF[StatsMode]; onpage[pgJump]; StatsPunt: AC3 ← 0c; * No args loadpage[pgLisp0]; AC2 ← (StatsOvflCodex), gotop[NoBackup]; onpage[pgLisp0]; :ENDIF; *** Page Fault, anywhere llspMapFaultPunt: * -3- Lfaults --, Sometime FN * Come here with AC0 = Fault page * Bcpl wants Ac0,1 = virtual addr of read fault T ← 374c, at[MapFaultPuntLoc]; T ← (lsh[Stack, 2]) xor T; * StkP points at PipeReg4 * = main col address in low 6 bits, complemented T ← (ldf[lspGenBr, 16, 2]) or T; * insert a within-quad address from * base reg (may be wrong, but it is right for * Getbase et al and Bcpl fetches, and we can't * do better) AC1 ← T; * AC1 now has within-page address in rh, normal T ← lsh[AC0, 10]; * low half of page AC1 ← (rhmask[AC1]) or T; * AC1 now has low half of fault addr AC0 ← rsh[AC0, 10]; * AC0 has high half Dispatch[lspInstFlag, 14, 4]; StkP ← xBuf2, disp[FaultDisp0]; :IF[FaultFlg]; ***** Fault switch context ****** FaultDisp0: lspDoFault: AC3 ← 177400c, at[FaultDisp, NormalState!]; * Do context switch AC2 ← FaultFXP, call[GetInterfaceBase]; lspGenBr ← (lspGenBr) + (IFPFAULTHI); * Store fault addr in interface page PStore1[lspGenBr, AC0, 0], call[retLBL]; :IF[Debugging]; lu ← (lspEp) - (minFaultPvar); PStore1[lspGenBr, AC1, 1], skip[Carry]; lspL1 ← (FaultInFault), goto[RaidPunt]; NWW ← (NWW) and not (100000c), goto[CheckforBackup, R>=0]; * Are interrupts on? :IF[BreakPoints]; breakpoint; :ELSE; lspL1 ← (FaultWithoutInterrupts), goto[RaidPunt]; :ENDIF; :ELSE; * if not debugging... PStore1[lspGenBr, AC1, 1], goto[CheckforBackup]; :ENDIF; :ELSE; ***** Fault call Bcpl ****** FaultDisp0: lspDoFault: lspL3 ← 0c, at[FaultDisp, NormalState!]; lspL2 ← (subrArgArea), task; * Point at subr arg area AC3 ← 1c; * One arg AC2 ← (PageFaultCodex); PStore1[lspL2, AC0, 0], call[retLBL]; * store fault addr as subr arg PStore1[lspL2, AC1, 1], goto[CheckforBackup]; :ENDIF; StorePuntArgs: lspL0 ← (smallpl); T ← (subrArgArea); PStore2[MDS, lspL0]; * Store subr args AC2 ← (UcodeCheckCodex), return; NoBackup: T ← PCFreg, goto[lspPuntStore]; *** Raid punt, disaster only RaidPunt: * -0- Ucode Check --Arg in L1 = Smallp code AC3 ← 1c, call[StorePuntArgs]; CheckforBackup: T ← (Pcxreg) - 1; * PC at start of inst - 1, so will be redone lu ← (Pcfreg) - T; goto[lspPuntStore, alu>=0]; PCB ← (PCB) - (4c), goto[lspPuntStore]; * If PCF < PCX-1 then buffer refill occurred, so decrement PCB lspPuntStore: PCB ← (lsh[PCB, 1]) + T; T ← lsh[lspIfuBr, 1]; T ← PCB ← (PCB) - T; * PC = 2*(PCB-Fnheader) + PCF lspPC ← T, loadpage[pgHStack]; * prepare it for PStore4 below callp[ClrHStk]; lspEp ← (lspEp) - (12c); * Point at FX PFetch1[lspEp, lspL4, 0]; * L4 ← flagword of current frame lspL0 ← (smallpl); * Note: this is set for SubrInCall branch below, and also * to make sure that L0,1 is a valid pointer in case of * contextswitch to a non-nopush context lu ← lspInstFlag, goto[SubrInCall, R<0]; * In a function call? *** Normal punt, just set No Push bit T ← lspTsp ← (lspTsp) + (2c); * Point at word after end of frame lspNext ← T, call[retLBL]; * Wait for reg to get written PStore4[lspEp, lspIfuBr, 2]; * Store fnheader, Next, PC lspL4 ← (lspL4) or (FxNoPushReturn), goto[SubrStFlags]; * Set no push bit *** Here if we were in function call... :IF[StkDebug]; * Are there 6 words on stack? SubrInCall: T ← (lspTsp) + (6c); ***** temp T ← (lspEsp) - T; ***** temp (should check for wraparound) skip[carry]; ***** temp breakpoint, goto[.]; ***** temp: die if < 6 words on stk :ELSE; SubrInCall: nop; :ENDIF; * Store on stack the number of args, as a smallp, and the function definition * Tsp currently points at TOS PStore2[lspTsp, lspDefx0, 4]; * store fn name T ← lspNargs; * lspL0 already = smallpos lspL1 ← T; PStore2[lspTsp, lspL0, 2], call[retLBL]; * Store Nargs as a smallp lspTsp ← (lspTsp) + (6c); * Next PStore1[lspEp, lspTsp, 4], call[retLBL]; * Store it lspL4 ← (lspL4) or (FxInCall); * Set call in progress SubrStFlags: PStore1[lspEp, lspL4, 0], goto[SubrMkFree]; SubrMkFree: T ← lspTsp; T ← (lspEsp) - T; * Compute # words free after frame lspL3 ← T, goto[SubrStkError, No Carry]; * error if Esp<Tsp lspL2 ← freeStackBlock, Skip[alu=0]; * don't store empty free block PStore2[lspTsp, lspL2, 0]; * make a free block lu ← AC3, goto[CxtSwitch, R<0]; :IF[StatsMode]; lspStatsPtr, goto[SubrStat, R>=0]; :ENDIF; SubrStatDone: ToBcpl: * Store current FX in interface page PCB ← (BcplStartAddress); * allocation constraint call[GetInterfaceBase]; PStore1[lspGenBr, lspEp, 0], gotoExternal[lStartNovaLoc]; CxtSwitch: lspInstFlag ← (NormalState), call[GetInterfaceBase]; T ← AC2; PFetch1[lspGenBr, lspLN], call[retLBL]; * Swap FX with one in Interfacepage loadpage[pgReturn]; PStore1[lspGenBr, lspEp], gotop[lspRtn2]; GetInterfaceBase: * Point GenBr pair at Interface page lspGenBrHi ← (INTERFACEspace); lspGenBr ← (INTERFACEbase), return; :IF[BreakPoints]; SubrStkError: breakpoint, goto[.]; :ELSE; SubrStkError: * turn this into raid punt instead T ← lspEsp; lspL1 ← T, call[StorePuntArgs]; AC3 ← 1c, goto[ToBcpl]; * 1 arg to ucodecheck :ENDIF; :IF[WithMidas]; lStartNova: gotoExternal[lStartNovaLoc]; :ENDIF;