Making a CPU from Boolean Gates from Scratch
By: Erik Engheim
Tags: Microprocessor, Learning, Arm, Cpu, Electronics

Have you looked at the current announcement of Apple’s transition from intel processors to ARM processors? Maybe you began reading up on things like instruction sets, RISC and CISC processors. You will quickly hit upon a lot of complicated terminology.

So how about going all the way back to basics, and look at what a CPU looks like if you strip it down to its bare bones. What are the most essential parts, and what is just cool stuff added to make it run faster?

Turns out that there is a treasure trove of web pages explaining simple CPU designs and really teaching you everything from scratch. I don’t really have to recreate what they have written, but instead give an overview of all the cool stuff out there.

Simple CPU Design

simplecpudesign.com is an amazing website. Could maybe do more with the layout, but in terms of content, this contains so many cool things it can make a geek go crazy.

Mike, author of this site goes through a whole bunch of ways of making a CPU designed like this:

Mike at simplecpudesign.com made this simple 8-bit CPU. Show how data from memory is fed into arithmetic logic unit (ALU), instruction register, accumulator etc.

You can make this on breadboard yourself if you want. Let me give some comments to the diagram of how to read it.

What are the Colored Lines?

The colored lines referred to as busses are usually an abstraction of 16 separate electric wires carrying digital signals. So e.g. the blue lines represent 16 wires carrying data from memory to the various parts of the CPU.

Every part of the CPU in principle gets the 16-bit number read from memory. However the red lines are used to decide which part is activated so it actually receives the number on the blue lines.

The green lines send 16-bit number representing an address. Notice how the RAM (the memory) contains 8 different memory slots numbered from 0 to 7. The green memory bus selects which slot will send the 16-bit number it contains out onto the blue line.

Please note I may be wrong about the green line being 16-bit as you don’t need 16-bits to represent 8 different memory locations. 3-bits would be enough.

Let us take a brief explanation of the the different parts on the diagram which you may not be familiar with.

MUX — Multiplexer

MUX is short for multiplexer. Conceptually it works as the diagram below.

A mechanical multiplexer, just to illustrate how the electronic version of it works.

This is a mechanical multiplexer, and obviously in a computer it would be electronic. However showing what it does mechanically is easier to grasp. Notice the red lines pointing into every MUX. The red lines are used to toggle which input should be selected and sent to the output. So you can see how activating the right most MUX over the ALU, lets you choose between sending an address number or a data number into the right part of the ALU.

Decoder

To understand anything about digital electronics, I highly recommend All About Circuits web site.

They describe Decoders more in detail here. Decoders pop up in all sorts of circumstances. You got decoders for turning a binary number into a representation of a number on a 7-segment display e.g.

7-segment display. You send binary numbers into a decoder to show these.

But inside the CPU, what we got is an instruction decoder. However common to a lot of these decoders is that you get a binary number as input, which then causes specific output lines to activate.

For a line decoded you usually just active a single output line.

Below is an example of this:

In this case you get a 2-bit binary number as input which can represent numbers from 0 to 3 (0b00 to 0b11). If the input is 0, then the first line D0 gets activated and all other lines go 0.

If input is 3, then D3 turns on (set to 1) and every other output turns 0. The instruction decoder will take inputs from the instruction register and use it to activate the parts of the CPU that the instruction wants to use.

Registers

All of these blocks are what we call registers:

Instruction Register (16-bit)

Program Counter (PC)

Accumulator (8-bit)

Basically an accumulator is just a memory cell. These would typically remember an 8-bit number that was placed in them. Some of the registers will be bigger such as the Instruction register because instructions are 16-bit wide. Why?

Because if we are to load 8-bit values into the Accumulator register, then the instructions have to be bigger than that. The operand will be 8-bit, while e.g. the opcode (instruction for what to do) will be 8-bit as well.

This is a common setup. The Nibbler computer e.g. work with 4-bit values in the Accumulator. Thus its instructions are 8-bit: 4-bit for the opcode and 4-bit for the operand (the number you want to e.g. load in accumulator).

Arithmetic Logic Unit (ALU)

This is basically the calculator of the CPU, and it is pretty dumb. It can only add and subtract. Multiplication and division is done by repeatedly adding or subtracting.

This means implementing an ALU in CPU isn’t that hard. You just need to implement a binary adder and a binary subtractor. You don’t need to learn a lot to do that. In fact Mike shows on his page how to do it. A good explanation can also be found on All About Circuits.

I also like this explanation as it shows how a full-adder can be made from two half-adders.

How you can combine half-adders to make a full-adder

Modern CPUs may be able to multiple and divide directly, but for most of history even if a CPU had a multiply instruction, it would internally be done as repeated additions.

Assembly Language

The cool thing about this is that a minimal CPU that can do anything does not need a very large instruction set. This is a list of all the instructions Mike’s Simple CPU Design supports.

Load ACC kk : 0000 XXXX KKKKKKKK

Add ACC kk : 0100 XXXX KKKKKKKK

And ACC kk : 0001 XXXX KKKKKKKK

Sub ACC kk : 0110 XXXX KKKKKKKK

Input ACC pp : 1010 XXXX PPPPPPPP

Output ACC pp : 1110 XXXX PPPPPPPP

Jump U aa : 1000 XXXX AAAAAAAA

Jump Z aa : 1001 00XX AAAAAAAA

Jump C aa : 1001 10XX AAAAAAAA

Jump NZ aa : 1001 01XX AAAAAAAA

Jump NC aa : 1001 11XX AAAAAAAA

E.g. because you got Jump and Add you can implement a loop and perform multiplication.

A simple comment on how to read this Instruction Set works. After the colon, we have an explanation of the bits used to implement that instruction. We can see each instruction is 16-bit long.

The firs 4-bits are used to pick the instruction itself. The remaining 12-bits are used to provide operands (arguments) to the instruction.

ACC means the accumulator register. So it refer to filling a value inside it.

KKKK KKKK means 8-bits are used for intermediate values. If it had said KKK it would have meant 3-bits.

means 8-bits are used for intermediate values. If it had said it would have meant 3-bits. XXXX refers to 4 unused bits in the instruction.

refers to 4 unused bits in the instruction. AAAAAAAA an 8-bit memory address.

With the Jump instruction you see letters such as:

Z Zero bit. Last calculation caused result to be zero.

Zero bit. Last calculation caused result to be zero. C Carry bit. Last addition caused a carry (result was larger than the number that could be held in register).

All of these are single bits in a status register which keeps track of how a calculation turned out. If it overflowed, got below, zero, got exactly zero etc.

Operations of CPU

Mike shows several illustrations such as the one, demonstrating how a program is executed on his simple chip.

He makes it easier to see what is going on by highlighting the lines showing where the data flows. We can look at the second picture, the decode step, to explain how to read this illustration.

The following instruction is being executed: INPUT ACC, 6

This instruction is telling the CPU to load the contents of memory address 6 into the accumulator (ACC).

Let us break down how this happens. I will not explain every step. Just a couple to help you understand how to read the diagram.

(1) Fetch: get instruction stored at PC

We are in a state where we are trying to get the next instruction our program to execute. The Decoder is bossing around all the other parts of the CPU, telling them what to do.

The red line flowing to the PC (program counter) register and the right most MUX is highlighted. It means the Decoder has told them to get busy. This causes the address stored in the PC register to flow into the address buss. PC contains 0, so the 16-bit number stored on memory address 0 is picked. Data from memory flows into IR register.

That completes fetching of the instruction. The next step is to figure out what this instruction is telling us to do. That is the Decode step.

(2) Decode: Set MUX, ALU transfer

Various bits in the instruction is read by the Decoder, which causes different outgoing red decoder lines to be activate.

Decoder tells left-most MUX to accept intermediate value from the instruction register (address of data we want to fetch). Dark blue highlight on data bus from IR to MUX shows this. Decoder also toggles on right-most MUX which causes this number 6 to flow out on the address bus. On location 6 in memory which we have picked, we find the value 250. 250 flows into the middle MUX. We can see this from the dark highlighting of the blue data line going into the middle MUX. Thus the right side of the ALU gets 250. Because the left side is not toggled on it gets a 0. The ALU is not setup to add 0 and 250.

In the next stage which is the execute stage we actually end up performing the addition and placing the result 250 in the accumulator (ACC).

Of course we did not ask for an addition, but this has the same effect as moving the value of address 6 into the accumulator. Mission accomplished.

How Would You Design Such a CPU?

So now you have some ideas of the basic operations of a CPU. You could read up more of the details if you want on the links. However the next question is how hard would it be to design such a computer.

I am not interested in taking you through the whole process but explain how some of the key parts which may seem trick works to remove the mystery of creating a CPU.

The trickiest parts are probably how to make the ALU and the Decoder. How would you go about doing that?

You need several tools in your tool-belt to do this:

You need to learn what a truth table is and how to write them up. Learn the rules of Boolean Algebra. How to simplify circuits using Boolean Algebra Rules. Converting truth tables into Boolean Expressions.

So to make an adder or decode e.g. you would first setup a truth table (1), which says what outputs this electronic component should give for given inputs.

Next you use knowledge from step (4), to convert this truth table to a boolean expression. This expression will initially be overly complex.

Thus you use knowledge from step (3), to simplify the boolean expression, using boolean algebra rules.

You then have the compact boolean expression you can use to draw up logical gates which will make the electronic component you want.

Erik’s Crash Course in Boolean Gates and Logic

Say you read the articles I linked to or already kind of, sort of know the material I will try to do a quick version here to fill in the wholes.

Usually in these documents we talk about inputs A, B and C and usually there will be some output Q. As programmers are used to writing this like:

Q = A | B # OR

Q = A & B # AND

Q = !A # NOT

However in Boolean Algebra discussed in electronics websites would write it like this:

Q = A + B # OR

Q = A.B # AND

Q = A̅ # NOT

A mathematician would write it more like on Wikipedia: