ARITHMETIC INSTRUCTIONS

This chapter describes all 8051 arithmetic and logic instructions. Program examples are given to illustrate the application of these instructions. In Section 6.1 we discuss instructions and programs related to addition, subtraction, multiplication, and division of unsigned numbers. Signed numbers are discussed in Section 6.2. In Section 6.3, we discuss the logic instructions AND, OR, and XOR, as well as the COMPARE instruction. The ROTATE instruction and data serialization are discussed in Section 6.4. In Section 6.5 we provide some real-world applications such as BCD and ASCII conversion and checksum byte testing.
SECTION 6.1: ARITHMETIC INSTRUCTIONS
Unsigned numbers are defined as data in which all the bits are used to represent data, and no bits are set aside for the positive or negative sign. This means that the operand can be between 00 and FFH (0 to 255 decimal) for 8-bit data.
Addition of unsigned numbers
In the 8051, in order to add numbers together, the accumulator register (A) must be involved. The form of the ADD instruction is

The instruction ADD is used to add two operands. The destination operand is always in register A while the source operand can be a register, immediate data, or in memory. Remember that memory-to-memory arithmetic operations are never allowed in 8051 Assembly language. The instruction could change any of the AF, CF, or P bits of the flag register, depending on the operands involved. The effect of the ADD instruction on the overflow flag is discussed in Section 6.3 since it is used mainly in signed number operations. Look at Example 6-1.
Example 6-1
Show how the flag register is affected by the following instructions.

After the addition, register A (destination) contains 00 and the flags are as follows:
CY = 1 since there is a carry out from D7.
P = 0 because the number of Is is zero (an even number).

AC = 1 since there is a carry from D3 to D4.



Addition of individual bytes
Chapter 2 contained a program that added 5 bytes of data. The sum was purposely kept less than FFH, the maximum value an 8-bit register can hold. To calculate the sum of any number of operands, the carry flag should be checked after the addition of each operand. Example 6-2 uses R7 to accumulate carries as the operands are added to A.
Example 6-2
Assume that RAM locations 40 – 44 have the following values. Write a program to find the sum of the values. At the end of the program, register A should contain the low byte and R7 the high byte. All values are in hex.
40=(7D) 41=(EB) 42=(C5) 43=(5B) 44=(30)
Solution:


Analysis of Example 6-2
Three iterations of the loop are shown below. Tracing of the program is left to the reader as an exercise.
  1. In the first iteration of the loop, 7DH is added to A with CY = 0 and R7 = 00,
    and the counter R2 = 04.
  2. In the second iteration of the loop, EBH is added to A, which results in A -
    68H and CY = 1. Since a carry occurred, R7 is incremented. Now the counter
    R2 = 03.
  3. In the third iteration, C5H is added to A, which makes A = 2DH. Again a carry
    occurred, so R7 is incremented again. Now counter R2 = 02.
At the end when the loop is finished, the sum is held by registers A and R7, where A has the low byte and R7 has the high byte.


ADDC and addition of 16-bit numbers
When adding two 16-bit data operands, we need to be concerned with the propagation of a carry from the lower byte to the higher byte. The instruction ADDC (add with carry) is used on such occasions. For example, look at the addition of 3CE7H + 3B8DH, as shown below.

When the first byte is added (E7 + 8D = 74, CY = 1). The carry is propagated to the higher byte, which results in 3C + 3B + 1 = 78 (all in hex). Example 6-3 shows the above steps in an 8051 program.
Example 6-3
Write a program to add two 16-bit numbers. The numbers are 3CE7H and 3B8DH. Place the sum in R7 and R6; R6 should have the lower byte.








BCD (binary coded decimal) number system
BCD stands for binary coded decimal. BCD is needed because in everyday life we use the digits 0 to 9 for numbers, not binary or hex numbers. Binary representation of 0 to 9 is called BCD (see Figure 6-1). In computer literature one encounters two terms for BCD numbers, (1) unpacked BCD, and (2) packed BCD. We describe each one next.
Unpacked BCD
In unpacked BCD, the lower 4 bits of the number represent the BCD number, and the rest of the bits are 0. For example, “0000 1001″ and “0000 0101″ are unpacked BCD for 9 and 5, respectively. Unpacked BCD requires 1 byte of memory or an 8-bit register to contain it.
Figure 6-1. BCD Code




Packed BCD
In packed BCD, a single byte has two BCD numbers in it, one in the lower 4 bits, and one in the upper 4 bits. For example, “0101 1001″ is packed BCD for 59H. It takes only 1 byte of memory to store the packed BCD operands. And so one reason to use packed BCD is that it is twice as efficient in storing data.
There is a problem with adding BCD numbers, which must be corrected. The problem is that after adding packed BCD numbers, the result is no longer BCD. Look at the following.

Adding these two numbers gives 0011 111 IB (3FH), which is not BCD! A BCD number can only have digits from 0000 to 1001 (or 0 to 9). In other words, adding two BCD numbers must give a BCD result. The result above should have been 17 + 28 = 45 (0100 0101). To correct this problem, the programmer must add 6 (0110) to the low digit: 3F + 06 = 45H. The same problem could have happened in the upper digit (for example, in 52H + 87H = D9H). Again to solve this problem, 6 must be added to the upper digit (D9H + 60H = 139H) to ensure that the result is BCD (52 + 87 = 139). This problem is so pervasive that most microprocessors such as the 8051 have an instruction to deal with it. In the 8051 the instruction “DA A” is designed/to correct the BCD addition problem. This is discussed next.
DA instruction
The DA (decimal adjust for addition) instruction in the 8051 is provided to correct the aforementioned problem associated with BCD addition. The mnemonic “DA” has as its only operand the accumulator “A”. The DA instruction will add 6 to the lower nibble or higher nibble if needed; otherwise, it will leave the result alone. The following example will clarify these points.


After the program is executed, register A wili contain 72H (47 + 25 = 72). The “DA” instruction works only on A. In other words, while the source can be an operand of any addressing mode, the destination must be in register A in order for DA to work. It also needs to be emphasized that DA must be used after the addition of BCD operands and that BCD operands can never have any digit greater than 9. In other words, A – F digits are not allowed. It is also important to note that DA works only after an ADD instruction; it will not work after the INC instruction.

Summary of DA action
After an ADD or ADDC instruction,
  1. If the lower nibble (4 bits) is greater than 9, or if AC = 1, add 0110 to the lower
    4 bits.
  1. If the upper nibble is greater than 9, or if CY = 1, add 0110 to the upper 4 bits.
In reality there is no other use for the AC (auxiliary carry) flag bit except for BCD addition and correction. For example, adding 29H and 18H will result in 41H, which is incorrect as far as BCD is concerned.


Since AC = 1 after the addition, “DA A” will add 6 to the lower nibble. The final result is in BCD format.
Example 6-4
Assume that 5 BCD data items are stored in RAM locations starting at 40H, as shown below. Write a program to find the sum of all the numbers. The result must be in BCD.
40= (71) 41=(11) 42=(65) 43=(59) 44=(37)


Subtraction of unsigned numbers

In many microprocessors there a^e two different instructions for subtraction: SUB and SUBB (subtract with borrow). In the 8051 we have only SUBB. To make SUB out of SUBB, we have to make CY = 0 prior to the execution of the instruction. Therefore, there are two cases for the SUBB instruction: (1) with CY = 0, and (2) with CY = 1. First we examine the case where CY = 0 prior to the execution of SUBB. Notice that we use the CY flag for the borrow.
SUBB (subtract with borrow) when CY=0
In subtraction, the 8051 microprocessors (indeed, all modern CPUs) use the 2′s complement method. Although every CPU contains adder circuitry, it would be too cumbersome (and take too many transistors) to design separate subtracter circuitry. For this reason, the 8051 uses adder circuitry to perform the subtraction command. Assuming that the 8051 is executing a simple subtract instruction and that CY = 0 prior to the execution of the instruction, one can summarize the steps of the hardware of the CPU in executing the SUBB instruction for unsigned numbers, as follows.
  1. Take the 2′s complement of the subtrahend (source operand).
  2. Add it to the minuend (A).
  3. Invert the carry.
These three steps are performed for every SUBB instruction by the internal hardware of the 8051 CPU, regardless of the source of the operands, provided that the addressing mode is supported. After these three steps the result is obtained and the flags are set. Example 6-5 illustrates the three steps.
Example 6-5


The flags would be set as follows: CY = 0, AC – 0, and the programmer must look at the carry flag to determine if the result is positive or negative.
Show the steps involved in the following.
If the C Y = 0 after the execution of SUBB, the result is positive; if C Y = 1, the result is negative and the destination has the 2′s complement of the result. Normally, the result is left in 2′s complement, but the CPL (complement) and INC instructions can be used to change it. The CPL instruction performs the 1 ‘s complement of the operand; then the operand is incremented (INC) to get the 2′s complement. See Example 6-6.
Example 6-6

SUBB (subtract with borrow) when CY= 1
This instruction is used for multibyte numbers and will take care of the borrow of the lower operand. If CY = 1 prior to executing the SUBB instruction, it also subtracts 1 from the result. See Example 6-7.
Example 6-7
Analyze the following program:

Solution:
After the SUBB, A = 62H – 96H = CCH and the carry flag is set high indicating there is a borrow. Since CY = 1, when SUBB is executed the second time A = 27H – 12H -1 = 14H. Therefore, we have 2762H – 1296H = 14CCH.

UNSIGNED MULTIPLICATION AND DIVISION
In multiplying or dividing two numbers in the 8051, the use of registers A and B is required since the multiplication and division instructions work only with these two registers. We first discuss multiplication.
Multiplication of unsigned numbers
The 8051 supports byte-by-byte multiplication only. The bytes are assumed to be unsigned data. The syntax is as follows:

In byte-by-byte multiplication, one of the operands must be in register A, and the second operand must be in register B. After multiplication, the result is in the A and B registers; the lower byte is in A, and the upper byte is in B. The following example multiplies 25H by 65H. The result is a 16-bit data that is held by the A and B registers.

Table6-1: Unsigned Multiplication Summary (MUL AB)
Note: Multiplication of operands larger than 8 bits takes some manipulation. It is left to the reader to experiment with.
Division of unsigned numbers
In the division of unsigned numbers, the 8051 supports byte over byte only. The syntax is as follows.

When dividing a byte by a byte, the numerator must be in register A and the denominator must be in B. After the DIV instruction is performed, the quotient is in A and the remainder is in B. See the following example.

Notice the following points for instruction “DIV AB”.

  1. This instruction always makes CY = 0 and OV = 0 if the denominator is not 0.
    1. If the denominator is 0 (B = 0), OV = 1 indicates an error, and CY = 0. The
      standard practice in all microprocessors when dividing a number by 0 is to
      indicate in some way the invalid result of infinity. In the 8051, the OV flag is
      set to 1.
    Table 6-2: Unsigned Division Summary (DIV AB)


An application for DIV instructions
There are times when an ADC (analog-to-digital converter) is connected to a port and the ADC represents some quantity such as temperature or pressure. The 8-bit ADC provides data in hex in the range of 00 – FFH. This hex data must be converted to decimal. We do that by dividing it by 10 repeatedly, saving the remainders as shown in Example 6-8.
Example 6-8
Write a program (a) to make PI an input port, (b) to get a byte of hex data in the range of 00 – FFH from PI and convert it to decimal. Save the digits in R7, R6, and R5, where the least significant digit is in R7.
Solution:

The input value from PI is in the hex range of 00 – FFH or in binary 00000000 to 11111111. This program will not work if the input data is in BCD. In other words, this program converts from binary to decimal. To convert a single decimal digit to ASCII format, we OR it with 30H as shown in Sections 6.4 and 6.5.
Example 6-9
Analyze the program in Example 6-8, assuming that PI has a value of FDH for data. Solution:
To convert a binary (hex) value to decimal, we divide it by 10 repeatedly until the quotient is less than 10. After each division the remainder is saved. In the case of an 8-bit binary such as FDH we have 253 decimal as shown below (all in hex).

Therefore, we have FDH = 253. In order to display this data it must be converted to ASCII, which is described in a later section in this chapter.






Next post:

Previous post: