:TITLE[Faults.0mc, July 29, 1983  4:39 PM, van Melle];

* Punt cases, going to Bcpl

* SubrCall opcode:  AC2 = Subr Number, AC3 = Number of Args
@SubrCall:
	nop, opcode[175];
	T ← NextData[IBuf];		* Get Subr #
	AC2 ← T;
	T ← NextData[IBuf];		* Get Nargs
	AC3 ← T, loadpage[pgHStack];
	callp[ClrHStk];

	lspL2 ← SubrArgArea;		* Address the subr arg area
	lspL3 ← (0c);
	T ← lsh[AC3, 1];			* Nargs*2
	lspTsp ← (lspTsp) - T;
	lspTsp ← (lspTsp) + (2c);	* Point tsp at first arg

SubrLp:	T ← (Form-2[AllOnes]) + T;	* T ← T-2
	goto[lspSubr1, alu<0];		* (T = 0 for final iteration)
	PFetch2[lspTsp, lspL0];		* L0,1 ← TOS
	call[retLBL];			* (alloc constraint keeps out of prev)
	PStore2[lspL2, lspL0], goto[SubrLp];	* Arg ← L0,1

lspSubr1:
	T ← PCFreg;
	PCB ← (lsh[PCB, 1]) + T;
	T ← lsh[lspIfuBr, 1];
	T ← PCB ← (PCB) - T;		* PC = 2*(PCB - Fnheader) + PCF
	lspPC ← T;			* prepare to store it
	T ← lspTsp, loadpage[pgLisp0];	* was addr of first arg = FX:Next
	lspNext ← T;			* this comes after lspIfuBrHi
onpage[pgLisp0];
	lspEp ← (lspEp) - (12c);		* point at FX
	PStore4[lspEp, lspIfuBr, 2], goto[SubrMkFree];
					* Store fnheader, Next, PC

:IF[WindFlg];

* ContextSwitch op.  TOS = context # (smallp)

@ContextSwitch:
	T ← Stack&-1, loadpage[pgLisp0], opcode[176];	* context #
	lu ← (Stack&+1) xor (smallpl);		* Verify that it is smallp
onpage[pgLisp0];
	AC2 ← T, skip[alu=0];			* AC2 ← context#
	  lspUfn ← 176c, goto[ufnLBL];
* If we were switching from kbd context, need interrupts back on
EnableInterrupts:
	NWW ← (NWW) and not (100000c), goto[CxS1, R>=0];
	  FreezeResult, call[CheckInterrupts];
			* interrupts were off, may need to set IntPending
	  nop;					* Alloc constraint
CxS1:	AC3 ← 177400c, goto[NoBackup];		* AC3<0 signals contextswitch

*  While in Lisp, all interrupt bits are in NWW; don't have to worry about WW.

CheckInterrupts:
	T ← (SStkP&NStkP) xor (377c), skip[alu#0];
	  return;				* no interrupts called for
	lspLN ← IP[RSImage]c;
	StkP ← lspLN, lspLN ← T, NoRegILockOK;	* => RS232 image register
	T ← Stack ← (Stack) or (IntPendingBit);	* OR in the intpending bit
	StkP ← lspLN, RS232 ← T, return;	* restore stkp, stow RS232

:ELSE;
	lspUFN ← 176c, goto[ufnLBL], opcode[176];	* punt contextswitch
:ENDIF;

* Assorted punt cases

*** NWW Interrupt, between instructions

:IF[WindFlg];

onpage[opPage0];		* From Nww opcode (0)
NWWPunt:				* -2- Fetch --No args, Never FN
	AC3 ← 0c;
	loadpage[pgLisp0];
:ELSE;
onpage[pgLisp0];
lspNWWInt:
	AC3 ← 0c;
:ENDIF;
	AC2 ← (LispExitCodex), goto[CheckforBackup];


onpage[pgFrame3];

*** Stack overflow in function call (Context switch)

lspSubovPunt:		* -1- Frame --Ac1= # of additional words, Always FN
	AC3 ← 177400c;					* => do context switch
	loadpage[pgLisp0];
	AC2 ← SubovFXP, goto[CheckforBackup];		* Ac2 = Context#


onpage[pgLisp0];

*** Stack overflow in push, end of instruction (Context switch)

StackFullPunt:		* -1- Stack --Ac1= # words, Never FN
	AC3 ← 177400c;
	AC2 ← SubovFXP, goto[NoBackup];


*** Stats overflow (Checked in Return, at end of inst)

:IF[StatsMode];
	onpage[pgJump];
StatsPunt:
	AC3 ← 0c;		* No args
	loadpage[pgLisp0];
	AC2 ← (StatsOvflCodex), gotop[NoBackup];

	onpage[pgLisp0];
:ENDIF;



*** Page Fault, anywhere

llspMapFaultPunt:	* -3- Lfaults --, Sometime FN
			* Come here with AC0 = Fault page
			* Bcpl wants Ac0,1 = virtual addr of read fault
	T ← 374c, at[MapFaultPuntLoc];
	T ← (lsh[Stack, 2]) xor T;
			* StkP points at PipeReg4
			* = main col address in low 6 bits, complemented
	T ← (ldf[lspGenBr, 16, 2]) or T;
				* insert a within-quad address from
				* base reg (may be wrong, but it is right for
				* Getbase et al and Bcpl fetches, and we can't
				* do better)
	AC1 ← T;	* AC1 now has within-page address in rh, normal
	T ← lsh[AC0, 10];	* low half of page
	AC1 ← (rhmask[AC1]) or T;	* AC1 now has low half of fault addr
	AC0 ← rsh[AC0, 10];		* AC0 has high half
	Dispatch[lspInstFlag, 14, 4];
	StkP ← xBuf2, disp[FaultDisp0];

:IF[FaultFlg];
*****  Fault switch context ******

FaultDisp0:
lspDoFault:
	AC3 ← 177400c, at[FaultDisp, NormalState!];	* Do context switch
	AC2 ← FaultFXP, call[GetInterfaceBase];
	lspGenBr ← (lspGenBr) + (IFPFAULTHI);	* Store fault addr in interface page
	PStore1[lspGenBr, AC0, 0], call[retLBL];

:IF[Debugging];
	lu ← (lspEp) - (minFaultPvar);
	PStore1[lspGenBr, AC1, 1], skip[Carry];
	  lspL1 ← (FaultInFault), goto[RaidPunt];
	NWW ← (NWW) and not (100000c), goto[CheckforBackup, R>=0];
					* Are interrupts on?
:IF[BreakPoints];
	breakpoint;
:ELSE;
	lspL1 ← (FaultWithoutInterrupts), goto[RaidPunt];
:ENDIF;

:ELSE;	* if not debugging...
	PStore1[lspGenBr, AC1, 1], goto[CheckforBackup];
:ENDIF;

:ELSE;
*****  Fault call Bcpl ******

FaultDisp0:
lspDoFault:
	lspL3 ← 0c, at[FaultDisp, NormalState!];
	lspL2 ← (subrArgArea), task;	* Point at subr arg area
	AC3 ← 1c;			* One arg
	AC2 ← (PageFaultCodex);
	PStore1[lspL2, AC0, 0], call[retLBL];	* store fault addr as subr arg
	PStore1[lspL2, AC1, 1], goto[CheckforBackup];
:ENDIF;

StorePuntArgs:
	lspL0 ← (smallpl);
	T ← (subrArgArea);
	PStore2[MDS, lspL0];	* Store subr args
	AC2 ← (UcodeCheckCodex), return;


NoBackup:
	T ← PCFreg, goto[lspPuntStore];

*** Raid punt, disaster only

RaidPunt:			* -0- Ucode Check  --Arg in L1 = Smallp code
	AC3 ← 1c, call[StorePuntArgs];

CheckforBackup:
	T ← (Pcxreg) - 1;	* PC at start of inst - 1, so will be redone
	lu ← (Pcfreg) - T;
	goto[lspPuntStore, alu>=0];
	  PCB ← (PCB) - (4c), goto[lspPuntStore];	
		* If PCF < PCX-1 then buffer refill occurred, so decrement PCB

lspPuntStore:
	PCB ← (lsh[PCB, 1]) + T;
	T ← lsh[lspIfuBr, 1];
	T ← PCB ← (PCB) - T;		* PC = 2*(PCB-Fnheader) + PCF
	lspPC ← T, loadpage[pgHStack];	* prepare it for PStore4 below
	callp[ClrHStk];

	lspEp ← (lspEp) - (12c);	* Point at FX
	PFetch1[lspEp, lspL4, 0];	* L4 ← flagword of current frame

	lspL0 ← (smallpl);
		* Note: this is set for SubrInCall branch below, and also
		* to make sure that L0,1 is a valid pointer in case of
		* contextswitch to a non-nopush context

	lu ← lspInstFlag, goto[SubrInCall, R<0];	* In a function call?

*** Normal punt, just set No Push bit
	T ← lspTsp ← (lspTsp) + (2c);	* Point at word after end of frame
	lspNext ← T, call[retLBL];	* Wait for reg to get written
	PStore4[lspEp, lspIfuBr, 2];	* Store fnheader, Next, PC
	lspL4 ← (lspL4) or (FxNoPushReturn), goto[SubrStFlags];
					* Set no push bit


*** Here if we were in function call...

:IF[StkDebug];				* Are there 6 words on stack?
SubrInCall:					
	T ← (lspTsp) + (6c);		***** temp
	T ← (lspEsp) - T;		***** temp (should check for wraparound)
	skip[carry];			***** temp
	 breakpoint, goto[.];		***** temp: die if < 6 words on stk
:ELSE;
SubrInCall:	nop;
:ENDIF;

* Store on stack the number of args, as a smallp, and the function definition
* Tsp currently points at TOS

	PStore2[lspTsp, lspDefx0, 4];		* store fn name
	T ← lspNargs;			* lspL0 already = smallpos
	lspL1 ← T;
	PStore2[lspTsp, lspL0, 2], call[retLBL]; * Store Nargs as a smallp
	lspTsp ← (lspTsp) + (6c);		* Next
	PStore1[lspEp, lspTsp, 4], call[retLBL];	* Store it

	lspL4 ← (lspL4) or (FxInCall);		* Set call in progress
SubrStFlags:
	PStore1[lspEp, lspL4, 0], goto[SubrMkFree];


SubrMkFree:
	T ← lspTsp;
	T ← (lspEsp) - T;		* Compute # words free after frame
	lspL3 ← T, goto[SubrStkError, No Carry];	* error if Esp<Tsp
	lspL2 ← freeStackBlock, Skip[alu=0];	* don't store empty free block
	PStore2[lspTsp, lspL2, 0];	* make a free block
	lu ← AC3, goto[CxtSwitch, R<0];

:IF[StatsMode];
	lspStatsPtr, goto[SubrStat, R>=0];
:ENDIF;

SubrStatDone:
ToBcpl:					* Store current FX in interface page
	PCB ← (BcplStartAddress);	* allocation constraint
	call[GetInterfaceBase];
	PStore1[lspGenBr, lspEp, 0], gotoExternal[lStartNovaLoc];

CxtSwitch:
	lspInstFlag ← (NormalState), call[GetInterfaceBase];
	T ← AC2;
	PFetch1[lspGenBr, lspLN], call[retLBL];
				* Swap FX with one in Interfacepage
	loadpage[pgReturn];
	PStore1[lspGenBr, lspEp], gotop[lspRtn2];


GetInterfaceBase:			* Point GenBr pair at Interface page
	lspGenBrHi ← (INTERFACEspace);
	lspGenBr ← (INTERFACEbase), return;

:IF[BreakPoints];
SubrStkError:
	breakpoint, goto[.];
:ELSE;
SubrStkError:				* turn this into raid punt instead
	T ← lspEsp;
	lspL1 ← T, call[StorePuntArgs];
	AC3 ← 1c, goto[ToBcpl];		* 1 arg to ucodecheck
:ENDIF;


:IF[WithMidas];
lStartNova:
	gotoExternal[lStartNovaLoc];
:ENDIF;