:Title[LFaults.dmc, 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)
	ManyFaults		More than one fault
	NotEmuFault		Fault in non-emulator task
	NotMapFault		Memory system fault other than map fault
	UnknownFault		Fault of unknown origin

(In emulator task, having reset FaultInfo)
	AEmuStackError		Stack error from Alto emulator
	AEmuMapFault		Map fault from Alto emulator

(In emulator task, the fault task never having been awakened)
	LispIFUMapFault	Map fault caused by IFU reference
	LispIFUFGParity	FG parity error
	LispIFURamPE		IFU decoding Ram parity error
	BogusIFUMapFault	IFU 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:

	FltErrors	NOT (Errors')
	FaultInfo	NOT (Pipe2')
	FltEmuPC	Emulator TPC at time of fault
	FaultVal	DBuf -- 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:
   T← EMU, CoReturn;
TopLevel;

Fault0: RBase← RBase[FltPipe0], 
   Call[RestoreALUFM];	* In case interrupted from BITBLT

   PD← (FaultInfo) AND (fi.numFaults);	* Which kind of fault?
   FaultMapVal← NOT (Map'), Branch[StackError, ALU#0];
   T← VAHi;
   T← FltPipe0← T AND (7777C);	* only want low bits
   FltPipe1← Q← VALo;
   FaultMapVal← not (Pipe4');	* ref bits in pipe

* Which emulator was running at the time?
   FltTemp← NOT (IFUMLH');
   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];

*--------------------------------------------------------------------
* IFU traps from lisp emulator

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

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

.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 other Reschedule conditions:
   rbase← rbase[LTEMP0];

: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;
   T← ESP← (ESP) + (Md);
   LEFT← T - (TSP);				* recompute Left
   LEFT← (LEFT) rsh 1;
   LEFT← (LEFT) - (LeftOffset), branch[RestartIFU];

*--------------------------------------------------------------------
LispIFUFGparity:
   At[LispTrapBase, 4], Branch[.], Breakpoint;
*--------------------------------------------------------------------
LispIFURamPE:
   At[LispTrapBase, 74], Branch[.], Breakpoint;
*--------------------------------------------------------------------
LispIFUMapFault:
   At[LispTrapBase, 0], MemBase← ifuBR;

	CHECKPCX;
	PAGEFAULTOK;

   T← NOT (PCX');
   T← T RSH 1;		* PCX/2 = word address in code segment
   T← (FETCH← T) + 1;
   T← MD, FETCH← T;
   T← MD;		* Wait for fault to occur

BogusIFUMapFault:
   Branch[.], Breakpoint;


*-----------------------------------------------------------
StackError:
   uCodeCheck[HWStackError];