# Arithmetic Instructions

**Using Them for Simple Calculations**

### Welcome

Hi! Welcome to the third chapter of this series. Now, we'll try to learn a bit more about doing math in assembly. I hope that you really grasped the idea discussed in the previous chapter. The arithmatic operations discussed here is done in integers. No reals yet.

Doing math in assembly will likely change the flag. To refresh our mind: Flags are just the way to tag something after the processor executes an operation: whether the last operation holds zero value, negatives, has a carry or borrow (for addition and subtractions), and so on. If you'd like to review, please click here.

### Addition And Subtraction

Additions and subtractions are straightforward. It takes the following formats:

add x, y ; --> means: x = x + y sub x, y ; --> means: x = x - y

Additions and substractions can be done on any registers except the segment registers.
Just like the `mov` command, you can have one of them as memory locations.
I encourage you to experiment on how to use this command. What is allowable and
what is not. The following is legal in assembly (assuming the variables are already defined):

add ax, 5 ; --> means: ax = ax + 5 add bx, cx ; --> means: bx = bx + cx add [n], ax ; --> means: [n] = [n] + ax add cx, [n] ; --> means: cx = cx + [n] sub di, di ; --> means: di = di - di (in other words: di = 0) sub ax, si ; --> means: ... sub ax, 4 ; --> means: ...

As I pointed out in the previous chapter, for those of you
that has 80286 processor or faster may actually add or subtract variables with constants. But
don't forget to add the `word ptr` or `dword ptr` as appropriate. For example:

add [word ptr i], 10

Ah... that's simple! However, remember that the operation depends on the registers you are
using. For example, if you say `add al, cl`, you are doing an 8-bit addition. So, the
processor actually "expects" (well... sort of) the result to be bounded within 8-bit range (i.e.
0 to 255). Similarly, for 16-bit addition, it should be within 0 to 65535. For substraction,
the processor also "expects" it to be non-negative (i.e. no borrows). "Oh? So we have such
limitation?" you asked. Well, we actually have a "work around" to do that.

If the result of an addition overflows, the carry flag is set to 1, otherwise it is 0. By detecting the carry flag after doing the addition, we'll know whether the last addition overflows or not. Similarly, if the result of subtraction requires a borrow, then ... (guess what) the carry flag is also set to 1, otherwise it is 0. Wait.... is this a typo? No... The internal circuitry to store carry or borrow is the same. How can this be? Well, this will involve a deeper understanding about computer logic, which is out of scope of this chapter. Don't bother... :-) Just accept it for now.

Now the next question would be: "So, if the last addition overflows, does the next add
automatically count the carry flag too?" Good question. The answer is no. However, Intel processor
has a special instruction called `adc`. This command behaves similarly as the `add`
command. The only extra thing is that it also add the value carry flag along. So, this
may be very handy to add large integers. Suppose you'd like to add a 32-bit integers with 16-bit
registers. How can we do that? Well, let's say that the first integer is held on the register
pair DX:AX, and the second one is on BX:CX. This is how:

add ax, cx adc dx, bx

Ah, so first, the lower 16-bit is added by `add ax, cx`. Then the higher 16-bit
is added using `adc` instead of `add`. It is because: if there are overflows,
the carry bit is automatically added in the higher 16-bit. So, no cumbersome checking.
This method can be extended to 64 bits and so on... Note that: If the 32-bit integer
addition overflows too at the higher 16-bit, the result will not be correct and the carry
flag is set, e.g. Adding 5 billion to 5 billion.

For the subtraction, we have similar instruction called `sbb`. It is pretty much
the counterpart for `sub`. I won't discuss it much here. You should try it out yourself.

How about adding and subtracting negative values? `add`, `adc`, `sub`,
and `sbb` handles that "automatically". Well, again, the internal logic for addition
and subtraction both for positive and negative values are the same. So, don't worry if you have
negative operands. These instruction can go smoothly.

### Multiplication, Division, and Remainder

While addition and subtraction can be done on any register, multiplication and division do not. Multiplication and division always assume AX as the place holder. The format is as follows:

mul x ; --> If x is 8-bit, then AX = AL * x; ; if x is 16-bit, then DX:AX = AX * x; div x ; --> If x is 8-bit, then AL = AX / x, AH stores the remainder; ; if x is 16-bit, then AX = DX:AX / x, DX stores the remainder;

See, that's different depending on the source. As far as I recall, you cannot have
variables for x in 8086. In 80286 or above you could (but again you must mention the
`xxxx ptr` modifier). If you'd like to multiply or divide by constants (i.e. x is a
constant), you'll need to load the constants into one of the registers (especially 8086).
In 80286, you probably could. Anyone may correct this. I'm not quite remember.

Doing division is the same. The result of division is always rounded down. The nice extra is that we can obtain the remainder for free.

If there is an overflow in multiplication, the overflow flag will be set. There is no
extra instruction like `adc` or `sbb`. So, you'll want to have an extra caution
on this. Similarly, if you divide a number by 0, you'll likely to trigger an error. In windows
machines this may cause a blue screen of death. So, watch out.

Note: `mul` and `div` will treat every numbers as positive. If you have
negative values, you'll need to replace them `imul` and `idiv` respectively.

### Increment and Decrement

Often times, we'd like to incrementing something by 1 or decrement thing by 1. You can use
`add x, 1` or `sub x, 1` if you'd like to, but Intel x86 assembly has
a special instruction for them. Instead of `add x, 1` we use `inc x`. These
are equivalent. Likewise in subtraction, you can use `dec x` for subtitution.
Beware that neither `inc` nor `dec` instruction sets the carry flag as
`add` and `sub` do.

### A Nice Tip

The arithmatic operations can have special properties. For example: `add x, x` is
actually equal to multiplying `x` by 2. Similarly, `sub x, x` is actually
setting `x` to 0. In 8086 processor, these arithmatic is faster than doing `mul`
or doing `mov x, 0`. Ha! Even more, its code size is smaller. No wonder why the
assembly wizards often fond of this subtitution.

### Closing

OK, I think that's all for now. See you next time. The next chapter would be about bitwise operation.

### Where to go

**Chapter 4
News Page
x86 Assembly Lesson 1 index
Contacting Me**

Roby Joehanes © 2001