1010 程序是怎么来的
第 2 站 1945 — 1975

把程序变成数据

第 1 站的痛苦有一副统一的解药:如果程序也能像数字一样存在内存里,那么换程序就只是换数据——一根线都不用动。 这一步叫存储程序(stored program)。而它顺手带来的第一个小麻烦,就是引导程序。

1945:一个大胆的想法

1945 年,冯·诺依曼(John von Neumann)和同事为下一台机器 EDVAC 写了一份报告, 把一件事说清楚了:指令和数据可以住在同一个内存里。 机器从内存里取出一个数字,如果把它当“指令”用,就执行它;把它当“数字”用,就拿它去算。

这个想法不是他一个人想出来的:ENIAC 团队在讨论中已经有了它,图灵 1936 年的“万能机器”也指向同一个方向。 所以今天更准确的说法是“存储程序结构”,而不是“冯·诺依曼结构”。

好处立刻看得见:

1948 年 6 月 21 日:小宝宝第一次跑起来

曼彻斯特大学的一台小机器,被大家叫作“小宝宝”(Manchester Baby)。 它是第一台真正把程序存进内存、然后照着跑起来的电子计算机。它的内存小得可怜:只能装下 32 个 32 位的“字”。

它跑的第一个程序是一个测试:找出 218(也就是 262144)的最大因数。 机器算了几十分钟,给出了答案 131072。 这台机器没有键盘,程序是用一排开关一个一个拨进去的。

曼彻斯特“小宝宝”(SSEM)的复原机。1948 年 6 月 21 日,第一段存储程序在这里跑起来。
曼彻斯特“小宝宝”(SSEM)的复原机。1948 年 6 月 21 日,第一段存储程序在这里跑起来。图片:Parrot of Doom · CC BY-SA 3.0 · Wikimedia Commons

程序怎么“进去”?——引导程序

内存有一个坏脾气:一断电就忘光。所以每次开机,都得重新把程序放进去。 于是有了层层接力:

  1. 人用机器前面板的开关,先拨进去一小段很短的指令(通常只有几十条以内)。
  2. 这一小段指令唯一的任务,是从纸带、打孔卡或磁盘里读进一个更大的程序。
  3. 那个更大的程序,再把操作系统读进来。

这段“先把自己拉起来”的小程序,英文叫 bootstrap loader(引导程序)。

boot 这个词的来历

bootstrap 的字面意思是“靴子上的带子”。有一个老笑话(来自孟乔森男爵的故事): 一个人掉进沼泽里,靠抓着自己的靴带把自己拎了出来。

开机叫 boot,就是因为机器也得先抓着自己的靴带,把自己从“什么都没有”拉到一个能用的状态。 中文把它翻成“引导”,也翻成“自举”——对,和后面第 4 站讲的自举是同一个词。

① 手指拨开关 几十条指令 ② 引导程序 只干一件事:读 ③ 纸带上的程序 几百条指令 ④ 操作系统 能用了 每一级都比上一级大,而每一级都要靠上一级才能被读进来
“引导”就是接力:一小段手拨的指令,负责把更大的一段读进来。今天你按下电源键后电脑做的事,就是这四步的现代版。
EDSAC 复原机(由计算机保护协会建造)。程序用打孔纸带送进机器。 打孔纸带(5 孔与 8 孔):一排孔就是一个字符。写错了,剪开用胶带接上继续用。

程序进来靠纸带,进机器之前先变成一排排的孔。图片:Geni · CC BY-SA 4.0 · Wikimedia Commons 图片:TedColes · 公有领域 · Wikimedia Commons

手写机器码的日子

有了存储程序,程序员开始在纸上“手写机器码”。那是一种什么样的体验?

你知道吗:最早的“调试器”是一排灯

1950 到 1970 年代的机器,前面板往往有一排小灯,一个灯对应一位(bit)。 程序跑飞了,程序员就盯着灯看:现在地址是几、累加器里是什么数。 今天你在屏幕上看到“断点”“单步执行”,源头就是这排灯。

1975:Altair 8800,一排开关的浪漫

1975 年,第一台让普通人买得起的微型计算机 Altair 8800 上市。 它的面板上没有键盘、没有屏幕,只有一排开关和一排红灯。

开机时,用户照着杂志上的表格,把二十几条指令的引导程序一个开关一个开关地拨进去, 再用它从纸带机里读入 BASIC 语言——这时候,才终于能开始写自己的程序。 也就是说:每次开机都要重新拨一遍,才能用上键盘。

Altair 8800(德国德意志博物馆藏)。面板上只有一排开关和一排红灯,开机全靠手拨。
Altair 8800(德国德意志博物馆藏)。面板上只有一排开关和一排红灯,开机全靠手拨。图片:Maksym Kozlenko · CC BY-SA 4.0 · Wikimedia Commons

为什么这段“痛苦”不能跳过

因为它是整条链条的根。 后面所有好用的东西——汇编器、编译器、操作系统——都必须由某一段已经存在、已经能跑的东西读进来、跑起来。 而链条最底下那一段,一定是人用手指拨进去的。

想一想

内存一断电就忘光。那么“把一个程序永久保存下来”要靠什么? 提示:打孔卡、纸带、磁带、磁盘、闪存……以及今天你手机里的 App Store。 再想一想:如果程序能从外面被读进来,那么被读进来的东西,能不能是另一个程序?

小结

存储程序把程序变成了数据:能复制、能搬运、能被别的程序读进来。 于是历史上第一次,程序可以处理程序——这是自举的必要条件。

可是机器只懂数字,人脑子里装的却是想法。这中间的落差,就是第 3 站要解决的: 造一个翻译官,让人写字,让机器干活。