: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=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;