We started with the idea of code — data consisting of instructions in a special language. Code can express an algorithm, a process consisting of instruction steps. That implies an engine that understands the code language and executes the steps in the code.
Last time we started with Turing Machines, the abstract computers that describe algorithms, and ended with the concrete idea of modern digital computers using stored-programs and built on the Von Neumann architecture.
Today we look into that architecture a bit…
An algorithm is an abstraction of the state diagram that defines it. If you understand the diagram (if you can read the flowchart), you can trace through and execute the algorithm yourself — you can be the engine.
Generally, if you know the code language, you can execute an algorithm using that code in your head (or with the aid of pen and paper). Programmers routinely scribble their thoughts in pseudo-code, a pretend language no computer actually understands.
One distinction among languages is how easy or hard it is to follow along with the computer. (Attempting to execute a suite of algorithms manually becomes a formidable — but theoretically possible — task.)
The whole point of programming languages is to elevate the level of abstraction to a point where humans can manage it (and in those abstractions discard a lot of details). The code the computer actually uses is made of just ones and zeros.
The thing about computers is that they are extremely simple-minded devices. Simulating a computer is actually very easy, because when you come down to it, there’s not much to them. Here’s the executive summary on what computers can do:
- Input some numbers into them.
- Do math or logic on those to make new numbers.
- Output the resulting numbers.
That’s it. That’s all computers do.
The thing is, they do it really, really, really fast. And you can make them output useful numbers, even numbers that do things (like control machines or make pictures).
But they’re still just over-grown calculators — keep that in mind.
My ultimate goal here is to characterize the complexity of a computer, but doing that requires understanding more about their architecture — the topic de jour — so let’s get to it.
Your average digital computer has three fundamental parts (besides control circuits and power supplies and other miscellanea):
• The Processor (the “engine” or “brain” that executes code) — often called the CPU (central processing unit). All the math and logic happens inside this. The processor also controls (directly or through co-processors) the operation of the system.
• Storage, also called memory. Exactly as the name implies, a place to store stuff. In particular, the code and data for the system. Memory includes both short-term (RAM) and long-term (disks, et al.) storage — any place you can stash data.
• I/O (Input/Output). The “senses” and “muscles” of a computer. This is how data (including code) gets into the system and how results of processing get out. Common examples include keyboards, mice and other pointing devices, video displays, and printers, but that only scratches the surface of I/O devices.
All three of these are connected via a common parallel data highway mainly consisting of the address and data buses (and some control lines).
In a sense, the CPU, the RAM, and the I/O, all live on the same “street” — the address bus carries the “house number” of the one the CPU is talking to at any given moment. (Those moments, as mentioned, are very, very brief.) The data bus, obviously, carries the data.
The “width” (number of wires, one per bit, usually a multiple of eight) of the address and data bus is correlated with a computer’s processing power. A wider data bus means more information exchanged each cycle; a wider address bus means more memory (the more addresses available, the more “houses” can be on the “street”).
One thing that’s interesting about this architecture is that it plays out again inside the CPU!
The Processor is a self-contained computer with its own microcode engine (arithmetic and logic units that perform operations), local memory (cache and registers), and I/O (to connect outside the chip).
The width of the data bus inside the CPU is even more correlated with processing power than the system data bus. A bigger data bus means the processor can calculate with larger numbers.
References to “32-bit” or “64-bit” computers usually refer to the size of the CPU data bus.
Typically the system buses are the size as the CPU buses, especially the data bus, but there are exceptions.
We’ll come back to the CPU internal architecture in a bit. For the moment, we’ll stick to the system level.
Let’s suppose the code the computer is running right now is tallying up a sum of some kind and has reached the point in the algorithm where it needs to add an amount to the running total.
The programmer who wrote the code likely used a programming language with a high level of abstraction that allowed them to write a human-readable fragment of code something like this:
total := total + amount
This says to take the current value of the total variable and the value of the amount variable, add them together, and put the resulting sum back into the total variable. (The “:=” part means put the value on the right into the object on the left.)
Remember that variables are code objects that act like scratch pads for calculation. We’ll assume some memory location is known to the code as total and another is known to it as amount. (That is, it knows the address of those objects in memory.)
The code running in the computer looks something more like this (a register is a special memory location inside the CPU):
LOAD register-1, [total] LOAD register-2, [amount] ADD register-1, register-2 STOR register-1, [total]
Note that this is still an abstraction for us humans to read and discuss. The CPU is actually just reading a code stream of binary numbers — bits — from memory.
An application called a compiler converted the programmer’s high-level source code into low-level assembly code similar to this so the CPU can run it. This low-level code represents what the CPU can actually understand and do.
Therefore we can view these steps in light of the earlier list of the Three Things Computers Can Do:
The first two steps read numbers from memory into the CPU (ability #1). The third step adds those two numbers together resulting in a sum (ability #2). The last step writes that sum back into memory (ability #3).
That’s it. That’s all computers do.
We’ll wrap this up by jumping inside the processor to see how it handles those four instructions internally.
The CPU has been reading instructions and comes to the first
LOAD instruction. It looks this up in an internal table and finds (and runs) a micro-program for doing a
The microcode knows that following the
LOAD instruction is the name of a target register and a memory location, so it reads those (which may require using the very process described next).
To read from a memory location the microcode goes through the steps to place the memory address specified (total) onto the external address bus. (That is: it outputs a number from the CPU!)
Then it waits for system memory to access that location and put the value it finds on the data bus.
(This is a real-world operation that takes a tiny faction of time. Signals on the control bus tell the processor when the data is ready.)
Finally, the CPU reads the returned value off the data bus and into the register specified. (It inputs a number!)
The next instruction is another
LOAD that inputs a different memory location into a different register, but the process is identical otherwise.
ADD instruction also invokes a micro-program from the internal table (all instructions do). In this case, the next two items in the code stream name two registers that hold values to be added.
The CPU uses its arithmetic logic unit to perform the addition with those values and places the result of the addition in the first register named (which destroys the value — the previous total — it originally had).
STOR instruction is the reverse of the
The CPU again outputs the memory address, but this time it also outputs the register value to the data bus. The system memory takes that value and writes it to the memory location specified.
(Again, control signals tell the CPU when the operation is complete.)
If you think this sounds involved, be advised that by today’s standards it’s quaintly old-fashioned and simplistic. Modern CPUs are hideously involved to the point that writing even halfway decent assembly code is best left to the experts who design modern compilers for those chips.
As the same time, as the saying goes, “Calm Down! It’s only ones and zeros!” Underneath all the complexity is a simple machine that does only three things.
Fast. Oh, so blindingly fast!
 In fact, that’s one of the values of flowcharts. It lets us see the algorithm we’re building and pretend to be the computer that will run it. (Another value of flowcharts is they let us communicate algorithms with other humans.)
 “Assembly” languages are an extremely low-level abstraction based directly on the binary code language the CPU uses. They give humans a fighting chance as working with the actual computer code run by the CPU:
As you can see, it’s an esoteric language. The numbers down the left-center are the hexadecimal versions (an abstraction) of the actual binary codes used by the CPU. The “assembly” language is the strange text filling the right half. (The numbers on the far left are the memory locations of this code.)
 The word, computer (one who computes), is just another word for calculator. (Historically, the word referred to humans who had the task of calculating things.) Computers calculate. Using numbers.
 In related Sideband posts, I plan take you way down the rabbit hole to the logic gates and transistors that make it all work.
 For example, a system that doesn’t need a large address space might not bother with a full-sized address bus.
 Which means a given dialect of assembly code is particular to a given CPU.
 And makers of computer viruses which need the low-level “close to the metal” access assembly allows. And therefore, likewise, makers of anti-virus software. It’s a very esoteric field!