From transistors to a CPU
The CPUs of the early 1980s typically contained 5,000 to 10,000 transistors. Today (2020) a mobile phone CPU may contain around five billion transistor. This makes it seem much more incomprehensible than it really is. How far can one go considering individual transistors?
CPUs represent zeros and ones by different voltages. Here we will assume that 0V represents a zero, and 5V represents a one. 5V was a very common voltage for CPUs, used from the Intel 8086 through the 286, 386 and up to the 486. Even the first Pentium used 5V, though later models soon changed to 3.3V. (The lower voltage requires rather less power, and therefore rather less cooling.)
Logic gates are often considered to be the building-blocks of computers. One of the simplest is the or gate. Its output is one if either of its two inputs is one. A very simplistic circuit for this would be simply a pair of diodes:
An or gate, and its conventional symbol. Two diodes, equivalent to one transistor.
The next most simple gate we will consider is the not gate. It inverts its single input, producing a one if the input is zero, and vice versa:
A not gate, and its conventional symbol. One transistor. If the input is one, the transitor switch is turned on, and the output is zero. If the transistor switch is off, the output is one.
The other gate we need is an and gate. It produces one on its output only if both of its inputs are one. But we already have an or gate which produces a zero on its output only if both of its inputs are zero. So if we invert the inputs to an or gate, and invert its output, we get an and gate:
Constructed like this, four transistors.
The next building-block we need is a two input adder. It needs two outputs, and needs to produce 00 if both inputs are zero, 01 if one input is one, and 10 if both inputs are 1, as 10 is two in binary, and 1+1=2.
The top bit is easy: it is one if both the inputs are one, and zero otherwise. It is the inputs fed through an and gate.
The bottom bit is harder. It is almost an or, but it is actually what is called an exclusive or (xor), that is or but not and. But we already have the result of an and, which we can invert to form not and, and then we can and this with the result of an or of the inputs.
Constructed like this, ten transistors.
But much more useful is a three input adder, which again has just two outputs so it can represent 00, 01, 10 and 11.
Constructed like this, twenty-one transistors.
A four bit Adder
We now have enough building blocks to produce something useful. A three input adder could be considered to be a two input adder with an extra carry bit. We can thus chain adders to add as many binary digits as we wish. The lowest two bits of each number feed into a two input adder, and the high bit of the output gets fed into a three bit adder which has as its other inputs the next highest bitrs of the inputs.
Note that the bits of b are represented backwards, and that an adder having as input two four-bit numbers produces five bits of output.
This is rather easy to generalise. An n-bit adder needs (n-1) three input one bit adders, and one two input one bit adder. With the building block we have above, this is 21(n-1)+10=21n-11 transistors. So a thirty-two bit adder needs 661 transistors, and a 64 bit one over a thousand.
So far we have assumed that n bits are used to represent the numbers 0 to 2n-1. If we consider this with four bits, we can represent the numbers 0 (as 0000) to 15 (as 1111). If the result of an addition is greater than 15, the answer simply wraps around. So 8+11=3, as one example. More interestingly, 15 (1111) plus one equals zero. Usually we think of -1 as being the number which gives zero when one is added to it.
So what happens if we interpret the bit pattern 1111 as -1, 1110 as -2, down to 1000 as -8, and the patterns 0000 to 0111 as zero through to seven? Answers now wrap around if they are greater than seven, or less than minus eight, but, apart from that they are correct. Our adder's response of 1010+0111=0001 we could interpret as 10+7=17 wraps to 1, or we could interpret it as -6+7=1.
This convention for negative numbers has several useful properties. The first bit can be regarded as a sign bit, for if it is one the number is negative. The range of positive numbers representable (1 to 7) is as close as possible to the range of negative numbers representable (-1 to -8). With sixteen possible bit patterns, reducing to fifteen once one is assigned for zero, precise equality of the ranges is not possible.
Changing the sign of a number (multiplying by -1) is reasonably simple. One inverts each bit, and then adds one. So to change the sign of 1010 one inverts the bits to form 0101, and adds 1 to get 0110 (six). And to go back one inverts the bits to get 1001, and adds 1 to get 1010.
This system, call "two's complement" has been used by almost every computer for many decades. A 32 bit integer can thus represent from zero to 4,294,967,295 if it is unsigned, or, if one wishes to allow negative numbers as well, it can represent -2,147,483,648 to 2,147,483,647.
A four bit Subtractor
The above is very similar to the adder, save that each bit of b is inverted, and an extra one is added in by making the first adder of the chain three input, not two. So it should calculate a-b.
It even works with large unsigned numbers. It will calculate 1011-1001=1011+0110+1=0010 (actually 10010, but the extra bit is ignored). Is this 11-9=2, or (-5)-(-7)=2? The same circuit supports both representations.
A four bit add/sub unit
Suppose there existed an inverter which either inverted, or did not invert, based on the presence of some control signal. Then it would be easy to make a unit which could be switched from an adder to a subtractor with a single control input.
It is possible to build such an inverter from standard inverters, and gates and or gates. (How?)
Each gate will take a small amount of time to react to a change. In our circuits the or gate will be fast, but the and gate rather slower, as the not gate on each input has to stabilise to the correct output after a change in its input, only then can the or gate start to stabilise, and only once that has happened can the final not gate start to stabilise. Our two-input adder is worse. Its delay will be two ands plus a not. The three-input adder has a delay of two two-input adders plus a not gate. The thirty-two bit adder has to wait for one two-input adder, then each of 31 3-input adders to stabilise sequentially.
If our 32 bit adder were used in a real computer, and if that computer expected the adder to operate in one clock cycle, then the clock cycle could not be faster than the above delay. If it were, the adder would not have finished stabilising, and an incorrect output might be given.
How can one make a transistor switch faster? Using a higher voltage tends to help. But higher voltages mean more power, and then it becomes too hot to operate correctly, and again starts to give incorrect results.
The details of the above examples are not very representative of those used in real CPUs. But the basic principles are sound, and we have shown how quickly one can move from gates containing no more than half a dozen transistors to functional units containing over a thousand.