The Apple I Didn't Exist Yet—So How Did Woz Write BASIC?

Woz wrote the BASIC interpreter for the Apple I before it existed, relying on his own hardware specs and segmented verification.
The article centers on a question from Retrocomputing Stack Exchange: how did Wozniak write the BASIC interpreter for the Apple I before the hardware existed? The answer isn't a linear "hardware first, software later" process, but a collaborative back-and-forth between software and hardware. Woz already had a complete frame of reference—his own CPU choice, memory addressing, and I/O address layout, plus his familiarity with the 6502 instruction set—which let him trace code on paper. During development he used available computing resources to verify critical logic in segments rather than waiting for real hardware. The extremely low input bandwidth of paper tape and manual toggle switches in turn constrained code size and organization. The article ultimately distills an engineering fact: a deep understanding of the target platform can itself serve as a development tool—a methodology that holds even under extreme constraints, not merely a myth of genius.
A computer that didn't exist yet, and code that already ran
A seemingly simple question on Retrocomputing Stack Exchange sparked 256 points and 133 comments on Hacker News: How did Wozniak write the BASIC interpreter for the Apple I before the machine had even been built?
What makes this question so compelling is that it exposes a blind spot in modern software engineering thinking. Today, when you write code, you almost always start with a machine that can run programs—even if it's just an emulator. But around 1976, Woz faced a different situation: the hardware was still on paper and breadboards, and what he had to deliver was system software running on a board that didn't yet exist.
The answers on Stack Exchange and the HN discussion together trace a path: this wasn't a linear "hardware first, then software" process, but a collaborative back-and-forth between software and hardware, each informing the other.
First the machine on paper, then the code on paper
Woz didn't write BASIC out of thin air. He already had a complete frame of reference: the Apple I hardware architecture he had designed himself. Which CPU to use, how to address memory, which address ranges the I/O ports would occupy—all of this was settled before he wrote a single line of the interpreter. The depth of a software author's knowledge of the target platform often determines how far they can go without real hardware.
A key fact mentioned in the discussion: Woz had already done design work along similar lines before, and his familiarity with the 6502 instruction set and memory map allowed him to "run" code in his head. When writing the BASIC interpreter, he wasn't guessing at hardware behavior—he was doing arithmetic within an address space he had already planned out himself.
In other words, the hardware spec was his compiler. When every byte of the target platform comes from your own design, you don't need a physical machine to verify your logic.
The 6502 instruction set is the instruction set for the 8-bit microprocessor introduced by MOS Technology in 1975, and it was the core of a whole generation of classic machines including the Apple I, Apple II, and Commodore 64. It uses variable-length instruction encoding (1 to 3 bytes), supports 56 basic instructions and 13 addressing modes, and has only the accumulator A, index registers X/Y, a stack pointer, and a program counter as registers. For programmers of that era, memorizing every opcode, every addressing mode, and every cycle count of the 6502 was a basic skill for writing code without an assembler or debugger. Woz's mastery of this instruction set allowed him to trace a program's execution step by step on paper without relying on machine feedback.
A memory map refers to the convention governing what each range of addresses in the CPU's address space is allocated to—for example, zero page for fast access, a certain range mapped to ROM, another range corresponding to I/O registers. In the Apple I era there was no memory management unit, and the address space was hardcoded, so the memory map had to be planned by the hardware designer before work began. The interpreter's variable storage, stack layout, and character output buffer all depended on this map. By defining the address boundaries himself, Woz was effectively pre-defining the entire "system call interface" that the software could rely on.
Paper, pencil, and a board that could run code
What really allowed him to debug was another machine.
According to the discussion, Woz used existing computing resources to verify code fragments during BASIC development—not the Apple I, but whatever hardware environment he had access to at the time. He wrote the program in segments, then found ways to run the critical logic on available equipment. This "divide and conquer" strategy was the only viable path in an era without integrated development environments or emulators.
Someone in the HN comments pointed out that this way of working was not unusual among hobbyists of the time: first "run" the system through design documents and hand-drawn circuit diagrams, then implement it piece by piece. The difference is that Woz took this to the extreme—what he delivered wasn't a toy program, but a working BASIC interpreter.
An emulator is a program that simulates the behavior of one piece of hardware in software on another, allowing developers to run and debug code when the target machine doesn't yet exist. In the mid-1970s it barely existed in the personal computing world—hobbyists of the time either waited for the hardware to be built or, like Woz, found existing equipment with a compatible or borrowable instruction set to verify fragments. The modern workflow developers take for granted—"write code, then run it in an emulator"—required additional hardware conditions and creative alternatives back then, which is why this piece of history feels so foreign today.
The real bottleneck wasn't writing—it was input
One easily overlooked detail in the multi-source discussion: In an era without a keyboard, monitor, or disk, how did the code get in?
The answer points to paper tape and manual toggle switches. Programs had to be converted into a form the machine could accept, then fed into memory bit by bit. This meant that when Woz wrote BASIC, he not only had to ensure logical correctness but also had to control code size and input methods—every debugging cycle was extremely costly.
This also explains why early BASIC implementations generally pursued compactness: it wasn't an aesthetic preference, but a hard constraint of input bandwidth. According to community analysis, Woz's engineering trade-offs in this regard directly influenced how he later organized code structure.
Paper tape is an early program storage and input medium that represents binary data through holes punched in paper, read line by line by an optical or mechanical tape reader. Its capacity was limited, reading speed was slow, and the punching process itself required specialized equipment. Manual toggle switches refer to setting bits byte by byte through toggle switches on a panel, then pressing a button to write to memory—a single byte often required multiple flips. Together they constituted extremely low input bandwidth: loading a program of just a few hundred bytes into the machine could take tens of minutes or more, and any modification meant re-punching or re-toggling. This constraint directly shaped the size consciousness and one-shot-correct engineering habits of early software.
What can be learned from this question
The value of this discussion isn't in recreating a piece of history, but in the engineering fact it exposes, one that is often overlooked: software can exist before hardware, provided the author has sufficiently deep control over the hardware.
Woz's case is extreme because he was both the hardware designer and the software author. When he wrote BASIC, every detail of the target platform was in his head—including the parts that hadn't yet been soldered to the board. Most developers today don't have this condition, but that precisely illustrates: a deep understanding of the target platform is itself a development tool.
Among the 133 comments on HN, many attributed this to "people back then were more hardcore." But a more accurate way to put it might be: different constraints lead to different engineering paths. No real machine? Use the design spec as your reference. No emulator? Use segmented verification instead of whole-system debugging. Woz's approach isn't myth—it's an engineering methodology that still holds under extreme constraints.
Original link: Retrocomputing Stack Exchange | Discussion: Hacker News
Related articles

Pi Agent Minimal Core Explained: MCP, Skills, and the Philosophy of Extension Design
Why is Pi Agent gaining attention alongside Codex and Claude Code? We break down its minimal core design, developer autonomy, and on-demand extensions from model config to MCP and Skills.

Open-Source Humanoid Hand at the $100 Level Achieves Real-Time Teleoperation
The open-source Amazing Hand project enables real-time teleoperation of a $100-level humanoid robotic hand and supports integration with the SO101 arm for full-body control.

DKIM2: Making Every System That Handles an Email Sign for What It Did
DKIM2 proposes that every system handling an email sign for its own operations, extending email authentication from the sender to the entire delivery chain. This article examines its core claims, its relationship with existing DKIM, and the practical problems that must be faced in deployment.