Building Simple CPUs
CS 641 Lecture, Dr. Lawlor
Silicon FET Transistors to Logic Gates
Modern transistors are FET transistors:
you charge up a small channel called the "gate", and it conducts
current between two terminals. In an "n-channel FET", the gate
already has plenty of electrons, so you need to discharge them with a
positive voltage to allow it to conduct. In a
"p-channel FET", you open the gate with a negative voltage. I
like Wikipedia's pictures for these: n-channel is a positive logic
input, and p-channel is an inverting input with an inverting circle.
You can build logic gates from FET transistors quite easily in a "totem pole" configuration. Here's an inverter:
When A is positive, it turns off the high gate, disconnecting Q from
positive voltage (Vdd); and turns on the low gate, connecting Q to the
negative voltage (Vss): A positive makes Q negative. When A is
negative, it turns on the high gate and off the low gate, connecting Q
to positive voltage and disconnecting negative voltage; A negative
makes Q positive.
Here's an AND gate built from FET transistors, and the corresponding silicon implementation:
It's surprisingly easy to build all the logic gates with FET transistors!
Logic Gates to Flip Flops
Once you've got logic gates, the next step is data storage. You can store data by chaining together logic gates in a flip-flops.
It's just a two inverters in series, looped back on the other one, so
it has two stable states: one inverter outputting true, or the other
outputting true.
Of course, it's handy to be able to write values into a flip flop, so a
"RS" (Reset and Set) flip-flop is made from NOR gates.
If both switches are off, the flip-flop just remembers its previous
value. If you turn on the left switch, "Reset", it makes the
middle wire go high and the right wire go low, storing a zero. If
you turn on the right switch, "Set", it makes the wrap-around wire go
low and the middle wire high, storing a one.
Often you want a "data" input, so you decode data and a write enable
line typically called "clock" to make the set and reset lines above:
Flipflops are normally drawn with the two NOR gates' wires crossed,
which looks a little more symmetrical but substantially more confusing
(to me). This is the same circuit:
These flip-flops can be replicated one after another to store an
arbitrary number of bits. A collection of bits that can be read
or written together is a "register". A collection of registers is
called a "register file".
Logic and Registers into a CPU
First, a short survey of how to get work done in Logisim:
- To run the program, download the .jar file, and double-click it. Save often, because it can crash!
- Use the arrow tool to move parts around. Use the hand tool to push buttons and enter values.
- "Base -> Pin" is a very handy generic input. For data input, you probably don't want "three-state"": 0, 1, and x (don't care).
- "Base -> Probe" is a generic output. It automatically
sizes to match the wire you hook it to. Connect an Pin directly
to a Probe. Use the hand tool to poke at the pin, and the values
immediately change on the probe.
- "Gates -> AND Gate" is a scalable logic gate. Set the Gate Size to Narrow, and the Number O... to 2. Hook up two Pins to the input, and Probe to the output. Play with the gate.
- You can set the number of bits on the Pin and AND gate, such as 8
bits. It immediately scales the output Probe up to 8 bits.
You get an orange "Incompatible widths" error if input and outputs don't match up. Either change them to match, or use a Splitter or Bit Extender to address the mismatch.
- Try replacing the AND gate with an "Arithmetic ->
Adder". It's got optional carry-in and carry-out, but you can
leave them unconnected and it'll still work.
Here's a basic Register, which stores a value (displayed inside),
always outputs the value on the Q output, clears the value to zero with
the "0" input (bottom right side), and reads a new value from D when
you bring the "en" clock input high. I'm using an
"Input->Button" as a momentary input to clock in values, or reset
the value to zero. Click the image to get a Logisim .circ file to
play with.
Here's the same register's output fed into an adder, which is then fed
back into the register's input again. This circuit just doubles
the value every time you hit "clock in".
Of course, a real CPU has lots of operations, not just addition.
But we can support different operations by multiplexing which operation
we want, using a "Plexers -> Multiplexer" or "mux". The mux's
input determines which operation we perform.
Finally, a real CPU can store more than one value at once. We can
choose which register to use as an input, by using a mux the same
way. We can now poke the various buttons, and get addition or
multiplication on any of the stored register values, store the value
back to any register, and operate back and forth indefinitely.
Given a list of button values, this circuit can compute stuff.
It's a CPU!