:Title[LARITH];
**Edit History
* 7-Jul-85 10:56:18, masintermake sure (TIMES max.smallp max.smallp) punts
* March 29, 1985  11:09 AM, Masinter, reformatting
* March 13, 1985  9:44 AM, Masinter, Remove call to SAVEUCODESTATE
* January 5, 1985 10:45 PM, JonL, Add overflow check opIPLUS2, opIDIFFERENCE
* February 2, 1984  10:06 AM, JonL, fix all CallUFN's to be alone
*	on line (permits new def of CallUFN)
* January 13, 1984  10:44 PM, JonL, spawned this file off LOW.mc
* January 12, 1984  12:22 AM, JonL, fix wrong-parity branches at
*	 .unboxB1 and .unboxA1, and straighten out mess at .unboxAcl
* January 6, 1984  8:16 AM, JonL, fixed .BOX2 and .BOX to account for
*	TSP height when tailing into TL.CREATECELL
* January 5, 1984  1:02 AM, JonL, fixed bug caused by no comments in
*	kludgy .STOREBOX code!
* January 4, 1984  7:08 PM, JonL, added label TL.GREATERP for
*	 opFGREATERP to use.
* January 3, 1984  10:59 PM, JonL, Mucked with .UNBOX* some more,
*	finding several bugs
* December 30, 1983  4:53 PM JonL& Masinter, fix TSP on entry to
*	TL.CREATECELL, fix TT.** in .UNBOX2
* December 29, 1983  8:42 PM, JonL, added opMAKENUMBER
* December 29, 1983  12:21 PM, JonL, Re-format some (flushing CR's),
*	add .numfail as a place to UFN out rather than .unboxfail; fix bug
* 	of LRSH sometimes entering .BOX with ALU bad branch conditions
* December 27, 1983  9:50 PM, JonL, let .BOX tail into TL.CREATECELL
*	instead of punting out; cleanup .UNBOX2 to flush TT.*** bits etc.
* 	Used symbolic (sub[SmallNeg!, SmallHi!]c) instead of 1 in .unbox.
* December 26, 1983  6:46 PM, JonL, moved opEQ and opNOP to LOPS;
* December 26, 1983  1:22 PM, JonL, LLSH and LRSH use LCY and RCY;
*	cause .UNBOX* to flush TT.*** bits from type table
* December 21, 1983  5:08 AM, JonL, Move opSWAP to LSTACK, opGCSCAN to
* 	LGC, opRCLK to LOPS.
*   - - -       , Masinter

   TOP LEVEL;
   knowrbase[LTEMP0];
   InsSet[LispInsSet, 1];

*--------------------------------------------------------------------
opLOGAND2:
*--------------------------------------------------------------------
   T← (fetch← TSP) - 1, flipMemBase, Call[.UNBOX2];
   LTEMP1← (LTEMP1) and Q;
   LTEMP0← (LTEMP0) and T, branch[.BOX2];

regOP1[345, StackM2BR, opLOGAND2, noNData];

*--------------------------------------------------------------------
opLOGOR2:
*--------------------------------------------------------------------
   T← (fetch← TSP) - 1, flipMemBase, Call[.UNBOX2];
   LTEMP1← (LTEMP1) or Q;
   LTEMP0← (LTEMP0) or T, branch[.BOX2];

regOP1[344, StackM2BR, opLOGOR2, noNData];

*--------------------------------------------------------------------
opLOGXOR2:
*--------------------------------------------------------------------
   T← (fetch← TSP) - 1, flipMemBase, Call[.UNBOX2];
   LTEMP1← (LTEMP1) xor Q;
   LTEMP0← (LTEMP0) xor T, branch[.BOX2];

regOP1[346, StackM2BR, opLOGXOR2, noNData];

*--------------------------------------------------------------------
opLLSH1:	* Replace TOS with fixp shifted left one
*--------------------------------------------------------------------
   T← (fetch← TSP) - 1, flipMemBase, Call[.UNBOX1];
   LTEMP1← (LTEMP1) + (LTEMP1);
   LTEMP0← T + T, XorSavedCarry, branch[.BOX];

regOP1[340, StackM2BR, opLLSH1, noNData];

*--------------------------------------------------------------------
opLRSH1:	* Replace TOS with fixp shifted right one
*--------------------------------------------------------------------
   T← (fetch← TSP) - 1, flipMemBase, Call[.UNBOX1];
   LTEMP1 ← RCY[T,LTEMP1,1];
   	* Masking may cause a false "No" answer to the alu=0 question in
   	*   .BOX, but it will recuperate by testing LTEMP0 again.
   LTEMP0 ← RSH[LTEMP0,1], branch[.BOX];

regOP1[342, StackM2BR, opLRSH1, noNData];

*--------------------------------------------------------------------
opLRSH8:
*--------------------------------------------------------------------
   T← (fetch← TSP) - 1, flipMemBase, Call[.UNBOX1];
   LTEMP1 ← RCY[T,LTEMP1,10];
   LTEMP0 ← RSH[LTEMP0,10], branch[.BOX];	* See comment at opLRSH1

regOP1[343, StackM2BR, opLRSH8, noNData];

*--------------------------------------------------------------------
opLLSH8:
*--------------------------------------------------------------------
   T← (fetch← TSP) - 1, flipMemBase, Call[.UNBOX1];
   LTEMP1 ← LSH[LTEMP1,10];
   T ← Q;	* Can't specify Q in shifts
   LTEMP0 ← LCY[T,LTEMP0,10], branch[.BOX];	* See comment at opLRSH1

regOP1[341, StackM2BR, opLLSH8, noNData];

*--------------------------------------------------------------------
opIPLUS2:
*--------------------------------------------------------------------
   T← (fetch← TSP) - 1, flipMemBase, call[.UNBOX2];
   LTEMP1← (LTEMP1) + Q;
   LTEMP0← (LTEMP0) + T, XorSavedCarry, branch[.ovchk];
.ovchk:
   branch[.BOX2, overflow'], pd← LTEMP0;	* test for overflow, & punt
   TSP← (TSP) + (4c), CallUFN;	*  if it happens

regOP1[330, StackM2BR, opIPLUS2, noNData];	* IPLUS

*--------------------------------------------------------------------
opIDIFFERENCE:
*--------------------------------------------------------------------
   T← (fetch← TSP) - 1, flipMemBase, call[.UNBOX2];
   LTEMP1← (Q) - (LTEMP1);
   LTEMP0← (T) - (LTEMP0) - 1, XorSavedCarry, branch[.ovchk];

regOP1[331, StackM2BR, opIDIFFERENCE, noNData];	* IDIFFERENCE

*--------------------------------------------------------------------
opBOXIPLUS:
*--------------------------------------------------------------------
   LTEMP4← 1s;
* When .UNBOX2 unboxes two args, it does the first one last, and leaves
*  its lo.word address LTEMP4.  That address must have the low-order bit
*	zero, since it will be a cell-aligned address.
   T← (fetch← TSP) - 1, flipMemBase, call[.UNBOX2];
   LTEMP1← (LTEMP1) + Q;
   LTEMP0← (LTEMP0) + T, XorSavedCarry, branch[.STOREBOX2];

regOP1[366, StackM2BR, opBOXIPLUS, noNData];

*--------------------------------------------------------------------
opBOXIDIFFERENCE:
*--------------------------------------------------------------------
   LTEMP4← 1s;    	* See comment in opBOXIPLUS
   T← (fetch← TSP) - 1, flipMemBase, call[.UNBOX2];
   LTEMP1← (Q) - (LTEMP1);
   LTEMP0← (T) - (LTEMP0) - 1, XorSavedCarry, branch[.STOREBOX2];

regOP1[367, StackM2BR, opBOXIDIFFERENCE, noNData];

.STOREBOX2:
   Branch[.+2, R even], T← (LTEMP4), memBase← ScratchLZBR;
   	TSP← (TSP) + (4c), CallUFN;	* First arg wasn't fixp type
   T← (store← T) + 1, dbuf← LTEMP0;	* Smash results from LTEMP0,1
   store← T, dbuf← LTEMP1;	*  into the first arg's loc
   TSP← (TSP) + (2c), NextOpCode;

*--------------------------------------------------------------------
opITIMES2:
*--------------------------------------------------------------------
   T← (fetch← TSP) - 1, flipMemBase, call[.UNBOX2];
   pd← T or (LTEMP0);
   branch[.+2, alu=0], T← LTEMP1;
      TSP← (TSP) + (4c), CallUFN;	* More than 32 bits => punt
   call[MulSub], NARGS← (2c);	* T * Q -> (T, Q)
   CELLHINUM← pd← T;
   branch[.+2, alu#0], FreezeBC, LTEMP1← Q;
      T← (store← TSP) + 1, dbuf← SmallHi, branch[.BOXretsmp];
   branch[.+2, alu>0], CELLLONUM← Q;
      TSP← (TSP) + (4c), CallUFN;	* high bit on, punt (full 32 bit ans)
   T← (NARGS) + 1, membase← dtdBR, branch[.boxtail];

regOP1[332, StackM2BR, opITIMES2, noNData];	* ITIMES

*--------------------------------------------------------------------
opIQUOTIENT:
*--------------------------------------------------------------------
   T← (fetch← TSP) - 1, flipMemBase, call[.UNBOX2];
   pd← T or (LTEMP0);
   branch[.+2, alu=0];	* (could handle big positives)
   	TSP← (TSP) + (4c), CallUFN;
   DivTEMP1← LTEMP1, SCall[DivSub];	* T,,Q / DivTEMP1
   	branch[.+2], TSP← (store← TSP) + 1, dbuf← SmallHi;
   	TSP← (TSP) + (4c), CallUFN;	* Failure return
   TSP← (store← TSP) + 1, dbuf← Q, NextOpCode;	* Q has quotient

regOP1[333, StackM2BR, opIQUOTIENT, noNData];	* IQUOTIENT

*--------------------------------------------------------------------
opIREMAINDER:
*--------------------------------------------------------------------
   T← (fetch← TSP) - 1, flipMemBase, call[.UNBOX2];
   pd← T or (LTEMP0);
   branch[.+2, alu=0];
   	TSP← (TSP) + (4c), CallUFN;
   DivTEMP1← LTEMP1, SCall[DivSub];	* T,,Q / DivTEMP1
   	branch[.+2], TSP← (store← TSP) + 1, dbuf← SmallHi;
   	TSP← (TSP) + (4c), CallUFN;	* failure return
   TSP← (store← TSP) + 1, dbuf← T, NextOpCode;	* T has remainder

regOP1[334, StackM2BR, opIREMAINDER, noNData];


*--------------------------------------------------------------------
opIGREATERP:
*--------------------------------------------------------------------
   T← (fetch← TSP) - 1, flipMemBase, Call[.UNBOX2];
   pd← T - (LTEMP0);
   branch[TL.GREATERP, alu=0], pd← (Q) - (LTEMP1) - 1;
   T← T xor (100000c);	* hi parts differ, so complement
   LTEMP0← (LTEMP0) xor (100000c);	* sign, and try again
   pd← T - (LTEMP0) - 1;
TL.GREATERP:	* opFGREATERP also comes here
   branch[.+2, carry], TSP← (store← TSP) + 1, dbuf← (atomHiVal);
   	TSP← (store← TSP) + 1, dbuf← AT.NIL, NextOpCode;	* push NIL
   TSP← (store← TSP) + 1, dbuf← AT.T, NextOpCode;	* push T

regOP1[361, StackM2BR, opIGREATERP, noNData];	* IGREATERP

*--------------------------------------------------------------------
* Generic arithmetic entries
*--------------------------------------------------------------------
regOP1[324, StackM2BR, opIPLUS2, noNData];	* PLUS
regOP1[325, StackM2BR, opIDIFFERENCE, noNData];	* DIFFERENCE
regOP1[326, StackM2BR, opITIMES2, noNData];	* TIMES
regOP1[327, StackM2BR, opIQUOTIENT, noNData];	* QUOTIENT
regOP1[363, StackM2BR, opIGREATERP, noNData];	* GREATERP

*--------------------------------------------------------------------
opMAKENUMBER:
*--------------------------------------------------------------------
   T← (fetch← TSP) - 1, flipMemBase, Call[.UNBOX2];
   pd← T or (LTEMP0);	* Ascertain that both args are SmallPosp's
   branch[.+2, alu=0];
   	TSP← (TSP) + (4c), CallUFN;
   pd← LTEMP0← Q, branch[.BOX2];

regOP1[365, StackM2BR, opMAKENUMBER, noNdata];

*--------------------------------------------------------------------
SUBROUTINE;	.UNBOX1:	GLOBAL,
*--------------------------------------------------------------------

* Enter with one argument A on top of stack
*            memBase set to StackM2BR, then do
*            T← (fetch← TSP) - 1, flipMemBase, call[.UNBOX1];
* Exit with A hi.word in LTEMP0, T
*           A lo.word in LTEMP1, Q
*           TSP "pulled back" over the the argument
*           memBase set to StackBR
*	clobbers LTEMP2, SaveLink

   LTEMP2← T← Md, fetch← T;	* Now memBase is StackBR
   LTEMP0← T← T - (SmallHi);
.unbox1.0:
   branch[.unbox1.1, alu#0], Q← LTEMP1← Md;
   	* Note how the branch falls thru on SmallHi with LTEMP0 and
   	*  T set to 0;  This is a "fast case" exit for SmallPosp's
   TSP← (TSP) - (2c), return;

.unbox1.1:
   T← T - (sub[SmallNeg!, SmallHi!]c);	* This "sub" had better be 1
   branch[.+2, alu#0], LTEMP0← T← T - 1;	* LTEMP0← -1 in case A is a
   	TSP← (TSP) - (2c), return;	*  SmallNeg (and fast exit)
.unbox1cl:
* "A" may be stored in a cell -- check it out
   T← LTEMP2, memBase← tyBaseBR;	  	* Otherwise, restore T

*	Think of the following as a subroutine:
*	LTEMP2,T have hi.word, LTEMP1 has lo.word, memBase is tyBaseBr
   T← RCY[T, LTEMP1, 11];	* Fetch the type table entry
   fetch← T;
   T← Md, memBase← ScratchLZBR;
   T← (T) and (rhmask); 	* Foo on TT.*** bits
   pd← (T) xor (fixptype);
   branch[.+2, alu=0], BrHi← LTEMP2;
   	TOPLEVEL; CallUFN; SUBROUTINE;	* not fixp type
PAGEFAULTOK;
   T← (FETCH← LTEMP1) + 1;
*	This would be the subroutine exit

   LTEMP0← T← MD, fetch← T;
PAGEFAULTNOTOK;
   pd← T - T, memBase← StackBr, Branch[.unbox1.0];

*--------------------------------------------------------------------
.UNBOX2: GLOBAL,
*--------------------------------------------------------------------
*
* Enter with two arguments A and B on top of stack (B on top)
*            memBase set to StackM2BR
*            T← (fetch← TSP) - 1, flipMemBase, call[.UNBOX2];
* Exit with  A hi.word in T
*            A lo.word in Q
*            B hi.word in LTEMP0
*            B lo.word in LTEMP1
*            TSP "pulled back" over both A and B,  LEFT← LEFT - 1
*            memBase set to StackBR
*	clobbers LTEMP2, LTEMP3, LTEMP4 and SaveLink

   LTEMP0← Md, T← (fetch← T) - (3c);	 * LTEMP0← Bhi
   LTEMP1← Md, T← (fetch← T) + 1;	 * LTEMP1← Blo
   LTEMP0← (LTEMP0) - (SmallHi);	 * LTEMP0← Bhi-SmallHi

.unboxB:	 * B is unboxed first
   Branch[.unboxB1, alu#0], LTEMP3← Md, fetch← T;	 * LTEMP3← Ahi (unbox)
   	T← (LTEMP3) - (SmallHi), branch[.unboxA];	 * B done if SmallPosp
.unboxB1:
   LTEMP0← (LTEMP0) - (sub[SmallNeg!, SmallHi!]c); * LTEMP0← -1 if B is
   branch[.+2, alu#0], LTEMP0← (LTEMP0) - 1;	 *  a SmallNeg
   	T← (LTEMP3) - (SmallHi), branch[.unboxA];	 * B done if SmallNeg
   Branch[.unboxBcl], Q← Md, LEFT← (LEFT) + 1; 	 * Q← Alo word

.unboxA:	 * pd has Ahi-SmallHi
   DblBranch[.ubxBothdone, .unboxA1, alu=0],	 * A done if SmallPosp
   	 Q← Md, LEFT← (LEFT) + 1;	 * Q← Alo word
.ubxBothdone:
   TSP← (TSP) - (4c), return;

.unboxA1:
   T← T - (sub[SmallNeg!, SmallHi!]c);	* T← -1 if A is
   branch[.unboxAcl, alu#0], T← T - 1;	*  SmallNeg
   	TSP← (TSP) - (4c), return;	* A done if SmallNeg

.unboxBcl:
*  "B" may be stored in a cell -- check it out.
   T← (LTEMP0) + (add[SmallNeg!, 1]c);	 * Restore Bhi &
   LTEMP2← T, memBase← tyBaseBR;	 *  put in T & LTEMP2

* This could be a subroutine
   T← RCY[T, LTEMP1, 11];
   fetch← T;
   T← Md, memBase← ScratchLZBR;
   T← T and (rhmask);	* flush TT.*** bits
   pd← (T) xor (fixptype);
   branch[.+2, alu=0], BrHi← LTEMP2;
   	TOPLEVEL; CallUFN; SUBROUTINE;	* not fixp type
PAGEFAULTOK;
   T← (FETCH← LTEMP1) + 1;
* This would be the end of the subroutine

   fetch← T, LTEMP0← MD;
PAGEFAULTNOTOK;
   T← (LTEMP3) - (SmallHi);	 * Unbox Ahi, and
   DblBranch[.ubxBothdone, .unboxA1, alu=0],	 * re-join code to
   	LTEMP1← Md, memBase← StackBR; 	 * finish unboxing "A"

.unboxAcl:
*  "A" may be stored in a cell -- check it out.
   LTEMP2← T← LTEMP3;	* LTEMP2← Ahi, freeing
   LTEMP3← Q, memBase← tyBaseBR;	*  LTEMP3

* This would be the subroutine
   T← RCY[T, LTEMP3, 11];
   fetch← T;
   T← Md, memBase← ScratchLZBR;
   T← (T) and (rhmask);	* flush TT.*** bits
   pd← (T) xor (fixptype);
   branch[.+2, alu=0], BrHi← LTEMP2;
   	TOPLEVEL; CallUFN; SUBROUTINE;	* not fixp type
PAGEFAULTOK;
   T← (FETCH← LTEMP3) + 1;
* End of subroutine

   T← MD, fetch← T, LTEMP4← Q;	* Kludge for .STOREBOX
PAGEFAULTNOTOK;
   Q← Md; 	* Q← lo.word of A, and
   memBase← StackBR, branch[.ubxBothdone]; 	*  restore memBase

TOP LEVEL;
*--------------------------------------------------------------------
* BOX results	* Make a fixp of result in LTEMP0,,LTEMP1
*--------------------------------------------------------------------
.BOX2:
   branch[.+2, alu=0], NARGS← (2c);  * NARGS "adjusts" TSP in CreateCell
     pd← (LTEMP0) + 1, Branch[.box.1];
   T← (store← TSP) + 1, dbuf← SmallHi;
.BOXretsmp:
   TSP← (store← T) + 1, dbuf← LTEMP1, NextOpCode; * Easy, when SmallPosP

* Enter with Hi word in LTEMP0 (and generally on Pd -- see "ALU" below)
*            Lo word in LTEMP1
*  memBase is StackBR
* 	and with TSP "pulled back" over inputs, and LEFT decremented by 1

.BOX:	branch[.+2, alu=0], NARGS← A0;
   	pd← (LTEMP0) + 1, Branch[.box.1];  * easy when SmallPosP
   T← (store← TSP) + 1, dbuf← SmallHi, Branch[.BOXretsmp];

.box.1:	* Check for negative smallps too
   branch[.+2, alu#0], pd← CELLHINUM← LTEMP0;
     T← (store← TSP) + 1, dbuf← SmallNegHi, Branch[.BOXretsmp];
.box.1.fixp:
   branch[.+2, alu#0], CELLLONUM← LTEMP1;	* Check hi.word again
   T← (store← TSP) + 1, dbuf← SmallHi, Branch[.BOXretsmp];

* Shift masking can => false non-0 alu test

*  Since TSP was "pulled back" upon entry, it must be restored.  So add
*  4 in the case of .BOX2 (4 words for 2 args), or 2 for .BOX
   T← (NARGS) + 1, membase← dtdBR;
.boxtail:
   TSP← (TSP) + T + 1;
   T← (LShift[fixpType!, 4]c), branch[TL.CREATECELL];