Code_ The Hidden Language of Computer Hardware and Software - Charles Petzold [75]
This diagram is missing a few pieces, but it shows all the 8-bit data paths between the various components. The 16-bit counter provides an address for the two RAM arrays. The output of the Data RAM array goes into the 8-Bit Adder, as usual, to perform the Add instruction. But the input to the 8-bit latch can be either the output of the Data RAM array (in the case of a Load instruction) or the output of the adder (in the case of an Add instruction). This situation requires a 2-to-1 Selector. The output of the latch circles back to the adder, as usual, but it's also the data input of the Data RAM array for a Store instruction.
What this diagram is missing are all the little signals that control these components, known collectively as the control signals. These include the Clock and Clear inputs to the 16-bit counter, the Clock and Clear inputs to the 8-bit latch, the Write input to the Data RAM array, and the Select input to the 2-to-1 Selector. Some of these signals will obviously be based on the output of the Code RAM array. For example, the Select input to the 2-to-1 Selector must be 0 (selecting the Data RAM output) if the output of the Code RAM array indicates a Load instruction. The Write input to the Data RAM array must be 1 only when the opcode is a Store instruction. These control signals can be generated by various combinations of logic gates.
With a minimal amount of extra hardware and the addition of a new opcode, we can also persuade this circuit to subtract a number from the value in the accumulator. The first step is to expand the table of operation codes:
Operation
Code
Load
10h
Store
11h
Add
20h
Subtract
21h
Halt
FFh
The codes for Add and Subtract differ only by the least-significant bit of the code value, which we'll call C0. If the operation code is 21h, the circuit should do the same thing it does for an Add instruction, except that the data out from the Data RAM array is inverted before it goes into the adder, and the carry input to the adder is set to 1. The C0 signal can perform both those tasks in this revised automated adder that includes an inverter:
Now suppose we wish to add 56h and 2Ah together and then subtract 38h from the sum. You can do it with the following codes and data stored in the two RAM arrays:
After the Load operation, the accumulator contains the value 56h. After the Add operation, the accumulator contains the sum of 56h and 2Ah, or 80h. The Subtract operation causes the bits of the next value in the Data RAM array (38h) to be inverted. The inverted value C7h is added to 80h with the carry input of the adder set to 1:
The result is 48h. (In decimal, 86 plus 42 minus 56 equals 72.)
One persistent problem that hasn't yet been adequately addressed is the meager 8-bit data width of the adder and everything else that's attached to it. In the past, the only solution I've offered is to connect two 8-Bit Adders (and two of mostly everything else) together to get 16-bit devices.
But a much less expensive solution is possible. Suppose you want to add two 16-bit numbers, for example:
This 16-bit addition is the same as separately adding this rightmost byte (often called the low-order byte):
and then the leftmost, or high-order, byte:
for a result of 99D7h. So if we store the two 16-bit numbers in memory like this:
the result D7h will be stored at address 0002h, and the result 99h will be stored at address 0005h.
Of course, this won't work all the time. It works for the numbers I've chosen as an example, but what if the two 16-bit numbers to be added were 76ABh and 236Ch? In that case, adding