Early Computing: How the Modern Computer Was Born

kirkr.xyz

The earliest computers were not devices in any modern sense. They were installations. Entire rooms filled with racks of electronics, thick bundles of wiring, panels of switches and status lights. Operating them required teams of specialists. Programming them often meant physically rewiring sections of the machine by hand. Change the program, change the wiring. Thus, it took days.

Computing is no longer concentrated in a few enormous machines but scattered through everyday objects, e.g. laptops or phones, but these are just the surface. Autonomous vehicles process sensor data in real time using embedded computers. Robotics systems fold perception, control, and motion planning directly into their hardware. Network routers push enormous volumes of traffic through the internet using specialised packet-processing silicon. A PlayStation contains hardware powerful enough to have qualified as a supercomputer not too long ago.

Abstraction Layers in Computer Systems

Modern computer architecture is a hierarchy of abstractions, each layer hiding the details of everything below it.

At the bottom, electrons moving through semiconductor materials. From that you get transistors, then circuits, then logic structures, described using register-transfer level (RTL) representations. From those, microarchitectures that implement an instruction set architecture (ISA). Above the ISA: operating systems and virtual machines, which manage hardware resources and present controlled environments to programs. Then programming languages, algorithms, and finally user applications.

The practical effect of this stack is that a modern programmer writing a sorting algorithm has never so much as thought about transistor switching behaviour. Nor does a circuit designer have to worry about how the OS schedules threads. Each layer of abstraction allows the whole system to scale in complexity without anyone having to hold all of it in their head at once. This is really what allowed the modern proliferation of software.

What counts as "computer architecture" has expanded over time. In the first few decades of computing (say, roughly the 1950s through the 1980s) architects focused on the layers between circuits and operating systems: how instructions executed, how memory was organised, how control logic worked. By the 1990s, reliability and power consumption became central concerns as transistor counts climbed and systems grew more complex. From the mid-2000s onwards, parallel architectures, hardware accelerators, and security mechanisms became core parts of the field. The boundaries between hardware design, systems software, and application behaviour have been obscured ever since.

Technology and Software

Technology moves fast. New transistor designs, fabrication processes, and integrated circuit technologies can change what's physically buildable within a few years. The transistor replaced vacuum tubes, and integrated circuits put many transistors on a single chip. VLSI pushed that into the millions, then billions. The physical substrate keeps changing, and each shift opens up architectures that simply weren't possible before.

Software moves slower but persists deeper. As programmers build more complex systems, patterns emerge. Certain structures appear repeatedly. Certain inefficiencies become obvious. Over decades, the accumulated knowledge of how programs actually behave at runtime improves, and that knowledge feeds back into hardware design. Architects start optimising for the workloads that genuinely dominate real use, not theoretical ones. Instruction sets change to match common programming idioms. Compilers get better at translating high-level abstractions into efficient machine code. Hardware and software become tightly interdependent. You can't design one well without understanding the other.

Architecture Under Constraints

Performance is usually the most visible metric, but it's far from the only one. Manufacturing cost obviously matters: a chip that performs brilliantly but costs too much to fabricate will never get deployed at scale. Power consumption matters, particularly for mobile devices and data centres where electricity is a direct operating expense. Reliability too: systems need to keep working despite component failures or transient errors. And development cost matters more than people often acknowledge. Designing a modern processor requires enormous engineering effort and specialised tools. For most programmable devices, the surrounding software costs more to create and maintain than the hardware itself.

Architectural design involves balancing all of this simultaneously. A supercomputer prioritises raw throughput. A smartphone has to stay cool in your hand while running all day on a battery. An embedded controller in a medical device might care more about certified reliability than peak speed. The result is a wide range of architectures, each suited to its particular use, which is why a smartphone chip and a data centre CPU look almost nothing alike, even though both run software.

Early Developments in Computing

In the nineteenth century, Charles Babbage designed mechanical calculating machines: first the Difference Engine, a machine for computing polynomial tables, and then the more ambitious Analytical Engine, which introduced the concept of a programmable general-purpose machine. The Analytical Engine had a mill (equivalent to a processor), a store (equivalent to memory), and was designed to read instructions from punched cards. It was never completed though Ada Lovelace, who worked closely with Babbage, wrote what many consider the first algorithm intended for machine execution, a method for computing Bernoulli numbers, along with a rather remarkably clear analysis of what the Analytical Engine could and couldn't do.

By the late nineteenth century, tabulating machines were already being used for large-scale data processing. Herman Hollerith's electromechanical system was used to process the 1890 US census, reducing a job that might have taken years to less than a year. Hollerith later founded the company that eventually became IBM. In the 1930s, early electronic digital machines appeared, though most were designed for fixed tasks. Konrad Zuse built the Z3 in Germany in 1941, arguably the first programmable, fully automatic digital computer, though it used electromechanical relays rather than electronics. In Britain, the Colossus machines at Bletchley Park, completed in 1943-44, were used to break German cipher traffic. They were electronic, fast, and programmable to a degree, but fixed to a single task class.

A transition to fully electronic general-purpose computers happened during and just after the Second World War.

ENIAC and the Stored-Program Problem

The most consequential machine from this period was ENIAC (the Electronic Numerical Integrator and Computer), built between 1943 and 1945 by J. Presper Eckert and John Mauchly at the University of Pennsylvania. ENIAC weighed around thirty tons, occupied a large room, and contained roughly 18,000 vacuum tubes. Its primary job was calculating artillery ballistics tables for the US Army. It could do in hours what would take human calculators weeks.

But ENIAC had a fundamental limitation: there was no stored program. Programming it meant physically configuring external patch cables and switches. Changing the computation could take two days of rewiring. The machine was fast at arithmetic and glacially slow to reprogram. That trade-off made it useful for repetitive ballistics calculations, where you ran the same computation thousands of times on different inputs, but badly suited to general use.

The person who did most to resolve this was John von Neumann, the Hungarian-American mathematician who was already a formidable intellectual by the time he got involved in computing. Von Neumann had worked on the Manhattan Project, made lasting contributions to quantum mechanics and game theory, and had a reputation for absorbing the contents of technical papers at something close to reading speed. When he encountered the ENIAC project in 1944, he grasped its significance and its central flaw.

The solution he articulated, building on earlier thinking by Eckert, Mauchly, and the British mathematician Alan Turing, was the stored-program computer. The idea is to store program instructions in the same memory as data, using the same format, and execute them sequentially. Instead of rewiring the machine to change what it does, load a new program into memory. The hardware stays fixed with only the instructions changing.

In 1945, von Neumann wrote a draft report titled "First Draft of a Report on the EDVAC," named for the successor machine to ENIAC then being designed. The report was circulated informally, without von Neumann's name on the cover, and described the architecture in full: a central processing unit, an arithmetic unit, memory that holds both data and instructions, and input/output mechanisms. Because the report circulated under his name, this design became known as the "von Neumann architecture," a label that somewhat undersells the contributions of Eckert and Mauchly.

Copies of the report reached research groups in Britain, the United States, and elsewhere, and shaped the design of nearly every computer built in the following decade. Whether von Neumann "invented" the stored-program concept or codified ideas that were already floating amongst the ENIAC team remains a point of debate.

Once the stored-program model was out in the world, new machines appeared quickly. The Manchester Small-Scale Experimental Machine (nicknamed "Baby") ran the world's first stored program in June 1948, a simple factorisation calculation that took 52 minutes. EDSAC at Cambridge followed in 1949 and became the first full-scale operational stored-program computer. Von Neumann's IAS machine at Princeton was completed around 1951 and served as the template for a generation of scientific computers. UNIVAC I, completed in 1951, became the first commercial computer sold in the United States, famously used to predict the result of the 1952 presidential election on live television.

The Challenges of Early Computing

Machines like ENIAC ran on vacuum tubes, components that generated heat, consumed significant power, and failed constantly. With 18,000 tubes in ENIAC, any one of which could fail at any time, keeping the machine running was a continuous maintenance job. Operators often located failed tubes by smell, or by watching for the one that had gone dark. Memory was equally fragile. Early machines used mercury delay lines (tubes of liquid mercury through which acoustic pulses were transmitted to store bits) or Williams tubes, which stored data as charge patterns on a cathode ray tube screen. Both were temperamental, temperature-sensitive, and required constant calibration. Early magnetic drum and core memory was more reliable but expensive and slow to develop.

The mean time between failures for many early machines was measured in minutes. The Whirlwind computer at MIT, a rather ambitious machine built for real-time flight simulation, reportedly had an MTBF of around twenty minutes when first operational. Much of early computing history is, frankly, a story of engineers coaxing machines to stay alive long enough to finish a calculation.

By the mid-1950s, hardware costs were still enormous and memory capacities tiny, often around a thousand words, which meant there was no room to store an operating system. Memory access was far slower than processor cycles, sometimes by a factor of ten to fifty, so execution time was dominated by waiting for memory rather than performing arithmetic. The central challenge of early computing wasn't making arithmetic faster. It was building control circuits reliable enough to coordinate the machine's operations at all.

Early Instruction Sets

Early instruction sets were minimal. Many machines had fewer than two dozen instructions: load a value from memory, store a value, add, subtract, compare, jump. Most early architectures used an accumulator model. One special register (the accumulator) held the operand for arithmetic. Instructions loaded values into it, performed a computation, and wrote the result back to memory. This design reflected mechanical calculators and kept hardware simple, because registers were expensive to implement.

Programming under these constraints required ingenuity. Consider iterating through an array. Early machines had no convenient way to modify addresses automatically. There was no index register, no pointer arithmetic. Programmers instead wrote code that modified its own instructions during execution. After each loop iteration, the program would update the address field of the next load instruction so it pointed to the next array element. This technique, self-modifying code, worked. Though, it was also inefficient. Much of the execution time was spent on bookkeeping rather than computation. And debugging it was a particular kind of unpleasant, because the program you were looking at wasn't the program that would run once it had modified itself.

A major improvement came in the mid-1950s with index registers, specialised registers holding offsets for address calculations. Tom Kilburn at the University of Manchester introduced the idea: instead of modifying instructions, a program could keep a base address in the instruction and add the index register's value automatically. An instruction like LOAD X, IX would access memory at X + (value in IX). Loops became far simpler. You could increment the index register at the end of each iteration and jump back to the top of the loop. The code that did the actual work was no longer tangled up with the code managing its own addresses.

The trade-off was modestly more complex control logic and slightly longer instructions, worthwhile.

Modern Architectural Ideas

Once index registers existed, it became natural to add instructions for manipulating them: increment, load from memory, store to memory. Over time, the distinction between accumulators and index registers began to blur. Both were registers holding values and participating in computations. The logical step was to have several of them, with no special designation: general-purpose registers that any instruction could use. This idea eventually became standard. Modern processors typically have sixteen or more general-purpose integer registers. The accumulator model essentially disappeared. Addressing modes became more sophisticated alongside this. Architectures added ways to compute addresses from combinations of registers, offsets, and base values. These made complex data structures (linked lists, trees, dynamically allocated arrays) far easier to implement efficiently.

By the mid-1950s, instruction sets varied widely between machines, but they all shared one characteristic: the programmer's mental model of the computer was essentially identical to the engineer's description of the physical hardware. If you programmed the machine, you understood its registers, its memory layout, its specific quirks. The separation between what the hardware was and what it appeared to be was minimal. That separation between the hardware implementation and the software abstraction above it would grow enormously over the following decades. Virtual memory, operating systems, high-level languages, virtual machines: all of these layers were built on top of the physical machine, each one letting programmers write software without thinking about what the silicon was actually doing. The accumulator and the index register were early signs of a pattern that would run through the entire field: finding the right abstraction, encoding it in hardware, and watching what became possible once programmers could stop worrying about the details below.