5
Stack Instructions |
The stack instructions manipulate the evaluation stack; except for the code stream, they do not reference memory. All of the usual logical and arithmetic operations (including some comparisons) are described in this chapter, as are primitives for manipulating the stack pointer and the order of the elements on the stack. Support for range checking and NIL pointer checking is also included. The basic arithmetic operators and the Not, And, Or, Xor, Shift, LongNot, LongAnd, LongOr, LongXor, LongShift, and SignExtend routines are defined in §5.2. The stack routines Push, Pop, Recover, and Discard are discussed in §3.3.2.
Note: None of the stack instructions operate on a stack element "in place"; they always remove their operands to check for stack underflow.
The instructions below are used to maintain the stack. Recover obtains the word above the top of the stack. Recover Two obtains the double word above the top of the stack. Discard Two removes the double word on top of the stack. Exchange interchanges the order of the top two words of the stack. Double Exchange interchanges the order of the top two double words of the stack. Duplicate makes a copy of the top word of the stack. Double Duplicate makes a copy of the top double word of the stack. Exchange Discard interchanges the order of the top two words on the stack, then removes the top word.
REC: PROCEDURE = BEGIN Recover[]; END;
REC2: PROCEDURE = BEGIN Recover[]; Recover[]; END;
DIS: PROCEDURE = BEGIN Discard[]; END;
DIS2: PROCEDURE = BEGIN Discard[]; Discard[]; END;
There are limitations on how many Recover instructions can follow particular instructions, and on when they may not yield meaningful results. See §3.3.2 for a discussion of these restrictions.
EXCH: PROCEDURE = BEGIN v: UNSPECIFIED = Pop[]; u: UNSPECIFIED = Pop[]; Push[v]; Push[u]; END;
DEXCH: PROCEDURE = BEGIN v: LONG UNSPECIFIED = PopLong[]; u: LONG UNSPECIFIED = PopLong[]; Pushlong[v]; PushLong[u]; END;
DUP: PROCEDURE = BEGIN u: UNSPECIFIED = Pop[]; Push[u]; Push[u]; END;
DDUP: PROCEDURE = BEGIN u: LONG UNSPECIFIED = PopLong[]; PushLong[u]; PushLong[u]; END;
EXDIS: PROCEDURE = BEGIN u: UNSPECIFIED = Pop[]; v: UNSPECIFIED = PoP{]; Push[u]; END;
The check instructions are used to implement runtime checks on array indexes, subranges, and pointers. They restore their first parameter to the stack for use by subsequent instructions, providing that the check succeeds (or for use by the trap handler, if the check fails).
BNDCK: PROCEDURE = BEGIN range: CARDINAL = Pop[]; index: CARDINAL = Pop[]; Push[index]; IF index >= range THEN BoundsTrap[]; END;
BNDCKL: PROCEDURE = BEGIN range: LONG CARDINAL = PopLong[]; index: LONG CARDINAL = PopLong[]; PushLong[index]; IF index >= range THEN BoundsTrap[]; END;
NILCKL: PROCEDURE = BEGIN ptr: LONG POINTER = PopLong[]; nil: LONG POINTER = LOOPHOLE[LONG[O]]; PushLong[ptr]; IF ptr = nil THEN PointerTrap[]; END;BoundsTrap and PointerTrap are defined in §9.5.1.
The unary instructions operate on the top single- or double-word element of the stack. They treat their operands as signed (two's complement) or unsigned binary numbers.
Programming Note: As long as overflow is ignored and does not occur, these instructions can be used both for signed and unsigned operations. Mesa does no overflow checking.
NEG: PROCEDURE = BEGIN i: INTEGER = Pop[]; Push[-i]; END;
INC: PROCEDURE BEGIN s: CARDINAL = Pop[]; Push[s + 1]; END;
DINC: PROCEDURE = BEGIN s: LONG CARDINAL = PopLong[]; PushLong[s + 1]; END;
DEC: PROCEDURE = BEGIN s: CARDINAL = Pop[]; Push[s - 1]; END;
ADDSB: PROCEDURE = BEGIN alpha: BYTE = GetCodeByte[]; i: INTEGER = Pop[]; Push[i + SignExtend[alpha]]; END;
DBL: PROCEDURE = BEGIN u: UNSPECIFIED = Pop[]; Push[Shift[u, 1]]; END;
DDBL: PROCEDURE = BEGIN u: LONG UNSPECIFIED = PopLong[]; PushLong[LongShift[u, 1]]; END;
TRPL: PROCEDURE = BEGIN s: CARDINAL = Pop[]; Push[s * 3]; END;
LINT: PROCEDURE = BEGIN i: INTEGER = Pop[]; Push[i]; Push[IF i < 0 THEN -1 ELSE 0]; END;
SHIFTSB: PROCEDURE = BEGIN alpha: BYTE = GetCodeByte[]; u: UNSPECIFIED = Pop[]; shift: INTEGER = SignExtend[alpha]; IF shift ~IN[-15..15] THEN ERROR; Push[Shift[u, shift]]; END;
The logical instructions perform bitwise logical functions on the top two single- or double word elements of the stack. The And instruction and Inclusive and Exclusive Or are defined in terms of the primitives in §2.1.3.1. The Shift instruction shifts u by ABS[shift] bits, left if shift is positive, right if shift is negative. Bits shifted off either end of u are lost; zeroes are shifted into u as necessary. A shift count greater than fifteen always yields a zero result.
AND: PROCEDURE = BEGIN v: UNSPECIFIED = Pop[]; u: UNSPECIFIED = Pop[] Push[And[u, v]]; END; DAND: PROCEDURE = BEGIN v: LONG UNSPECIFIED = PopLong[]; u: LONG UNSPECIFIED = PopLong[]; PushLong[LongAnd[u, v]]; END;
IOR: PROCEDURE = BEGIN v: UNSPECIFIED = Pop[]; u: UNSPECIFIED = Pop[]; Push[Or[u, v]]; END;
DIOR: PROCEDURE = BEGIN v: LONG UNSPECIFIED = PopLong[]; u: LONG UNSPECIFIED = PopLong[]; PushLong[LongOr[u, v]]; END;
XOR: PROCEDURE = BEGIN v: UNSPECIFIED = Pop[]; u: UNSPECIFIED = Pop[], Push[Xor[u, v]]; END;
DXOR: PROCEDURE = BEGIN v: LONG UNSPECIFIED = PopLong[]; u: LONG UNSPECIFIED = PopLong[]; PushLong[LongXor[u, v]]; END;
SHIFT: PROCEDURE = BEGIN shift: INTEGER = Pop[]; u: UNSPECIFIED = Pop[]; Push[Shift[u, shift]]; END;
DSHIFT: PROCEDURE = BEGIN shift: INTEGER = Pop[]; u: LONG UNSPECIFIED = PopLong[]; PushLong[LongShift[u, shift]]; END;
ROTATE: PROCEDURE = BEGIN rotate: INTEGER = Pop[]; u: UNSPECIFIED = Pop{]; Push[Rotate[u, rotate]]; END;
Programming Note: The Not function is obtained by using Xor with one operand set to ones.
The following instructions perform arithmetic functions on the top two single- or double-word elements of the stack. They treat their operands as signed (two's complement) or unsigned binary numbers, and leave their results on the stack.
ADD: PROCEDURE = BEGIN t: CARDINAL = Pop[]; s: CARDINAL = Pop[]; Push[s + t]; END;
SUB: PROCEDURE = BEGIN t: CARDINAL = Pop[]; s: CARDINAL = Pop[]; Push[s - t]; END;
The Double Add and Double Subtract instructions take thirty-two bit signed or unsigned operands and push a thirty-two bit result.
DADD: PROCEDURE = BEGIN t: LONG CARDINAL = PopLong[]; s: LONG CARDINAL = PopLong[]; PushLong[s + t]; END;
DSUB: PROCEDURE = BEGIN t: LONG CARDINAL = PopLong[]; s: LONG CARDINAL = PopLong[]; PushLong[s - t]; END;
Programming Note: If overflow is ignored, the result of an add or subtract instruction can be considered to be either signed or unsigned.
The Add Double to Cardinal and Add Cardinal to Double instructions take a thirty-two bit and a sixteen-bit operand and push a thirty-two bit result.
ADC: PROCEDURE = BEGIN t: LONG CARDINAL = PopLong[]; s: CARDINAL = Pop[]; PushLong[LONG[s] + t]; END;
ACD: PROCEDURE = BEGIN t: CARDINAL = Pop[]; s: LONG CARDINAL = PopLong[]; PushLong[s + LONG[t]]; END;
The Multiply instruction computes the thirty-two bit product of the top two elements of the stack. The least significant word of the product is pushed onto the stack; the most significant word is left above the top of the stack, so it can be obtained using a Recover instruction.
MUL: PROCEDURE = BEGIN t: CARDINAL = Pop[]; s: CARDINAL = Pop[]; PushLong[LONG[s] * t]; Discard[]; END;
Programming Note: If the most significant word of the product is not recovered, the operation can be considered either signed or unsigned if overflow is ignored; otherwise it is unsigned.
MUL: PROCEDURE = BEGIN t: LONG CARDINAL = PopLong[]; s: LONG CARDINAL = PopLong[]; PushLong[s * t]; END;
The divide instructions divide a signed (unsigned) sixteen-bit dividend by a signed (unsigned) sixteen-bit divisor. The quotient is pushed onto the stack, and the remainder is left above the top of the stack so it can be obtained using a Recover instruction. In SDIV, the signs of the results are computed according to the rules of algebra (§2.2.2). In all divide instructions, a DivZeroTrap occurs if the divisor is zero (see §9.5.1).
SDIV: PROCEDURE = BEGIN k: INTEGER = Pop[]; j: INTEGER = Pop[]; IF k = 0 THEN DivZeroTrap[]; Push[j / k]; Push[j MOD k]; Discard[]; END;
UDIV: PROCEDURE = BEGIN t: CARDINAL = Pop[]; s: CARDINAL = Pop[]; IF t = 0 THEN DivZeroTrap[]; Push[s / t]; Push[s MOD t]; Discard[]; END;
The Long Unsigned Divide instruction divides an unsigned thirty-two bit dividend by an unsigned sixteen-bit divisor. The sixteen-bit quotient is pushed onto the stack, and the remainder is left above the top of the stack so it can be obtained using a Recover instruction.
LUDIV: PROCEDURE = BEGIN t: CARDINAL = Pop[]; s: LONG CARDINAL = PopLong[]; IF t = 0 THEN DivZeroTrap[]; IF HighHalf[s] >= t THEN DivCheckTrap[]; Push[LowHalf[s / LONG[t]]]; Push[LowHalf[s MOD LONG[t]]]; Discard[]; END;
A DivCheckTrap (§9.5.1) is generated if the most significant word of the dividend is greater than the divisor, indicating that the quotient would overflow sixteen bits.
The double divide instructions divide a signed (unsigned) thirty-two bit dividend by a signed (unsigned) thirty-two bit divisor. The quotient is pushed onto the stack, and the remainder is left above the top of the stack so it can be obtained using a Recover Two instruction. In SDDIV, the signs of the results are computed according to the rules of algebra (§2.2.2). In all divide instructions, a DivZeroTrap occurs if the divisor is zero (see §9.5.1).
SDDIV: PROCEDURE = BEGIN k: LONG INTEGER = PopLong[]; j: LONG INTEGER = PopLong[]; IF k = 0 THEN DivZeroTrap[]; PushLong[j / k]; PushLong[j MOD k]; Discard[]; END;
UDDIV: PROCEDURE = BEGIN t: LONG CARDINAL = PopLong[]; s: LONG CARDINAL = PopLong[]; IF t = 0 THEN DivZeroTrap[]; PushLong[s / t]; PushLong[s MOD t]; Discard[]; Discard[]; END;
The double compare instructions compare two thirty-two bit signed or unsigned operands and push zero, one, or minus one depending on whether the operands compare equal, greater, or less.
DCMP: PROCEDURE = BEGIN k: LONG INTEGER = PopLong[]; j: LONG INTEGER = PopLong[]; Push[SELECT TRUE FROM j > k => l, j < k => -1, ENDCASE => 0]; END;
UDCMP: PROCEDURE = BEGIN t: LONG CARDINAL = PopLong[]; s: LONG CARDINAL = PopLong[]; Push[SELECT TRUE FROM s > t => l, s < t = > -1, ENDCASE = > 0]; END;
The floating point instruction set is currently under development (see §2.2.3).
[last edited 4/10/99 12:03AM]