CODE
The Hidden Language of Computer Hardware and Software
2nd Edition

Chapter 21. The Arithmetic Logic Unit

This chapter begins building an eight-bit CPU that is a functional subset of the Intel 8080 microprocessor.

It begins with the Arithmetic Logic Unit (ALU). In the circuits below, the ALU is divided into two parts: the first is the arithmetic unit that handles addition and subtration, and the second handles bitwise logical operations.

The Add/Subtract Unit (pages 321 – 323)

This circuit implements addition and subtraction. The two "spin controls" at the top allow you to select two hexadecimal numbers to be added. Click the arrows at the right of each number to increment or decrement by 1. The arrows at the left increment or decrement the number by 16 (hexadecimal 10).

The two buttons at the top left allow you to select one of four functions: Add, Add with Carry, Subtract, and Subtract with Borrow.

The Result in hexadecimal is shown at the bottom. Carries are handled by a CY In button at the left and a CY Out light at the right.

Your browser does not support the canvas element.

This is a little different from the circuits shown in the book in that the values of both CY In and CY Out are inverted for subtraction. (The entry in the lower-right corner of the table on page 322 should be CY)

An 8-bit CPU must be able to add and subtract 16-bit numbers, 24-bit numbers, 32-bit numbers, and so forth. For this reason, it must be able to save a carry from one 8-bit addition or subtraction, and use it for the next.

For the Add function, the CY In button at the left has no effect. The Result is the lower byte of the sum of the two numbers, ranging from 00h through FFh. The CY Out bit is 1 if the sum exceeds 255.

For Add with Carry, the CY In button causes 1 to be added to the sum of the two numbers by setting the CI input of the adder to 1.

When adding two multibyte numbers, use Add for the pair of least significant bytes. For each subsequent pairs of bytes, use Add with Carry and set CY In to the CY Out value of the addition of the previous bytes.

You might want to experiment with adding pairs of sample 16-bit numbers. Here are a few sample numbers you can use:

DecimalHexadecimal
10,0002710h
15,0003A98h
20,0004E20h
25,00061A8h
30,0007530h
40,0009C40h

For example, add 2710h and 7530h. You do this in two steps. First, Add 10h and 30h. The result is 40h with CY Out set to 0. Then Add with Carry the high bytes 27h and 75h with CY In set to 0. The result is 9Ch for a composite total is 9C40h.

Now try an example with a carry, for example adding 3A98h and 61A8h. First, Add the low bytes, 98h and A8h. The result is 40h and the CY Out bit set to 1. Second, Add with Carry the high bytes 3Ah and 61h but with CY In set to 1, which is the CY Out obtained when adding the first pair of bytes. The result is 9Ch for a composite total of 9C40h.

Now try adding 7530h and 9C40h. First Add 30h and 40h. The result is 70h and CY Out is 0. Now Add with Carry 75h and 9Ch setting CY In to 0. The result is 11 but a CY Out value of 1 indicates overflow.

This overflow means you're really dealing with 24 bit numbers. So, Add with Carry 00h and 00h with CY In set to 1. The result, of course, is just 01 indicating a 3-byte composite total of 011170h or 70,000 in decimal.

For the Subtract function, the CY In button at the left has no effect. The value of B is subtracted from A by inverting the bits of B, adding them to A, and adding 1 to that, which is accomplished by setting the CI input of the adder to 1. If B is less than or equal to A, the Result is the difference. If B is greater than A, the CY Out light indicates that a borrow is necessary.

Let's try some subtractions, for example 7530h minus 4E20h. Start with the low bytes: Set the function to Subtract, and set A to 30h and B to 20h. The difference is 10h and CY Out is set to 0. Now select Subtract with Borrow, set A and B to the high bytes 75h and 4Eh, and set CY In to 0. The result is 27h for a composite result of 2710h.

Now try 7530h minus 3A98h. Set the function to Subtract and set A to 30h and B to 98h. The result is 98h and CY Out is set to 1. Now use Subtract with Borrow for the high bytes 75h and 3Ah but set CY In to 1 to match the CY Out value of the first pair of bytes. The result is 3Ah for a composite result of 3A98h.

For a final example, try 3A98h minus 7530h. First Subtract the low bytes 98h and 30h. The result is 68h and the CY Out bit is 0. Now Subtract with Borrow the high bytes 3Ah and 75h and set CY In to 0. The result is C5h for a composite result of C568h, but the CY Out value of 1 indicates an overflow.

Your next step might be to do what was done with addition overflow and extend the calculation to 24 bits. Select Subtract with Borrow again but set both A and B to 0 and CY In to 1. Now the result is FFh and CY In is still 1.

You can keep going, but try using the Windows or macOS calculator in Programmer mode to calculate 3A98h minus 7530h. You'll get FFFFFFFFFFFFC598h, indicating a negative number equivalent to –15,000. (Or, you can calculate the two's complement of FFFFFFFFFFFFC598h by inverting all the bits and adding 1. That's 3A98h, which is decimal 15,000.)

The Logic Unit (pages 323 – 330)

The logic part of the ALU is considerably simpler than the arithmetic part. All that's needed are three boxes that perform bitwise AND, XOR, and OR operations, and a selector to select which of the tri-state buffers is enabled:

Your browser does not support the canvas element.

As with the Add/Subtract unit, you can select two hexadecimal numbers for the inputs. Select the operation with the buttons on the left:

If the leftmost button is 0, then none of the tri-state buffers are selected because that's an arithmetic operation. If the buttons are set for 1 1 1, that's a Compare operation, which is handled in the next circuit.

The Arithmetic Logic Unit (pages 332)

The Arithmetic Logic Unit combines the Add/Subtract Unit and the Logical Unit. The version on page 332 of the book is somewhat simplified and does not properly handle the Compare instructions. Handling the Compare instructions involves more complexity, as seen here:

Your browser does not support the canvas element.

The A and B inputs are set at the top on the left and right. The buttons to select the function are in the top center:

The Clock input at the bottom left saves the result of the calculation and the state of the three flags. and the Enable button at the bottom right displays the result.

The first four functions are handled by the Add/Sub module presented earlier in this chapter. The CY Out value is saved in the Flags Latch at the bottom, and then routed back to the CY In input.

The logical functions — AND, XOR, and OR — are handled by the Logic module towards the top on the right. These functions always clear the Carry flag (that is, set it to zero), which accounts for some of the logic towards the top leading to the CY input of the Flags Latch.

For both the arithmetic functions and the logical functions AND, XOR, and OR, the Zero flag is set if the result is zero. This is handled by the eight-input NOR gates in the middle of the circuit.

What complicates this is the Compare operation. The Compare operation sets the Zero and Carry flags as if a subtraction has occurred. The Zero flag is set if the A and B inputs are equal, and the CY flag is set if A is less than B.

However, the Compare operation doesn't result in a new value saved in the Accumulator. For this reason, if a Compare operation is occurring, the A input is enabled with the tri-state buffer at the far left to be saved in the Latch at the bottom right.

For the Compare operation, the Add/Sub module is performing a Subtract with Borrow because F1 and F0 are both 1. For this reason, the CY In is set to 0 when a Compare operation is performed.