:TITLE[Fault]; *Last edited 28 January 1981 by Fiala *Determine what to do based on the type of error and bits in FFault RM 366): * 0: MC2 errors return if 1, crash if 0 * 2: H4PE errors from EITask Return rather than crashing (because of * Ethernet problem delivering H4PE's if a malformed packet arrives) * 3: Midas is present (1), so "crash" means breakpoint after showing * code in MP; otherwise (0) do Goto[.] until booted. * 15: MC1/StackOvf errors handled by notifying PFEntry in emulator (1), * or by crashing (0) SetTask[4]; *Addresses for RM 100-107 when Midas is connected RV4[MapEntry,TaskNumber,RefType,CrashCode,0]; RV4[CardNumber,MapFlags,QuadAddr,Syndrome,4]; SetTask[17]; RV4[PipeReg,PipeReg1,PipeReg2,PipeReg3,60]; *Pipe Ram Entry goes here RV2[PipeReg4,PipeReg5,64]; *NextInst/NextData buffer refill traps at 0; pages with NextInst/NextData. *must field traps at location 377; the emulator trap subroutine then *continues on page 0 due to the LoadPage here. LoadPageExternal[0], GotoExternal[377], At[0]; *Fault entry. Save APC first, then the other volatile regs. **Critical timing: ** To return for Ethernet H4PE's is 55 cycles; ** To task on emulator MOB errors is 59 cycles; ** To task on emulator page faults is 63 or 72 cycles. T _ APCTask&APC, At[1]; *Absolute placement here to overwrite equivalent mi in Kernel or Initial, *which exist in the microstore when this code is loaded. RXAPC _ T, At[100]; T _ (CTask&NCIA) xnor (170000C), At[101]; *Uncomplement CIA RXCTask _ T, At[102]; T _ (SStkP&NStkP) xor (377C), At[103]; *Uncomplement StkP *Set StkP to IP[xBuf] in case stk ovf was pending RXStk _ IP[xBuf]C, At[104]; StkP _ RXStk, RXStk _ T, NoRegILockOK, At[105]; *ALUResult, SALUF both read complemented T _ (ALUResult&SALUF) xnor (0C), At[107]; RXALU _ T, At[110]; *This LoadPage is necessary because after ResetErrors, the Page register will *no longer be disabled by the error condition. T _ Page&Par&Boot, LoadPage[0], At[111]; *page, parity, bootreason RXPPB _ T, ResetErrors, GotoP[.+1], At[112]; LU _ (RXPPB) and (7000C), At[120]; *T _ StkOvf, CSPE, RMPE bits LU _ (RXPPB) and (400C), Goto[BadHWErr,ALU#0]; *Test MC1 or MC2 error StkP _ RXStk, Goto[MC12Err,ALU#0]; *Restore StkP *Probable real breakpoint; avoid calling PNIP if Midas is present because *RM 356/357 will be smashed (357 is RTimer, which will prevent proper storage *refresh), so code sequence is similar to but not the same as that at the *label "Crash" :IF[WithMidas]; ************************************ T _ BrkPCrash; T _ (LdF[RXCTask,0,4]) + T, Goto[BrkP]; :ELSE; ******************************************** T _ BrkPCrash, Goto[CTaskCrash]; :ENDIF; ******************************************** *If CSPE, or RMPE, then indicate RMCSCrash with bit-encoded other errors BadHWErr: LU _ (RXPPB) and (3000C); *Test CS or RM parity error T _ RMCSCrash, Skip[ALU#0]; FFault, T _ StkCrash, DblGoto[MC1Notify0,Crash,R Odd]; *StkOvf only T _ (LdF[RXPPB,4,4]) + T, Goto[Crash]; CTaskCrash: T _ (LdF[RXCTask,0,4]) + T, Goto[Crash]; CTaskNotify: T _ (LdF[RXCTask,0,4]) + T, Goto[MC1Notify0]; *The computation here is CrashCode+PipeTask = CrashCode+(PipeTask' xor 17b) *= CrashCode+(17b-PipeTask') = (CrashCode+17b)-PipeTask'. The value in T *when we get here is CrashCode+17b. PipeTaskCrash: T _ (LdF[PipeReg2,10,4]) - T; T _ (Zero) - T, Goto[Crash]; PipeTaskNotifyCrash: T _ (LdF[PipeReg2,10,4]) - T; T _ (Zero) - T, FFault, Goto[Crash,R Even]; *Notify task 0 at EmNotifyA if emulator was the interrupted task, else at *EmNotifyB. Timing to here from location 1 is 33 cycles on stkovf, *44 on MOB, and 48 or 57 on MC1 error. MC1Notify0: LU _ LdF[RXCTask,0,4]; RTMP _ 202C, Goto[.+3,ALU#0]; RTMP _ 200C; *Emulator task interrupted--notify EmNotifyA MNBR _ RXCTask; *Save emulator TPC for further consideration *Save crash code in SALUF for emulator APCTask&APC _ RTMP; SALUF _ T, Return; *Display maintenance panel code in T. Then, if Midas is present, jump to *the Kernel breakpoint or fault place. Otherwise, do Goto[.] until booted. *Save error code in right half of PipeReg5 Crash: LoadPage[PNIPPage]; *Even placement **Note: because of Lsh 10 below, crash codes must be less than 256d here. PipeReg5 _ (Lsh[PipeReg5,10]) or T, Call[PNIP]; :IF[WithMidas]; ************************************ BrkP: LU _ LdF[FFault,3,1], Call[.+3]; Refresh[REFR]; *Save storage for possible Midas connect later REFR _ (REFR) + (20C), Goto[.-1]; *Point StkP one before MapEntry for sequence of pushes below RTMP _ Or[And[IP[MapEntry],360],And[Sub[IP[MapEntry],1],17]]C, Goto[.-2,ALU=0]; *Reformat saved Pipe into RM 100-107 for Midas. Note that pipe info (other *than crash code and task number) is only interesting on MC2 crashes. LoadPage[MidasPage]; StkP _ RTMP; *Locate on page 16 or 17 with other parts of the Midas Kernel, so that this *code can be overwritten by overlays when Midas isn't present. OnPage[MidasPage]; T _ LdF[PipeReg,11,7]; *map row address PipeReg1 _ (Lsh[PipeReg1,7]) xnor T; *Complement row and column T _ LdF[PipeReg1,2,16], Call[FltPsh]; *MapEntry _ page no. T _ (LdF[PipeReg2,10,4]) xor T, Call[FltPsh]; *TaskNumber T _ (LdF[PipeReg2,14,4]) xor T, Call[FltPsh]; *RefType T _ RHMask[PipeReg5], Call[FltPsh]; *CrashCode *Card no. (0..7) into CardNumber; offset by 5 to get actual board number *in the card cage. NOTE: a value of 14b in Card implies that this part of *the pipe is not filled by the reference. (X xor 7) + 5 = 14b - X T _ 14C; T _ (LdF[PipeReg5,4,3]) - T; T _ (Zero) - T, Call[FltPsh]; *Map Flags (LogSE, WP, Dirty, Ref) into MapFlags T _ (LdF[PipeReg5,0,4]) xor T, Call[FltPsh]; T _ LdF[PipeReg4,12,6]; *Main column address' (6 bits) PipeReg3 _ (Lsh[PipeReg3,6]) or T; *x, x, Blk.1',,main row addr PipeReg5 _ LdF[PipeReg5,7,1]; T _ LdF[PipeReg3,2,16]; PipeReg5 _ (Lsh[PipeReg5,16]) or T; *And Blk.0... *The (15-bit) quadword number within a 128k card. Bits 1:2 give block number. T _ (PipeReg5) xnor (100000C), Call[FltPsh]; *Upright into QuadAddr T _ Rsh[PipeReg,10], Call[FltPsh]; *Interesting syndrome into 107 LU _ LdF[RXPPB,4,4]; *test parity register RTMP _ 177400C, Skip[ALU#0]; *Notify Midas Kernel at 7510b or 7512b RTMP _ (RTMP) or (110C), Skip; *Go overlay 'Break' RTMP _ (RTMP) or (112C); *Go overlay 'MidasFault' RXCTask _ (RXCTask) xnor (170000C); *Recomplement CIA APCTask&APC _ RTMP, Skip; FltPsh: UseCTask, Stack&+1 _ T; T _ 17C, Return; :ELSE; ********************************************* Refresh[REFR]; REFR _ (REFR) + (20C), Goto[.-1]; :ENDIF; ******************************************** OnPage[0]; *Timing is 29 cycles to here starting at the fault trap (location 1) *NOTE: MOB errors are nonsensical for Input and Output references because the *base register is unused; for this reason the MC1/MC2 microcode does not *cause MOB faults for these (RefType = 7 or 11b). However, an MOB error may *appear in the pipe when a fault is caused for some other reason, so an *MOB&H4PE on an Input reference should be treated like an H4PE. MC12Err: ReadPipe[PipeReg]; *Get A pipe (Refresh, Output, and ReadPipe *references don't get assigned pipe slots). Dispatch[PipeReg,4,2]; *Dispatch on H4PE, MapBnd Dispatch[PipeReg,0,2], Disp[.+1]; *Dispatch on MC2ErA', MC2ErB' *test MC1ErA' bit LU _ (PipeReg) and (20000C), Disp[MC2ErAB], DispTable[4,17,0]; *None T _ MOBCrash, FFault, DblGoto[CTaskNotify,CTaskCrash,R Odd]; *MOB LU _ LdF[FFault,2,1], Skip; *H4PE **Ignore improbable legit MOB&H4PE on IOStore4 to flush frequently **occurring fake MOB&H4PE on Input by Ethernet input task. LU _ LdF[FFault,2,1]; *H4PE & MOB *Check for Return to faulted task T _ Add[EITask,0]C, Skip[ALU=0]; ResetMemErrs, Goto[H4PECr]; *This H4PE stuff is needed because of a hardware problem in some Ethernet *controllers that causes H4PE's on Input's and IOStore4's; Ether.Mc has *been kludged to keep control in EITask until an H4PE is impossible *(So that the H4PE will not occur after a LoadPage by another task). LU _ (LdF[RXCTask,0,4]) xor T; ResetMemErrs, Skip[ALU=0]; *Skip for return to Ether Input task H4PECr: T _ H4PECrash, Goto[CTaskCrash]; T17Restore: T _ LdF[RXCTask,4,4], At[204]; *page bits LU _ (LdF[RXPPB,0,4]) xor T; *compare with saved page register T _ RXALU, Skip[ALU=0]; *Result register T _ LPCrash, Goto[CTaskCrash]; *LoadPage error APCTask&APC _ RXCTask; Restore, A _ RXAPC, LU _ T, NoRegILockOK, Return; *back to faulted task *Both MC2 A & B error--crash MC2ErAB:T _ MC22Crash, Goto[Crash], DispTable[4,17,0]; *MC2A & MC2B T _ LHMask[MemSyndrome], Goto[MC2Er]; *MC2A ReadPipe[PipeReg], ResetMemErrs, Goto[MC2ErB1]; *MC2B--read pipe B *No MC2 errors; skip if MC1ErA' = 0 (43 cycles to here) MC1ErAB:ResetMemErrs, Skip[ALU=0]; *Skip if MC1A ReadPipe[PipeReg], ResetMemErrs; *MC1B--read pipe B *MC1 error--notify or crash according to FFault.0 T _ MC1Crash, Goto[PipeTaskNotifyCrash]; MC2ErB1:T _ Lsh[MemSyndrome,10]; MC2Er: PipeReg _ (RHMask[PipeReg]) or T; *Relevant syndrome in LH FFault, ResetMemErrs, Skip[R<0]; *Return if FFault.0 is 1 T _ MC2Crash, Goto[PipeTaskCrash]; *Crash if FFault.0 is 0 **Initialize calls PFExit PFExit: Return; SetTask[0]; NotifyBack: xBuf2 _ (xBuf2) or (170000C); APCTask&APC _ xBuf2, Goto[PFExit]; *Emulator is notified here on an emulator page fault; save emulator's T in *xBuf and TPC in T and task switch. EmNotifyA: UseCTask, xBuf _ T, At[200]; T _ APCTask&APC, Call[PFExit]; *Note that if the emulator was NOT interrupted, then the *fault cannot have come from buffer refill. Since control *entered here, the emulator's PC is in MNBR. xBuf1 _ T, Call[CheckStackTrap]; LU _ LdF[xBuf2,4,4], Goto[CheckBufferRefill]; *Emulator is notified here on non-emulator page fault. EmNotifyB: UseCTask, xBuf _ T, At[202]; T _ APCTask&APC; *Prepare to notify back to task 17, location T17Restore xBuf2 _ 204C, Call[NotifyBack]; *PF handling starts here if non-emulator was interrupted. xBuf1 _ T, Call[CheckStackTrap]; Goto[CheckMemStat]; *cannot be buffer refill trap CheckStackTrap: T _ NStkCrash; *NStkCrash because SALUF read complemented LU _ (SALUF) xor T; T _ MNBR, Goto[StackErrorz,ALU=0]; *Setup to test page bits of emulator's PC xBuf2 _ T, Return; :IF[LispMode]; ******************************** *We have a stack error. Crash; can't happen in Lisp StackErrorz: T _ StkCrash, Goto[Crash]; :ELSE; **************************************** *We have a stack error. Cause the trap immediately. Set StkP back to *beginning of last instruction. Let the PC fall where it may. StackErrorz: *test SStkP for MaxStack+1 or more LU _ (SStkP&NStkP) - (LShift[Add[MaxStack!,1],10]C); T _ SStkP, Skip[Carry']; T _ MaxStack; xBuf2 _ T, LoadPage[opPage3]; StkP _ xBuf2, GotoP[.+1]; OnPage[opPage3]; T _ sStackError, GotoP[kfcr]; :ENDIF; *************************************** %At this point, we have: xBuf emulator's T at the time of the fault; xBuf1 emulator's TPC; xBuf2 CTask,,TPC of the aborted mi. The major problem with faults is to determine the PC to store in the frame, and whether to continue the instruction, or cause the trap immediately. The cases are: 1) The fault was detected at location 0, the 1st mi of the buffer refill trap. In this case, buffer refill was just starting when some previous reference faulted. Treat this as in case 5 below. 2) The fault was detected on page 0 and the emulator's TPC points at the 1st mi of a bytecode (TPC = 01xxxxxxxx01). In this case, it is assumed that the fault is due to a NextData/NextInst buffer refill; SStkP and PCX do not yet reflect advance from the previous bytecode, so the trap is started with PC = 2*PCB - 1 (NextData/NextInst was accessing an operand from location 0 of the buffer, so the opcode is at location 7 of the previous buffer, but PCB was incremented by 8 bytes before the fault was discovered) and with the current value of StkP rather than SStkP. 3) The fault was detected on page 0 and the emulator's TPC points elsewhere than as in case 1. In this case, it is assumed that the fault is due to a NextData or NextInst buffer refill which are differentiated by the low bit of F1 in the mi pointed at by the emulator's TPC. If the fault is due to a NextData, nothing special is done, but if it is due to a NextInst, IBuf is set to -1, PCF to 0, and control is sent to the NextInst so other work done by the mi containing the NextInst and the mi after that can be completed before the trap. Control then goes to opcode 377, which will cause the trap with PC = 2*PCB + PCX - 1. 4) The fault detected on page 6 was due to a PFetch4. This is a jump bytecode buffer refill. We proceed as in case 2 without setting PCF. 5) If none of these situations hold, the PC is (2*PCB) + q, where q = if (PCF>=PCX) then PCX-1 else PCX-9 (if PCF page fault LU _ T, LoadPage[pgLisp0]; StkP _ xBuf2, DblGoto[lspMapFaultPunt,lspMapWritePunt,ALU=0]; :ELSE; **************************************** *TPC = 01xxxxxxxx01, fault was from 1st mi of bytecode CIB1st: PCB _ (PCB) - (4C); PCF _ AllOnes; *PCF _ 7 T _ (SStkP&NStkP) xor (377C), Goto[SMTrpx]; *use current StkP CMSt3: Dispatch[MemStat,15,3], Goto[CMSt1]; CMSt2: Dispatch[MemStat,15,3], Goto[CMSt1]; CMSt0: Dispatch[MemStat,15,3], Goto[CMSt1]; CheckMemStat: Dispatch[MemStat,15,3]; CMSt1: Disp[FixPCOnly]; *The fault was due to an Xfer buffer refill (MemStat[13:15] = XferFixup). *Handle just like a jump. FixXfer: T _ xBuf, Goto[CIB1], At[FixDisp,1]; *The fault occured during the early phases of Xfer. We want to back out and *redo the bytecode, but CODE may have changed and we need it to compute the PC *to save. Fetch G and the overhead, and call LoadC to reload from the *current LOCAL. FixEarlyXfer: PFetch1[LOCAL,GLOBAL,0], At[FixDisp,4]; *Fetch G Call[FP1Ret]; T _ GLOBAL, LoadPage[xfPage1]; PFetch4[MDS,IBuf], Call[LoadC]; *Fetch the global frame overhead xfGFIWord _ T, Goto[FixPCOnly]; FixBLTL: T _ SStkP, At[FixDisp,2]; *Fixup relative to SStkP RTemp _ T; RTemp _ (RTemp) - (4C), Call[FSetStkP]; T _ xBuf, Call[BumpGlorp]; *source + T Stack&+1, Call[FBumpStk]; *count + 1 Stack&+1, Call[BumpGlorp]; *dest + T FPCOz: T _ (PCXReg) - 1, Goto[FPCOx]; *one byte inst cannot have refilled buffer BumpGlorp: Stack _ (Stack) + T; Stack&+1, Skip[Carry']; FBumpStk: Stack _ (Stack) + 1, Return; FP1Ret: Return; FSetStkP: StkP _ RTemp, RTemp _ T, NoRegILockOK, Return; *Prepare for fixup relative to saved StkP FixBlt: T _ (SStkP) - 1, At[FixDisp,3]; *Point StkP at operation, RTemp at count word *Operation (complemented) is low order four bits of Stack *We know the op was either PFetch1 (type = 4) or PStore1 (type = 10b) RTemp _ IP[PipeReg2]C, Call[FSetStkP]; T _ LdF[Stack,15,1]; *we test Stack[13]: 0=> fetch, 1=> store StkP _ RTemp, LU _ T, NoRegILockOK; *point to count, test result to alu *count + 1; now test fetch/store; if fetch, done with fixup Stack _ (Stack) + 1, Goto[FPCOz,ALU=0]; Stack&-1, Call[DecGlorp]; *source - 1 Stack&+2, Call[DecGlorp]; *dest - 1 T _ (PCXReg) - 1, Goto[FPCOx]; DecGlorp: Stack _ (Stack) - 1, Return; FixPCOnly: T _ (PCXReg) - 1, At[FixDisp,0]; *normal PC fixup FPCOx: RTemp _ T, Skip[ALU>=0]; PCB _ (PCB) - (4C); *PCX was 0, inst started in previous quadword LU _ (PCFReg) - T; *test for PCX large, PCF small PCF _ RTemp, Skip[ALU>=0]; *PCF is always PCX-1, only PC is in doubt PCB _ (PCB) - (4C); *Here PCB,PCF is correct PC to save for trap. It will be done through KFCB. StartMemTrap: T _ SStkP; SMTrpx: RTemp _ IP[PipeReg]C, Call[FSetStkP]; *Point StkP to pipe registers MemStat _ Normal; T _ (Stack&+1) and (177C); *low 7 bits of VPage T _ (Lsh[Stack&+1,7]) or T; *high 7 bits of VPage xfOTPReg _ (Zero) or not T; xfOTPReg _ (xfOTPReg) and not (140000C); Stack&+3, Task; *point to flags T _ LdF[Stack,12,1]; *Test Dirty': 0=> page fault StkP _ RTemp, LU _ T, NoRegILockOK; *Restore stkp LoadPage[opPage3], Skip[ALU=0]; T _ sWriteProtect, GotoP[kfcr]; T _ sPageFault, GotoP[kfcr]; :ENDIF; *************************************** :END[Fault];(1795)