:Title[LFaults];
*
* Edit History
* February 2, 1984 5:40 PM, JonL, set RBase before uCodeCheck at Fault0
* January 4, 1984 7:48 PM, JonL, CHECKPCXSUBR and FIXLEFT from LSTACK;
*
Let .intsoff in LispReschedule Call[FIXLEFT]; added more comments
* December 6, 1982 1:28 PM, Masinter

%
Lisp fault handler.

If the fault was an emulator map fault or a stack error, and the
emulator running at the time was Lisp, then calls the appropriate
trap procedure.

For any other fault, halts at one of the following breakpoints:

(In fault task, not having reset FaultInfo)
ManyFaultsMore than one fault
NotEmuFaultFault in non-emulator task
NotMapFaultMemory system fault other than map fault
UnknownFaultFault of unknown origin

(In emulator task, having reset FaultInfo)
AEmuStackErrorStack error from Alto emulator
AEmuMapFaultMap fault from Alto emulator

(In emulator task, the fault task never having been awakened)
LispIFUMapFaultMap fault caused by IFU reference
LispIFUFGParityFG parity error
LispIFURamPEIFU decoding Ram parity error
BogusIFUMapFaultIFU gave a map fault, but the page referenced
by PCX is not vacant and shouldn’t
have faulted.

In the case of faults passed to the emulator task, interesting information is left in R-registers, as follows:

FltErrorsNOT (Errors’)
FaultInfoNOT (Pipe2’)
FltEmuPCEmulator TPC at time of fault
FaultValDBuf -- value being stored if faulted on Store←

%

*-----------------------------------------------------------
* Fault Task
*-----------------------------------------------------------

Set[XTask, IP[FLT]];

SUBROUTINE;
FLTInitPC:
T← FLT, CoReturn;
TOPLEVEL;

T← A0, RBase← RBase[FaultInfo];
TIOA← T, Block;

FaultTask:
FltErrors← NOT (Errors’);* Read this always
FaultInfo← NOT (Pipe2’);* Doesn’t clear FaultInfo

* Test for memory system fault
T← (FaultInfo) AND (fi.numfaults);
PD← T XOR (fi.numFaults);* See if we have all bits set;
T← Pointers, Branch[CheckStackErr, ALU=0];* All ones => no fault

* Memory system fault, see what kind
PD← (FaultInfo) AND (fi.numFaults);* All zeroes => one fault
PD← (FaultInfo) AND (fi.emuFault), Branch[ManyFaults, ALU#0];
PD← (FltErrors) AND (pipe4.notMapTrouble),
Branch[NotEmuFault, ALU=0];
Branch[NotMapFault, ALU#0];

* Emulator map fault. Clear it and pass fault to emulator.
B← FaultInfo’, Branch[EmuFault];

* Not memory system fault, check for stack overflow or underflow
CheckStackErr:
PD← T AND (300c);* 200 = stack overflow, 100 = stack underflow
Branch[UnknownFault, ALU=0];

* Emulator map fault or stack error.
* Save emulator’s state and restart emulator at Fault0.

EmuFault:
FaultVal← DBuf;
RdTPC← EMU;
FltEmuPC← NOT (Link);* TPC data is complemented
Call[GetEmuFaultPC];
LdTPC← T;
Block, Branch[FaultTask];

* Fault conditions that we can’t handle:
ManyFaults:
Branch[.], Breakpoint;* More than 1 fault
NotEmuFault:
Branch[.], Breakpoint;* Not Emulator fault
NotMapFault:
Branch[.], Breakpoint;* Not map fault
UnknownFault:
Branch[.], Breakpoint;* Don’t know what fault occurred

*--------------------------------------------------------------------
* Emulator Task
* The emulator is restarted here by the fault task after an emulator
* map fault or stack error.
*-----------------------------------------------------------

Set[XTask, IP[EMU]];

SUBROUTINE;
GetEmuFaultPC:
* "Called" only because there is no way to know
T← EMU, CoReturn;* the u-address of Fault0 at assembly time
TOPLEVEL;

Fault0:
RBase← RBase[FltPipe0],
Call[RestoreALUFM];* If interrupted from BITBLT ?
PD← (FaultInfo) AND (fi.numFaults);* Which kind of fault?
Branch[.faultluz, alu#0], FaultMapVal← NOT (Map’);
T← VAHi;
T← FltPipe0← T AND (7777C);* Only want low bits
FltPipe1← Q← VALo;
FaultMapVal← not (Pipe4’);* Ref bits in pipe
FltTemp← NOT (IFUMLH’);* Which emulator was running?
PD← (FltTemp) AND (14000C);* Test InsSet (Alto=0)
branch[.+2, alu=0], rbase← rbase[spAC0];
branch[PAGEFAULTPUNT];
* Page fault from alto emulator: continue in next instruction
* with faulting address in AC0, 1
StkP← spAC0;
Stack&+1 ← T;
Stack&-1 ← Q, branch[EmuNext];

.faultluz:
RBase← RBase[LTEMP0];
uCodeCheck[HWStackError];

*--------------------------------------------------------------------
* IFU traps from lisp emulator
*--------------------------------------------------------------------


Set[LispTrapBase, Sub[300, LShift[LispInsSet, 6]]];
DontKnowRBase;
TOPLEVEL;

*--------------------------------------------------------------------
IFuNotReady:
IFUJump[0], at[LispTrapBase, 34];
*--------------------------------------------------------------------
LispIFUFGparity:
Branch[.], Breakpoint,at[LispTrapBase, 4];
*--------------------------------------------------------------------
LispIFURamPE:
Branch[.], Breakpoint,at[LispTrapBase, 74];
*--------------------------------------------------------------------


*--------------------------------------------------------------------
LispIFUMapFault:
*--------------------------------------------------------------------
MemBase← ifuBR,at[LispTrapBase, 0];
CHECKPCX;
PAGEFAULTOK;
T← not (PCX’);
T← T rsh 1;* PCX/2 = word address in code
T← (FETCH← T) + 1;
* segment addressed by ifuBR
T← MD, FETCH← T;
T← MD;
* Wait for fault to occur
BogusIFUMapFault:
Branch[.], Breakpoint;


:if[Debugging];
*--------------------------------------------------------------------
SUBROUTINE;
CHECKPCXSUBR:
*--------------------------------------------------------------------
pd← (PSTATE) and (PS.PCXBAD);
branch[.+2, alu#0];
return;
PSTATE← Link;
TOP LEVEL;
UCodeCheck[PuntInCall];
:endif;


*--------------------------------------------------------------------
LispReschedule:at[LispTrapBase, 14];
*--------------------------------------------------------------------
* cf AEmuReschedule in Start.mc
rbase← rbase[NWW];
PD← NWW;
branch[.+2, ALU>0];
NoReschedule, branch[.intsoff];
NWW← (NWW) and not (BcplKeyMask);* Always turn off BCPL bit. If
pd← (NWW) and not (LispKeyMask);* other bits on, do old NWW punt
branch[.checkWW, alu#0], pd← NWW;* If LispInterrupt on, do KeyPunt
NoReschedule, dblbranch[KEYPUNT, .intsoff, alu#0];

.checkWW:
MemBase← MDS;
T← (R400)+(52C);
T← (fetch← T) + 1;* WW (= 452B)
T← MD, ETemp← (Fetch← T) - 1;* ACTIVE (= 453B)
NWW← (NWW) OR T, T← MD;* WW OR NWW
NWW← T← T AND (Q← NWW);* (WW OR NWW) AND ACTIVE
branch[.+2, ALU=0];
branch[NWWPUNT];
* No pending channel is turned on.
* Save turned-off interrupts in WW, flush them from NWW,
*
and resume execution.
Store← ETemp, DBuf← Q;
NoReschedule, branch[RestartIFU];

.intsoff:
* No interrupt enabled; check for
rbase← rbase[LTEMP0];* other reschedule conditions.
:if[FNStats];
pd← (FnStatsPtr) - (StatsBufferBoundary);
branch[STATSPUNT, alu>=0];
:endif;
branch[.+2, R<0], LEFT;* is LEFT negative?
branch[RestartIFU];
memBase← StackBR;
ESP← (fetch← ESP) + 1;* fetch flagword
LTEMP2← Md, fetch← ESP;
pd← (LTEMP2) xor (FreeStackBlock);* is it a free block?
branch[STKOVPUNT, alu#0], ESP← (ESP) - 1;
ESP← (ESP) + (Md), Call[FIXLEFT];
Branch[RestartIFU];

*--------------------------------------------------------------------
SUBROUTINE;
FIXLEFT:
*--------------------------------------------------------------------
T← ESP;
LEFT← T - (TSP);
FIXLEFT1:
LEFT← (LEFT) rsh 1;
LEFT← (LEFT) - (LEFTOffset), return;
TOPLEVEL;