{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;