Contents Up << >>

### Arithmetic and Logical Instructions

All of the two-operand arithmetic and logical instructions offer the same range of addressing modes. For example, here are the valid forms of the `ADD` operation:

            ADD     reg8, r/m/i8
            ADD     mem8, reg8
            ADD     mem8, BYTE imm8

            ADD     reg16, r/m/i16
            ADD     mem16, reg16
            ADD     mem16, WORD imm16

Just as with the `MOV` instruction, the first operand is the destination and the second is the source; the result of performing the operation on the two operands is stored in the destination (if it gets stored anywhere). Unlike `MOV`, most of these instructions also set or clear the appropriate status flags to reflect the result of the operation (for some of the instructions, this is their only effect).

To add two numbers, use the `ADD` instruction. To continue adding further bytes or words of a multi-part number, use the `ADC` instruction to also add one if the Carry flag is set (indicating a carry-over from the previous byte or word). For example, to add the 32-bit immediate value `12345678h` to the 32-bit double word stored at location `500h`, do `ADD [500h], 5678h` followed by `ADC [502h], 1234h`.

Subtraction is analogous: use the `SUB` instruction to subtract a single pair of bytes or words, and then use the `SBB` ("Subtract with Borrow'') instruction to take the Carry into account for further bytes or words.

An important use of subtraction is in comparing two numbers; in this case, we are not interested in the exact value of their difference, only in whether it is zero or negative, or whether there was a carry or overflow. The `CMP` ("Compare'') instruction performs this task; it subtracts the source from the destination and adjusts the status flags accordingly, but throws away the result. This is exactly what is needed to get conditions such as `LE` to work; after doing `CMP AX, 10`, for example, the status flags will be set in such a way that the `LE` condition is true precisely when the value in AX (treated as a signed integer) is less than or equal to 10.

The two-operand logical instructions are `AND`, `OR`, `XOR`, and `TEST`. The first three perform the expected bitwise operations; for example, the nth bit of the destination after the `AND` operation will be 1 (set, true) if the nth bit of both the source and the destination were 1 before the operation, otherwise it will be 0 (clear, false). The `TEST` instruction is to `AND` as `CMP` is to `SUB`; it performs a bitwise and operation, but the result is only reflected in the flags. For example, after the instruction `TEST [321h], BYTE 12h`, the Zero flag will be set if neither bit 1 nor bit 4 (`12h` is `00010010` in binary, indicating that bits 1 and 4 are to be tested) of the byte at address `321h` were 1, otherwise it will be clear.

Multiplication and division are also binary operations, but the corresponding instructions on the 8086 only allow one of the operands to be specified (and it can only be a register or memory reference, not an immediate value). The other operand is implicitly contained in the accumulator (and sometimes also the DX register). The `MUL` and `DIV` instructions operate on unsigned numbers, while `IMUL` and `IDIV` operate on two's-complement signed numbers. Here are the valid forms for `MUL`; the others are analogous:

            MUL     reg8
            MUL     BYTE mem8

            MUL     reg16
            MUL     WORD mem16

For 8-bit multiplication, the quantity in AL is multiplied by the given operand and the 16-bit result is placed in AX. For 16-bit multiplication, the 32-bit product of AX and the operand is split, with the low word in AX and the high word in DX. In both cases, if the result spills into the high-order byte/word, then the Carry and Overflow flags will be set, otherwise they will be clear. The other flags will have garbage in them; in particular, you will not get correct information from the Zero or Sign flags (if you want that information, follow the multiplication with `CMP AX, 0`, for example).

For division, the process is reversed. An 8-bit operand will be divided into the number in AX, with the quotient stored in AL and the remainder left in AH. A 16-bit operand will be divided into the 32-bit quantity whose high word is in DX and whose low word is in AX; the quotient will be in AX and the remainder will be in DX after the operation. None of the status flags are defined after a division. Also, if the division results in an error (division by zero, or a quotient that is too large), the processor will trigger interrupt zero (as if it had executed `INT 0`).

The `CBW` and `CWD` instructions, which take no operands, will sign-extend AL into AX or AX into DX, respectively, just as needed before performing a signed division. For example, if AL contains `11010110`, then after `CBW` the AH register will contain `11111111` (and AL will be unchanged).

Multiplication and division by powers of two are frequently performed by shifting the bits to the left or right. There are several varieties of shift and rotate instructions, all of which allow the following forms:

            RCL     reg8, 1
            RCL     reg8, CL
            RCL     BYTE mem8, 1
            RCL     BYTE mem8, CL

            RCL     reg16, 1
            RCL     reg16, CL
            RCL     WORD mem16, 1
            RCL     WORD mem16, CL

The second operand specifies how many bit positions the result should be shifted by: either one or the number in the CL register. For example, the accumulator may be multiplied by 2 with `SHL AX, 1`; if CL contains the number 4, the accumulator may be multiplied by 16 with `SHL AX, CL`.

There are three shift instructions---`SAR`, `SHR`, and `SHL`. The "shift-left'' instruction, `SHL`, shifts the highest bit of the operand into the Carry flag and fills in the lowest bit with zero. The "shift-right'' instruction, `SHR`, does the opposite, moving zero in from the top and shifting the lowest bit out into the Carry; this is appropriate for an unsigned division, with the Carry flag giving a 1-bit remainder. On the other hand, the "shift-arithmetic-right'' instruction, `SAR`, leaves a copy of the highest bit in place as it shifts; this is appropriate for a signed division, since it preserves the sign bit.

For example, -53 is represented in 8-bit two's-complement by the binary number `11001011`. After a `SHL` by one position, it will be `10010110`, which represents -106. After a `SAR`, it will be `11100101`, which represents -27. After a `SHR`, it will be `01100101`, which represents +101 in decimal; this corresponds to the interpretation of the original bits as the unsigned number 203 (which yields 101 when divided by 2).

When shifting multiple words by one bit, the Carry can serve as the bridge from one word to the next. For example, suppose we want to multiply the double word (4 bytes) starting at address `1230h` by 2; the instruction `SHL WORD [1230], 1` will shift the low-order word, putting its highest bit into the Carry flag. Now we need an instruction that will shift the Carry into the lowest bit of the word at `1232h`; if we wanted to continue the process, we would also need it to shift the highest bit of that word back out into the Carry. The effect here is that the bits in the operand plus the Carry have been rotated one position to the left. The desired instruction is `RCL WORD [1232], 1` ("rotate-carry-left''). There is a corresponding "rotate-carry-right'' instruction, `RCR`; there are also two rotate instructions which directly shift the highest bit down to the lowest and vice versa, called `ROL` and `ROR`.

There are four unary arithmetic and logical instructions. The increment and decrement operations, `INC` and `DEC`, add or subtract one from their operand; they do not affect the Carry bit. The negation instruction, `NEG`, takes the two's-complement of its operand, while the `NOT` instruction takes the one's-complement (flip each bit from 1 to 0 or 0 to 1). `NEG` affects all the usual flags, but `NOT` does not affect any of them. The valid forms of operand are the same for all of these instructions; here are the forms for `INC`:

            INC     reg8
            INC     BYTE mem8

            INC     reg16
            INC     WORD mem16