{File name:  Stack.mc
 Author: R. Garner,
 Created: 12 April 1979,
 Description: PrincOps version 3.0 microcode for Dandelion,
   (ADD, SUB, DADD, and DSUB based on Wildflower microcode by R. Levin, 18 Oct 1978),
 Daniels, 15-Jun-83 18:31:45  new instruction set
 Sandman, February 10, 1982  2:17 PM  Restore stack on Divide traps,
 Sandman, January 25, 1982  1:55 PM  Don't advance PC on NILCKL,
 Sandman, Dec 3, 1981 9:02 AM  New instruction set,
 Last Edited: Jim Frandeen, March 26, 1981  3:16 PM: change SuppressTimingWarning to LOOPHOLE[niblTiming],
 Last Edited: Garner, April 8, 1980  5:29 PM,
}


{
REC	Recover
REC2	Recover Two
DIS	Discard
DIS2	Discard Two
EXCH	Exchange
DEXCH	Double Exchange
DUP	Duplicate
DDUP	Double Duplicate

BNDCK	Bounds Check

NEG	Negate
INC	Increment
DEC	Decrement
ADDSB	Add Signed Byte
DINC	Double Increment
DBL	Double
DDBL	Double Double
TRPL	Triple
LINT	Lengthen Integer (ESC opcode)

AND	And
IOR	Inclusive Or
XOR	Exclusive Or (ESC opcode)
SHIFTSB	Shift Signed Byte
ROTATE	Rotate
SHIFT	Shift
DAND	Double And
DIOR	Double Inclusive Or
DXOR	Double Exclusive Or
DSHIFT	Double Shift

ADD	Add
SUB	Subtract
DADD	Double Add
DSUB	Double Subtract
ADC	Add Double to Cardinal
ACD	Add Cardinal to Double

MUL	Multiply
UDIV	Unsigned Divide (ESC opcode)
LUDIV	Long Unsigned Divide (ESC opcode)

DCMP	Double Compare
UDCMP	Unsigned Double Compare

}

{*****************************************************************************
	REC
*****************************************************************************}

@REC:	push,							c1, opcode[242'b];
	STK ← TOS, PC ← PC + PC16, IBDisp, push, GOTO[SLa],		c2;


{*****************************************************************************
	REC2
*****************************************************************************}

@REC2:	push,							c1, opcode[243'b];
	STK ← TOS, push,						c2;
	TOS ← STK, pop, GOTO[@REC],					c3;


{*****************************************************************************
	DIS
*****************************************************************************}

@DIS:	push,							c1, opcode[244'b];
	STK ← TOS, PC ← PC + PC16, IBDisp, pop, GOTO[SLa],		c2;


{*****************************************************************************
	DIS2
*****************************************************************************}

@DIS2:	push,							c1, opcode[245'b];
	STK ← TOS, pop,							c2;
	TOS ← STK, pop, GOTO[@DIS],					c3;


{*****************************************************************************
	EXCH
*****************************************************************************}

@EXCH:	T ← STK, fXpop, fZpop, push, GOTO[LIn],			c1, opcode[246'b];


{*****************************************************************************
	DEXCH
*****************************************************************************}

@DEXCH:	Rx ← STK, pop,						c1, opcode[247'b];
	Q ← STK, pop,							c2;
	T ← STK, fXpop, push,						c3;
	
DDTail: STK ← Rx, push,							c1;
	STK ← TOS, push, PC ← PC + PC16, IBDisp,			c2;
	STK ← T, TOS ← Q, DISPNI[OpTable],				c3;


{*****************************************************************************
	DUP
*****************************************************************************}

@DUP:	fXpop, push,						c1, opcode[250'b];
	PC ← PC+PC16, push, IBDisp,					c2;
	STK ← TOS, push, fZpop, DISPNI[OpTable],			c3;


{*****************************************************************************
	DDUP
*****************************************************************************}

@DDUP:	T ← STK, fXpop, fZpop, push,				c1, opcode[251'b];
	Rx ← T,								c2;
	Q ← TOS, GOTO[DDTail],						c3;


{*****************************************************************************
	EXDIS
*****************************************************************************}

@EXDIS:	pop, GOTO[NegIB],					c1, opcode[252'b];


{*****************************************************************************
	BNDCK
*****************************************************************************}

@BNDCK:	TT ← STK, fXpop, fZpop, push,				c1, opcode[74'b];
	Ybus ← TT-TOS, CarryBr, push,					c2;
	T ← sBoundsTrap, STK ← TOS, pop, BRANCH[NotBND, BND],		c3;

NotBND:	TOS ← TT, pop, GOTO[NegIB],					c1;
BND:	GOTO[Trapc2],							c1;


{*****************************************************************************
	NILCKL
*****************************************************************************}

@NILCKL:
	[] ← STK or TOS, ZeroBr, fXpop, fZpop,		c1, at[6,10,ESC2n];
	T ← sPointerTrap, push, BRANCH[NotNIL, NIL],			c2;
NotNIL:	GOTO[NxtInstc1],						c3;
NIL:	PC ← PC - 1, GOTO[BND],						c3;


{*****************************************************************************
	NEG
*****************************************************************************}

@NEG:	TOS ← -TOS,						c1, opcode[253'b];
NegIB:	IBDisp, fXpop, push,						c2;
NegNI:	PC ← PC+PC16, DISPNI[OpTable],					c3;


{*****************************************************************************
	INC
*****************************************************************************}

@INC:	TOS ← TOS + 1, GOTO[NegIB],				c1, opcode[254'b];


{*****************************************************************************
	DEC
*****************************************************************************}

@DEC:	TOS ← TOS - 1, GOTO[NegIB],				c1, opcode[255'b];


{*****************************************************************************
	ADDSB
*****************************************************************************}

@ADDSB:	T ← ib, XLDisp,						c1, opcode[264'b];
	TT ← ~0FF xor T, BRANCH[AddSBP, AddSBN, XLowNeg],		c2;
AddSBP:	TOS ← TOS + T, GOTO[Addpc2],					c3;
AddSBN:	TOS ← TOS + TT, GOTO[Addpc2],					c3;

Addpc2:	PC ← PC+PC16, GOTO[NegIB],					c1;


{*****************************************************************************
	DINC
*****************************************************************************}

@DINC:	T ← STK, fXpop, fZpop, push,				c1, opcode[256'b];
	T ← T + 1, CarryBr,						c2;
	STK ← T, BRANCH[DINCa, DINCb, 2],				c3;

DINCa:  GOTO[NegIB],							c1;
DINCb:	TOS ← TOS + 1, GOTO[NegIB],					c1;


{*****************************************************************************
	DBL
*****************************************************************************}

@DBL:	TOS ← LShift1 TOS, GOTO[NegIB],				c1, opcode[257'b];


{*****************************************************************************
	DDBL
*****************************************************************************}

@DDBL:	T ← LShift1 STK, SE ← 0, XHDisp,			c1, opcode[260'b];
	STK ← T, fXpop, fZpop, push, BRANCH[DDBLa, DDBLb, 2],		c2;
DDBLa:  TOS ← TOS LShift1, SE ← 0, GOTO[DDBLc],				c3;
DDBLb:	TOS ← TOS LShift1, SE ← 1, GOTO[DDBLc],				c3;

DDBLc: GOTO[NegIB],							c1;


{*****************************************************************************
	TRPL
*****************************************************************************}

@TRPL:	T ← LShift1 TOS, GOTO[add],				c1, opcode[261'b];


{*****************************************************************************
	LINT
*****************************************************************************}

@LINT:	Ybus ← TOS, NegBr, fXpop, push,			c1, at[8,10,ESC1n];
	push, IBDisp, BRANCH[LINTa, LINTb],				c2;
LINTa:	TOS ← 0, push, fZpop, DISPNI[OpTable],				c3;
LINTb:	TOS ← TOS xor ~TOS, push, fZpop, DISPNI[OpTable],		c3;


{*****************************************************************************
	IOR
*****************************************************************************}

@IOR:	TOS ← STK or TOS, pop, GOTO[NegIB],			c1, opcode[263'b];


{*****************************************************************************
	AND
*****************************************************************************}

@AND:	TOS ← STK and TOS, pop, GOTO[NegIB],			c1, opcode[262'b];


{*****************************************************************************
	XOR
*****************************************************************************}

@XOR:	TOS ← STK xor TOS, fXpop, fZpop, GOTO[IBDispOnly], c1, at[2,10,ESC1n];


{*****************************************************************************
	ROTATE
*****************************************************************************}

@ROTATE:
	T ← STK, pop, L2←L2.Rotate,			c1, at[6,10,ESC1n];
	rhT ← 0, Ybus ← TOS, YDisp,					c2;
	TT ← T LRot1, fXpop, push, DISP4[CycleMask],			c3;
	
	GOTO[IBDispOnly],			c1, at[L2.Rotate,10,MaskRet];
	

{*****************************************************************************
	SHIFTSB
*****************************************************************************}

{	shift=	rotate	(shift-1)[12-15]	int mask	final mask
	000F	15 left		14'd		7FFF		8000
	000E	14 left		13'd		3FFF		C000
	  :	   :	    :	    :	    :
	0001	1 left		0		1		FFFE

	0000	none		15'd		FFFF		FFFF
	FFFF	15 left(1 r)	14'd		7FFF		7FFF
	FFFE	14 left(2 r)	13'd		3FFF		3FFF
	    :	    :	    :	    :	    :
	FFF2	2 left	1	3	3
	FFF1  (-15'd)	1 left(15 r)	0	1		1}

{At entry to SHIFT, TOS=shift and STK=u.  For CycleMask, shift is used to determine the rotation and (shift-1) the mask.  FOR SHIFTSB and SHIFT, (shift-1) is placed in RH[T] and used for both shift and mask.  Since we are rotating one less, we rotate it one before calling CycleMask.  (shift-1) is used to determine the mask since this has the same conventions as the size specifier of a field descriptor.  Thus shift=15 implies mask=7FFF, shift=1 implies mask=1, and shift=0 implies a mask of FFFF.

At the beginning of the SHIFT code, a check is made to determine if the absolute value of shift is greater than 15 (which implies a zero result).  If (shift-1) is positive, shifting is canceled if "shift" greater than 15.  If (shift-1) is negative, shifting is canceld if (shift-1) is less than -16  (i.e., (shift-1) + 16 doesn't produce a carry).

Link2 is loaded with the results of the (shift-1) test so that CycleMask returns to either SSBNorm or SSBInv.  For values of shift from 15 to 1, i.e. (shift-1) positive, the mask which CycleMask computes should be inverted, so control goes to ShInvRet in this case.  If (shift-1) was negative, control returns at ShNormRet and the mask in TT is not inverted.}

@SHIFTSB:
	Rx ← ib, XRefBr,					c1, opcode[174'b];
	T  ← ~0FF xor Rx, BRANCH[SSBa, SSBb],				c2;
SSBa:	rhT ← (Rx-1) LRot0, NegBr, LOOPHOLE[niblTiming], GOTO[SSBc],	c3;
SSBb:	rhT ← (T-1) LRot0, NegBr, LOOPHOLE[niblTiming], GOTO[SSBc],	c3;

SSBc:	PC ← PC + PC16, L2←L2.SSBInv, BRANCH[SSBd, SSBe],		c1;
SSBd:	T ← TOS LRot1, Xbus ← rhT, XDisp, GOTO[SSBf],			c2;
SSBe:	T ← TOS LRot1, Xbus ← rhT, XDisp, GOTO[SSBf],			c2;
SSBf:	TT ← LRot1 T, DISP4[CycleMask],				c3;

	{Subroutine CycleMask = 1 click}

	TOS ← ~TT and TOS, fXpop, push, GOTO[NegIB],	c1, at[L2.SSBInv,10,MaskRet];
	TOS ← TOS and TT, fXpop, push, GOTO[NegIB],	c1, at[L2.SSBNorm,10,MaskRet];

	
{*****************************************************************************
	SHIFT
*****************************************************************************}

@SHIFT:	rhT ← Q ← (TOS-1) LRot0, NegBr, LOOPHOLE[niblTiming],	c1, opcode[173'b];
	T ← STK LRot1, pop, L2←L2.SSBInv, BRANCH[Sa, Sb],		c2;
Sa:	[] ← TOS and ~0F, ZeroBr, GOTO[Sc],				c3;
Sb:	[] ← Q + 0F + 1, CarryBr, GOTO[Sc],				c3;

Sc:	TOS ← 0, BRANCH[NegIB, Sd],					c1;
Sd:	Xbus ← rhT, XDisp, GOTO[SSBf],					c2;


{*****************************************************************************
	DAND
*****************************************************************************}

@DAND:	T ← STK, pop,					c1, at[3,10,ESC1n];
	TOS ← TOS and STK, pop,						c2;
	T ← T and STK, fXpop, fZpop, push,				c3;

DANDa:	STK ← T, GOTO[IBDispOnly],					c1;
	

{*****************************************************************************
	DIOR
*****************************************************************************}

@DIOR:	T ← STK, pop,					c1, at[4,10,ESC1n];
	TOS ← TOS or STK, pop,						c2;
	T ← T or STK, fXpop, fZpop, push, GOTO[DANDa],			c3;
	

{*****************************************************************************
	DXOR
*****************************************************************************}

@DXOR:	T ← STK, pop,					c1, at[5,10,ESC1n];
	TOS ← TOS xor STK, pop,						c2;
	T ← T xor STK, fXpop, fZpop, push, GOTO[DANDa],			c3;
	

{*****************************************************************************
	DSHIFT
*****************************************************************************}

@DSHIFT:
	Rx ← -TOS, NegBr, pop,				c1, at[7,10,ESC1n];
	Q ← STK, fXpop, fZpop, push, BRANCH[DSa, DSb],			c2;
DSb:	T ← TOS and 1F, L0←0,						c3;

	Ybus ← TOS xor T, NZeroBr, push,				c1;
	TT ← STK, pop, BRANCH[DSc, DSd],				c2;
DSc:	T ← T - 1, NegBr, L0Disp,					c3;

	STK ← Q, DISP2[DSe],						c1;
DSe:	TT ← DLShift1 TT, Cin ← 1, GOTO[DSc],			c2, at[0,4,DSe];
	TOS ← TT, IBDisp, GOTO[DISPNIonly],			c2, at[1,4,DSe];
	TT ← DRShift1 TT, Cin ← 1, GOTO[DSc],			c2, at[2,4,DSe];
	TOS ← ~TT, IBDisp, GOTO[DISPNIonly],			c2, at[3,4,DSe];

DSa:	T ← Rx and 1F, L0 ← 2,						c3;

	Ybus ← Rx xor T, NZeroBr, push,					c1;
	TT ← ~STK, pop, BRANCH[DSc, DSd],				c2;

DSd:	STK ← TOS ← 0, GOTO[NxtInstc1],					c3;




{*****************************************************************************
	ADD
*****************************************************************************}

@ADD:	T ← STK, pop,						c1, opcode[265'b];
add:	TOS ← T + TOS, IBDisp, fXpop, push, GOTO[NegNI],		c2;


{*****************************************************************************
	SUB
*****************************************************************************}

@SUB:	T ← STK, pop,						c1, opcode[266'b];
	TOS ← T - TOS, IBDisp, fXpop, push, GOTO[NegNI],		c2;


{*****************************************************************************
	DADD
*****************************************************************************}

@DADD:	T ← STK {T ← b}, pop {point to u},			c1, opcode[267'b];
	Q ← STK {Q ← u}, pop {point to v},				c2;
	TT ← STK {TT ← v}, fXpop, fZpop, push,				c3;

DAdd:	T ← T+TT {t←v+b}, CarryBr,					c1;
	STK ← T, PC ← PC+PC16, IBDisp, BRANCH[DANC, DAC],		c2;
DANC:	TOS ← Q+TOS {TOS←u+a}, DISPNI[OpTable],				c3;
DAC:	TOS ← Q+TOS+1 {TOS←u+a+1}, DISPNI[OpTable],			c3;


{*****************************************************************************
	DSUB
*****************************************************************************}

@DSUB:	T ← STK {T ← b}, pop {point to u},			c1, opcode[270'b];
	Q ← STK {Q ← u}, pop {point to v},				c2;
	TT ← STK {TT ← v}, fXpop, fZpop, push, {Underflow?}		c3;

	T ← TT-T {t←v-b}, CarryBr,					c1;
	STK ← T, PC ← PC+PC16, IBDisp, BRANCH[DSNC, DSC],		c2;
DSNC:	TOS ← Q-TOS-1 {TOS←u-a-1}, DISPNI[OpTable],			c3;
DSC:	TOS ← Q-TOS {TOS←u-a}, DISPNI[OpTable],				c3;


{*****************************************************************************
	ADC
*****************************************************************************}

@ADC:	Q ← STK, pop,						c1, opcode[271'b];
	TT ← STK, fXpop, fZpop, push,					c2;
	PC ← PC+PC16,							c3;

ADCa:	TT ← TT + TOS, CarryBr, push, fZpop, {RRIT comes here}		c1;
	STK ← TT, TOS ← 0, IBDisp, BRANCH[DANC, DAC],			c2;


{*****************************************************************************
	ACD
*****************************************************************************}

@ACD:	T ← STK, pop,						c1, opcode[272'b];
	Q ← 0,								c2;
	TT ← STK, fXpop, fZpop, push, GOTO[DAdd],			c3;


{*****************************************************************************
	AL0IB
*****************************************************************************}

@AL0IB:	MAR ← [rhL, L+0], push,					c1, opcode[273'b];
	T ← ib,								c2;
	TOS ← MD, STK ← TOS, push, fZpop,				c3;

	PC ← PC + PC16, GOTO[add],					c1;


{*****************************************************************************
	MUL
*****************************************************************************}
{Timing:	18 clicks - click of init + 16*(click of inner loop) + click of cleanup}

{This code implements a basic add-shift unsigned mulitply.  Q holds the multiplicand (s) and TOS the mulitplier (t).  TT holds the loop count.  T and Q are the concatenated double word result, with the most significant bits being formed in T and the least significant in Q.  The DoubleRightShift1 shifts Cout of the current alu computation into bit 0 of the double length result (T,,Q).  At the end, Q is pushed onto the stack, and T is left above the stack.}


@MUL:	Q ← STK, fXpop, fZpop, push,				c1, opcode[274'b];
	T ← 0, push {point at ~},					c2;
	PC ← PC+PC16,							c3;

	TT ← 10,							c1;
MLoop:	Ybus ← Q and 1, NZeroBr,					c2;
	TT ← TT - 1, ZeroBr, BRANCH[MP0, MP1],				c3;

MP0:	T ← DARShift1 (T+0), BRANCH[MLoop, MLDEnd],			c1;
MP1:	T ← DARShift1 (T + TOS), BRANCH[MLoop, MLDEnd],			c1;
MLDEnd:	STK ← T, pop, IBDisp,						c2;
	TOS ← ~Q, pop, DISPNI[OpTable],					c3;


{*****************************************************************************
	UDIV
*****************************************************************************}

@UDIV:	T ← 0, L0←0,					c1, at[0C,10,ESC1n];
	Q ← STK, fXpop, fZpop, push, GOTO[LDiv],			c2;


{*****************************************************************************

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

@LUDIV:	T ← STK, pop, L0←2,				c1, at[0D,10,ESC1n];
	Q ← STK {long.low}, fXpop, fZpop, push,				c2;
LDiv:	Ybus ← TOS, ZeroBr,						c3;

	Ybus ← T - TOS, CarryBr, L0Disp, BRANCH[LDivNoZD, LDivZD],	c1;
LDivNoZD:
	TT ← sDivCheckTrap, DISP2[LDivOK],				c2;
LDivOK:	TT ← 10, GOTO[Quot0],				c3, at[0,4,LDivOK];
	TT ← 10, GOTO[Quot0],				c3, at[2,4,LDivOK];

LDivLoop:
	Ybus ← T - TOS, CarryBr, BRANCH[QuotUnk, QuotIs1],	c2, at[0,2,LDivEnd];
QuotUnk:
	TT ← TT - 1, ZeroBr, BRANCH[Quot0, Quot1, YOdd],	c3, at[0,2,QuotIs1];
QuotIs1:
	TT ← TT - 1, ZeroBr, CANCELBR[Quot1],			c3, at[1,2,QuotUnk];

Quot0:	T ← DLShift1 T, SE←0, NegBr, BRANCH[LDivLoop, LDivEnd],		c1;
Quot1:	T ← DLShift1 (T - TOS), SE←1, NegBr, BRANCH[LDivLoop, LDivEnd],	c1;
LDivEnd:
	push {point at rem}, BRANCH[RemAdj0, RemAdj1],	c2, at[1,2,LDivLoop];
RemAdj0:
	T ← RShift1 T, SE←0, GOTO[DEnd],				c3;
RemAdj1:
	T ← RShift1 T, SE←1, GOTO[DEnd],				c3;

DEnd:	GOTO[MLDEnd],							c1;

LDivZD:	TT ← sDivZeroTrap, DISP2[LDivOv,1],			c2, at[1,2,LDivNoZD];

LDivOv:	T ← TT, GOTO[DivTrap],				c3, at[1,4,LDivOK];
	T ← TT, push, GOTO[DivTrap],			c3, at[3,4,LDivOK];

DivTrap:
	PC ← PC - 1, GOTO[Trapc2],				c1;

{*****************************************************************************
	UDCMP
*****************************************************************************}
@UDCMP:	T ← STK {s}, pop,					c1, opcode[276'b];
	TT ← STK {x}, pop,						c2;
comp:	TT ← DARShift1 (TT-TOS)  {x-r}, ZeroBr,				c3;

	Ybus ← TT, NegBr {carry of x-r}, BRANCH[CHighNE, CompLow],	c1;
CHighNE:
	PC ← PC+PC16, IBDisp, pop, BRANCH[CompL, CompG],		c2;

CompL:	TOS ← ~TOS xor TOS, fXpop, push, DISPNI[OpTable],		c3;
CompG:	TOS ← 1, fXpop, push, DISPNI[OpTable],				c3;

CompLow:
	TT ← STK {y}, pop, CANCELBR[$],					c2;
	TT ← DARShift1 (TT-T)  {y-s}, ZeroBr,				c3;

	Ybus ← TT, NegBr {carry of y-s}, BRANCH[CLowNE, CompE],		c1;
CLowNE:	PC ← PC+PC16, IBDisp, BRANCH[CompL, CompG],			c2;

CompE:	TOS ← 0, IBDisp, fXpop, push, CANCELBR[NegNI],			c2;


{*****************************************************************************
	DCMP
*****************************************************************************}

@DCMP:	T ← STK {s}, pop,					c1, opcode[275'b];
	Q ← STK {x}, pop,						c2;
	TT ← u8000,							c3;

	TOS ← TOS + TT,							c1;
	TT ← TT + Q,  GOTO[comp]					c2;