{File name: Stack.mc
Last Edited: Jim Frandeen, March 26, 1981 3:16 PM: change SuppressTimingWarning to LOOPHOLE[niblTiming],
Last Edited: Garner, April 8, 1980 5:29 PM,
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),
}
{The Stack mesa op-codes consist of the following.
OP val bytes stk time
PUSH 164'b 1 +1 1
POP 165'b 1 1 1
EXCH 166'b 1 2+2 1
DUP 170'b 1 1+2 1
NILCK 171'b 1 1+1 2
NILCKL 172'b 1 2+2 2
BNDCK 173'b 1 2+1 2
NEG 256'b 1 1+1 1
INC 257'b 1 1+1 1
DEC xxxx 1 1+1 1
ADD2 xxxx 1 1+1 1
ADDSB xxxx 2 1+1 2
DBL 253'b 1 1+1 1
AND 260'b 1 2+1 1
OR 261'b 1 2+1 1
XOR 262'b 1 2+1 1
SHIFT 263'b 1 2+1 3
ADD 250'b 1 2+1 1
ADD01 271'b 1 2+1 1 {NOT in PrincOps}
SUB 251'b 1 2+1 1
DADD 264'b 1 4+2 3
DSUB 265'b 1 4+2 3
MUL 252'b 1 2+1 18
DIV 254'b 1 2+1 20
SDIV xxxx 1 2+1 x
LDIV 255'b 1 3+1 20
MAX xxxx 1 2+1 x
UMAX xxxx 1 2+1 x
MIN xxxx 1 2+1 x
UMIN xxxx 1 2+1 x
DCOMP 266'b 1 4+1 2/3
DUCOMP 267'b 1 4+1 3/4
}
{5.1 Stack Primitives}
{
PUSH
}
{Timing: 1 click}
{In order to maintain the Stack, TOS is saved into STK.}
{ entry: exit:
TOS = | v | | u |
STK = | u | | u |
| ~ | --> | v |
--> | t | | t | }
@PUSH: push {point to ~}, c1, opcode[164'b];
STK ← TOS, PC ← PC + PC16, IBDisp, push, GOTO[SLTail], c2;
{
POP
}
{Timing: 1 click}
{In order to maintain the Stack, TOS is saved into STK.}
{ entry: exit:
TOS = | v | | u |
STK = | ~ | | v |
--> | u | | u |
| t | --> | t | }
@POP: T ← STK, push, c1, opcode[165'b];
STK ← TOS, PC ← PC + PC16, IBDisp, pop, c2;
TOS ← T, pop, DISPNI[OpTable], c3;
{
EXCH
}
{Timing: 1 click}
{ entry: exit:
TOS = | v | | u |
STK = | ~ | | ~ |
--> | u | --> | v |
| t | | t | }
@EXCH: T ← STK {u}, fXpop, fZpop, push, {Underflow?} GOTO[LInTail], c1, opcode[166'b];
{
DUP
}
{Timing: 1 click}
{ entry: exit:
TOS = | v | | v |
STK = | ~ | --> | v |
--> | u | | u |
| t | | t | }
@DUP: fXpop, push, {Underflow?} c1, opcode[170'b];
PC ← PC+PC16, push, IBDisp, c2;
STK ← TOS, push, fZpop, {Overflow?} DISPNI[OpTable], c3;
{5.2 Check Instructions}
{
NILCK
}
{Timing: 2 clicks}
@NILCK: fXpop, push{underflow?}, c1, opcode[171'b];
[] ← TOS, ZeroBr, push, c2;
NilTest: T ← sPointerFault, STK ← TOS, pop, BRANCH[NotNIL, NIL], c3;
NotNIL: GOTO[NegIB], c1;
NIL: L2 ← L2.TRAPStashr, GOTO[Trapc2], c1;
{
NILCKL
}
{Timing: 2 clicks}
@NILCKL: fXpop, fZpop, push, c1, opcode[172'b];
[] ← STK or TOS, ZeroBr, push, GOTO[NilTest], c2;
{
BNDCK
}
{Timing: 2 clicks}
@BNDCK: TT ← STK, fXpop, fZpop, push, {underflow?} c1, opcode[173'b];
[] ← TT-TOS, CarryBr, push, c2;
T ← sBoundsFault, STK ← TOS, pop, BRANCH[NotBND, BND], c3;
NotBND: TOS ← TT, pop, GOTO[NegIB], c1;
BND: L2 ← L2.TRAPStashr, GOTO[Trapc2], c1;
{5.3 Unary Operations}
{Stack underflow is checked at NegIB.}
{
NEG
}
{Timing: 1 click}
@NEG: TOS ← -TOS, c1, opcode[256'b];
NegIB: IBDisp, fXpop, push, {Underflow?} c2;
NegNI: PC ← PC+PC16, DISPNI[OpTable], c3;
{
INC
}
{Timing: 1 click}
@INC: TOS ← TOS + 1, GOTO[NegIB], c1, opcode[257'b];
{
DBL
}
{Timing: 1 click}
@DBL: TOS ← LShift1 TOS, GOTO[NegIB], c1, opcode[253'b];
{NOT IN MESA 5.0
{
DEC
}
{Timing: 1 click}
@DEC: TOS ← TOS - 1, GOTO[NegIB], c1, opcode[406'b];
{
ADD2
}
{Timing: 1 click}
@ADD2: TOS ← TOS + 2, GOTO[NegIB], c1, opcode[216];
{
ADDSB
}
{Timing: 2 clicks}
@ADDSB: T ← ib, XLDisp, c1, opcode[217];
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, {finish PC update at NegIB} GOTO[NegIB], c1;
}
{5.4 Logic Operations}
{ entry: exit:
TOS = | v | | v * w |
STK = | ~ | | ~ |
--> | w | | w |
| t | --> | t | }
{Stack underflow is checked at NegIB.}
{
OR
}
{Timing: 1 click}
@OR: TOS ← STK or TOS, pop {point to t}, GOTO[NegIB], c1, opcode[261'b];
{
AND
}
{Timing: 1 click}
@AND: TOS ← STK and TOS, pop {point to t}, GOTO[NegIB], c1, opcode[260'b];
{
XOR
}
{Timing: 1 click}
@XOR: TOS ← STK xor TOS, pop {point to t}, GOTO[NegIB], c1, opcode[262'b];
{
SHIFT
}
{Timing: 3 clicks - |shift| <= 15,
3 clicks - |shift| > 15}
{ entry: exit:
TOS = | shift | | Shift[u] |
STK = | ~ | | ~ |
--> | u | | u |
| t | --> | t | }
{ 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 right) 14'd 7FFF 7FFF
FFFE 14 left(2 right) 13'd 3FFF 3FFF
: : : : :
FFF2 2 left 1 3 3
FFF1 (15'd) 1 left(15 right) 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. Thus, (shift-1) is placed in RH[T], and shift is dispatched on into 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).
Link1 is loaded with the results of the (shift-1) test so that CycleMask returns to either ShNormRet or ShInvRet. 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.}
@SHIFT: TT ← LRot1 STK, c1, opcode[263'b];
rhT ← Q ← (TOS 1) LRot0, NegBr, LOOPHOLE[niblTiming], c2;
T ← STK, [] ← TOS, YDisp, pCall2, pop, BRANCH[ShiftLeft, ShiftRight], c3;
ShiftLeft: [] ← ~0F and TOS, ZeroBr, DISP4[CycleMask], c1, at[L2.shiftInv,10,ShiftRight];
ShiftRight: [] ← Q + 0F + 1, CarryBr, DISP4[CycleMask], c1, at[L2.shiftNorm,10,ShiftLeft];
{Subroutine CycleMask = 1 click}
ShInvRet: TOS ← ~TT and TOS, IBDisp, fXpop, push, {Underflow?} GOTO[NegNI], c2, at[L2.shiftInv,10,MaskRet];
ShNormRet: TOS ← TT and TOS, IBDisp, fXpop, push, {Underflow?} GOTO[NegNI], c2, at[L2.shiftNorm,10,MaskRet];
{5.5 Arithmetic Operations}
{ entry: exit:
TOS = | t | | s * t |
STK = | ~ | | ~ |
--> | s | | s |
| r | --> | r | }
{
ADD
}
{Timing: 1 click}
@ADD: T ← STK, pop, c1, opcode[250'b];
add: TOS ← T + TOS, IBDisp, fXpop, push, {Underflow?} GOTO[NegNI], c2;
{NOT in PrincOps}
@ADD01: T ← STK, pop, GOTO[add], c1, opcode[270'b];
{
SUB
}
{Timing: 1 click}
@SUB: T ← STK, pop, c1, opcode[251'b];
TOS ← T - TOS, IBDisp, fXpop, push, {Underflow?} GOTO[NegNI], c2;
{
DADD
}
{Timing: 3 clicks}
{DADD computes the double length sum uv+ab, and leaves carry above stack}
{ entry: exit:
TOS = | a | | u+a |
STK = | ~ | | ~ |
--> | b | | carry |
| u | | u |
| v | --> | v+b | }
@DADD: T ← STK {T ← b}, pop {point to u}, c1, opcode[264'b];
Q ← STK {Q ← u}, pop {point to v}, c2;
TT ← STK {TT ← v}, fXpop, fZpop, push, {Underflow?} c3;
T ← T+TT {t←v+b}, CarryBr, c1;
STK ← T, push {point to u}, BRANCH[DaddLowNC, DaddLowC], c2;
DaddLowNC: TOS ← Q+TOS {TOS←u+a}, CarryBr, GOTO[DHigh], c3;
DaddLowC: TOS ← Q+TOS+1 {TOS←u+a+1}, CarryBr, GOTO[DHigh], c3;
DHigh: T ← 1, push {point to carry}, BRANCH[DHighNC, DHighC], c1;
DHighNC: STK ← 0, IBDisp, pop {point to u}, GOTO[DNI], c2;
DHighC: STK ← T, IBDisp, pop {point to u}, GOTO[DNI], c2;
DNI: PC ← PC+PC16, pop {point to v+b}, DISPNI[OpTable], c3;
{
DSUB
}
{Timing: 3 clicks}
{DSUB computes the double length difference uvab, and leaves carry above stack}
{ entry: exit:
TOS = | a | | u-a |
STK = | ~ | | ~ |
--> | b | | carry |
| u | | u |
| v | --> | v-b | }
@DSUB: T ← STK {T ← b}, pop {point to u}, c1, opcode[265'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, push {point to u}, BRANCH[DsubLowNC, DsubLowC], c2;
DsubLowNC: TOS ← Q-TOS-1 {TOS←u-a-1}, CarryBr, GOTO[DHigh], c3, ;
DsubLowC: TOS ← Q-TOS {TOS←u-a}, CarryBr, GOTO[DHigh], c3, ;
{
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.}
{ entry: exit:
TOS = | t | | long.low |
STK = | ~ | | long.high |
--> | s | | s |
| w | --> | w | }
@MUL: Q ← STK, fXpop, fZpop, push, {Underflow?} c1, opcode[252'b];
T ← 0, push {point at ~}, c2;
TT ← 10, c3;
MulLoop: [] ← Q and 1, NZeroBr, c1, at[0,2,MLDEnd];
TT ← TT 1, ZeroBr, BRANCH[MPlier0, MPlier1], c2;
MPlier0: T ← DARShift1 (T+0), BRANCH[MulLoop, MLDEnd], c3;
MPlier1: T ← DARShift1 (T + TOS), BRANCH[MulLoop, MLDEnd], c3;
MLDEnd: STK ← T {long.high/rem}, pop {point at s}, c1, at[1,2,MulLoop];
TOS ← ~Q {long.low/quot}, pop {point at w}, IBDisp, GOTO[NegNI], c2;
{
DIV
}
{Timing: 20 clicks - No Trap = 2 clicks of init + 16*(click of inner loop) + 2 clicks of cleanup}
{ entry: normal exit:
TOS = | t | | quot |
STK = | | | rem |
--> | s | | quot |
| ~ | --> | ~ | }
@DIV: T ← 0, GOTO[Ldiv], c1, opcode[254'b];
{NOT IN MESA 5.0
{
SDIV
}
{Timing: 20 clicks = 2 clicks of init + 16*(click of inner loop) + 2 clicks of cleanup}
@SDIV: xxxxxx, c1, opcode[407'b];
}
{
LDIV
}
{Timing: 20 clicks = 2 clicks of init + 16*(click of inner loop) + 2 clicks of cleanup}
{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.}
{ entry: normal exit:
TOS = | t | | quot |
STK = --> | long.high | | rem |
| long.low | | quot |
| w | --> | w | }
@LDIV: T ← STK {long.high}, pop {point at long.low}, c1, opcode[255'b];
Ldiv: Q ← STK {long.low}, fXpop, fZpop, push, {Underflow?} c2;
[] ← TOS, ZeroBr, c3;
[] ← T TOS, CarryBr, BRANCH[LDivNoZD, LDivZD], c1;
LDivNoZD: BRANCH[LDivOK, LDivOv], c2;
LDivOK: TT ← 0F + 1, GOTO[Quot0], c3;
LDivLoop: [] ← 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];
Quot0: T ← DLShift1 T, SE←0, NegBr, BRANCH[LDivLoop, LDivEnd], c1;
Quot1: T ← DLShift1 (T TOS), SE←1, NegBr, BRANCH[LDivLoop, LDivEnd], c1;
QuotIs1: TT ← TT 1, ZeroBr, CANCELBR[Quot1], c3, at[1,2,QuotUnk];
LDivEnd: push {point at rem}, BRANCH[RemAdj0, RemAdj1], c2, at[1,2,LDivLoop];
RemAdj0: T ← RShift1 T, SE←0, GOTO[MLDEnd], c3;
RemAdj1: T ← RShift1 T, SE←1, GOTO[MLDEnd], c3;
LDivZD: T ← sZeroDivisor, pop, CANCELBR[Trapc3], c2, at[1,2,LDivNoZD];
LDivOv: T ← sDivideCheck, pop, GOTO[Trapc1], c3, at[1,2,LDivOK];
{5.6 Comparison}
{
DUCOMP
}
{Timing: 2 clicks - High Halfs not equal
3 clicks - High Halfs equal}
{ entry: exit:
TOS = | r | | comp |
STK = --> | s | | s |
| x | | x |
| y | | y |
| ~ | --> | ~ | }
{SELECT TRUE FROM
(x<r) OR (x=r AND y<s) => PUSH[-1];
(x=r AND y=s) => PUSH[0];
(x>r) OR (x=r AND y>s) => PUSH[1];
ENDCASE;}
@DUCOMP: T ← STK {s}, pop, c1, opcode[267'b];
TT ← STK {x}, pop, c2;
comp: TT ← DARShift1 (TT-TOS) {x-r}, ZeroBr, c3;
[] ← TT, NegBr {carry of x-r}, BRANCH[CHighNE, CompLow], c1;
CHighNE: PC ← PC+0, Cin←pc16, IBDisp, pop {skip y}, 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;
[] ← 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;
{
DCOMP
}
{Timing: 3 clicks - High Halfs not equal
4 clicks - High Halfs equal}
@DCOMP: T ← STK {s}, pop, c1, opcode[266'b];
Q ← STK {x}, pop, c2;
TT ← RShift1 0, SE←1 {TT←8000}, c3;
TOS ← TOS + TT {r+8000}, c1;
TT ← TT + Q {x+8000}, GOTO[comp] c2;