0003.b Hardware, software, and how they interact
On this page
The devices in the previous section are the edges of a computer, and this section looks at what lies between them. A computer is best understood as a stack of layers, each built from the one below it and each hiding the details of that layer from the one above. At the bottom are transistors, which form logic gates, which form the circuits of the processor and memory. The processor runs machine language, which people can write more readably as assembly language. Firmware stored on the hardware starts the machine, the operating system manages the hardware once it is running, and drivers connect the operating system to particular devices. Applications sit at the top, written in high-level languages that compilers and interpreters translate down into machine language. The section climbs this stack from the bottom, and then looks at embedded systems, where a whole stack is dedicated to a single job inside a larger device.
Gates and the processor#
Computer hardware is built from transistors, tiny electronic switches that are either on or off, and those two states are the 1 and 0 of binary that 0003.h describes. Transistors are combined into logic gates, which take binary signals as inputs and produce one as output.1 AND outputs 1 only if both inputs are 1, so a gate that turns on a light only when a motion sensor detects movement and a switch is on is an AND gate with the sensor and switch as inputs. OR outputs 1 if either input is 1. NOT inverts a single input. XOR, exclusive or, outputs 1 if its inputs differ. These are the same operations as the logical operators in 0002.j, where expressions are evaluated from left to right, so TRUE OR TRUE AND FALSE gives FALSE, because TRUE OR TRUE is TRUE and TRUE AND FALSE is FALSE.
Gates matter because they combine into circuits that do arithmetic and store values. A half adder, which adds two bits, shows how. Adding two one-bit numbers gives a sum bit and a carry bit: 1 + 1 is 10 in binary, a sum of 0 with a carry of 1. The sum bit is 1 exactly when the inputs differ, which is XOR, and the carry is 1 only when both are 1, which is AND. If someone builds the sum from an OR gate by mistake, the circuit works for every input except 1 + 1, because that is the one case in which OR and XOR differ. Larger circuits built the same way add whole numbers, compare them, and hold them in memory.
Those circuits make up the central processing unit (CPU), which executes a program's instructions in a repeating cycle. In each fetch, decode, and execute cycle it fetches the next instruction from memory, decodes it to determine what operation is called for, and executes it. Three parts of the CPU work together in this. The control unit directs the sequence of instructions. Registers are small, fast storage locations inside the processor that hold the values currently being operated on, so even though the running program sits in memory, the numbers being added at a given moment are in registers. The arithmetic logic unit (ALU) carries out the operation that the instruction register names, using values held in registers, and places the result in the accumulator, a register that holds it for further operations. If the instruction register calls for addition and two registers hold 1 and 3, the ALU produces 4 and sends it to the accumulator. Despite the emphasis of its name, the ALU performs logical operations, such as AND, OR, and comparisons, as well as arithmetic. The division of labor is worth keeping straight: the control unit coordinates, and the ALU computes.
Clock speed sets how many of these cycles occur per second, so a faster clock completes the same instructions in less time. Each instruction is very simple, such as adding two numbers, comparing them, or copying a value, and all the complex behavior of a computer, from a word processor to a game, arises from executing enormous numbers of these simple instructions.
Memory and storage#
The processor needs somewhere to keep the programs and data it is working on, and computers use two kinds of memory that trade speed against persistence. Random access memory (RAM) is fast memory for running programs, and it is volatile, meaning it loses its contents without power. Storage, such as a solid-state drive, is slower and nonvolatile: it retains data without power. A computer uses both because neither does both jobs. When you open a file, it is loaded from storage into RAM so a program can work on it, and saving moves data in the opposite direction, back to storage. This is why edits made since the last save vanish when the power fails: they existed only in RAM. It also explains a common misunderstanding about slow computers. Running programs use RAM, so a computer with many programs open slows down when RAM runs short, regardless of how much free space its drive has, and the remedy is installing more RAM. Section 0003.f returns to storage devices in more detail.
From machine language to high-level code#
A CPU executes only machine language, binary instructions that it runs directly. Each processor architecture has its own instruction set, the collection of instructions it understands, so machine language for one processor family doesn't run on another. Writing in binary is impractical for people, so assembly language gives a human-readable form of the same instructions, such as MOV R1, 5, which moves the value 5 into register R1. Assembly is still tied to one architecture, since each of its instructions corresponds to one in that architecture's instruction set, and it doesn't carry across processor families. An assembler translates assembly language into machine code.
Most programs are written instead in high-level languages such as Python, and since the processor executes only binary instructions, that source code must be translated into machine language to run. There are two approaches. A compiler translates a whole program in advance, sometimes generating assembly language as an intermediate step on the way to machine code. This adds a build step before the program can run, which can later pay off in running speed. Because the compiler processes the whole program before it runs, it can report some errors before any line executes. A company can also distribute only the compiled binaries, the machine-language files, so customers can run a program without receiving its source code, although binaries can still be analyzed. An interpreter instead translates a program during execution, as it runs. There's no build step, but the interpreter may reach an error only when execution gets to the faulty line, so a mistake late in a script can go unnoticed until then.
Firmware, the operating system, and drivers#
Between the bare hardware and the applications sit layers of system software. The lowest is firmware, low-level software stored on a hardware device that controls its basic operation. It resides in the device's own nonvolatile memory, so it is available before any drive or operating system is used. When a computer boots, the system firmware stored on its main circuit board initializes the hardware and starts the operating system. Routers, cameras, printers, and network switches have firmware too. Flaws in it are fixed by firmware updates applied to the device itself, and these need care, because an interrupted update can leave a device without the software it needs to start up.
Once the computer is running, the operating system (OS) manages it. It manages hardware, memory, files, and processes, which are running programs. It allocates memory among those processes, and its scheduler switches among them rapidly so that they can share the CPU, which is how many programs appear to run at once. It also enforces permissions, the access rules set on files in the file system. Just as important, it gives applications a consistent interface to the hardware. An application asks the OS to save a file, and the OS's file services hide the differences among a solid-state drive, a USB drive, and a network folder. Application developers can therefore largely ignore hardware specifics. This interface hides device details, but it doesn't remove the OS's other roles: permissions still apply, and the hardware isn't any faster for being hidden.
The OS can't know the details of every printer, camera, or sound card ever made, and device drivers fill that gap. A driver is software that lets the operating system communicate with a specific hardware device, translating general requests into ones a particular printer model understands. Drivers make hardware support modular, so new hardware can be supported by adding a driver without rewriting the operating system. This also explains a familiar problem: a computer with a clean installation of its operating system may have no sound, even though the speakers work on other machines and every application is silent, because the installation left out the sound driver supplied by the manufacturer. Drivers often run with high privileges, close to the operating system, so a faulty driver can crash the whole system, which is a more severe failure than an ordinary application crashing.
Embedded systems#
Not every computer is general-purpose. An embedded system is a dedicated computer within a larger device, such as a car, a microwave, or the controller that runs the wash cycles of a cafeteria dishwasher, performing specific functions. Embedded systems often use input from sensors, which tell them about their environment, as when a thermostat's controller reads a sensor measuring the conditions inside a room. They usually have limited memory and power and strict timing needs, since a car's braking system can't wait. Many are long-lived devices, and those with no way to receive security updates can remain vulnerable for years. Embedded systems and the general-purpose computers above share the same layered stack, which means a problem can arise in any layer. Finding which layer is at fault is the subject of the next section.
- transistor: a tiny electronic switch, the basic building block of computer hardware
- logic gate: a circuit that combines binary signals, such as
AND,OR,NOT, orXOR - half adder: a circuit that adds two bits, using
XORfor the sum andANDfor the carry - central processing unit (CPU): the processor that executes instructions
- fetch, decode, and execute cycle: the repeating cycle in which the CPU executes instructions
- control unit: the part of the CPU that directs the sequence of instructions
- register: a small, fast storage location inside the CPU
- arithmetic logic unit (ALU): the part of the CPU that performs arithmetic and logical operations
- accumulator: the register that receives the ALU's result
- clock speed: the number of cycles a CPU completes per second
- random access memory (RAM): fast, volatile memory for running programs
- volatile: losing contents without power
- storage: slower, nonvolatile memory, such as a solid-state drive, that retains data
- machine language: binary instructions executed directly by a CPU
- assembly language: a human-readable, architecture-specific form of machine language
- assembler: a program that translates assembly language into machine code
- compiler: a program that translates a whole program to machine language in advance
- interpreter: a program that translates and runs code during execution
- firmware: low-level software stored on a hardware device that controls its basic operation
- operating system (OS): software that manages hardware, memory, files, processes, and permissions, and gives applications a consistent interface
- scheduler: the part of the OS that shares the CPU among processes
- device driver: software that lets the OS communicate with a specific hardware device
- embedded system: a dedicated computer within a larger device that performs specific functions
Practice: practice questions for 0003.b