苹果一代还没造,Woz是怎么写出BASIC的?

沃兹在 Apple I 尚未造出时,靠自设计的硬件规格与分段验证写出 BASIC 解释器。
文章围绕 Retrocomputing Stack Exchange 上的一个提问展开:沃兹尼亚克如何在 Apple I 硬件尚未存在时写出其 BASIC 解释器。答案并非“先硬件后软件”的线性流程,而是一场软硬件协同推演。沃兹手中已有完整的参照系——他亲手设计的 CPU 选型、内存编址与 I/O 地址布局,加之对 6502 指令集的熟稔,使他能在纸面上推演代码。开发期间他借助可用的计算资源分段验证关键逻辑,而非等待真机。纸带与手工拨码构成的极低输入带宽,又反过来约束了代码的体积与组织方式。文章最终提炼出一个工程事实:对目标平台的深入理解本身就可以充当开发工具,这是极端约束下仍然成立的方法论,而非单纯的天赋神话。
一台还不存在的计算机,一段已经能跑的代码
Retrocomputing Stack Exchange 上一个看似朴素的问题,在 Hacker News 上引发了 256 点热度、133 条讨论:沃兹尼亚克在 Apple I 还没造出来的时候,是怎么写出这台机器的 BASIC 解释器的?
这个问题之所以耐嚼,是因为它戳中了现代软件工程的一个思维盲区。今天写代码,你几乎总是先有一台能跑程序的机器——哪怕只是模拟器。而在 1976 年前后,沃兹面对的是另一种局面:硬件还停留在纸面和面包板上,而他要交付的,是运行在这块还不存在的板子上的系统软件。
Stack Exchange 上的回答与 HN 的讨论共同勾勒出一条路径:这不是"先硬件后软件"的线性流程,而是一场软件与硬件互为参照的协同推演。
先有纸上的机器,才有纸上的代码
沃兹并非凭空写 BASIC。他手里已经有一个完整的参照系:他亲手设计的 Apple I 硬件架构。CPU 用哪颗、内存怎么编址、I/O 端口落在哪个地址区间——这些在动笔写解释器之前就已经确定。软件作者对目标平台的了解程度,往往决定了他在没有真机时能走多远。
讨论中提到的一个关键事实是:沃兹此前已经用相似的思路做过设计工作,他对 6502 指令集和内存映射的熟悉程度,让他可以在脑中"运行"代码。写 BASIC 解释器时,他并不是在猜硬件行为,而是在自己已经规划好的地址空间里做算术。
换句话说,硬件规格就是他的编译器。当目标平台的每一个字节都出自你自己的设计,你就不需要一台实体机器来验证逻辑。
6502 指令集是 MOS Technology 于 1975 年推出的 8 位微处理器指令系统,也是 Apple I、Apple II、Commodore 64 等一大批经典机器的核心。它采用变长指令编码(1 至 3 字节),支持 56 条基本指令、13 种寻址模式,寄存器只有累加器 A、索引寄存器 X/Y、栈指针和程序计数器。对当时的程序员而言,熟记 6502 的每条操作码、每个寻址模式与周期数,是在没有汇编器、没有调试器的条件下写代码的基本功。沃兹对这套指令集的精通,使他能在纸面上逐条推演程序的执行流程,而不必依赖机器反馈。
内存映射(memory map) 指 CPU 地址空间中各段地址被分配给何种用途的约定,例如零页用于快速访问、某段区间映射 ROM、某段区间对应 I/O 寄存器。在 Apple I 时代,没有内存管理单元,地址空间是硬编码的,因此内存映射必须由硬件设计者在动工前就规划清楚。解释器的变量存储、栈布局、字符输出缓冲区都依赖这份映射。沃兹自己划定地址边界,等于提前定义了软件可以依赖的全部“系统调用接口”。
用纸、铅笔和一块能跑代码的板子
真正让他能调试的,是另一台机器。
据讨论中的说法,沃兹在开发 BASIC 期间借助了已有的计算资源来验证代码片段——不是 Apple I,而是他当时能接触到的硬件环境。他把程序分段写出来,再想办法在可用的设备上跑通关键逻辑。这种"分而治之"的策略,在没有集成开发环境、没有模拟器的年代是唯一可行的路径。
HN 评论区里有人指出,这种工作方式在当时的 hobbyist 圈子里并不罕见:先在设计文档和手绘电路图上把系统"跑"一遍,再逐段落地。区别在于,沃兹把这件事做到了极致——他交付的不是玩具程序,而是一个能用的 BASIC 解释器。
模拟器(emulator) 是在一种硬件上通过软件模拟另一种硬件行为的程序,开发者可以借此在尚无目标机器时运行和调试代码。它在 1970 年代中期几乎不存在于个人计算领域——当时的 hobbyist 要么等硬件造好,要么像沃兹一样寻找已有的、指令集兼容或可借用的设备来验证片段。现代开发者习以为常的“先写代码、再在模拟器里跑”的流程,在当时需要额外的硬件条件与创造性的替代方案,这也是这段历史在今天看来格外陌生的原因。
真正的瓶颈不是写,而是输入
多源讨论中一个容易被忽略的细节是:在没有键盘、没有显示器、没有磁盘的年代,代码是怎么进去的?
答案指向纸带和手工拨码。程序需要先被转换成机器能接受的形式,再一点点灌进内存。这意味着沃兹写 BASIC 时,不仅要保证逻辑正确,还要控制代码体积和输入方式——每一次调试循环的成本都极高。
这也解释了为什么早期 BASIC 实现普遍追求紧凑:不是审美偏好,而是输入带宽的硬约束。据社区分析,沃兹在这方面的工程取舍,直接影响了他后来对代码结构的组织方式。
纸带(paper tape) 是一种早期程序存储与输入介质,通过在纸带上打孔表示二进制数据,由光电或机械读带机逐行读入。它的容量有限、读取速度慢,且打孔过程本身需要专门设备。手工拨码则指通过面板上的拨动开关逐字节置位,再按按钮写入内存,一个字节往往需要多次拨动。两者共同构成了极低的输入带宽:一段只有几百字节的程序,灌入机器可能耗费数十分钟甚至更久,任何一次修改都意味着重新打孔或重新拨码。这种约束直接塑造了早期软件的体积意识与一次性写对的工程习惯。
从这个问题里能学到什么
这场讨论的价值不在于复刻一段历史,而在于它暴露了一个常被忽略的工程事实:软件可以先于硬件存在,前提是作者对硬件有足够深的掌控。
沃兹的案例之所以极端,是因为他同时是硬件的设计者和软件的作者。当他写 BASIC 时,目标平台的每一个细节都在他的脑子里——包括那些还没被焊到板子上的部分。今天的大多数开发者没有这种条件,但这恰恰说明:对目标平台的深入理解,本身就是一种开发工具。
HN 上 133 条评论里,不少人把这归结为"那个年代的人更硬核"。但更准确的说法或许是:约束条件不同,工程路径就不同。没有真机,就用设计规格当参照;没有模拟器,就用分段验证代替整体调试。沃兹的做法不是神话,而是一套在极端约束下仍然成立的工程方法论。
相关推荐

Pi Agent极简内核解析:MCP、Skills与扩展设计哲学
Pi Agent为何在Codex、Claude Code之外受到关注?本文解析其极简内核设计、开发者自主控制理念,以及从模型配置到MCP、Skills、项目记忆的按需扩展路径。

百元级开源人形手实现实时遥操作
开源项目Amazing Hand实现百元级人形机械手实时遥操作,成本低至100美元,支持与SO101机械臂集成实现全身控制。了解这一由Pollen Robotics等推动的低成本机器人方案。

DKIM2:让每封邮件经手的系统都签名负责
DKIM2 提出让每一个处理过邮件的系统都为自己的操作签名,把邮件认证从发件方扩展到整条传输链路。本文解析其核心主张、与现有 DKIM 的关系,以及部署中必须面对的现实问题。