: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<PCX, then the buffer was
*refilled between the NextInst and the fault, and PC has been advanced
*by 8 bytes). In the normal case, the trap is started using this PC, and
*it is not necessary to unwind the instruction. If any special unwinding
*is necessary,it is indicated by a value in MemStat[13:15].
CheckBufferRefill:
T ← 6c, goto[CameFromPage0,ALU=0]; *test for emulator page 0 fault
lu ← (ldf[xBuf2,4,4]) xor (T);
T ← (GETRSPEC[103]) xor (377c), goto[CheckMemStat,ALU#0]; *get ready to save stackpointer
*We came from page 6. If the operation was PFetch4, this is a jump buffer refill
IBuf3 ← pPipeReg2; *IBuf3 is a guaranteed free temporary
Stkp ← IBuf3, IBuf3 ← T, Task, NoRegILockOK; *now pointing at the operation
T ← 11c; *not 6 (PFetch4)
lu ← (ldf[Stack,14,4]) xor (T);
Stkp ← IBuf3, dblgoto[CMSt2,ContinueInterruptedBytecode,ALU#0];
*We have a PFetch4 from Page 6, i.e. JumpCity. We continue the jump after filling IBuf with -1’s,
*and eventually get to opcode 377.
CameFromPage0:
xBuf1 ← lcy[xBuf1,6]; *set up to test for TPC = 01xxxxxxxx01.
lu ← xBuf2;* test for aborted pc = 0
T ← 101c, goto[FPCOy, alu = 0];* high 2 and low 2 bits or addr, task 0 in middle
lu ← (rhmask[xBuf1]) xor (T);
goto[CBR1, ALU#0], T ← rcy[xBuf1,6]; * put TPC back
PC ← (PC) -(4c); *TPC = 01xxxxxxxx01, fault was from first instruction of bytecode
PCF ← AllOnes; * PCF ← 7
T ← (GetRSpec[103]) xor (377c), goto[SMTrpx]; * use current Stkp
CBR1:xBuf2 ← T;* xBuf2 now contains TPC instead of aborted PC
T ← 0c; *Does TPC point to a NextInst?
APC&APCTask ← xBuf2;
ReadCS;
CSDATA, goto[CMSt0,Rodd];
PCF ← RZERO; *PCF ← 0
ContinueInterruptedBytecode:T ← xBuf; *xBuf2 points to place to resume the bytecode
CIB1:IBuf ← (Zero)-1, task;*force bytecode 377
IBuf1 ← (Zero)-1;
IBuf2 ← (Zero)-1;
IBuf3 ← (Zero)-1;
APC&APCTask ← xBuf2, goto[PFExit1];*Return to the NextInst
CMSt2:Dispatch[MemStat,15,3], goto[CMSt1];
CMSt0:Dispatch[MemStat,15,3], goto[CMSt1];
CheckMemStat:Dispatch[MemStat,15,3];
CMSt1:Disp[FixPCOnly];
FixXfer:T ← xBuf, goto[CIB1],AT[FixDisp,1];
FixEarlyXfer:PFetch1[LOCAL,GLOBAL,0],AT[FixDisp,4]; *Fetch G
T ← GLOBAL, task;
PFetch4[MDS,IBUF]; *Fetch the global frame overhead
LoadPage[xfPage1];
call[LoadC];
xfGfiWord ← T;
FPCOy:T ← (PCXReg) - 1, goto[FPCOx];
FixBLTL:T ← SStkp,AT[FixDisp,2];* prepare for fixup relative to saved stkp
RTEMP ← (T), task;
RTEMP ← (RTEMP) - (4c);
Stkp ← RTEMP;
T ← xBuf,Call[BumpGlorp];* source + T
Stack&+1, Call[FBumpStk];* count + 1
Stack&+1, Call[BumpGlorp];* dest + T
T ← (PCXReg) - 1, goto[FPCOx];* one byte inst cannot have refilled buffer
BumpGlorp:Stack ← (Stack) + T;
Stack&+1,skip[NoCarry];
FBumpStk:
Stack ← (Stack) + 1, Return;
PFExit1:
Return;
FSetStkP:
StkP ← RTemp, RTemp ← T, NoRegILockOK, Return;
FixBlt:T ← (SStkp) - 1, AT[FixDisp,3];* prepare for fixup relative to saved stkp
RTEMP ← pPipeReg2, Call[FSetStkP]; *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)
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
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];