This blog was last modified 428 days before.

Logical Calculation

CMP, AND, TEST, OR, XOR, NOT.

These are logical operaion instructions on CPU 8086. They just do the thing that what they called, try these out by yourself on simulator.

ADD, SUB, MUL, IMUL, DIV, IDIV, NEG

These are arithmetical operation.

CMP and Lexical Flag Analyze

We could think that CMP instruction is actually using SUB to subtract one number from another number, but only update the flags and do not store the result.

For example:

mov ax, 1
mov bx, 2
sub ax, bx
mov ax, 1
mov bx, 2
cmp ax, bx

Run these two different code, you would got the same flags status. But in the first case you got an -1 in ax, but in the second cases the value of ax is still 1.

Try these out on your own.

Where's the result?

As we said above, the CMP instruction do NOT store the result, then how can we know the result of this CMP instruction? The answer is through those tiny flags.

I would give the conclusion first: In case of running instruction cmp ax, bx

  • OF == SF => [ax] >= [bx]
  • OF <> SF => [ax] <= [bx]

Note: <> means not equal here.

Why?

Let's discuss the situation.

(1) When OF == 0

Since no overflow occured, we could know that:

  • SF == 0 => ax - bx >= 0 => ax >= bx
  • SF == 1 => ax - bx <= 0 => ax <= bx

(2) When OF == 1

There are two types of overflow:

  • Upper Bound Overflow: ax >= 0 and bx <= 0 => ax >= bx
  • Lower Bound Overflow: ax <= 0 and bx >= 0 => ax <= bx

And:

  • When Upper Bound Overflow occured, SF should be 1, since the result cross the upper bound and goes in to the range of the negatives.
  • When Lower Bound Overflow occured, SF should be 0, since the result cross the lower bound and goes in to the range of the positives.

Then we have:

  • SF == 1 => ax >= bx
  • SF == 0 => ax <= bx

Finally we have:

OF SF REL
0 0 >=
0 1 <=
1 0 <=
1 1 >=

That's what is given at fisrt:

  • OF == SF => [ax] >= [bx]
  • OF <> SF => [ax] <= [bx]

Arithmetic Operation

Most of the arithmetic operation instruction just do as what they called. ADD do addition, MUL do multiplication etc.

  • IMUL and IDIV means doing multiplication/division but with the consideration of the sign.

MUL / IMUL Carry

; arithmetic calculation test
    
; add
mov ax, un_word_max
mov bx, un_word_max
add ax, bx       

; usigned mul (byte) carry
mov al, un_byte_max
mov bl, 2
mul bl

; unsigned mul carry
mov ax, un_word_max
mul bx     
; result stored in H:dx L:ax

; signed imul overflow 
mov ax, sg_word_max
mov bx, 2
imul bx

; idiv test
mov ax, 3
mov bx, -1
idiv bx


ret
un_word_max dw 0ffffh
sg_word_max dw 07fffh

un_byte_max db 0ffh
sg_byte_max db 07fh

Here notice that AX is default register used when using instruction MUL, IMUL, DIV, IDIV.

When doing diviation, AX will be the dividend and BX will be the divisor: idiv bx == ax / bx

Carry of multiplication

  • When doing 8-bit multiplication, we will use the whole AX to store the possibly 16-bit answer.
  • When doing 16-bit multiplication, we will use DX and AX to store the possibly 32-bit answer, with the more significant word stored in DX (For example for a 32-bit number: 12345678h => DX: 1234h AX: 5678h).

Even if the result is not out of the range of 16-bit, the DX will also be updated to 0000f.

Since we have reserved enough place for this result, so there is no such Carry or Overflow in MUL and IMUL.

Division

Similar to multiplication, division operation also use AX and DX. Means if you want to doing 16-bit operation, you need to set DX to 0000f first.

For example:

mov ax, 6
mov bx, 3
div bx

You may supposed that you get a 0002h in AX, but actually the result is unpredictable as we don't know what's the value in DS. If DX = 0001h, then you will actually get `

Run the ASM code above to try it yourself.

Increase & Decrease

INC and DEC is quite like the ++ and -- operator in C/C++. In old processors, INC AX would be faster than doing ADD AX, 1