{File name LispArith4K.mc
Description:  DandeLion InterLisp Emulator Arith Instructions
Author: Charnley
Last modified: Charnley   16-Jan-84 11:20:10
Last modified: Charnley 31-Aug-83 10:11:23 modified ufn's to use ufnX's
Created: 15-Aug-83 14:48:53
}

{	OPCODES
	two arg functions
	0	1	321	vag2	2
	0	4	324	plus2	2
	0	5	325	difference	2
	0	6	326	times2	2
	0	7	327	quot	2
	0	10	330	iplus2	2
	0	11	331	idifference	2
	0	12	332	itimes2	2
	0	13	333	iquot	2
	0	14	334	remainder	2
	4	4	344	logor2	2
	5	5	345	logand2	2
	6	6	346	logxor2	2
	one arg functions
	0	15	335	addn	1
	0	16	336	subn	1
	0	0	340	llsh1	1
	1	1	341	llsh8	1
	2	2	342	lrsh1	1
	3	3	343	lrsh8	1
}

SetTask[0];
Set[L3.First, 0C];
Set[L3.Second, 9];
RegDef[uA1Hi,	U,	5];
RegDef[uA1Lo,	U,	7];

{*************************
	IPLUS2, IDIFF, LOGOR2, LOGAND2, LOGXOR2, VAG2	5%  3 click
**************************}
@PLUS:	opcode[330'b],
	MAR ← [rhS, S + 0], {L2 = 0}, GOTO[ArithShortC2],	c1;
@IPLUS2:	opcode[324'b],
	MAR ← [rhS, S + 0], {L2 = 0}, GOTO[ArithShortC2],	c1;
@OR:	opcode[344'b],
	uTOS ← TOS, {L2 = 4}, GOTO[ArithC2],	c1;
@AND:	opcode[345'b],
	uTOS ← TOS, {L2 = 5}, GOTO[ArithC2],	c1;
@XOR:	opcode[346'b],
	uTOS ← TOS, {L2 = 6}, GOTO[ArithC2],	c1;
@VAG2:	opcode[321'b],
	MAR ← [rhS, S + 0], GOTO[ArithVag],	c1;
@IDIFF2:	opcode[331'b],
	MAR ← [rhS, S + 0], L2 ← 07'b, GOTO[ArithShortC2],	c1;
@DIFF:	opcode[325'b],
	MAR ← [rhS, S + 0], L2 ← 07'b, GOTO[ArithShortC2],	c1;
@IGREATERP:	opcode[361'b],
	uTOS ← TOS, L2 ← 10'b, GOTO[ArithComp2],	c1;
@GREATERP:	opcode[363'b],
	uTOS ← TOS, L2 ← 10'b, GOTO[ArithComp2],	c1;

ArithShortC2:
	Ybus ← TOSH xor smallpl, ZeroBr,	c2;
	Rx ← MD, uTOS ← TOS, L2Disp, BRANCH[ArithOut1, $],	c3;

	MAR ← [rhS, S - 1], DISP4[ArithShortOp],	c1;

	TOS ← TOS + Rx, CarryBr, CANCELBR[$, 2],	c2, at[00'b, 10, ArithShortOp];{add}
	TT ← MD, BRANCH[$, ArithOut2],	c3;

	Ybus ← TT xor smallpl, ZeroBr, GOTO[ArithShortCom],	c1;

	TOS ← Rx - TOS, CarryBr, CANCELBR[$, 2],	c2, at[07'b, 10, ArithShortOp];{sub}
	TT ← MD, BRANCH[ArithOut3, $],	c3;

	Ybus ← TT xor smallpl, ZeroBr, GOTO[ArithShortCom],	c1;


ArithShortCom:
	BRANCH[ArithOut4, $],	c2;
	TOSH ← smallpl,	c3;

	S ← S - 2, GOTO[IB.pc1],	c1;

ArithOut1:
	TOS ← uTOS, CANCELBR[ArithShort2, 0F],	c1;

ArithOut2:
	TOS ← uTOS, GOTO[ArithShort2],	c1;

ArithOut3:
	TOS ← uTOS, GOTO[ArithShort2],	c1;

ArithOut4:
	GOTO[ArithOut1],	c3;

ArithShort2:
	uTOSH ← TOSH, L3 ← L3.First, GOTO[ArithC3],	c2;

ArithComp2:
	uTOSH ← TOSH, L3 ← L3.First, GOTO[ArithC3],	c2;
ArithSub2:
	uTOSH ← TOSH, L3 ← L3.First, GOTO[ArithC3],	c2;
ArithC2:
	uTOSH ← TOSH, L3 ← L3.First, GOTO[ArithC3]	c2;

ArithC3:	CALL[ArithUnbox],	c3;

ArithUnbox:
	Ybus ← TOSH xor smallpl, ZeroBr, L1 ← L1.fixFV,	c1;
	Ybus ← TOSH xor smallneg, ZeroBr, BRANCH[$, ArgPos],	c2;
	L3Disp, BRANCH[$, ArgNeg],	c3;

	Rx ← TOS, CANCELBR[ArgNotSmall, 0F],{ArgNotSmall}	c1;

ArgPos:
	TOSH ← 0, L3Disp, CANCELBR[ArgSmall],	c3;
ArgNeg:
	TOSH ← TOSH xor ~TOSH, DISP4[UnboxRet],	c1;
ArgSmall:
	DISP4[UnboxRet],	c1;

	,	c1, at[L3.First, 10, EvalGetRet];
	uA1Hi ← TOSH, L3 ← L3.Second,	c2, at[L3.First, 10, UnboxRet];
	uA1Lo ← TOS,	c3;

	MAR ← [rhS, S - 1],	c1;
	CANCELBR[$, 2],	c2;
	TOSH ← MD,	c3;

	MAR ← [rhS, S + 0],	c1;
	,	c2;
	TOS ← MD, CALL[ArithUnbox],	c3;

	,	c1, at[L3.Second, 10, EvalGetRet];
	TT ← uA1Hi, L2Disp,	c2, at[L3.Second, 10, UnboxRet];
	Rx ← uA1Lo, DISP4[ArithDoit],	c3;

	TOS ← Rx + TOS, CarryBr, GOTO[ArithAddTail],	c1, at[00'b, 10, ArithDoit];{plus}
	TOS ← TOS - Rx, CarryBr, GOTO[ArithSubTail],	c1, at[07'b, 10, ArithDoit];{idifference}
	TOS ← Rx or TOS,	c1, at[04'b, 10, ArithDoit];{Or}
	TOSH ← TT or TOSH, GOTO[ArithLog],	c2;

	TOS ← Rx and TOS,	c1, at[05'b, 10, ArithDoit];{And}
	TOSH ← TT and TOSH, GOTO[ArithLog],	c2;

	TOS ← Rx xor TOS,	c1, at[06'b, 10, ArithDoit];{Xor}
	TOSH ← TT xor TOSH, GOTO[ArithLog],	c2;

	Ybus ← Rx - TOS, CarryBr, GOTO[ArithCompTail],	c1, at[10'b, 10, ArithDoit];{igreaterp}

ArithAddTail:
	BRANCH[$, ArithAddCar],	c2;
	TOSH ← TT + TOSH, PgCrOvDisp, GOTO[ArithCom],	c3;
ArithAddCar:
	TOSH ← TT + TOSH + 1, PgCrOvDisp, GOTO[ArithCom],	c3;

ArithSubTail:
	BRANCH[$, ArithSubCar],	c2;
	TOSH ← TOSH - TT - 1, PgCrOvDisp, GOTO[ArithCom],	c3;
ArithSubCar:
	TOSH ← TOSH - TT, PgCrOvDisp, GOTO[ArithCom],	c3;

ArithCompTail:
	Ybus ← TT xor TOSH, NegBr, BRANCH[$, ArithCompCar],	c2;
	Ybus ← TT - TOSH - 1, NegBr, BRANCH[ArithCompSSgn, ArithCompDSgn],	c3;
ArithCompCar:
	Ybus ← TT - TOSH, NegBr, BRANCH[ArithCompSSgn, ArithCompDSgn],	c3;

ArithCompSSgn:
	TOSH ← 0, BRANCH[ArithResNIL0, ArithResT0],	c1;

ArithCompDSgn:
	Ybus ← TOSH, NegBr, CANCELBR[$],	c1;
	TOSH ← 0, BRANCH[ArithResT, ArithResNIL],	c2;

ArithResT0:
	,	c2;
ArithResT:
	TOS ← KTval, GOTO[ArithEnd],	c3;

ArithResNIL0:
	,	c2;
ArithResNIL:
	TOS ← 0, GOTO[ArithEnd],	c3;

ArithEnd:
	S ← S - 2, GOTO[IB.pc1],	c1;

ArithLog:
	,	c3;

ArithCom:
	Ybus ← TOSH, ZeroBr, BRANCH[ArithNoOv, ArithOv, 2],	c1;
ArithNoOv:
	Ybus ← TOSH + 1, ZeroBr, BRANCH[$, ArithResSmP],	c2;
	TOSH ← smallneg, BRANCH[$, ArithEnd],	c3;

	GOTO[ufnZ2],{result not small}	c1;

ArithOv:
	CANCELBR[ufnZ3],{overflow}	c2;

ArithResSmP:
	TOSH ← smallpl, CANCELBR[ArithEnd],	c3;

ArithVag:
	,	c2;
	TOSH ← MD, GOTO[ArithEnd]	c3;


ArgNotSmall:
	Q ← 0FF,	c2;
{	GOTO[ufnZ1],	c3;l4ka3:}
	rhRx ← MDSTYPEspaceReal,	c3;

	MAR ← Rx ← [Rx{TOS}, TOSH + 0],{not mem req}	c1;
	Rx ← Rx LRot8,	c2;
	Rx ← Rx RShift1, getTypemsBit,	c3;

	MAR ← [rhRx, Rx + 0],	c1;
	rhTT ← TOSH LRot0,	c2;
	Q ← MD and Q,	c3;

	Q ← Q xor FixpType, ZeroBr,	c1;
	TT ← TOS, BRANCH[ArithArgNotFixp, $],	c2;
	CALL[EvalGet],	c3;

	GOTO[NoFixes],	c3,at[L3.First,10,fvfixup];
	GOTO[NoFixes],	c3,at[L3.Second,10,fvfixup];

ArithArgNotFixp:
	CANCELBR[ufnZ1],	c3;


{*************************
	LLSH1, LLSH8, LRSH1, LRSH8	2%  2 clicks
**************************}
LLSH1:	Rx ← TOS LShift1, NegBr, GOTO[NoRots],	c1, opcode[340'b];{E0}
LLSH8:	Ybus ← TOS and uFF00, NZeroBr, GOTO[RotTOS],	c1, opcode[341'b];
LRSH1:	Rx ← TOS RShift1, GOTO[NoRots],	c1, opcode[342'b];
LRSH8:	Rx ← TOS and ~0FF, GOTO[Rot],	c1, opcode[343'b];

RotTOS:	Rx ← TOS LRot8, BRANCH[Unary, ufnUnary],	c2;
Rot:	Rx ← Rx LRot8, BRANCH[Unary, ufnUnary],	c2;
NoRots:	BRANCH[Unary, ufnUnary],	c2;

Unary:	Ybus ← TOSH xor smallpl, NZeroBr,	c3;

	BRANCH[$, ufnUnary2],	c1;
	TOS ← Rx, IBDisp, L2 ← L2.0, GOTO[DNI.pc1],	c2;


{exceptions:}
ufnUnary2:	GOTO[ufnX3],	c2;{arg not smallPos}
ufnUnary:	GOTO[ufnX1],	c3;{result more than 16 bits}

{	FROM MoreLisp.mc}

{*******************************************************************
	MUL			%  20 clicks
*******************************************************************}
{This code implements a basic add-shift unsigned mulitply.  Q holds the multiplicand  and TOS the mulitplier .  TT holds the loop count.  Rx and Q are the concatenated double word result, with the most significant bits being formed in Rx and the least significant in Q.  The DoubleRightShift1 shifts Cout of the current alu computation into bit 0 of the double length result (Rx,,Q).  At the end, the product replaces the top of stack.  Punts occur if the resultant product is longer than 16 bits, or if either multiplier or multiplicand is not legal.}
{	OLD CODE START
@TIMES2:	opcode[326'b],
	MAR ← [rhS, S + 0], GOTO[ArithMul],	c1;

@ITIMES2:	opcode[332'b],
	MAR ← [rhS, S + 0], GOTO[ArithMul],	c1;
ArithMul:
	Ybus ← TOSH xor smallpl, NZeroBr,	c2;
	Rx ← MD, BRANCH[$, Mulufn],	c3;

	MAR ← [rhS, S - 1],	c1;
	Q ← Rx, CANCELBR[Mul3, CB2],	c2;
Mul3:	TT ← MD xor TOSH,	c3;

	Rx ← TT, NZeroBr,	c1;
	TT ← 10, BRANCH[$, MulUfn3],	c2;
	Ybus← Q and 1, NZeroBr, GOTO[MulCon],	c3;

MulLoop:	Ybus← Q and 1, NZeroBr,	c3;

MulCon:	TT ← TT - 1, ZeroBr, BRANCH[MPlier0, MPlier1],	c1;

MPlier0:	Rx ← DARShift1 (Rx+0), BRANCH[MulLoop, MLDEnd],	c2;
MPlier1:	Rx ← DARShift1 (Rx + TOS), BRANCH[MulLoop, MLDEnd],	c2;

MLDEnd:	Ybus ← Rx, ZeroBr,	c3;

	S ← S - 2, BRANCH[MulUfn2, $],	c1;
	TOS ← ~Q {long.low}, L2 ← L2.0, IBDisp, GOTO[DNI.pc1],	c2;
{	PC ← PC + PC16, L2 ← L2.0, DISPNI[OpTable],	c3;}


MulUfn2:	S ← S + 2,	c2;{result not smallPos}
MulUfn3:	GOTO[ufnX1],	c3;{arg 2 not smallPos}
Mulufn:	GOTO[ufnX2],	c1;{arg 1 not smallPos}
	OLD CODE END }
@TIMES2:	opcode[326'b],
	MAR ← [rhS, S + 0], GOTO[ArithMul],	c1;

@ITIMES2:	opcode[332'b],
	MAR ← [rhS, S + 0], GOTO[ArithMul],	c1;
ArithMul:
	Ybus ← TOSH xor smallpl, NZeroBr,	c2;
	TT ← MD, BRANCH[$, Mulufn],	c3;

	MAR ← [rhS, S - 1],	c1;
	Rx ← TOS, CANCELBR[$, 2],	c2;
	Q ← MD xor TOSH,	c3;

	Ybus ← Rx and 1, NZeroBr, GOTO[firstmore],	c1;
firstmore:
	Ybus ← Q, NZeroBr, BRANCH[ftimes0, ftimes1],	c2;
ftimes1:
	Q ← TT, BRANCH[mulloopA, mulerrA],	c3;
ftimes0:
	Q ← 0, BRANCH[mulloopA, mulerrA],	c3;
mulloop:
	Rx ← RShift1 Rx, SE ← 0, YDisp, BRANCH[mulmore, multhru],	c1;
mulmore:
	TT ← TT + TT, CarryBr, BRANCH[times0, times1, 0D],	c2;
times1:
	Q ← Q + TT, CarryBr, BRANCH[mulloopA, mulerrA],	c3;
times0:
	Ybus ← Rx, ZeroBr, BRANCH[mulloop, mulfin],	c3;
mulloopA:
	Rx ← RShift1 Rx, SE ← 0, YDisp, BRANCH[mulmoreA, mulerr],	c1;
mulmoreA:
	TT ← TT + TT, CarryBr, BRANCH[times0, times1, 0D],	c2;
mulfin:
	BRANCH[mulerrB, multhruB],	c1;
multhru:
	TOS ← Q, CANCELBR[ArithResSmP, 0F],	c2;
multhruB:
	TOS ← Q, GOTO[ArithResSmP],	c2;

mulerr:
	CANCELBR[ufnX3, 0F],	c2;
mulerrA:
	CANCELBR[ufnX2, 1],	c1;
mulerrB:
	GOTO[ufnX3],	c2;
Mulufn:
	GOTO[ufnX2],	c1;

{*******************************************************************
	ADDN, SUBN		%  2 clicks
*******************************************************************}

{SUBN:	Q ← ibNA - TOS -1, CarryBr,	c1, opcode[336'b];
	Q ← -Q - 1, BRANCH[addTail, ufnAdd],	c2;

ADDN:	Q ← TOS + ibNA, CarryBr,	c1, opcode[335'b];
	BRANCH[addTail, ufnAdd],	c2;
addTail:	Ybus ← TOSH xor smallpl, NZeroBr,,	c3;

	BRANCH[$, ufnAdd2],	c1;
	TOS ← Q, IBDisp, Xbus ← ib, L2←L2.0,	c2;
	PC ← PC + 1, L2←L2.0, DISPNI[OpTable],	c3;

{exceptions:}
ufnAdd2:	GOTO[ufnX3],	c2;{arg not smallPos}
ufnAdd:	GOTO[ufnX1],	c3;{result not smallPos}
}
@ADDN:	GOTO[ufnX2],	c1, opcode[336'b];
@SUBN:	GOTO[ufnX2],	c1, opcode[335'b];


{	FROM LispGC.mc}

{*******************************************************************
	DIV			%  20 clicks
*******************************************************************}
{This code implements a basic subtract-shift unsigned restoring divide.  TOS holds the divisor  and the concatenation Rx,,Q holds the double length dividend (long).  TT holds the loop count.  The final quotient appears in Q and the remainder in Rx.  The DoubleLeftShift1 shifts Cin into bit 17B of the accumulating quotient.  At the end, Q or Rx is pushed onto the stack.}

@IQUOT:
	MAR ← [rhS, S + 0], GOTO[QotS2], {L2 is 0}	c1,opcode[333'b];

@QUOT:
	MAR ← [rhS, S + 0], GOTO[QotS2], {L2 is 0}	c1,opcode[327'b];

@REMAINDER:
	MAR ← [rhS, S + 0], L2 ← 1'b, {L2 was 0}	c1,opcode[334'b];
QotS2:
	Ybus ← TOSH xor smallpl, NZeroBr,	c2;
	Rx ← MD, BRANCH[$, Qotufn1],	c3;

	MAR ← [rhS, S - 1],	c1;
	Q ← Rx, CANCELBR[$, 2],	c2;
	Rx ← MD xor TOSH,	c3;

	Ybus ← TOS, ZeroBr,	c1;
	Ybus ← Rx, NZeroBr, BRANCH[$, Qotufn3{DivByZero}],	c2;
	TT ← 0F + 1, BRANCH[$, Qotufn1a],	c3;

	Rx ← DLShift1 Rx, SE←0, NegBr, GOTO[QotLoop],	c1;

QotLoop:	Ybus← Rx - TOS, CarryBr, BRANCH[QuotUnk, QuotIs1],	c2;

QuotIs1:	TT ← TT - 1, ZeroBr, CANCELBR[Quot1],	c3;
QuotUnk:	TT ← TT - 1, ZeroBr, BRANCH[Quot0, Quot1],	c3;

Quot0:	Rx ← DLShift1 Rx, SE←0, NegBr, BRANCH[QotLoop, QotEnd],	c1;
Quot1:	Rx ← DLShift1 (Rx - TOS), SE←1, NegBr, BRANCH[QotLoop, QotEnd],	c1;


QotEnd:	S ← S - 2, L2Disp, BRANCH[RemAdj0, RemAdj1],	c2;

RemAdj0:	Rx ← RShift1 Rx, SE←0, BRANCH[QotDiv, QotRem],	c3;
RemAdj1:	Rx ← RShift1 Rx, SE←1, BRANCH[QotDiv, QotRem],	c3;

QotDiv:
	TOS ← ~Q, GOTO[IB.pc1],	c1;
QotRem:
	TOS ← Rx, GOTO[IB.pc1],	c1;
IB.pc1: {common tail}
	PC ← PC + PC16, L2 ← L2.0, IBDisp, GOTO[DNI.nop],	c2;

Qotufn3:	CANCELBR[$, 1],	c3;{division by zero}
Qotufn1a:	GOTO[ufnX2],	c1;{A2 not smallPos}
Qotufn1:	GOTO[ufnX2],	c1;{A1 not smallPos}

{	E N D }