The Assembly Language: Part II

Next in line are the arithmetic instructions. It wouldn't be much of a computer if it couldn't perform arithmetic computations.

First come the addition instructions. These are self explanatory mainly, except perhaps for the carry. When a computation needs to add numbers bigger than 16 bits, it needs to do a carry just like you and I do when we add two digits together and the result is too large to store in a single digit. E.g: 5+7 = 2 carry 1. In the next column, if we had to add 3+4, we would make it 3+4+1=8, because of the carry.

In the same way, to add two 32 bit numbers, we first add the lower 16 bits of the numbers together. But this might result in a carry. This is indicated by the carry flag being set automatically as a result of an addition instruction. Now we need to add the higher 16 bits of the two numbers being added, but we need to also add the carry if there is one. To perform such an addition, taking into account the carry, an instruction like ADC is used, which performs a normal addition, but then adds an extra 1 if the carry flag is currently set.

A similar process is used for subtraction, where a particular subtraction may require a borrow. This is again indicated by the carry flag being automatically set after the subtraction. To carry out this borrow in the next part of the subtraction, we use the special form of the subtraction instruction with borrow, which will perform the subtraction and take an extra 1 if the carry flag happens to be set.

There are also two forms of the multiplication and division instructions. One is for unsigned operations and the other is for signed operations. For addition and subtraction we did not need special forms of the instructions for signed numbers (numbers that can be positive or negative). This is simply because arithmetically, precisely the same operation is carried out in both cases, so we don't need to specify whether our numbers are being thought of as having a sign or not.

However for multiplication and division it makes a difference whether we are thinking of a 16 bit number as being a value from 0 to 65535 (i.e. an unsigned number) or a value from -32768 to 32767 (i.e. a signed value).

Finally note that there are two forms of division instructions, one to return the whole number part of the division operation and the other to return the remainder. This corresponds to the two parts of the answer that we get when we do a normal long division.

Next come the logical instructions. These are used to isolate various parts of a piece of data. Sometimes the individual bits in a 16 bit number are being used to signify different things. For example, bit 4 might indicate that a particular condition is true, and bit 5 might represent a totally different condition. To combine such combinations together (much as we would combine conditions in an if statement in C, we use the logical instructions.

Each of the first four logical instructions performs the logical operation on the two pieces of data and stores the result in the second of the two locations mentioned. The four logical instructions are AND which sets the resulting bit to 1 if the first and second bits being compared are 1. The OR sets the resulting bit to 1 if either of the bits being compared are 1. The XOR (exclusive or) sets the result to 1 if one or other of the bits being compared is 1, but not both.

Finally NOT operates on a single location and simply switches the value of each of its bits, from one to zero or vice versa.

Note that all of the logical instructions operates bitwise. In other words, each instruction performs 16 small logical operations, one for each of the 16 bits in the data being operated on.

As an example:

ANI 8

performs an and operation on the value in the accumulator and the value 8 (whose binary is 0000 0000 0000 1000) and stores the result in the accumulator. This has the effect of setting all bits in the accumulator to zero except the bit in the 4-th place from the right, which remains as it is. This is because if you and a bit with a 1, it remains what it was, however if you and it with a 0, it will always become 0.

Next are the shift and rotate instructions. These shift the bits in the accumulator left or right. Any bits that fall off the ends are lost, unless you use a rotate, which puts them back in at the other end again, i.e. just rotates all the bits around as though the two ends of the accumulator were joined up. Rotating left and right is a quick way of multiplying and dividing by powers of 2, just as in decimal notation, multiplying by 10 is a simple matter of adding an extra 0, i.e. shifting digits one place to the left, etc.

Next we have some instructions for clearing and setting individual flags. The flags are automatically updated by most instructions, but occassionally we want them set to particular values, and these instructions accomplish precisely that. Of course these instructions do not need any operands.