Code_ The Hidden Language of Computer Hardware and Software - Charles Petzold [78]
The machine is said to execute an instruction when it does a series of actions in response to the instruction code. But it's not as if the machine is alive or anything. It's not analyzing the machine code and deciding what to do. Each machine code is just triggering various control signals in a unique way that causes the machine to do various things.
Notice that by making this machine more versatile, we've also slowed it down. Using the same oscillator, it adds numbers at only one-fourth the speed of the first automated adder I showed in this chapter. This is the result of an engineering principle known as TANSTAAFL (pronounced tans toffle), which means "There Ain't No Such Thing As A Free Lunch." Usually, whenever you make a machine better in one way, something else tends to suffer as a result.
If you were actually building such a machine out of relays, the bulk of the circuit would obviously be the two 64-KB RAM arrays. Indeed, much earlier you might have skimped on these components and decided that initially you would need only 1 KB of memory. If you made sure you stored everything in addresses 0000h through 03FFh, using less memory than 64 KB would work out just fine.
Still, however, you probably weren't thrilled that you needed two RAM arrays. And in fact, you don't. I originally introduced two RAM arrays—one for code and one for data—so that the architecture of the automated adder would be as clear and simple as possible. But now that we've decided to make each instruction 3 bytes long—with the second and third bytes indicating an address where the data is located—it's no longer necessary to have two separate RAM arrays. Both code and data can be stored in the same RAM array.
To accomplish this, we need to have a 2-to-1 Selector to determine how the RAM array is addressed. Usually, the address is the 16-bit counter, as before. The RAM Data Out is still connected to three latches that latch the instruction code and the 2 address bytes that accompany each instruction. But the 16-bit address is the second input to the 2-to-1 Selector. After the address is latched, this selector allows the latched address to be the address input to the RAM array:
We've made a lot of progress. Now it's possible to enter the instructions and the data in a single RAM array. For example, the diagram on the next page shows how to add two 8-bit numbers together and subtract a third.
As usual, the instructions begin at 0000h because that's where the counter starts accessing the RAM array after it has been reset. The final Halt instruction is stored at address 000Ch. We could have stored the three numbers and the results anywhere in the RAM array (except in the first 13 bytes, of course, because those memory locations are occupied by instructions), but we chose to store the data starting at address 0010h.
Now suppose you discover that you need to add two more numbers to that result. Well, you can replace all the instructions you just entered with some new instructions, but maybe you don't want to do that. Maybe you'd prefer to just continue with the new instructions starting at the end of these instructions, first replacing the Halt instruction with a new Load instruction at address 000Ch. But you also need two new Add instructions, a Store instruction, and a new Halt instruction. Your only problem is that you have some data stored at address 0010h. You have to move that data someplace at a higher memory address. And you then have to change the instructions that refer to those memory instructions.
Hmmm, you think. Maybe combining Code and Data into a single RAM array wasn't such a hot idea after all. But I assure you, a problem such as this would have come up sooner or later. So let's solve it. In this case, maybe what you'd like to do is enter the new instructions beginning at address