:TITLE[Fault]; *Fault handler *Error Codes for Fault Handler MC[RCSCrash,200]; *R or CS parity error MC[BPCrash,201]; *Real Breakpoint MC[MOBCrash,202]; *Map Out of Bounds MC[H4PECrash,203]; *H4PE MC[MOB&H4PECrash,204]; *MOB and H4PE MC[MC2Crash, 205]; *MC2 error when unable to handle it by RETURNing MC[MC22Crash,206]; *2 MC2 errors MC[MC1Crash,207]; *MC1 fault when emulator couldn't accept it MC[LPCrash,210]; *Fault from the instruction following a LoadPage MC[StkCrash,211]; *Stack over/underflow MC[NStkCrash,166]; *Not Stack over/underflow (8 bits) *Fault handler *Determine what to do based on the type of error and bits in FFAULT RM 366). *Bits in FFAULT are: * 0: MC2 errors RETURN if 1, crash if 0 * 2: H4PE errors from task 7 return to the task that faulted rather * than crashing (because of Ethernet problem of delivering H4PE's * if a malformed packet arrives) * 3: Midas is present (1), so "crash" means breakpoint, else put a * code in MP and halt. * 15: MC1/StackOvf errors handled by notifying PFEntry in emulator (1), * or by crashing (0) *The following code (nearly a copy of the page 0 code in Kernel) sends *control to FaultStart after saving state, and FaultStart figures out whether *Midas is present and whether to send a breakpoint or a fault message. OnPage[0]; SetTask[17]; RV[PipeReg,60]; *Pipe Ram Entry goes here MC[pPipeReg,360]; MC[pPipeReg2,362]; RV[PipeReg1,61]; RV[PipeReg2,62]; RV[PipeReg3,63]; RV[PipeReg4,64]; RV[PipeReg5,65]; *Page Zero stuff *We put the instruction for BufferRefill here.. x377x: gotop[x377x], at[377]; *dummy instruction loadpage[0], goto[x377x], at[0]; *Emulator buffer refill code is on page 0 T _ APCTASK&APC, AT[1]; *Fault entry. Save APC first, then the other volatile regs. RXAPC _ T, AT[100]; T _ GETRSPEC[147], AT[101]; *ctask, ncia RXCTASK _ T, AT[102]; T _ (GETRSPEC[103]) xor (377c), AT[103]; *sstkp, stkp (stkp is read complemented) RXSTK _ T, AT[104]; RTMP _ 20c, AT[105]; *Set stkp to 20 in case there was a stack overflow pending Stkp _ RTMP, AT[106]; T _ (GETRSPEC[107]) xnor (0c), AT[107]; *aluresult, saluf (both read complemented) RXALU _ T, AT[110]; T _ GETRSPEC[157], LOADPAGE[0], AT[111]; *page, parity, bootreason RXPPB _ T, RESETERRORS,goto[FaultStart], AT[112]; FaultStart: lu _ (RXPPB) and (3000c), at[120]; *test R & CS parity goto[RCSErr, ALU#0], lu _ (RXPPB) and (400c); *test memory error goto[MC12Err, ALU#0], lu _ (RXPPB) and (4000c); *test stack ovf goto[TryBP, ALU=0]; StkEr: FFAULT, dblgoto[MC1NotifyEmulator, Crash,RODD], T _ StkCrash; *can emulator take fault? RCSErr: T _ RCSCrash, goto[Crash]; TryBP: T _ BPCrash, goto[Crash]; *Get here with error code in T. If Midas is present, breakpoint. Otherwise, put *the code into the maintenance panel and halt. Crash: lu _ ldf[FFAULT,3,1]; goto[Midas,ALU#0],PipeReg5 _ (lsh[PipeReg5,10]) or (T); *save error code in right half of PipeReg5 nop; call[PNIP]; goto[.]; Midas: RTMP _ 117c; *Reformat saved Pipe into RM 100-105 for Midas. Note that pipe info (other *than crash code and task number) is only interesting if CrashCode=205 Stkp _ RTMP; SetTask[4]; *To allow symbolic names for RM 100-106 RV[MapEntryNumber,0]; RV[TaskNumber,1]; RV[RefType,2]; RV[CrashCode,3]; RV[CardNumber,4]; RV[MapFlags,5]; RV[QuadAddr,6]; RV[Syndrome,7]; SetTask[17]; T _ ldf[PipeReg,11,7]; *map row address PipeReg1 _ (lsh[PipeReg1,7]) or T; *Map location (page number) in bits 2-17b... *goes into location 100 (but the bits are inverted) T _ ldf[PipeReg1,2,16], Call[FltPsh]; Stack _ (Stack) xnor (140000c); *now contains the virtual page number T _ 17c; *task number (upright)... T _ (ldf[PipeReg2,10,4]) xor T, Call[FltPsh]; *into location 101 T _ 17c; *reference type (upright)... T _ (ldf[PipeReg2,14,4]) xor T, Call[FltPsh]; *into location 102 T _ rhmask[PipeReg5], Call[FltPsh]; *Crash code into 103 T _ 7c; T _ (ldf[PipeReg5,4,3]) xor T, Call[FltPsh]; *Card no. (0..7) into 104 T _ 17c; T _ (ldf[PipeReg5,0,4]) xor T, Call[FltPsh]; *Map Flags (4 bits) into 105 T _ ldf[PipeReg4,12,6]; *Main column address (6 bits) T _ (lsh[PipeReg3,6]) or T; *And Blk.1,,main row address T _ (lsh[PipeReg5,16]) or T; *And Blk.0... *This is the (15-bit) quadword number within a 128k card. *Bits 1 and 2 give the block number. T _ (zero) xnor T, Call[FltPsh]; *All upright into 106 T _ rsh[PipeReg,10], Call[FltPsh]; *The interesting syndrome into 107 lu _ ldf[RXPPB,4,4]; * test parity register RTMP _ 177400c, skip[alu#0]; *Notify Midas at 7510b or 7512b RTMP _ (RTMP) OR (110C), goto[MidasNotify]; *Go overlay 'Break' RTMP _ (RTMP) OR (112C); *Go overlay 'MidasFault' MidasNotify: APCTask&APC _ RTMP, goto[PNret]; FltPsh: UseCTask, Stack&+1 _ T, Goto[PNret]; MC12Err: Stkp _ RXSTK; * not stack error, restore pointer ReadPipe[PipeReg]; *get A pipe Dispatch[PipeReg,4,2]; *dispatch on H4pe, MapBnd Dispatch[PipeReg,0,2], Disp[NoH4BndEr]; *dispatch on MC2ErA', MC2ErB' NoH4BndEr: Disp[MC2ErAB], lu _ (PipeReg) and (20000c), AT[H4disp,0]; *test MC1ErA' bit BndEr: T _ MOBCrash, goto[Crash], AT[H4disp,1]; *MOB error only H4Er: RTMP _ H4PECrash, AT[H4disp,2]; H4Er1: lu _ ldf[FFAULT,2,1]; *Check for return to faulted task Stkp _ RXSTK, skip[ALU=0]; T _ RTMP, goto[Crash]; *check for faulted task = 7 (Ether Input) T _ 7c; *Ether Input task number lu _ (ldf[RXCTASK,0,4]) xor (T); skip[ALU#0]; ResetMemErrs, goto[T17Restore]; *back to faulted task T _ RTMP, goto[Crash]; *Note: the following is not quite correct, since a REAL MOB error will be continued *if it occurs with an H4PE. Life is hard... H4BndEr: RTMP _ MOB&H4PECrash, goto[H4Er1], AT[H4Disp,3]; *H4PE & MOB MC2ErAB: T _ MC22Crash, goto[Crash], AT[MC2ErDisp,0]; *Have both MC2 A & B error - crash MC2ErA: T _ lhmask[MemSyndrome], goto[MC2Er], AT[MC2ErDisp,1]; *MC2A error MC2ErB: ReadPipe[PipeReg], ResetMemErrs, AT[MC2ErDisp,2]; *MC2B error - read pipe entry T _ lsh[MemSyndrome,10], goto[MC2Er]; NoMC2Er: Goto[MC1Er,ALU=0], ResetMemErrs, AT[MC2ErDisp,3]; *Branch if MC1ErA' = 0 ReadPipe[PipeReg], ResetMemErrs; *MC1B error - read pipe entry MC1Er: FFAULT, dblgoto[MC1NotifyEmulator,Crash,RODD], T _ MC1Crash; *can emulator take fault? MC2Er: ResetMemErrs; lu _ ldf[FFAULT,0,1]; *check for return (1) or crash (0) goto[MC2ErRet,ALU#0], PipeReg _ (rhmask[PipeReg]) or (T); *Stash the proper syndrome in **PipeReg[0:7] T _ MC2Crash, goto[Crash]; MC2ErRet: return; *Notify emulator at EmNotifyA if emulator was the interrupted task, else at EmNotifyB MC1NotifyEmulator: lu _ ldf[RXCTask,0,4]; RTMP _ 202c, goto[MC1NEx,ALU#0]; RTMP _ 200c; *emulator task interrupted - notify EmNotifyA MNBR _ RXCTask; *save the emulator's PC for further consideration MC1NEx: APC&APCTask _ RTMP; SALUF _ T, return; *save the crash code in saluf, so that the emulator can use it T17Restore: RXCTask _ (RXCTask) xnor (170000c), AT[204]; *complement CIA T _ ldf[RXCTask,4,4]; *page bits lu _ (ldf[RXPPB,0,4]) xor (T); *compare with saved page register goto[LoadPageError,ALU#0], T _ RXALU; *result register APC&APCTask _ RXCTask; Restore, A _ RXAPC, lu _ T, NoRegILockOK, Return; *back to faulted task LoadPageError: T _ LPCrash, goto[Crash]; SetTask[0]; NotifyBack: RTEMP _ (RTEMP) or (170000C); APC&APCTask _ RTEMP, goto[PFExit]; PFExit: return; EmNotifyA: usectask, xBuf _ T, AT[200]; *save the emulator's T in xBuf T _ APC&APCTask, call[PFExit]; *save emulator's TPC in T, and task switch * PF handling starts here if the emulator was interrupted. * 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 (complemented) is in MNBR. PFEntryA: xBuf1 _ T, loadpage[FaultPage1]; gotop[PFEntryAx]; EmNotifyB: usectask, xBuf _ T, AT[202]; T _ APC&APCTask; RTEMP _ 204c, call[NotifyBack]; *Prepare to notify back to task 17, location T17Restore * PF handling starts here if non-emulator was interrupted. PFEntryB: xBuf1 _ T, loadpage[FaultPage1]; gotop[PFEntryBx]; OnPage[FaultPage1]; PFEntryAx: T _ NStkCrash, Call[CheckStackTrap]; lu _ ldf[xBuf2,4,4], goto[CheckBufferRefill]; PFEntryBx: T _ NStkCrash, Call[CheckStackTrap]; goto[CMSt1], Dispatch[MemStat,15,3]; *cannot be buffer refill trap CheckStackTrap: lu _ (SALUF) xor (T); T _ MNBR, goto[StackErrorz, ALU=0]; *set up to test page bits of emulator's PC xBuf2 _ (ZERO) xnor (T); *complement value xBuf2 _ (xBuf2) and not (170000c), return; *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: lu _ (GetRSpec[103])-(lshift[11,10]c); *test SStkp for 9 or more T _ SStkp, skip[nocarry]; RTEMP _ 10c, goto[.+2]; RTEMP _ T; Stkp _ RTEMP; loadpage[7]; T _ sStackError, gotop[kfcr]; *At this point, xBuf contains the emulator's T at the time of the fault, *xBuf1 contains the emulator's TPC, and xBuf2 contains the PC of the *aborted instruction. 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 caused by a NextInst (PC is on page 0, TPC points to *a NextInst). We set IBUF to -1, PCF to 0, and send control back to *the NextInst. This will cause the faulted instruction to be completed, *and control will go to opcode 377, which will cause the trap with *PC = 2*PC + PCX -1. *2) The fault was due to a NextData in the first microinstruction of *a bytecode (TPC = 01xxxxxxxx01). The trap is started immediately, with *PC = 2*PC - 1 (The NextData was trying to get an operand from location *0 of the buffer, so the opcode is at location 7 of the previous buffer, *but PC was incremented by 8 bytes before the fault was discovered). *3) The fault was detected on page 6 and was due to a Pfetch4. This is *a jump instruction buffer refill. We proceed as in case 1 without *setting PCF. *4) The fault was due to an Xfer buffer refill (MemStat[13:15] = *XferFixup). This is handled just like a jump. *5) The fault occured during the early phases of Xfer. We want to back *out and redo the instruction, 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. *If none of these situations hold, the PC is (PC*2) + q, where q = if *(PCF>=PCX) then PCX-1 else PCX-9 (if PCF fetch, 1=> store Stkp _ RTEMP, lu _ T, NoRegILockOK; * point to count, test result to alu Stack _ (Stack) + 1, skip[alu#0]; * count + 1; now test fetch/store T _ (PCXReg) - 1, goto[FPCOx]; * fetch; done with fixup 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]; PC _ (PC) - (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 PC _ (PC) - (4c); *Here PC,PCF is correct pc to save for trap. It will be done through KFCB. StartMemTrap: T _ SStkp; SMTrpx: RTEMP _ pPipeReg, 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 skip[ALU=0], LoadPage[7]; T _ sWriteProtect, gotop[kfcr]; T _ sPageFault, gotop[kfcr]; :END[Fault];(1795)