Previous [TOC] Next

| 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.

### 5.1 Stack Primitives

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 Recover

    REC: PROCEDURE =
        BEGIN
        Recover[];
        END;

#### REC2 Recover Two

    REC2: PROCEDURE =
        BEGIN
        Recover[];
        Recover[];
        END;

#### DIS Discard

    DIS: PROCEDURE =
        BEGIN
        Discard[];
        END;

#### DIS2 Discard Two

    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 Exchange

    EXCH: PROCEDURE =
        BEGIN
        v: UNSPECIFIED = Pop[];
        u: UNSPECIFIED = Pop[];
        Push[v]; Push[u];
        END;

#### DEXCH Double Exchange

    DEXCH: PROCEDURE =
        BEGIN
        v: LONG UNSPECIFIED = PopLong[];
        u: LONG UNSPECIFIED = PopLong[];
        Pushlong[v]; PushLong[u];
        END;

#### DUP Duplicate

    DUP: PROCEDURE =
        BEGIN
        u: UNSPECIFIED = Pop[];
        Push[u]; Push[u];
        END;

#### DDUP Double Duplicate

    DDUP: PROCEDURE =
        BEGIN
        u: LONG UNSPECIFIED = PopLong[];
        PushLong[u]; PushLong[u];
        END;

#### EXDIS Exchange Discard

    EXDIS: PROCEDURE =
        BEGIN
        u: UNSPECIFIED = Pop[];
        v: UNSPECIFIED = PoP{];
        Push[u];
        END;

### 5.2 Check Instructions

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 Bounds Check

    BNDCK: PROCEDURE =
        BEGIN
        range: CARDINAL = Pop[];
        index: CARDINAL = Pop[];
        Push[index];
        IF index >= range THEN BoundsTrap[];
        END;

#### BNDCKL Bounds Check Long

    BNDCKL: PROCEDURE =
        BEGIN
        range: LONG CARDINAL = PopLong[];
        index: LONG CARDINAL = PopLong[];
        PushLong[index];
        IF index >= range THEN BoundsTrap[];
        END;

#### NILCKL Nil Check Long

    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.

### 5.3 Unary Operations

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 Negate

    NEG: PROCEDURE =
        BEGIN
        i: INTEGER = Pop[];
        Push[-i];
        END;

#### INC Increment

    INC: PROCEDURE
        BEGIN
        s: CARDINAL = Pop[];
        Push[s + 1];
        END;

#### DINC Double Increment

    DINC: PROCEDURE =
        BEGIN
        s: LONG CARDINAL = PopLong[];
        PushLong[s + 1];
        END;

#### DEC Decrement

    DEC: PROCEDURE =
        BEGIN
        s: CARDINAL = Pop[];
        Push[s - 1];
      END;

#### ADDSB Add Signed Byte

    ADDSB: PROCEDURE =
        BEGIN
        alpha: BYTE = GetCodeByte[];
        i: INTEGER = Pop[];
        Push[i + SignExtend[alpha]];
        END;

#### DBL Double

    DBL: PROCEDURE =
        BEGIN
        u: UNSPECIFIED = Pop[];
        Push[Shift[u, 1]];
        END;

#### DDBL Double Double

    DDBL: PROCEDURE =
        BEGIN
        u: LONG UNSPECIFIED = PopLong[];
        PushLong[LongShift[u, 1]];
        END;

#### TRPL Triple

    TRPL: PROCEDURE =
      BEGIN
      s: CARDINAL = Pop[];
      Push[s * 3];
      END;

#### LINT Lengthen Integer

    LINT: PROCEDURE =
        BEGIN
        i: INTEGER = Pop[];
        Push[i];
        Push[IF i < 0 THEN -1 ELSE 0];
        END;

#### SHIFTSB Shift Signed Byte

    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;

### 5.4 Logical Operations

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 And

    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 Inclusive Or

    IOR: PROCEDURE =
        BEGIN
        v: UNSPECIFIED = Pop[];
        u: UNSPECIFIED = Pop[];
        Push[Or[u, v]];
        END;

#### DIOR Double Inclusive Or

    DIOR: PROCEDURE =
        BEGIN
        v: LONG UNSPECIFIED = PopLong[];
        u: LONG UNSPECIFIED = PopLong[];
        PushLong[LongOr[u, v]];
        END;

#### XOR Exclusive Or

    XOR: PROCEDURE =
        BEGIN
        v: UNSPECIFIED = Pop[];
        u: UNSPECIFIED = Pop[],
        Push[Xor[u, v]];
        END;

#### DXOR Double Exclusive Or

    DXOR: PROCEDURE =
        BEGIN
        v: LONG UNSPECIFIED = PopLong[];
        u: LONG UNSPECIFIED = PopLong[];
        PushLong[LongXor[u, v]];
        END;

#### SHIFT Shift

    SHIFT: PROCEDURE =
        BEGIN
        shift: INTEGER = Pop[];
        u: UNSPECIFIED = Pop[];
        Push[Shift[u, shift]];
        END;

#### DSHIFT Double Shift

    DSHIFT: PROCEDURE =
        BEGIN
        shift: INTEGER = Pop[];
        u: LONG UNSPECIFIED = PopLong[];
        PushLong[LongShift[u, shift]];
        END;

#### ROTATE Rotate

    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.

### 5.5 Arithmetic Operations

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 Add

    ADD: PROCEDURE =
        BEGIN
        t: CARDINAL = Pop[];
        s: CARDINAL = Pop[];
        Push[s + t];
        END;

#### SUB Subtract

    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 Double Add

    DADD: PROCEDURE =
        BEGIN
        t: LONG CARDINAL = PopLong[];
        s: LONG CARDINAL = PopLong[];
        PushLong[s + t];
        END;

#### DSUB Double Subtract

    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 Add Double to Cardinal

    ADC: PROCEDURE =
        BEGIN
        t: LONG CARDINAL = PopLong[];
        s: CARDINAL = Pop[];
        PushLong[LONG[s] + t];
        END;

#### ACD Add Cardinal to Double

    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 Multiply

    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.

#### DMUL Double Multiply

    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 Signed Divide

    SDIV: PROCEDURE =
        BEGIN
        k: INTEGER = Pop[];
        j: INTEGER = Pop[];
        IF k = 0 THEN DivZeroTrap[];
        Push[j / k];
        Push[j MOD k];
        Discard[];
        END;

#### UDIV Unsigned Divide

    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 Long Unsigned Divide

    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 Signed Double Divide

    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 Unsigned Double Divide

    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;

### 5.6 Comparison Operations

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 Double Compare

    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 Unsigned Double Compare

    UDCMP: PROCEDURE =
        BEGIN
        t: LONG CARDINAL = PopLong[];
        s: LONG CARDINAL = PopLong[];
        Push[SELECT TRUE FROM
            s > t => l,
            s < t = > -1,
            ENDCASE = > 0];
        END;

### 5.7 Floating Point Operations

The floating point instruction set is currently under development (see §2.2.3).

Previous [TOC] Next

[last edited 4/10/99 12:03AM]