Experiment 2 - Arithmetic Operations

In Experiment 1, we saw how to move data into, out of, and around the Intel 8080's working registers. In Experiment 2, we explore the Intel 8080's arithmetic instructions. The Intel 8080 has instructions for two basic arithmetic operations, 8/16-bit addition and 8-bit subtraction. This may seem rather limiting, but, using only these arithmetic instructions, programs can be written to handle large (even decimal) numbers and perform operations like multiplication and division.

As we explore the Intel 8080 ADD/SUB group of instructions, here are some things to keep in mind.

- The ADD/SUB group of instructions
*operate*on the A register and leave the result in the A register. Any value in A before executing the instruction is lost. - One of the corresponding
*operands*(values to be added/subtracted) - The Intel 8080 uses two's complement arithmetic, which greatly simplifies the handling of positive and negative integer values.

Addition with the Intel 8080.

Intel 8080 addition instructions add two values, one in register A and the other either (1) in a working register using ADD and ADC instructions or (2) in the immediate (following) data byte using ADI and ACI instructions. ADD and ADI ignore the Carry Bit; ADC and ACI add the Carry Bit into the sum. Let's look first at the immediate addition instructions ADI and ACI.

**Note: In the descriptions below, r is the
**
**
Register Reference Number**** and v is an 8-bit
data value.**

ADI v Add Immediate to A v is added to the value in
A with result in A. The code byte for ADI is 306Q and is followed by
a data byte of value v.

Status bits affected
- Carry, Sign, Zero, Parity, Auxiliary Carry

ACI v Add Immediate to A with Carry v and the carry
bit are added to the value in A with result in A. The code byte for ACI is
316Q and is followed by a data byte of value v.

Status bits affected - Carry, Sign, Zero, Parity, Auxiliary Carry

"Status bits affected" means that, after the instruction is executed, the listed status bits in the Processor Status Word (PSW) will change to reflect the result of the operation. Status bits not listed will be unaffected. For instance, if the sum exceeds 255, the 8-bit maximum value, the Carry Bit is set. For a thorough explanation of the status bits and the PSW refer to page 5 of the Intel 8080 Assembly Language Programming Manual.

Try it!

Before trying the first example, let's take a moment to describe how machine code will be presented. Generally, each line will consist of four columns as shown below.

- Split octal address
- Code byte or data byte in octal
- Intel 8080 assembly assembly mnemonic for the instruction
- Comment

The "Comment" column contains information about the line, often what the code byte does operationally. We will use a pseudo-code that I developed early when working with the Intel 8080. It's self-explanatory for the most part. For instance, an arrow (g) is used to indicate that a value or the result of an operation is stored in a register. An equal sign "=" means exactly that; one value equals another such as 25=031Q.

Example 1 - Create and test code that adds an immediate data value using ADI v.

000 000 076 MVI A, 25
25gA

000 001 031
25= 031Q

000 002 306 ADI 12
A+12gA

000 003 014
12= 014Q

000 004 166 HLT
Halt execution

a) Enter the code above to add 25 and 12. Click Reset to get back to address 000
000Q then Single Step through the program. Click Display A to check the
value in the accumulator. It should be 25 + 12 = 37 = 045Q. Now click
Display Status. D0 (Bit 0 of the status bits) is the Carry Bit. It
is cleared (zero) indicating the sum was within the range of the 8-bit
accumulator (register A).

b) Change the immediate value in address 000 003Q from 12
(014Q) to 245 (365Q). Reset and this time, click Run. The code will execute
and halt at address 000 004Q. Click Display A. It is 016Q or 14,
not the expected result.
The correct value is 25+245=270. The problem is that the largest value A register can hold is 377Q (all bits 1) or 255. Click Display Status and note that the Carry Bit (D0) is now set (one). The Carry Bit
set indicates
arithmetic overflow into the next larger bit position, 2^{8} = 256 in
this case. If
we add 256 and 14, we get 270, the expected result. We can use the Carry Bit to do multi-byte addition.

Example 2 - Add 25 and 12 with ACI so that the Carry Bit will be added into the sum.

000 000 067 STC
Set Carry Bit (Carry Bit = 1)

000 001 077 CMC
Complement Carry Bit to clear it (Carry Bit = 0)

000 002 076 MVI A, 25 25gA

000 003 031
25=031Q

000 004 316 ACI 12
A+12+CgA

000 005 014
12=014Q

000 006 166 HLT
Halt execution

In this example we use ACI, a variant of the ADI instruction, that adds in
the Carry Bit to bit 0 of the sum. We use the STC (Set Carry)
instruction to set the Carry Bit making it one and follow with the CMC (Complement Carry)
instruction to "flip" the Carry Bit making it zero.

Load and run the code then click Display A. The Data LED's should display 045 octal, which is the expected result 37. Note that the Carry Bit is cleared and did not affect the sum. Now replace the CMC instruction at location 000 001Q with 000Q, a NOP (No Operation) instruction that does nothing except waste a little time. Run the program again and display the result. It should be 046Q or 38 because the Carry Bit, now set, has been added to the sum.

The ADD and ADC instructions work similarly except the value to be added to A is in one of the working registers.

ADD r Add contents of register r to A
The
contents of register r is added to the value in
A with result in A. The octal code byte for ADD is 20r. For
example, ADD H
is 204Q, "4" being the *Register Reference Number* for register H.

Status bits affected
- Carry, Sign, Zero, Parity, Auxiliary Carry

ADC r Add contents of register r to A with Carry
The contents of register r and the carry bit are added to the value in
A with result in A. The octal format of ADD is 21r. For example, ADC H
is 214Q.

Status bits affected
- Carry, Sign, Zero, Parity, Auxiliary Carry

Try it yourself!

Rewrite and test Examples 1 and 2 using ADD and ADC instructions respectively. Instead of immediate values, use MVI E,v to load the data 12 into the E register then use ADD E or ADC E to complete the addition.

Something to think about!

ADD A is a valid instruction. It is a simple way to multiply A by 2; that is, A + A = 2 * A. Also, multiplying by 2 or doubling shifts all the bits in A one place to the left, which is another useful way of thinking of doubling.

Subtraction with the Intel 8080.

SUB, SBB, SUI, and SBI are the subtraction counterparts to ADD, ADC, ADI, and ACI. The minuend is in the A register and the subtrahend (value to be subtracted from the minuend) is either (1) in a working register for SUB and SBB instructions or (2) n an immediate (following) data byte for SUI and SBI instructions. The Carry Bit in this case acts as a Borrow Bit that is set to one if the subtrahend is larger than the minuend. SUB and SUI ignore the Borrow Bit; SBB and SBI subtract the Borrow Bit along with the subtrahend. Let's look first at the immediate subtraction instructions SUI and SBI.

SUI v SUI Immediate v from A v is subtracted from the value in
A with result in A. The code for SBI is 326Q.

Status bits affected
- Carry, Sign, Zero, Parity, Auxiliary Carry

SBI v Subtract Immediate v from A with Carry v and the carry
bit are subtracted the value in A with result in A. The code for SBI is
336Q.

Status bits affected - Carry, Sign, Zero, Parity, Auxiliary Carry

The Intel 8080 uses two's complement arithmetic (TCA) for signed numbers. This permits us to easily handle the addition and subtraction of negative numbers. With TCA in an 8-bit byte, bit 7 becomes a sign bit and is lost for numeric value. What was a 0 to 255 unsigned number range becomes a signed number range -128 to +127. By using multi-byte TCA representation, however, the range of signed numbers can be increased to whatever is desired. The best part of using TCA is that all variations of adding and subtracting both positive and negative numbers can be accomplished directly with the ADD/SUB group of Intel 8080 instructions. For instance, 25 + (-18) using the ADD instruction produces the same result as 25 - (+18) using the SUB instruction. The table below illustrates how twos complement numbers are assigned. It's not what we might think: bit 7 the sign and bits 0-6 representing 128 to give +/- 128! Instead, it's more like a car odometer rolling forward and backward around zero.

Decimal Number | TCA Binary Number |

127 | 01 111 111 |

126 | 01 111 110 |

125 | 01 111 101 |

... | ... |

3 | 00 000 011 |

2 | 00 000 010 |

1 | 00 000 001 |

0 | 00 000 000 |

-1 | 11 111 111 |

-2 | 11 111 110 |

-3 | 11 111 101 |

... | ... |

-126 | 10 000 010 |

-127 | 10 000 001 |

-128 | 10 000 000 |

One nifty thing about TCA is that a number can be negated by simple complementing it and adding 1. Take -126 = 10 000 010. For -(-126), complement each bit giving 01 111 101 then add 1. We get 01 111 110, the expected result 126 from the above table.

Try it!

Example 3 - Create and test code that subtracts a value using SUI v.

000 000 076 MVI A, 25
25gA

000 001 031
25=031Q

000 002 326 SUI 18
A-12gA

000 003 014
12=014Q

000 004 166 HLT Halt execution

a)
Enter the code to subtract 12 from 25. Click Reset and Single Step
through the program. Use the Display A button to check the value in the
accumulator. It should be 015Q or 13.
Now click Display Status. The Borrow (Carry) Bit should be zero since no borrow was
needed.

b) Subtract 25 from 12 by reversing the immediate values in addresses 000 001Q and 000 003Q above. Reset and this time, click Run. The code will execute and halt at address 000 004Q. The correct decimal value is -13. Display A should show 363Q or -13, the two's complement of 13. Click Display Status and see that the Borrow (Carry) Bit is one indicating a borrow was needed. The Borrow Bit can be used to do multi-byte subtraction.

Example 4 - Subtract 12 from 25 with SBI so that the Borrow (Carry) Bit will be subtracted along with the immediate value.

000 000 067 STC
Set Carry Bit (C=1)

000 001 077 CMC
Complement Carry Bit (C=0)

000 002 076 MVI A, 25 25gA

000 003 031
25=031Q

000 004 336 SBI 12 A-12-CgA

000 005 014
12=014Q

000 006 166 HLT
Halt execution

Load and run the code then
click Display A. It should be 015 or 25-12-0=13. The zero Borrow (Carry) Bit
made no difference. Replace the CMC as before with a NOP
instruction. Run the code again and display the result. It should be
014Q or 25-12-1=12 because the Borrow Bit, now one,
has been subtracted along with 12.

The SUB and SBB instructions work similarly except the
value to be subtracted from A is in one of the registers. Note: In the
definitions below, r is a *Register Reference Number*.

SUB r Subtract contents of register r to A
The
contents of register r is subtracted from the value in
A with result in A. The octal code byte for SUB is 22r. For example,
SUB H
is 224Q.

Status bits affected
- Carry, Sign, Zero, Parity, Auxiliary Carry

SBB r Subtract contents of register r to A with Borrow (Carry)
The contents of register r and the carry bit are subtracted from the value in
A with result in A. The octal code byte for SBB is 23r. Example: SBB H
is 234Q.

Status bits affected
- Carry, Sign, Zero, Parity, Auxiliary Carry

Try it yourself!

Rewrite and test Examples 3 and 4 using SUB and SBB instructions respectively. Instead of immediate values, use MVI L,v to load the data (12) into the L register then use SUB or SBB to complete the subtraction.

Something to think about!

SUB A is a valid instruction. What is the result in A? What is the Carry Bit? Could SUB A be used instead of STC followed by CMC to clear the carry, thus saving a byte?

How to do a two's complement conversion.

Let's look at how Intel 8080 code can do a two's complement conversion. Assume that the value to be two's complemented is in the A register. The instruction CMA instruction 057Q complements the A register; that is, 0's become 1's and 1's become 0. To complete twos complement conversion, simply follow with the ADI 1 instruction.

Try it !

Example 5 - Create and test code that verifies that the negative of a negative is a positive.

000 000 076 MVI
A, 25 25gA

000 001 031
25=031Q

000 002 057 CMA
A'gA (The apostrophe indicates the bit-wise complement of A.)

000 003 306 ADI 1
A+1gA

000 004 001
1=001Q

000 005 166 HLT
Halt execution

Use the example code above and verify the two's complement value for 25 as shown in the table below. Then rerun the code starting with -25 to see if -(-25) = 25.

N Decimal |
N Octal |
N Binary |
-N Binary |
-N Octal |
-N Decimal |

25 | 031 | 00 011 001 | 11 100 110 +1 = 11 100 111 |
347 | -25 |

-25 | 347 | 11 101 110 | 00 010 001 + 1 = 00 010 010 | 031 | 25 |

Example 6 - Create and test code that verifies the variety of addition and subtraction examples shown in the table below.

Use the code of Example 1 substituting the appropriate instruction (ADI v or SUI v) and the table values to verify the results indicated.

A | Operation | B | = | = (in Binary) | = (in Octal) |

25 | + | 18 | 43 | 00 101 011 | 053 |

25 | + | (-18) | 7 | 00 000 111 | 007 |

-25 | + | 18 | -7 | 11 111 001 | 371 |

-25 | + | -18 | -43 | 11 010 101 | 325 |

25 | - | 18 | 7 | 00 000 111 | 007 |

-25 | - | 18 | -43 | 11 010 101 | 325 |

-25 | - | -18 | -7 | 11 111 001 | 371 |

Something to think about!

What would happen if we added 125 and 85 using signed numbers? The result is greater than the two's complement maximum of +127 and would appear to be an erroneous negative number. This is signed arithmetic overflow. A similar situation occurs when subtraction yields a value less than -128. In a later experiment, we will see how to detect this overflow and report it as an error. Of course, if unsigned numbers arithmetic is assumed, the sum would be 210 and perfectly acceptable. Overflow in this case could be monitored by the Carry bit.

Continue to next Experiment - Click Here