: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:
xBufemulator’s T at the time of the fault;
xBuf1emulator’s TPC;
xBuf2CTask,,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<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. Any special unwinding is indicated by
a value in MemStat[13:15].
%

OnPage[0];

CheckBufferRefill:
T ← 6C, Goto[CameFromPage0,ALU=0];*test for emu page 0 fault
LU ← (LdF[xBuf2,4,4]) xor T;
*Get ready to save StkP
T ← (SStkP&NStkP) xor (377C), Goto[CheckMemStat,ALU#0];

*From page 6. If the operation was PFetch4, this is a jump buffer refill
IBuf3 ← IP[PipeReg2]C;*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,ResumeByteCode,ALU#0];


CameFromPage0:
LU ← xBuf2;*test for aborted CTask,,CIA = 0 ***Why?***
*set up to test for TPC = 01xxxxxxxx01 (= 2001b + 4*n).
xBuf1 ← Lcy[xBuf1,6], Goto[CMSt3,ALU=0];*xBuf1 ← 101 + Lcy[n,10b]
T ← 101C;*High 2 and low 2 bits of addr, task 0 in middle
LU ← (RHMask[xBuf1]) xor T;
*Branch if trap occurred on the 1st mi of a bytecode.
T ← Rcy[xBuf1,6], Goto[CIB1st,ALU=0];*T ← restored TPC
*No--some other mi; distinguish NextData from NextInst by testing
*the low order bit of the F1 field.
CBR1:
xBuf2 ← T, Task;*xBuf2 now contains emulator TPC instead of
*aborted mi’s TPC
T ← 0C;*Does TPC point to a NextInst?
APCTask&APC ← xBuf2;
ReadCS;
*Branch on probable NextData; fall through on probable NextInst
***NOTE: Perhaps we should verify that this is really a PFetch4 being
***done here before restricting the faults on page 0 to be only those for
***buffer refill. This could be accomplished by putting the PFetch4 check
***now after the on-page-6 check before both the from-page-0 and from-page-6
***checks.
CSData, Goto[CMSt0,R Odd];**Even placement not needed here
PCF ← RMZero;*(Possibly unnecessary, but would have to
*replace this mi with a Nop if removed)
*Jump here on PFetch4 from Page 6, i.e. JumpCity. We continue the jump after
*filling IBuf with -1’s and eventually get to opcode 377.
ResumeByteCode:
T ← xBuf;*Restore T; even placement

***Since the PCF← for the jump opcodes is the 3rd mi after the PFetch4 and
***the PCF← for buffer refill is the 1st mi after the PFetch4, PCF might be
***correct here always, in which case it would be safe to do PCF[IBuf] ←
***(Zero) - 1 below, ignoring other words in IBuf. However, it might be
***possible for data transport to intervene between the PFetch4 and the PCF←,
***so didn’t make the change below--should think through this.

CIB1:
IBuf ← (Zero) - 1;*force bytecode 377 and return to the NextInst
IBuf1 ← (Zero) - 1, Task;
IBuf2 ← (Zero) - 1;
APCTask&APC ← xBuf2;*xBuf2 points to place to resume the bytecode
IBuf3 ← (Zero) - 1, Return;

:IF[LispMode]; ********************************

*TPC = 01xxxxxxxx01, fault was from NextData at 1st mi of bytecode
CIB1st:
BreakPoint;

CMSt3:
Goto[MemFault];*Non page 0 or 6 fault
CMSt2:
Goto[MemFault];*Regular fault on page 6
CMSt0:
Goto[MemFault];*NextData fault, not 1st mi of bytecode
CheckMemStat:
Goto[MemFault];*Non-emu fault or non-page 0 or 6 fault

FPCOx:
Goto[MemFault];*Regular fault on page 0


RV[lspGenBr,50];
Set[pgLisp0,10];

MemFault:
T ← SStkP;
SMTrpx:
xBuf2 ← IP[PipeReg]C, Task;*Point StkP to pipe registers
StkP ← xBuf2, xBuf2 ← T, NoRegILockOK;
T ← (Stack&+1) and (177C);*Low 7 bits of VPage
T ← (Lsh[Stack&+1,7]) xnor T;*High 7 bits of VPage and complement
AC0 ← T;
T ← AC0 ← (AC0) and not (140000C);
AC1 ← T;
Stack&+2, Task;
T ← (Stack&+1) or not (77C);
AC1 ← (Lsh[AC1,6]) or not T;
T ← (lspGenBr) and (3C);
AC1 ← (Lsh[AC1,2]) or T;
AC0 ← Rsh[AC0,10];
T ← LdF[Stack,12,1];*Test Dirty’:0 => 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];