*----------------------------------------------------------- Title[Stack.mc...November 23, 1982 5:12 PM...Taft]; * Stack instructions (PrincOps, chapter 5) *----------------------------------------------------------- % CONTENTS, by order of occurence Stack primitives REC Recover REC2 Recover Two DIS Discard DIS2 Discard Two EXCH Exchange DEXCH Double Exchange DUP Duplicate DDUP Double Duplicate EXDIS Exchange Discard Check instructions BNDCK Bounds Check NILCKL Nil Check Long Unary operations NEG Negate INC Increment DINC Double Increment ADDSB Add Signed Byte DEC Decrement DBL Double DDBL Double Double TRPL Triple LINT Lengthen Integer SHIFTSB Shift Signed Byte Logical operations AND And DAND Double And IOR Inclusive Or DIOR Double Inclusive Or XOR Exclusive Or DXOR Double Exclusive Or SHIFT Shift DSHIFT Double Shift ROTATE Rotate Arithmetic operations ADD Add SUB Subtract DADD Double Add DSUB Double Subtract ADC Add Double to Cardinal ACD Add Cardinal to Double MUL Multiply DMUL Double Multiply (not implemented) SDIV Signed Divide UDIV Unsigned Divide LUDIV Long Unsigned Divide SDDIV Signed Double Divide (not implemented) UDDIV Unsigned Double Divide (not implemented) DCMP Double Compare UDCMP Unsigned Double Compare % TopLevel; *----------------------------------------------------------- IFUR[REC, 1]; * Recover * SP _ SP+1; * This is legal (to a maximum of two levels): * 1. After instructions that only pop the stack (i.e., that don't * push any results onto it), or * 2. After instructions that explicitly leave results above TOS (e.g., DIV). *----------------------------------------------------------- StkP+1, NextOpcode; *----------------------------------------------------------- IFUR[REC2, 1]; * Recover Two * SP _ SP+2; *----------------------------------------------------------- StkP+2, NextOpcode; *----------------------------------------------------------- IFUR[DIS, 1]; * Discard * SP _ SP-1; *----------------------------------------------------------- StkP-1, NextOpcode; *----------------------------------------------------------- IFUR[DIS2, 1]; * Discard Two * SP _ SP-2; *----------------------------------------------------------- StkP-2, NextOpcode; *----------------------------------------------------------- IFUR[EXCH, 1]; * Exchange * v: UNSPECIFIED _ Pop[]; u: UNSPECIFIED _ Pop[]; Push[v]; Push[u]; *----------------------------------------------------------- T_ Stack&-1, Call[StackSwap]; StackGetsQ: Stack_ Q, NextOpcode; *----------------------------------------------------------- IFUR[DEXCH, 1]; * Double Exchange * v: LONG UNSPECIFIED _ PopLong[]; u: LONG UNSPECIFIED _ PopLong[]; * PushLong[v]; PushLong[u]; *----------------------------------------------------------- T_ Stack&-2, Call[StackSwap]; T_ Stack&-2; Stack&+2_ T, Cnt_ Stack&+2; Stack&+1_ Cnt, Branch[StackGetsQ]; Subroutine; StackSwap: Stack&+1_ T, Q_ Stack&+1, Return; TopLevel; *----------------------------------------------------------- IFUR[DUP, 1]; * Duplicate * u: UNSPECIFIED _ Pop[]; Push[u]; Push[u]; *----------------------------------------------------------- Stack+1_ Stack&+1, NextOpcode; *----------------------------------------------------------- IFUR[DDUP, 1]; * Double Duplicate * u: LONG UNSPECIFIED _ PopLong[]; PushLong[u]; PushLong[u]; *----------------------------------------------------------- T_ Stack&-1; Stack+2_ Stack&+2, Branch[ExitPushT]; *----------------------------------------------------------- IFUR[EXDIS, 1]; * Exchange Discard * u: UNSPECIFIED _ Pop[]; [] _ Pop[]; Push[u]; *----------------------------------------------------------- Stack-1_ Stack&-1, NextOpcode; *----------------------------------------------------------- IFUR[BNDCK, 1]; * Bounds Check * range: CARDINAL _ Pop[]; index: CARDINAL _ Pop[]; Push[index]; * IF index>=range THEN BoundsTrap[]; *----------------------------------------------------------- T_ Stack&-1; PD_ T-(Stack)-1; * Carry_ 1 iff index0, right if shift<0. *----------------------------------------------------------- T_ Stack&-1; * If left shift (shift >= 0): LCY[T, R, shift mod 20B] -- T=0 in both cases * If right shift (shift < 0): LCY[R, T, shift mod 20B] ShiftStackByT: RTemp0_ LSH[T, 10], Branch[.+2, ALU<0]; * Position shift to count field PD_ (17S)-T, Branch[.+2]; * Test for shift > 15 PD_ (17S)+T; * Test for shift < -15 T_ (RTemp0) XOR (20000C), Branch[ShiftGr15, ALU<0]; ShiftStackWithShCT: T_ A0, ShC_ T; ShiftTail: Stack_ ShiftNoMask[Stack]; RestoreStdShC: ShC_ StdShC, NextOpcode; * |Shift| > 15 ShiftGr15: Stack_ A0, NextOpcode; *----------------------------------------------------------- NewOp; ESCEntry[DSHIFT], * Double Shift * shift: INTEGER _ Pop[]; u: LONG UNSPECIFIED _ PopLong[]; PushLong[LongShift[u, shift]]; *----------------------------------------------------------- RTemp0_ T; * Placement; ESCEntry: T = STK[StkP] T_ T+(37C), StkP-2; * See if shift IN [-37B..37B] PD_ T-(77C); T_ DPF[RTemp0, 4, 10], * Position shift to ShC count field Branch[DShiftZero, Carry]; * Branch if out of range RTemp0_ LSH[RTemp0, 13], * Position 20 bit to sign Branch[DShiftRight, R<0]; * Branch if shift negative * Left shift. Set up ShC for LCY[T, R, shift MOD 20B] T_ T OR (20000C); T_ A0, ShC_ T, RTemp0, DblBranch[DShL0to17, DShL20to37, R>=0]; * Right shift. Set up ShC for LCY[R, T, shift MOD 20B] DShiftRight: T_ T OR (10000C), StkP+1; T_ A0, ShC_ T, RTemp0, DblBranch[DShR1to17, DShR20to37, R<0]; * Shift IN [0..17] (left shift). LCY[T, R, shift MOD 20B]. * StkP addresses low-order word; T=0 DShL0to17: Stack&+1_ ShiftNoMask[Stack&+1], Q_ Stack&+1; * low_ LCY[0, low, shift MOD 20B] T_ Q, Branch[ShiftTail]; * T_ low; high_ LCY[low, high, shift MOD 20B] * Shift IN [20..37] (left shift). LCY[T, R, shift MOD 20B]. * StkP addresses low-order word DShL20to37: T_ Stack&+1_ A0, Q_ Stack&+1; * low_ 0 Stack_ Q, Branch[ShiftTail]; * high_ low; high_ LCY[0, low, shift MOD 20B] * Shift IN [-1..-20] (right shift). LCY[R, T, shift MOD 20B]. * StkP addresses high-order word; T=0 DShR1to17: Stack&-1_ ShiftNoMask[Stack&-1], Q_ Stack&-1; * high_ LCY[high, 0, shift MOD 20B] T_ Q; * T_ high RShiftTail: Stack&+1_ ShiftNoMask[Stack&+1], * low_ LCY[low, high, shift MOD 20B] Branch[RestoreStdShC]; * Shift IN [-21..-37] (right shift). LCY[R, T, shift MOD 20B]. * StkP addresses high-order word DShR20to37: T_ Stack&-1_ A0, Q_ Stack&-1; * high_ 0 Stack_ Q, Branch[RShiftTail]; * low_ high; low_ LCY[high, 0, shift MOD 20B] * Shift NOT IN [-37B..37B]. Just set the answer to zero. DShiftZero: Stack_ T_ A0, Branch[ExitPushT]; *----------------------------------------------------------- NewOp; ESCEntry[ROTATE]; * Rotate * rotate: INTEGER _ Pop[]; u: UNSPECIFIED _ Pop[]; Push[Rotate[u, shift]]; * Rotates left if shift>0, right if shift<0. *----------------------------------------------------------- * Set to perform LCY[R, R, shift mod 20B] T_ DPF[Stack&-1, 4, 10], Branch[ShiftStackWithShCT]; *----------------------------------------------------------- IFUR[ADD, 1]; * Add * t: CARDINAL _ Pop[]; s: CARDINAL _ Pop[]; Push[s+t]; *----------------------------------------------------------- T_ A_ Stack&-1; * Carry_ 0 (so AddTail can be used by DADD) AddTail: Stack_ (Stack)+T, XorSavedCarry, NextOpcode; *----------------------------------------------------------- IFUR[SUB, 1]; * Subtract * t: CARDINAL _ Pop[]; s: CARDINAL _ Pop[]; Push[s-t]; *----------------------------------------------------------- T_ (Stack&-1)-(0C); * Carry_ 1 (so SubTail can be used by DSUB) SubTail: Stack_ (Stack)-T-1, XorSavedCarry, NextOpcode; *----------------------------------------------------------- IFUR[DADD, 1]; * Double Add * t: LONG CARDINAL _ PopLong[]; s: LONG CARDINAL _ PopLong[]; PushLong[s+t]; *----------------------------------------------------------- T_ Stack&-1, Call[QGStackPop2]; DAddTail: Stack&+1_ (Stack&+1)+Q, Branch[AddTail]; *----------------------------------------------------------- IFUR[DSUB, 1]; * Double Subtract * t: LONG CARDINAL _ PopLong[]; s: LONG CARDINAL _ PopLong[]; PushLong[s-t]; *----------------------------------------------------------- T_ Stack&-1, Call[QGStackPop2]; Stack&+1_ (Stack&+1)-Q, Branch[SubTail]; *----------------------------------------------------------- IFUR[ADC, 1]; * Add Double to Cardinal * t: CARDINAL _ Pop[]; s: LONG CARDINAL _ PopLong[]; PushLong[s+LONG[t]]; *----------------------------------------------------------- T_ Stack&-2; ADCTail: * Here from DINC Stack&+1_ (Stack&+1)+T; Stack_ A_ Stack, XorSavedCarry, NextOpcode; *----------------------------------------------------------- IFUR[ACD, 1]; * Add Cardinal to Double * t: LONG CARDINAL _ PopLong[]; s: CARDINAL _ Pop[]; PushLong[LONG[s]+t]; *----------------------------------------------------------- T_ Stack&-1; Stack&-1_ A0, Q_ Stack&-1, Branch[DAddTail]; *----------------------------------------------------------- QGStackPop2: * Executes "Q_ Stack&-2" * Common part of setup for several Double logical and arithmetic instructions. *----------------------------------------------------------- Subroutine; Q_ Stack&-2, Return; TopLevel; *----------------------------------------------------------- IFUR[MUL, 1]; * Multiply * t: CARDINAL _ Pop[]; s: CARDINAL _ Pop[]; PushLong[LONG[s]*t]; [] _ Pop[]; * Note: computes 32-bit result and leaves high word above TOS. *----------------------------------------------------------- Q_ Stack&-1; T_ Stack&+1, Call[MulSub]; * T,,Q _ Q*T Stack&-1_ T, Branch[StackGetsQ], DispTable[1, 2, 2]; * Squash leftover Multiply dispatch *----------------------------------------------------------- ESCOpcodeUnimpl[DMUL]; * Double Multiply * t: LONG CARDINAL _ PopLong[]; s: LONG CARDINAL _ PopLong[]; * PushLong[LONG[s]*t]; * Note: returns only low 32 bits of (potentially) 64-bit result. *----------------------------------------------------------- *----------------------------------------------------------- MulSub: * Unsigned 16-bit by 16-bit multiply subroutine * Entry conditions: * T = multiplicand * Q = multiplier * Exit conditions: * T = high-order 16 bits of product * Q = low-order 16 bits of product * May leave a Q[14] dispatch pending, which must be squashed by the caller. * Clobbers MulDivArg *----------------------------------------------------------- Subroutine; MulDivArg_ Q; MulDivArg, Cnt_ 16S, Branch[.+2, R odd]; MulDivArg_ A0, Multiply, Branch[M0]; MulDivArg_ A0, Multiply, Branch[M1]; *----------------------------------------------------------- DispTable[4]; * here after Q[14] was 0 (no add) and continue M0: MulDivArg_ (A_ MulDivArg), Multiply, DblBranch[M0E, M0, Cnt=0&-1]; * here after Q[14] was 0 (no add) and exit M0E: MulDivArg_ (A_ MulDivArg), Multiply, Branch[MXIT0]; * here after Q[14] was 1 (add) and continue M1: MulDivArg_ (MulDivArg)+T, Multiply, DblBranch[M0E, M0, Cnt=0&-1]; * here after Q[14] was 1 (add) and exit MulDivArg_ (MulDivArg)+T, Multiply, Branch[MXIT0]; *----------------------------------------------------------- * This squashes one Multiply dispatch, but there is still one pending. MXIT0: T_ MulDivArg, DispTable[1, 2, 2], Return; TopLevel; *----------------------------------------------------------- NewOp; ESCEntry[SDIV]; * Signed Divide * k: INTEGER _ Pop[]; j: INTEGER _ Pop[]; * IF k=0 THEN DivZeroTrap[]; * Push[j/k]; Push[j MOD k]; [] _ Pop[]; *----------------------------------------------------------- MulDivArg_ Stack&-1, Branch[.+2, R>=0]; MulDivArg_ (0S)-(MulDivArg); * Divisor negative, make positive T_ Stack&+1; RTemp0_ (Stack&-1) XOR T, Branch[.+2, ALU>=0]; * Remember XOR of signs T_ (0S)-T; * Dividend negative T_ A0, Q_ T; * DivSub computes [Q: quotient, T: remainder] _ (T,,Q) / MulDivArg * It does not return but traps directly if an overflow occurs. Call[DivSub]; Stack+1_ T, Stack&+1, Branch[.+2, R>=0]; * Remainder should have sign of dividend Stack_ (0S)-(Stack); T_ Q, RTemp0, Branch[.+2, R>=0]; * Quotient sign should be XOR of operand signs T_ (0S)-T; Stack-1_ T, NextOpcode; *----------------------------------------------------------- NewOp; ESCEntry[UDIV], * Unsigned Divide * t: CARDINAL _ Pop[]; s: CARDINAL _ Pop[]; * IF t=0 THEN DivZeroTrap[]; * Push[s/t]; Push[s MOD t]; [] _ Pop[]; *----------------------------------------------------------- T_ A0; MulDivArg_ Stack&-1, Branch[DoLongUDiv]; *----------------------------------------------------------- NewOp; ESCEntry[LUDIV]; * Long Unsigned Divide * t: CARDINAL _ Pop[]; s: LONG CARDINAL _ PopLong[]; * IF t=0 THEN DivZeroTrap[]; * IF HighHalf[s]>=t THEN DivideCheckTrap[]; * Push[LowHalf[s/LONG[t]]; Push[LowHalf[s MOD LONG[t]]; [] _ Pop[]; *----------------------------------------------------------- MulDivArg_ Stack&-1; T_ Stack&-1; * DivSub computes [Q: quotient, T: remainder] _ (T,,Q) / MulDivArg * It does not return but traps directly if an overflow occurs. DoLongUDiv: Q_ Stack&+1, Call[DivSub]; Stack&-1_ T, Branch[StackGetsQ]; * Leave remainder above TOS *----------------------------------------------------------- ESCOpcodeUnimpl[SDDIV]; * Signed Double Divide * k: LONG INTEGER _ PopLong[]; j: LONG INTEGER _ PopLong[]; * IF k=0 THEN DivZeroTrap[]; * PushLong[j/k]; PushLong[j MOD k]; [] _ PopLong; *----------------------------------------------------------- *----------------------------------------------------------- ESCOpcodeUnimpl[UDDIV]; * Unsigned Double Divide * t: LONG CARDINAL _ PopLong[]; s: LONG CARDINAL _ PopLong[]; * IF t=0 THEN DivZeroTrap[]; * PushLong[s/t]; PushLong[s MOD t]; [] _ PopLong; *----------------------------------------------------------- *----------------------------------------------------------- DivSub: * Unsigned 32-bit by 16-bit divide * Enter: T,,Q = dividend * MulDivArg = divisor * Normal exit: T=remainder, Q=quotient * Failure: does not return but rather generates one of the following traps: * sDivZeroTrap division by zero * sDivCheckTrap high half of dividend >= divisor * Clobbers MulDivArg, DivTemp *----------------------------------------------------------- Subroutine; PD_ T-(MulDivArg); * Trap if T >= MulDivArg (unsigned) PD_ MulDivArg, Branch[DivTrap, Carry]; Cnt_ 17S, PD_ T, Branch[Dneg, ALU<0]; T_ T-(MulDivArg), Divide, DblBranch[NormalExit, D3, Cnt=0&-1]; D2: T_ T+(MulDivArg), Divide, Branch[NormalExit, Cnt=0&-1]; D3: Branch[D2, Carry']; T_ T-(MulDivArg), Divide, Branch[D3, Cnt#0&-1]; NormalExit: Branch[DaddLabel, Carry']; T-(MulDivArg), Divide; T_ T-(MulDivArg), DblBranch[FinalAdd, OKExit, ALU<0]; DaddLabel: T+(MulDivArg), Divide; T_ T+(MulDivArg), Branch[FinalAdd, ALU<0]; OKExit: Return; FinalAdd: T_ T+(MulDivArg), Return; Dneg: DivTemp_ T+T, Branch[Dneg1, ALU<0]; Dneg0: T_ A_ T, Divide, Branch[Fudge2, Cnt=0&-1]; DivTemp_ T+T, DblBranch[Dneg1, Dneg0, R<0]; Dneg1: T_ T-(MulDivArg), Divide, Branch[Fudge3, Cnt=0&-1]; Dneg3: PD_ T, Branch[.+2, Carry']; DivTemp_ T+T, DblBranch[Dneg1, Dneg0, ALU<0]; T_ T+(MulDivArg), Divide, Branch[Fudge4, Cnt=0&-1]; DnegG: PD_ T, Branch[.+2, ALU>=0]; T_ T-(MulDivArg), CDivide, DblBranch[Fudge4, DnegG, Cnt=0&-1]; DivTemp_ T+T, DblBranch[Dneg1, Dneg0, ALU<0]; Fudge2: PD_ T-(MulDivArg); Fudge21: Branch[F23, Carry]; F22: PD_ A_ T, Divide, Return; F23: PD_ T-(MulDivArg), Divide, Branch[Fudge42]; Fudge3: PD_ T-(MulDivArg), Branch[Fudge21, Carry]; PD_ A_ T, CDivide, Branch[FinalAdd]; Fudge4: PD_ T-(MulDivArg), Branch[.+2, ALU<0]; DblBranch[F23, F22, Carry]; PD_ T-(MulDivArg), CDivide; Fudge42: T_ T-(MulDivArg), Return; TopLevel; DivTrap: Branch[.+2, ALU#0]; T_ sDivZeroTrap, Branch[SavePCAndTrap]; T_ sDivCheckTrap, Branch[SavePCAndTrap]; *----------------------------------------------------------- IFUR[DCMP, 1]; * Double Compare * t: LONG INTEGER _ PopLong[]; u: LONG INTEGER _ PopLong[]; * Push[SELECT TRUE FROM * s>t => 1, * s=t => 0, * s -1, * ENDCASE]; *----------------------------------------------------------- * Complement the signs of both 32-bit operands, then do an unsigned compare. T_ (Stack&-2) XOR (100000C); Stack&+1_ (Stack&+1) XOR (100000C), Branch[UnsignedComp1]; *----------------------------------------------------------- IFUR[UDCMP, 1]; * Unsigned Double Compare * t: LONG CARDINAL _ PopLong[]; u: LONG CARDINAL _ PopLong[]; * Push[SELECT TRUE FROM * s>t => 1, * s=t => 0, * s -1, * ENDCASE]; *----------------------------------------------------------- T_ Stack&-1; * Compute s-t UnsignedComp1: T_ Stack&-2, Q_ T; T_ (Stack&+1)-T; Stack_ (Stack)-Q-1, XorSavedCarry; * Have carry out of last (high) subtraction iff s>=t T_ (Stack&-1) OR T, Branch[.+2, Carry]; Stack_ T-T-1, NextOpcode; * s