# 阿波罗 11 号制导计算机 · 博学者读本

> 把这台机器放回它所在的年代：它用什么做的、装着什么程序、怎么知道自己在哪、以及理论是在多久之后变成工程的。

> 证据分两类：**源码实证**标了文件与行号可回仓库核对；**外部资料**来自 NASA、MIT 原始设计报告与公开史料，单独标出。

- 总行数：130,186
- 源文件：173 个 .agc
- 集成电路：约 2,800 个
- 只读内存：36,864 字
- 可写内存：2,048 字

---

### 先说清楚单位：位、字、以及没有字节

这一篇里「位」和「字」是两个不同层级的单位，而且这台机器里根本没有字节。先花一分钟分清，后面就不会读错。

- **位（bit）** —— 最小单位。一个开关只有 0 或 1 两种状态，就是一个 bit。操作码 3 位、地址 12 位，说的都是 bit。
- **字（word）** —— 这台机器一次能处理的完整一份数据。**1 个字 = 15 位数据（最高位是符号）+ 1 位奇偶校验；程序按字寻址，不按 8 位字节**，物理上占 16 位。校验位由硬件自动生成与检查，程序碰不到。内存容量全用字：可写 2,048 字，只读 36,864 字。
- **字节（byte）** —— **这台机器里没有字节这个概念。** 今天说的 1 字节 = 8 位，是后来才通行的。所以看到「2,048 字」不要按字节去想。

换算一次就明白了：36,864 字 × 16 位 ÷ 8 ÷ 1,024 = **72 KB**；2,048 字 × 16 位 ÷ 8 ÷ 1,024 = **4 KB**。这就是常见说法里「阿波罗有 4 KB 内存、72 KB 只读存储」的来处——当年的人只说字，是后人按字节折算出来的。

### 四种内容，四种可信度

本册把事实和解释分开摆放。读到任何一句，先看清它属于哪一类。

- **源码实证** —— 可在仓库里按文件与行号直接核对的事实。引证固定在 commit 911e5c0。
- **外部资料** —— 来自 NASA / MIT / 公开史料。不能回仓库核对，单独标出并给出参考文献编号。
- **作者推导** —— 不是原文直接写明的，是我从源码数据算出来或推出的结论。会写明推导过程，读者可自行复核。
- **解释性类比** —— 为了帮助理解而打的比方，属于解释工具，不是证据。

## 目录

- 0　一句话的任务（The Goal）
- 1　没有「一颗 CPU」的计算机（Hardware · 芯片）
- 2　一套只有十来条的指令集（Architecture · 指令集）
- 3　编织出来的存储器（Hardware · 存储）
- 4　八天（Mission · 任务过程）
- 5　我们怎么知道自己在哪（Navigation · 导航）
- 6　它到底在算什么（Guidance · 制导与控制）
- 7　飞船上的四套计算系统（Systems · 系统）
- 8　一百多个模块怎么分工（Software · 模块全景）
- 9　那一夜（Story · 1969 年 7 月 20 日）
- 10　更大的坐标系（Perspective · 博学者视角）


---

## 0　一句话的任务

*The Goal. 1961 年，美国承诺在十年之内把人送上月球并安全带回来。1969 年 7 月，阿波罗 11 号兑现了这句话。本册要讲的是：兑现它的那台计算机，到底是什么。*

**当时的处境。** 阿波罗计划里，航天员不是像早期飞行那样握着操纵杆手动飞。大部分飞行由计算机控制，只有在着陆的最后阶段才由人接管。这个分工决定了软件必须是任务里最可靠的一环。

### 【外部资料】`NASA / 公开史料`

```agc
任务目标：在 1960 年代结束前实现载人登月并安全返回。
阿波罗 11 号是首次成功的载人登月任务。
任务成果：带回约 21.5 公斤月球样品；据估计约 6 亿人观看了直播。
```

> 这类数字来自 NASA 与公开史料，源码仓库里查不到，所以标为外部资料。凡是我没法在代码里指给你看的，都不会混进源码实证。

### 【源码实证】`Luminary099/ALARM_AND_ABORT.agc:26-29`

```agc
# Notations on the hardcopy document read, in part:
#
#	Assemble revision 001 of AGC program LMY99 by NASA 2021112-061
#	16:27 JULY 14, 1969
```

> 登月舱程序的装订时间是 1969 年 7 月 14 日 16 点 27 分，离 7 月 20 日着陆只剩六天。这不是改完了，是改不动了——下一章会讲为什么。

**要点。**

- 任务目标是把人送上月球并安全带回，1969 年 7 月由阿波罗 11 号完成。
- 飞行主要由计算机控制，人在着陆末段接管。
- 登月舱软件在着陆前六天装订完成，之后无法再改。


---

## 1　没有「一颗 CPU」的计算机

*Hardware · 芯片. 问这台计算机的芯片是什么型号，这个问题需要先把话说准：它没有一个现代意义上的单芯片 CPU——没有一块微处理器，处理器功能是由约 2,800 个双三输入 NOR 门连同周边电路一起搭出来的。*

**打个比方。** 今天去电子市场买一块芯片，拿回来是一整块做好了的东西，插上就能用。当年他们拿到手的是 2,800 个一模一样的小零件，得自己动手，一个一个连起来，才能凑出一台会算数的机器。好处是零件只有一种，备料和排查都简单；难处是再复杂的事，也得用这一种零件慢慢凑出来。

**当时的处境。** 这里得先挡掉一个容易说过头的讲法。「这台计算机没有 CPU」听着很带劲，但对学体系结构的人来说是错句。NASA 自己的技术文件把 AGC 称作 general purpose computer，同时补了一句：它是为制导导航控制专门定制的。准确的说法是：**不存在今天意义上的「一颗 CPU 芯片」**，中央处理器的全部功能由大量同型号的分立逻辑门构成。差别不在于「有没有处理器」，而在于处理器是怎么被造出来的。另外，全机只用一种门并非随意：NOR 是通用门，任何逻辑都能由它搭出来，代价是门数多。同期 Minuteman II 导弹的制导计算机混用了二极管晶体管逻辑和二极管逻辑，被多种逻辑族的兼容性问题拖累——不过这条对照的证据等级偏低，见下面第一条说明。

*图 1：全机由同一种双三输入 NOR 门构成逻辑的方式。（图示见 HTML 版）*

### 【外部资料】`NASA NTRS 20230005922，Appendix F（p.288 / p.292）`

```agc
Although technically a "general purpose computer," the AGC was customized
design essentially for GN&C functions operating with a priority driven
operating system with a very specialized I/O.

Component Description Performance Computer
  AGC (Block II): Priority-interrupt driven, parallel 16-bit, 1-MHz
  digital computer.
```

> ★ NASA 一手文件的原话，用来校准「没有 CPU」这个说法。它承认 AGC 是一台通用计算机，但紧接着说明它是为制导导航控制定制的、跑的是**优先级驱动的操作系统**、I/O 非常专门化。第二句给出了硬件规格：优先级中断驱动、并行 16 位、1 MHz 数字计算机。第一句里 priority driven operating system 这个说法，正是第 8 章要讲的 Executive。

### 【外部资料】`公开技术文档（源码仓库无记载；非 NASA 原件）`

```agc
AGC Block II（载人飞行所用）主要规格：
· 集成电路约 2,800 个，绝大多数为双三输入 NOR 门
· 制造商：仙童半导体（Fairchild Semiconductor）
· 工艺：电阻晶体管逻辑 RTL，扁平封装 flat-pack
· 互连：绕线连接后整体灌铸环氧树脂
· 飞行件由 Raytheon 制造
```

> 这些硬件事实源码里一个字都没有，全部来自公开技术文档。要说明两点：第一，「双三输入 NOR 门」与「约 2,800 个」这两个数字出自公开技术综述与器件资料，本册没能找到 NASA 原文逐字确认（尝试过 NTRS 19700015154，该文件为扫描件、无法提取文本），因此不挂 NASA 的名头，只按公开资料的等级使用。第二，前面提到的 Minuteman II 对照出自同一类综述，而该综述自己在这一句上标了「缺引注」，所以只当流传很广的对照，不当定论——后面的论证也不依赖它。

### 【外部资料】`NASA NTRS 20230005922，Appendix F（p.271）`

```agc
Component Description Performance Computer
  AGC (Block II): Priority-interrupt driven, parallel 16-bit, 1-MHz
  digital computer.
  36 K ROM, 2 K RAM
  1 ft^3, 70 lb, 55 W
  1 each: CM & LM
  No failures during missions
  19 Failures caught by testing (Integration, Pre-Launch, Vibration,
  Thermal Cycle) while in "On Flight" status
```

> ★ 整台机器的规格被这一行写完了，而且出自 NASA 一手文件：36K 只读、2K 可写、约 1 立方英尺、70 磅（约 32 公斤）、55 瓦，指令舱与登月舱各一台。比规格更值得停一下的是最后两行：**整个计划里 AGC 在任务中没有失败过一次**；另有 19 次失效是在「已交付飞行状态」之后，被集成、发射前、振动、热循环这几道测试拦下来的。这 19 次比任何赞美都更能说明前面讲的交叉引用表、告警码表、装订前自检到底是干什么用的。

### 【外部资料】`公开技术综述（证据等级偏低，仅作对照）`

```agc
Block I 与 Block II 的差别（此说出自公开综述，非 NASA 原件）：
· Block I：约 4,100 个集成电路，每个封装一个三输入 NOR 门
· Block II：约 2,800 个，多数为双三输入 NOR 门，另加扩展器与读出放大器

整机尺寸常见说法约 61 × 32 × 17 厘米；
与 NASA 原文的 1 立方英尺量级相符（1 立方英尺约合 28 升）。
时钟由 2.048 MHz 晶振产生，二分频得到四相 1.024 MHz 内部时钟。
```

> 这一条里的芯片数与尺寸来自公开综述，不是 NASA 原件，因此单独放一条并标明等级。只有 36K／2K、70 磅、55 瓦、1 立方英尺这几项是上面那条 NASA 原文直接给的。Block I 用的芯片更多但每个只装一个门，Block II 改用双门封装，总数反而下降——集成电路集成度的提升，直接体现在这个数字上。

**为什么这个选择值得记住。** 只用一种门，设计复杂度就从「协调五种元件的电气特性」降为「用一种元件拼出一切」。代价是门数暴涨、布线工作量巨大。阿波罗把风险从「元件不可控」转移到「数量庞大但性质单一」，而后者是可以靠工程管理和自动化布线消化掉的。这是一种很清醒的风险转移：把不可控变成可控但笨重。

**要点。**

- 它没有现代意义上的单芯片 CPU：处理器功能由约 2,800 个双三输入 NOR 门连同周边电路搭出来。
- 全机只使用一种集成电路，是为了避开多逻辑族混用带来的兼容性问题。
- 整机约 55 瓦、32 公斤。按 11.72 微秒一个存储周期、多数指令占两个周期估算，运算速度约合每秒四万条指令。


---

## 2　一套只有十来条的指令集

*Architecture · 指令集. 一个字长 15 位（bit）、操作码只占 3 位的指令集能有多少条指令？答案是 8 个基本操作码，然后靠两种扩展手法把它撑起来。*

**打个比方。** 像一套只有 8 个字母的字母表，想说的话太多，字母不够用。一个办法是加一个「上档键」——就像键盘上的 Shift，按住之后再敲同一个键，出来的是另一个意思；另一个办法是让同一个字母在不同的词里读成不同的音。这两种办法，这台机器都用上了。

**当时的处境。** 一个指令字总共 15 位（bit），3 位给操作码，12 位给地址。3 位只能表示 8 种操作。设计者没有加长指令字——那会让内存占用暴涨——而是想出两种在既有字长里塞进更多指令的办法。

*图 2：15 位指令字中操作码与地址的划分，以及 EXTEND 与 partial codes 两种扩充手法。（图示见 HTML 版）*

*图 3：指令字里的地址字段与组寄存器如何拼成完整地址。12 位字段单独只能覆盖 4,096 字，靠组寄存器才够到 38,912 字。（图示见 HTML 版）*

### 【外部资料】`MIT 原始设计报告 R-500（PART VI GUIDANCE COMPUTER DESIGN）`

```agc
three bits of an instruction word are devoted to operation code...

The three bits reserved for instruction codes are capable of rendering a
selection among eight operations with no further refinement.  Two techniques
are employed in the computer to expand the number of operations 4-fold.  These
are called "extension" and "partial codes" respectively.

Extension is like using a teletype shift code.  When an extend instruction
occurs, it signifies that the next instruction code in sequence is to be
interpreted otherwise than normally.

Partial codes are instruction codes that encroach upon the address field.
```

> 这是 MIT 自己的设计报告原文，属于一手资料。扩充指令集的两招：EXTEND 相当于打字机换档键；partial codes 让操作码去侵占地址字段——同一个操作码在不同地址区间表示不同指令。

### 【外部资料】`MIT R-500 / 公开技术文档`

```agc
Block I 共 11 条指令：
  基本指令 8 条：TC  CCS  INDEX  XCH  CS  TS  AD  MASK
  额外指令 3 条：SU  MP  DV（需前置 EXTEND）

中央寄存器 4 个：
  A  累加器
  Z  程序计数器
  Q  兼作除法余数与 TC 的返回地址
  L  低位乘积（Block I 文献中记作 LP）

指令耗时以存储周期 MCT 计：TC = 1 MCT，CA = 2 MCT，DCA = 3 MCT。
```

> 11 条指令在今天看来少得有点出乎意料。但配上 EXTEND 和解释器那层虚拟机，它能表达的东西远不止 11 条。

### 【源码实证】`Luminary099 全部 90 个源文件统计（本地统计结果）`

```agc
识别出的机器指令行：20,256 行
其中 EXTEND 出现：1,672 次，约占全部指令的 8%

使用频次最高的几条：
  TC     3,592      TCF    2,134
  TS     2,393      CAF    1,357
  EXTEND 1,672      CA     1,328
```

> 每 12 条指令里就有一条是 EXTEND。这个比例是「操作码空间不够用」留下的化石——如果 3 位够用，就不需要这么多换档。统计方法：逐行解析登月舱 90 个源文件，剔除伪指令后取标签后的操作码字段计数（脚本见 _build/vol2_stats.py）。

### 【源码实证】`Luminary099/ERASABLE_ASSIGNMENTS.agc:90-96`

```agc
L		EQUALS	1		# L AND Q ARE BOTH CHANNELS AND REGISTERS
Q		EQUALS	2
EBANK		EQUALS	3
FBANK		EQUALS	4
Z		EQUALS	5		# ADJACENT TO FBANK AND BBANK FOR DXCH Z
BBANK		EQUALS	6		# (DTCB) AND DXCH FBANK (DTCF).
					# REGISTER 7 IS A ZERO-SOURCE, USED BY ZL.
```

> ★ 这是理解寻址的关键一条。EBANK、FBANK、BBANK 是三个组选择寄存器，分别管可写内存组、只读内存组、以及两者合一；SUPERBNK 是再上面一级。**指令字里那 12 位从来就不是完整的物理地址**——它要和这几个寄存器合起来，才构成真正要访问的单元。这一点后面做反事实推算时会用到：不能把 12 位地址当成能直接覆盖整个存储的字段。

### 【外部资料】`CMC Data Cards 基本指令表（参考文献 [14]）`

```agc
Block II 基本操作码（八进制）：
  0  TC      转移控制，返回地址存入 Q
  1  CCS     计数、比较、跳转
  2  DAS     双精度加到存储
  3  CA      取数送入累加器
  4  CS      取反送入累加器
  5  INDEX   用某存储单元的内容修改下一条指令
  6  AD      加法
  7  MASK    按位与

EXTEND 在操作码表里记为 0.0006，即落在 TC 槽、地址 0006。
```

> ★ 需要提醒一件事：公开资料里扩展指令的操作码记法并不统一。例如乘法在数据卡上记作 17，除法记作 11.0，减法记作 16.0。这些二位写法怎么映射到 15 位字里的具体比特，公开整理稿并未交代清楚。**本册不逐条解码扩展指令**，只给出能核对的部分：8 个基本操作码的值、EXTEND 的编码、以及字长划分。下面那个算例也只用到这几项。遇到不确定的地方，宁可少说一句，也不要猜。

### WALKTHROUGH：把一个 15 位指令字拆开

15 位按八进制写正好是 5 位：第 1 位是操作码（3 位），后 4 位是地址（12 位）。下面手工拆三条，再把字长带来的后果算一遍。

**已知条件**

- 一个字 15 位，写成八进制是 5 位：**首位 = 操作码，后四位 = 地址**。
- 基本操作码的八进制值（参考文献 [14]）：TC=0、CCS=1、DAS=2、CA=3、CS=4、INDEX=5、AD=6、MASK=7。
- EXTEND 在操作码表里记为 **0.0006**。
- 存储容量：只读 36,864 字（word），可写 2,048 字。
- **指令字里的地址不是完整物理地址**，要和 EBANK / FBANK / BBANK / SUPERBNK 这些组选择寄存器合起来才是。

| 步 | 代码在算什么 | 代入本例 | 结果 |
| --- | --- | --- | ---: |
| 1 | `30174`（拆成操作码位与地址位） | `3 ‖ 0174` | **CA 0174** |
| 2 | `03000`（首位 0 是 TC，后四位是地址） | `0 ‖ 3000` | **TC 3000** |
| 3 | `00006`（首位 0 但地址是 0006，这一条不是转移） | `0 ‖ 0006` | **EXTEND** |
| 4 | `2^12`（12 位地址能直接寻址多少个字） | `2^12` | **4,096 字** |
| 5 | `36864 + 2048`（整个存储空间有多少字，要靠地址字段加组寄存器一起覆盖） | `36,864 + 2,048` | **38,912 字** |
| 6 | `38912 / 4096`（存储空间是单个 12 位地址字段能覆盖的多少倍） | `38,912 / 4,096` | **约 9.5 倍** |
| 7 | `36864 / 1024`（只读内存按 1K 一组要分多少组） | `36,864 / 1,024` | **36 个 bank** |

**换个算法再算一次分组数**

```
可写内存按 256 字一组：
  2,048 / 256 = 8      -> 8 个 bank

只读内存按 1,024 字一组：
  36,864 / 1,024 = 36  -> 36 个 bank

反推验证：
  36 x 1,024 = 36,864      <-- 与只读内存容量一致
   8 x   256 =  2,048      <-- 与可写内存容量一致
```

> 两条路算出来的分组数能对上，说明「12 位地址装不下整个存储空间、必须分组切换」不是猜测，而是字长与容量之间的算术必然。这也解释了为什么源码里到处都是换组的写法——不是讲究，是因为地址字段单独挑不起这副担子，得让 EBANK / FBANK / BBANK 一起出力。

**如果当年把操作码加到 4 位（这里容易推错，慢慢看）**

```
先算最直观的一步：15 位的字，操作码拿走 4 位，地址字段就只剩 11 位
  2^11 = 2,048 字     单条指令能直接说出的地址，从 4,096 缩到 2,048

到这里如果直接说「那 36,864 字的只读内存就够不着了」，是错的。
因为那 12 位（改成 4 位操作码后是 11 位）本来就不是完整的物理地址，
它要和 EBANK / FBANK / BBANK / SUPERBNK 合起来才构成要访问的位置。
固定存储能不能访问，不取决于地址字段单独有多宽。

所以真正的代价是另一件事：
  地址字段从 12 位降到 11 位 -> 单条指令的直接表达能力减半
  本来就有一部分得靠换组，现在要靠换组的更多
  -> 指令编码和寻址机制都更复杂，写代码的人也更累

正确的结论是：
  加长操作码不是「走不通」，而是「更贵」——
  换来 16 条基本指令，代价是整个寻址体系再紧一档。
  设计者选择把操作码钉在 3 位，是因为这个交换不划算。

一个很容易犯的错就在这里：把「地址字段缩到 2,048 字」直接读成「36,864 字的
只读内存访问不到了」。读不读得到，要看地址字段加上组寄存器之后的整体能力，
不能只看字段本身有多宽。准确的说法是「直接寻址能力减半、机制更复杂」，
而不是「存不下、够不着」。
```

**要点。**

- 指令字 15 位：3 位操作码 + 12 位地址，只有 8 个基本操作码。
- 两种扩展：EXTEND 换档、partial codes 让同一操作码在不同地址区间表示不同指令。
- 本仓库统计到 EXTEND 用了 1,672 次，约占全部指令的 8%。
- 中央寄存器只有 4 个：A、Z、Q、L。


---

## 3　编织出来的存储器

*Hardware · 存储. 这台计算机有两种存储器。可写的那部分是我们熟悉的磁芯；只读的那部分是绳芯——程序是被工人用线一根一根穿进磁芯里的。*

**打个比方。** 可写的那部分像一张草稿纸，写了擦、擦了写，随你改；只读的那部分像一块织好的布——程序不是「写」进去的，是工人拿线一根一根织进去的。布一旦织完，想改一个字，就得把整块重新织一遍。

**当时的处境。** 绳芯存储的原理其实很朴素：导线穿过磁芯代表 1，从磁芯外侧绕过代表 0。一根磁芯可以穿多根线，所以密度高。代价是它只能写一次，而且写的过程是手工劳动。

*图 4：绳芯存储中导线穿过磁芯表示 1、从外侧绕过表示 0。（图示见 HTML 版）*

### 【外部资料】`NASA NTRS 20230005922（Appendix F）／公开技术文档`

```agc
存储配置（容量单位都是字 word）：
· 可擦写内存 2,048 字 —— 磁芯存储器 magnetic core memory
· 只读内存 36,864 字 —— 绳芯存储器 core rope memory
· 两者访问周期均为 11.72 微秒
· 字长 16 位（bit）= 15 位数据 + 1 位奇校验
· CPU 内部字格式：14 位数据 + 1 位溢出 + 1 位符号（反码表示）

绳芯由工厂工人手工编织，完成一块需要数月。
当年程序员给它起了个外号：LOL memory，即 Little Old Lady memory。
```

> 绳芯「编一次要几个月」这条直接决定了软件工程方式：代码必须冻结。它不是技术细节，是管理铁律。——这里补一次取舍说明：流传很广的「绳芯密度约 72 KB 每立方英尺、是可读写磁芯的 18 倍」这一句，只有 Wikipedia 条目在引，条目自己还带着 citation needed 标记。本册的原则是**维基用来找路，不用来给结论背书**，所以这句删掉了。LOL memory 这个外号同理，属于口口相传的行话，不是技术参数，读到这里知道就行。

### 【源码实证】`Luminary099/ERASABLE_ASSIGNMENTS.agc:432-437`

```agc
# VAC AREAS. -- BE CAREFUL OF PLACEMENT --	(220D)

VAC1USE		ERASE
VAC1		ERASE	+42D
VAC2USE		ERASE
VAC2		ERASE	+42D
```

> 可写内存这边，每个字都要手工分配。注释里那句 BE CAREFUL OF PLACEMENT（小心摆放位置）是当年程序员留下的原话。

### 【源码实证】`Luminary099/ERASABLE_ASSIGNMENTS.agc:374-378`

```agc
# DYNAMICALLY ALLOCATED CORE SETS FOR JOBS	(84D)

MPAC		ERASE	+6		# MULTI-PURPOSE ACCUMULATOR.
MODE		ERASE			# +1 FOR TP, +0 FOR DP, OR -1 FOR VECTOR.
LOC		ERASE			# LOCATION ASSOCIATED WITH JOB.
```

> 这是可写内存里分给「作业」工作位的一段——作业指计算机正在处理的一项任务，这个词后面讲调度时还会反复出现。整块可写内存 2,048 字，对比只读的 36,864 字约为十八分之一，而且还要再切成一块块手工摆位。

### 【作者推导】`Luminary099/EXECUTIVE.agc:157,162,318 ／ ERASABLE_ASSIGNMENTS.agc:383`

```agc
# EXECUTIVE.agc:157
		CAF	NO.CORES	# SEVEN SETS OF ELEVEN REGISTERS EACH.
# EXECUTIVE.agc:162
NO.CORES	DEC	7
# EXECUTIVE.agc:318
COREINC		DEC	12		# 12 REGISTERS PER CORE SET.
# ERASABLE_ASSIGNMENTS.agc:383
		ERASE	+83D		# EIGHT SETS OF 12 REGISTERS EACH
```

> ★ 一处可以自己动手验算的地方。数据说得很清楚：核心集 7 个（NO.CORES DEC 7），每集步长 12 个字（COREINC DEC 12），7 × 12 = 84，正好对上上一条批注里的 84D。批注里那句 EIGHT SETS OF 12 是把 MPAC 起头那 12 个字也算作一集，96 = 8 × 12，同样自洽。唯一对不上的是第 157 行注释里的 ELEVEN（十一）——和数据矛盾，应该是早期版本改过数之后忘记同步的注释。这类残留在这份源码里不止一处，读到时不必替它圆场，照实记下即可。

**绳芯带来的工程后果。** 因为改代码的成本是几个月，这个团队被迫把正确性做在前面：交叉引用表、逐页页码、告警码表、装订前自检，都是为了让「一次织对」成为可能。今天我们把软件当成可以无限修改的东西，于是把验证推到了发布之后。绳芯不允许这样。需要说明：**「质量保障被前置」是从今天的软件工程视角回看时做的归纳**，不是当年团队自己写下的正式方法。源码里能确证的是那些具体做法——交叉引用表、逐页页码、告警码表、装订前自检；把它们统称为质量保障，是本册的概括。

**要点。**

- 可写内存 2,048 字用磁芯，只读内存 36,864 字用绳芯。
- 绳芯靠导线穿过或绕过磁芯表示 1 和 0，由工人手工编织，耗时数月。
- 所以软件必须冻结：装订之后改一行，等于重织整块存储。
- 可写内存只有只读内存的约十八分之一，每一个字都要手工分配。


---

## 4　八天

*Mission · 任务过程. 从发射到溅落，一共八天三小时十八分。下面是这条时间线，以及飞船上那几台计算机在这八天里各自负责什么。*

**当时的处境。** 整个任务由一系列轨道机动串起来：进入地球停泊轨道、地月转移、进入月球轨道、下降着陆、月面起飞、交会对接、返回地球。其中由机载系统控制的那些点火，都由制导系统计算并执行。

*图 5：阿波罗 11 号八天任务的关键节点（UTC）。（图示见 HTML 版）*

### 【外部资料】`Planetary Society / 史密森尼国家航空航天博物馆`

```agc
阿波罗 11 号关键节点（UTC）：
07-16 13:32:00  发射
07-16 13:43:49  进入地球停泊轨道
07-16 16:2x     地月转移点火
07-16 16:56:03  与登月舱对接
07-19 17:21:50  进入月球轨道
07-20 12:52     航天员进入登月舱
07-20 17:44:00  鹰号分离
07-20 19:08:14  下降轨道切入
07-20 20:05:05  动力下降开始
07-20 20:17:39  着陆
07-21 02:39:33  舱门打开
07-21 02:56:15  人类第一步
07-21 17:54:00  上升级起飞
07-21 21:35:00  与指令舱对接
07-22 04:55:42  地月返回点火
07-24 16:50:35  太平洋溅落
```

> ⚠️ 一处需要说明：地月转移点火的时刻，不同资料记载有差异（约在 16:16 至 16:22 之间）。核对到两个来源不一致，所以这条会继续标注为待核。

### 【源码实证】`Luminary099/P40-P47.agc:31-47`

```agc
# PROGRAM DESCRIPTION: P40BOTH		DECEMBER 22, 1966
# MOD 03 BY PETER ADLER			MARCH 3, 1967
# CALLED VIA JOB FROM V37E
#
# FUNCTIONAL DESCRIPTION
#
#	1)	TO COMPUTE A PREFERRED IMU ORIENTATION AND A PREFERRED VEHICLE ATTITUDE FOR A LM DPS
#		THRUSTING MANEUVER.
# 	(There is no item #2 in the original program listing --- RSB 2009.)
#	3)	TO DO THE VEHICLE MANEUVER TO THE THRUSTING ATTITUDE.
#	4)	TO CONTROL THE PGNCS DURING COUNTDOWN, IGNITION, THRUSTING, AND THRUST TERMINATION OF A
#		PGNCS CONTROLLED DPS MANEUVER.
#	5)	IN POSTBURN --- ZERO RENDEZVOUS COUNTER, MAINTAIN VG CALCULATIONS FOR POSSIBLE RCS MANEUVER,
#		SET MAXIMUM DEADBAND IN DAP, RESET STEERLAW CSTEER TO ZERO.
#
#	NOTE:	P42, WHICH IS IN THIS LOG SECTION, DOES THE SAME FOR AN APS BURN, AND P41 DOES 1-3 FOR
#		RCS PLUS DISPLAYS PARAMETERS FOR MANUAL CONTROL.
```

> 时间线上由 PGNCS 控制的每一次点火，在代码里是这样拆的：先算出该摆什么姿态，再把飞船转到那个姿态，然后管倒计时、点火、燃烧、关机，最后处理烧完之后的事。P42 对上升级发动机做同样的事，P41 用姿控推进器做前三步（DPS 是下降级发动机，APS 是上升级发动机）。括号里那句不是 1969 年的原文，是后来整理这份源码的人加的注——本册照录，但不把它当成当年的东西。

### 控制流：一次点火在代码里被拆成了四步

*时间线上每一个「点火」节点，落到源码里都是这条流程*

1. **算出该摆什么姿态** —— 先计算一次推力机动所需要的惯性基准取向与飞行器姿态。　`Luminary099/P40-P47.agc:37-38`
2. **把飞船转到那个姿态** —— 执行姿态机动，让飞行器真正对准。　`Luminary099/P40-P47.agc:40`
3. **倒计时、点火、燃烧、关机** —— 由 PGNCS 全程接管这一段，包括点火前的倒计时和推力终止。　`Luminary099/P40-P47.agc:41-42`
4. **处理烧完之后** —— 清零交会计数器、维持速度增量计算、把自动驾驶仪死区放到最大、复位控制律。　`Luminary099/P40-P47.agc:43-44`
5. **点火本身是共用的** —— P12、P40、P42、P61、P63 共用同一个主点火例程——下降、上升、中途修正走的是同一段代码。　`Luminary099/BURN_BABY_BURN--MASTER_IGNITION_ROUTINE.agc:53`

**要点。**

- 全程八天三小时十八分，由发射、转移、入轨、着陆、月面作业、起飞交会、返回七个大段组成。
- 动力下降从 20:05:05 开始，12 分 34 秒后着陆。
- 由 PGNCS 控制的点火在代码里拆成：算姿态 → 转姿态 → 倒计时点火燃烧关机 → 收尾。


---

## 5　我们怎么知道自己在哪

*Navigation · 导航. 飞船上有计算机在算位置，地面上也有计算机在算位置，两边还一直在对表。要说清阿波罗的导航，得先分清「定轨」和「用轨」是两件不同的事。*

**打个比方。** 像在陌生的山里赶路：自己数着步子往前走，走着走着就偏了；路边偶尔有块路牌，能帮你对一下；半山腰还有个人拿着望远镜一直看着你，隔一阵在对讲机里说一句「你现在在大石头那儿」。三种办法互相校正，你才敢确定自己到底在哪。

**当时的处境。** 这里要先纠正一句流传很广的简化说法。常见版本是「阿波罗的主导航在地面，机载计算机只是备份」——这个说法有一半是对的，另一半会让人产生错误的心理模型。准确的分工是这样的：航天器位置与轨道参数的**主要确定手段**在地面（测控网雷达跟踪，休斯顿的大型机做整体定轨），结果通过上行链路注入机载计算机；而**状态传播、测量处理、制导计算、姿态与推力控制**始终在机上由 AGC 自主完成，不依赖地面。可以粗略地记成：地面主要提供「你在哪」的更新，机载负责拿到之后怎么飞（这只是帮助记忆的概括，上面那句分工描述才是准确的）。而且机载必须能在失去地面支持时独立撑住——月球背面没有通讯，着陆末段也来不及等地面回话。

*图 6：地面测控、惯性推算、雷达与光学测量三者的互相校正关系。（图示见 HTML 版）*

*图 7：一次测量合并的四步数据流：ZI、GAMMA、OMEGA、DELTAX，最后写回状态向量。行号见各步下方。（图示见 HTML 版）*

### 【源码实证】`Luminary099/MEASUREMENT_INCORPORATION.agc:29-35`

```agc
# INCORP1 -- PERFORMS THE SIX DIMENSIONAL STATE VECTOR DEVIATION FOR POSITION
# AND VELOCITY OR THE NINE-DIMENSIONAL DEVIATION OF POSITION, VELOCITY, AND
# RADAR OR LANDMARK BIAS. THE OUTPUT OF THE BVECTOR ROUTINE ALONG WITH THE
# ERROR TRANSITION MATRIX (W) ARE USED AS INPU TO THE ROUTINE. THE DEVIATION
# IS OBTAINED BY COMPUTING AN ESTIMATED TRACKING MEASUREMENT FROM THE
# CURRENT STATE VECTOR AND COMPARING IT WITH AN ACTUAL TRACKING MEASUREMENT
# AND APPLYING A STATISTICAL WEIGHTING VECTOR.
```

> 这一条把「测量怎么并进状态向量」写得清清楚楚：先用当前状态向量算出估计的测量值，再和实际的测量值比，差值乘一个统计加权向量，得到状态向量的修正量。六维是位置与速度各三个分量，九维再加上雷达或地标偏差的三个分量。原文中 INPU 是 INPUT 的笔误，照录未改。

### 【源码实证】`Luminary099/MEASUREMENT_INCORPORATION.agc:37-48`

```agc
# INPUT
#	 DMENFLG = 0 (6-DIMENSIONAL BVECTOR), =1 (9-DIMENSIONAL)
#	       W = ERROR TRANSITION MATRIX 6X6 OR 9X9
#	VARIANCE = VARIANCE (SCALAR)
#	  DELTAQ = MEASURED DEVIATION (SCALAR)
#	 BVECTOR = 6 OR 9 DIMENSIONAL BVECTOR
#
# OUTPUT
#	  DELTAX = STATE VECTOR DEVIATIONS 6 OR 9 DIMENSIONAL
#	      ZI = VECTOR USED FOR THE INCORPORATION 6 OR 9 DIMENSIONAL
#	   GAMMA = SCALAR
#	   OMEGA = OMEGA WEIGHTING VECTOR 6 OR 9 DIMENSIONAL
```

> 这是一份完整的算法契约，输入输出写得比很多现代代码还规范。注意输入里**没有**协方差矩阵 P——只有 W、测量方差、测量偏差和 B 向量。这一点很重要，下面会回到它。

### 【源码实证】`Luminary099/MEASUREMENT_INCORPORATION.agc:74-94（其余三个量定义在 :100-146 ／ :163-181 ／ :192-202）`

```agc
Z123		VLOAD	MXV*
			BVECTOR		# BVECTOR (0)
			W +54D,1
		STORE	ZI +18D,2
		VLOAD
			BVECTOR +6	# BVECTOR (1)
# Page 1150
		MXV*	VAD*
			W +108D,1
			ZI +18D,2
		STORE	ZI +18D,2
		VLOAD
			BVECTOR +12D	# BVECTOR (2)
		MXV*	VAD*
			W +162D,1
			ZI +18D,2	# B(0)*W+B(1)*(W+54)+B(2)*(W+108) FIRST PASS
		STORE	ZI +18D,2	# ZI THEN Z2 THEN Z3
		TIX,1
			INCOR1
INCOR1		TIX,2	BON
			Z123		# LOOP FOR Z1,Z2,Z3
```

> ★ 源码注释里直接写着公式，四步依次是：① ZI = W·B（:74-94，注释原文 B(0)*W+B(1)*(W+54)+B(2)*(W+108)）；② TRIPA = ‖ZI‖² + VARIANCE（:100-116）。源码注释里写作 ZI*2 + Z2*2 + Z3*2 + VARIANCE，那个 *2 是硬拷贝上「平方」上标的转录写法，不是乘 2。算完再经归一化与定标，存进 GAMMA（:128-146）；③ OMEGA = W·ZI（:163-181，注释 COMPUT OMEGA1,2,3）；④ DELTAX = OMEGA 乘上 DELTAQ 并按 GAMMA 归一（:192-202，注释 DELTAQ/A）。代码里那些 NORM / SL* / VSL* 是定点定标操作，作用是把中间量拉回 15 位字长能表示的范围，不改变数学含义。

### 【作者推导】`由上面三条源码数据推导，非原文写明`

```agc
教科书卡尔曼更新的标准形式（现代记号）：

    增益    K  = P·Hᵀ / (H·P·Hᵀ + R)
    修正    Δx = K · (z − ẑ)
    协方差  P' = P − K·(H·P)

本册的对应关系（作者推导，可自行复核）：

    W          ↔ 协方差的平方根因子，使 P = W·Wᵀ
    BVECTOR    ↔ Hᵀ（测量对状态的灵敏度向量）
    VARIANCE   ↔ R（测量噪声方差）
    DELTAQ     ↔ z − ẑ（残差）
    ZI = W·B   ↔ P·Hᵀ
    GAMMA      ↔ H·P·Hᵀ + R
    OMEGA=W·ZI ↔ P·Hᵀ 的另一种写法
    DELTAX     ↔ K · (z − ẑ)
```

> ★ 这段是本册唯一一处纯推导，所以要说清依据：源码把 GAMMA 算成 ‖W·B‖² + VARIANCE，而不是 Bᵀ·P·B + R。如果 W 就是 P 本身，GAMMA 就该写成 Bᵀ·W·B + R；写成 ‖W·B‖² 说明 P 从未被显式构造，W 自始至终以因子形式参与运算——这正是 Potter 平方根形式滤波的特征。**这是推导，不是源码原文写明的事实**，读者可以拿着 GAMMA 那一行自己判断。

### 【源码实证】`Luminary099/ASSEMBLY_AND_OPERATION_INFORMATION.agc:249-250`

```agc
# 80	UPDATE LEM STATE VECTOR
# 81	UPDATE CSM STATE VECTOR
```

> Verb 80 更新登月舱状态向量，Verb 81 更新指令舱状态向量。这就是地面把定轨结果上行注入 AGC 的入口。

### 【源码实证】`Luminary099/ASSEMBLY_AND_OPERATION_INFORMATION.agc:226-227`

```agc
# 57	PERMIT LANDING RADAR UPDATES
# 58	INHIBIT LANDING RADAR UPDATES
```

> 着陆雷达的更新可以被宇航员手动允许或禁止。说明雷达数据不是无条件相信的，是否采纳由人决定。

### 【源码实证】`Luminary099/ASSEMBLY_AND_OPERATION_INFORMATION.agc:790-798`

```agc
# LANDING RADAR		xxxxx. FEET		DP	LOW ORDER BIT OF LOW ORDER
# ALTITUDE						WORD = 1.079 FEET

# -X-
# LANDING RADAR		xxxxx. FEET/SEC		DP	LOW ORDER BIT OF LOW ORDER
# VELX							WORD = -.6440 FEET/SEC

# -Y-
# LANDING RADAR		xxxxx. FEET/SEC		DP	LOW ORDER BIT OF LOW ORDER
```

> 着陆雷达提供三个量：高度（英尺）与两个方向的速度（英尺每秒）。这就是最后几公里最要命的数据来源。

### 【源码实证】`Luminary099/P20-P25.agc:602`

```agc
#	TO PROCESS AUTOMATIC RR MARK DATA TO UPDATE THE STATE VECTOR OF EITHER
```

> RR 是交会雷达。雷达打出的标记数据被用来更新状态向量。同文件第 45 行写明该程序的目的是控制交会雷达。

### 【源码实证】`Luminary099/INPUT_OUTPUT_CHANNEL_BIT_DESCRIPTIONS.agc:137`

```agc
#	  BIT 3		OPTICS X-AXIS MARK SIGNAL FOR ALIGN OPTICAL TSCOPE
```

> 连硬件通道的每一位都有登记，这里记的是光学望远镜 X 轴的标记信号。光学测量是惯性基准的校正来源。

### 【外部资料】`NASA NTRS 20230005922，Appendix F（Apollo GN&C System Components）`

```agc
After launch, the Apollo Guidance and Navigation System was the primary onboard
equipment that provided guidance and control for all of the midcourse burns,
lunar orbit injection, trans-Earth burn, and entry guidance.

The Apollo guidance system received position updates from the DSP network,
which the on-board system propagated based on the velocity and state vector
between updates.

The onboard system determined the spacecraft velocity and controlled its
attitude maneuvers and velocity burns.
```

> ★ 这一段是本册导航章的定盘星，也是我改写这一章的直接原因。NASA 一手文件的说法是：**位置更新**由地面测控网提供，机载系统在这些更新之间**自己做状态传播**，而且**速度由机载自己测定**、姿态机动与速度修正都由机载控制。流行说法「主导航在地面、机载只是备份」，错就错在把这两件事混成了一件。注意：这份文件把测控网写作 DSP network，照录未改。

### 【外部资料】`Kalman 1960；NASA / MIT 的应用记录（参考文献 [9][5][10]）`

```agc
1960 年　Kalman 发表《A New Approach to Linear Filtering and Prediction Problems》
1960 年　NASA Ames 的 Stanley F. Schmidt 将其引入载人登月导航研究
1961 年　IBM 704 上的仿真确认该方法在精度相当的前提下更省内存与算力
　　　　 MIT 仪表实验室 Richard Battin 团队为航天器导航采用这一递推方法
　　　　 MIT 的 James Potter 提出平方根形式，使其适配阿波罗机载计算机的短字长
1969 年　阿波罗 11 号登月
```

> ★ 这条时间线很容易被讲成「1960 年出理论，1969 年直接用上」，但那样讲会漏掉真正困难的部分。从论文到飞行，中间至少经过四次转化：①**理论**——Kalman 的递推最优估计；②**算法**——Battin 把它改写成适合航天器导航的递推形式；③**数值表示**——Potter 提出平方根形式，因为 15 位（bit）字长的定点机存不下、也算不稳一个显式协方差矩阵；④**硬件与指令集**——必须塞进只有 8 个基本操作码、2K 可写内存、每秒约四万条指令的机器；⑤**飞行软件**——还要能被中断、能重启、能从相位表接回来。第 ③ 步尤其关键，也正是本册在第 2 章讲 15 位字长、在这一章讲 W 矩阵以因子形式参与运算的原因。**这一段属外部史料，源码里查不到，单独标注。**

### 控制流：一次测量合并的数据流

*从「有一个新测量」到「状态向量被修正」，中间经过九个量*

1. **轨道积分外推状态向量** —— 没有新测量时，靠轨道积分把状态向量往前推——这一步会累积误差。　`Luminary099 轨道积分子系统`
2. **生成 BVECTOR** —— 计算测量对状态的灵敏度向量 B——「这个测量对哪个状态量敏感」。　`Luminary099/MEASUREMENT_INCORPORATION.agc:42`
3. **算出残差 DELTAQ** —— 用当前状态向量预测一个测量值，与实际测量值相减，得到偏差。　`Luminary099/MEASUREMENT_INCORPORATION.agc:41`
4. **ZI = W · B** —— 误差转移矩阵乘灵敏度向量，注释里直接写着这个式子。　`Luminary099/MEASUREMENT_INCORPORATION.agc:74-94`
5. **GAMMA = ‖ZI‖² + VARIANCE** —— 先验不确定度与测量噪声合起来，构成归一基准。　`Luminary099/MEASUREMENT_INCORPORATION.agc:100-146`
6. **OMEGA = W · ZI** —— 得到未归一的增益向量。　`Luminary099/MEASUREMENT_INCORPORATION.agc:163-181`
7. **DELTAX = OMEGA × DELTAQ / GAMMA** —— 噪声越大，同样的残差换来的修正越小。　`Luminary099/MEASUREMENT_INCORPORATION.agc:192-202`
8. **写回状态向量** —— INCORP2 把修正量并进登月舱或指令舱的状态向量，由 VEHUPFLG 决定更新哪一个。　`Luminary099/MEASUREMENT_INCORPORATION.agc:207-236`
9. **同时更新 W 矩阵** —— W 做一次秩一修正，不确定度随之下降——做完这一步，一次更新才算完整。　`Luminary099/MEASUREMENT_INCORPORATION.agc:275-300`

### WALKTHROUGH：一次测量合并，手算一遍

前面几条证明了「源码在算什么」，但还没证明它算出来的是最优估计。下面把 INCORP1 的四步退化成一维标量情形，取一组极小的数，读者可以拿笔跟着算。这不是阿波罗的真实参数，是为了让公式可被手算验证而构造的简化例子。

**已知条件**

- 待估计量 x（例如到某个目标的距离），先验估计 x̂ = 100.0
- W 退化为标量 w = 3.0，故先验方差 P = w² = 9.0（标准差 3.0）
- BVECTOR 退化为 B = 1.0（直接测量这个量）
- VARIANCE = R = 7.0（测量噪声方差，标准差约 2.65）
- DELTAQ = ΔQ = +8.0（实际测量值与预测测量值之差，即残差）

| 步 | 代码在算什么 | 代入本例 | 结果 |
| --- | --- | --- | ---: |
| 1 | `ZI = W · B`（把测量灵敏度映射到状态空间） | `3.0 × 1.0` | **3.0** |
| 2 | `TRIPA = ‖ZI‖² + VARIANCE`（先验不确定度 + 测量噪声，共同构成归一基准） | `3.0² + 7.0` | **16.0** |
| 3 | `OMEGA = W · ZI`（未归一的增益向量，同时含先验与灵敏度信息） | `3.0 × 3.0` | **9.0** |
| 4 | `DELTAX = OMEGA × DELTAQ / GAMMA`（噪声越大，同样的残差换来的修正越小） | `9.0 × 8.0 ÷ 16.0` | **4.5** |

**用教科书公式独立验算**

```
K = P / (P + R) = 9.0 / (9.0 + 7.0) = 9/16 = 0.5625
    Δx = K × ΔQ = 0.5625 × 8.0 = 4.5          ← 与代码一致

    更新后   x̂' = 100.0 + 4.5 = 104.5
             P' = P·R / (P + R) = 9.0 × 7.0 / 16.0 = 3.9375
             标准差由 3.0 降到约 1.98
```

> 要说清这个 4.5 证明了什么、没证明什么。它证明的是：**这个一维退化算例与教科书标准卡尔曼测量更新在数学上完全一致**。它没有证明、也不能证明「阿波罗的完整实现等于教科书卡尔曼滤波」。NASA 自己的材料还专门强调过，机载导航软件相对正统卡尔曼滤波做了若干简化与改造：用 W 矩阵而不是显式的协方差矩阵，一次只合并一个测量，以及测量值的事前剔除。准确的说法是：代码走的是同一套数学骨架，但装的是为 15 位定点机改造过的平方根／递推形式。这也是本册唯一一处「用数值证明源码在算什么」的地方。

**换个参数，看结果怎么动**

```
同一套公式，只改测量噪声 R，看修正量怎么变：

    R = 0    （测量完全可信）  K = 9/9  = 1.000   Δx = 8.0    全盘接受测量
    R = 7    （本例）          K = 9/16 = 0.5625  Δx = 4.5    两边各信一半
    R = 100  （测量很不可信）  K = 9/109 = 0.083  Δx = 0.66   几乎不动

这就是源码里那个 statistical weighting vector（统计加权向量）在做的事：它不是无条件相信任何一个信息源，而是按各自的不确定度分配信任。
```

**一个容易搞错的地方。** 源码里有两个带 Kalman 字样但用途不同的东西：KALCMANU 是姿态机动例程（ATTITUDE_MANEUVER_ROUTINE.agc:36 写明它给自动驾驶仪生成改姿态的指令，并避免万向锁）；KALMAN_FILTER.agc 位于数字自动驾驶仪分区，与喷气控制相关。真正把测量并入轨道状态向量的是 MEASUREMENT_INCORPORATION。把这三者混为一谈是常见错误，本册特意区分。

**要点。**

- 校正来源有三类：光学望远镜测星、雷达测距测速、地面测控上行注入。
- 源码 MEASUREMENT_INCORPORATION 的四步（ZI / GAMMA / OMEGA / DELTAX）与教科书卡尔曼测量更新在数学上一致，可用一维算例手算验证；但阿波罗的完整实现是针对机载约束改造过的平方根／递推形式，不等于教科书原样照搬。
- 地面主导轨道确定，机载主导状态传播与制导控制，两者协同而非主备；机载还必须能独立撑住——月球背面没有通讯，着陆末段也来不及等地面回话。


---

## 6　它到底在算什么

*Guidance · 制导与控制. 知道自己在哪之后是第二个问题：往哪去、油门踩多深、姿态怎么摆。这三件事分别叫导航、制导、控制。*

**当时的处境。** 制导方程算出应该往哪加速、加速多久；自动驾驶仪负责把姿态和推力执行到位。这两层在源码里是分开的模块，各负其责。

### 【源码实证】`Luminary099/BURN_BABY_BURN--MASTER_IGNITION_ROUTINE.agc:53`

```agc
# THE MASTER IGNITION ROUTINE IS DESIGNED FOR USE BY THE FOLLOWING LEM PROGRAMS:  P12, P40, P42, P61, P63.
```

> 主点火例程被哪些程序共用，注释里列得清清楚楚，P63 就在其中。这里要分清两件事：**P63 是动力下降阶段的制导／控制程序，点火这件事由它去调用这套共用的点火设施**——P63 本身不是点火例程。这样讲架构更清楚：点火只写一份，谁要点谁去调。文件名本身是当年程序员开的玩笑。

### 【源码实证】`Luminary099/BURN_BABY_BURN--MASTER_IGNITION_ROUTINE.agc:159`

```agc
BURNBABY	TC	PHASCHNG	# GROUP 4 RESTARTS HERE
```

> 点火这件事被登记在第 4 重启组。万一中途发生重启，系统从这一行把它重新拉起来，而不是从头重新点火。

### 【源码实证】`Luminary099/ASSEMBLY_AND_OPERATION_INFORMATION.agc:988,1040`

```agc
# 01412		DESCENT IGNALG NOT CONVERGING			P63
# 00500		SWITCH		LR ANTENNA TO POSITION 1		P63
```

> 这两条都挂在 P63 名下：一条是下降点火算法不收敛的告警，一条是切换着陆雷达天线位置的操作提示。LR 即着陆雷达。源码能确证 P63 与下降段直接相关。

### 【源码实证】`Luminary099 着陆与姿控相关模块`

```agc
LUNAR_LANDING_GUIDANCE_EQUATIONS   着陆制导方程
THROTTLE_CONTROL_ROUTINES          油门控制
THE_LUNAR_LANDING                  登月着陆主程序
P-AXIS_RCS_AUTOPILOT               P 轴姿控自动驾驶
Q_R-AXIS_RCS_AUTOPILOT             Q、R 轴姿控自动驾驶
TJET_LAW                           喷气控制律
GIMBAL_LOCK_AVOIDANCE              万向锁规避
TRIM_GIMBAL_CONTROL_SYSTEM         发动机摆动控制
```

> 制导、油门、姿控、喷气、万向锁规避各自独立成模块。万向锁这种纯数学上的奇点问题，也被单独写成一个模块来规避。

**关于着陆阶段编号的说明。** 常见资料会把下降分成若干阶段程序并逐一编号说明。本册只写源码能确证的部分：P63 与下降点火直接相关（BURN_BABY_BURN:53、ASSEMBLY:988 与 :1040 三条互证）。其余阶段编号与具体分工属于 NASA 任务文件的记载，本册没有在仓库里找到对应证据，因此不逐条展开——宁可少写，不写没有出处的东西。

**要点。**

- 导航（在哪）、制导（往哪去）、控制（怎么执行）是三件分开的事，源码里也是分开的模块。
- P63 是源码能确证的动力下降阶段制导／控制程序，它调用共用的主点火例程；点火被登记在重启组，被中断后从这里接着跑。
- 姿态控制有专门的自动驾驶模块，连万向锁这种数学奇点都单独处理。


---

## 7　飞船上的四套计算系统

*Systems · 系统. 一次登月任务不止一台计算机。指令舱一台、登月舱一台，火箭上一台，登月舱里还有一台备用的。*

**当时的处境。** 备用计算机叫中止制导系统 AGS，它能在主系统失效时把航天员从月面送回轨道并完成交会，但它不能执行着陆。这个能力边界是设计时就定死的。

*图 8：一次登月任务中四台计算机的分布与职责边界。（图示见 HTML 版）*

### 【源码实证】`Luminary099/AGS_INITIALIZATION.agc:41-47`

```agc
# FUNCT. DESC.:	(1) TO PROVIDE THE AGS ABORT ELECTRONICS ASSEMBLY (AEA) WITH THE LEM AND CSM STATE VECTORS
#		(POSITION,VELOCITY,TIME) IN LEM IMU COORDINATES BY MEANS OF THE LGC DIGITAL DOWNLINK.
#
#		(2) TO ZERO THE ICDU, LGC, AND AEA GIMBAL ANGLE COUNTER SIMULTANEOUSLY IN ORDER TO ESTABLISH A
#		COMMON ZERO REFERENCE FOR THE MEASUREMENT OF GIMBAL (EULER) ANGLES WHICH DEFINE LEM ATTITUDE
#		(3) TO ESTABLISH THE GROUND ELAPSED TIME OF AEA CLOCK ZERO.  (IF AN AEA CLOCK ZERO IS
#		REQUESTED DURING THIS PROGRAM
```

> ★ 这条证据很能说明当年的工程态度：主计算机主动向备用计算机传送状态向量（位置、速度、时间），并且把三台设备的陀螺角计数器同时归零——LGC 是主计算机本身，AEA 是备用计算机 AGS 的电子部分，ICDU 是惯性测量单元的计数器——以此建立公共零参考，连时钟零点都要对齐。备件不是摆设，是要随时能接手的。宇航员按 V47E 触发这个程序。

### 【外部资料】`NASA / 公开技术文档`

```agc
每次登月任务携带的计算机：
· AGC —— 指令舱，制导导航控制核心
· AGC —— 登月舱，运行 PGNCS（读作 pings）
· LVDC —— 土星五号仪器环，运载火箭的数字计算机
· AGS —— 登月舱的中止制导系统，可起飞与交会，但不能执行着陆
```

> AGS 的能力边界（能起飞、能交会、不能着陆）是设计定死的，不是能力不足，是职责划分。

**要点。**

- 一次任务带着四套数字计算系统：指令舱 AGC、登月舱 AGC、火箭 LVDC、备用 AGS。后两者的内部组成与 AGC 并不相同，所以严谨的说法是「四套计算系统」而不是「四台 AGC」。
- AGS 能起飞和交会，但不能着陆——这是职责划分而非能力缺陷。
- 主备一致性由软件保证：AGC 主动向 AGS 传状态向量，并把三边陀螺角计数器同时归零。


---

## 8　一百多个模块怎么分工

*Software · 模块全景. 登月舱 89 个源文件、指令舱 84 个，合计 173 个，13 万行。它们不是平铺的，源码目录里早就分好了组，而且分组名字起得相当随意。*

**打个比方。** 像一个老车间的工具墙：这边挂螺丝刀，那边放量具，角落是焊接的家伙。只是每个区域的名字不是印的，是工人拿记号笔自己写的——一个叫「飞行」，一个叫「接吻」，还有一个叫「船长」。外人看了摸不着头脑，车间里的人闭着眼都能摸到。

**当时的处境。** 分组名出现在源码目录注释里，是当年团队内部使用的代号。它们之所以被保留下来，是因为整个项目没有链接器，所有文件靠一个总目录 include 拼起来——目录本身就是架构文档。

*图 9：源码目录里的分组代号及其大致职责。（图示见 HTML 版）*

### 【源码实证】`Luminary099/ASSEMBLY_AND_OPERATION_INFORMATION.agc:60-147`

```agc
#		AGS INITIALIZATION
#		FRESH START AND RESTART
#		RESTART TABLES
#		AOTMARK
#		EXTENDED VERBS
#		PINBALL NOUN TABLES
#		LEM GEOMETRY
#		IMU COMPENSATION PACKAGE
#		R63
#		ATTITUDE MANEUVER ROUTINE
#		GIMBAL LOCK AVOIDANCE
#		KALCMANU STEERING
#		SYSTEM TEST STANDARD LEAD INS
#		IMU PERFORMANCE TESTS 2
#		IMU PERFORMANCE TESTS 4
#		PINBALL GAMES BUTTONS AND LIGHTS
#		R60,R62
#		S-BAND ANTENNA FOR LM
#	LEMP20S
#		RADAR LEADIN ROUTINES
#		P20-P25
#	LEMP30S
#		P30,P37
#		P32-P35, P72-P75
#		GENERAL LAMBERT AIMPOINT GUIDANCE
#	KISSING
#		GROUND TRACKING DETERMINATION PROGRAM - P21
#		P34-P35, P74-P75
#		R31
#		P76
#		R30
#		STABLE ORBIT - P38-P39
# Page 3
#	FLY
#		BURN, BABY, BURN -- MASTER IGNITION ROUTINE
#		P40-P47
#		THE LUNAR LANDING
#		THROTTLE CONTROL ROUTINES
#		LUNAR LANDING GUIDANCE EQUATIONS
#		P70-P71
#		P12
#		ASCENT GUIDANCE
#		SERVICER
#		LANDING ANALOG DISPLAYS
#		FINDCDUW -- GUIDAP INTERFACE
#	LEMP50S
#		P51-P53
#		LUNAR AND SOLAR EPHEMERIDES SUBROUTINES
#	SKIPPER
#		DOWN-TELEMETRY PROGRAM
#		INTER-BANK COMMUNICATION
#		INTERPRETER
#		FIXED-FIXED CONSTANT POOL
#		INTERPRETIVE CONSTANTS
#		SINGLE PRECISION SUBROUTINES
#		EXECUTIVE
#		WAITLIST
#		LATITUDE LONGITUDE SUBROUTINES
#		PLANETARY INERTIAL ORIENTATION
#		MEASUREMENT INCORPORATION
#		CONIC SUBROUTINES
#		INTEGRATION INITIALIZATION
#		ORBITAL INTEGRATION
#		INFLIGHT ALIGNMENT ROUTINES
#		POWERED FLIGHT SUBROUTINES
#		TIME OF FREE FALL
#		AGC BLOCK TWO SELF-CHECK
#		PHASE TABLE MAINTENANCE
#		RESTARTS ROUTINE
#		IMU MODE SWITCHING ROUTINES
#		KEYRUPT, UPRUPT
#		DISPLAY INTERFACE ROUTINES
#		SERVICE ROUTINES
#		ALARM AND ABORT
#		UPDATE PROGRAM
#		RTB OP CODES
#	LMDAP
#		T6-RUPT PROGRAMS
#		DAP INTERFACE SUBROUTINES
#		DAPIDLER PROGRAM
#		P-AXIS RCS AUTOPILOT
#		Q,R-AXIS RCS AUTOPILOT
#		TJET LAW
# Page 4
#		KALMAN FILTER
#		TRIM GIMBAL CONTROL SYSTEM
#		AOSTASK AND AOSJOB
#		SPS BACK-UP RCS CONTROL
```

> 分组代号一望而知是内部俚语：FLY 管动力飞行与着陆，KISSING 管地面跟踪与定轨，SKIPPER 是基础软件层，LMDAP 是自动驾驶。调度器 Executive、解释器 Interpreter、轨道积分、测量合并全在 SKIPPER 里。

### 【源码实证】`本地 Apollo-11 仓库统计`

```agc
登月舱 Luminary099：90 个 .agc 文件，64,838 行
指令舱 Comanche055：85 个 .agc 文件，65,348 行
合计：175 个文件，130,186 行
版权：Public domain（公有领域）
```

> 两套程序规模几乎一样，但功能完全不同：一个要把人放下去，一个要在轨道上等着接。

**要点。**

- 173 个源文件，13 万行，登月舱与指令舱各占一半。
- 源码目录里早有分组：FLY、KISSING、SKIPPER、LEMP20S/30S/50S、LMDAP。
- 基础软件层（调度、解释器、轨道积分、测量合并）集中在 SKIPPER。


---

## 9　那一夜

*Story · 1969 年 7 月 20 日. 动力下降开始后不久，显示器上跳出 1202，接着是 1201。地面上有人认得这两个数字，有人不认得。着陆继续。*

**打个比方。** 就像开车走长下坡时，仪表盘上突然亮了两盏灯。要是不知道灯是什么意思，第一反应多半是赶紧靠边停车。可要是你事先就把每种灯的含义写进了手册、还练过几遍，你就知道哪盏可以先不管、哪盏得马上动手。

**当时的处境。** 1202 的含义是核心集耗尽，即同时运行的作业数超过了系统能承载的上限。官方告警表给它标了一个星号，含义是会导致软件重启。重启不等于从头来——关键动作事先登记了恢复点。

### 【源码实证】`Luminary099/ASSEMBLY_AND_OPERATION_INFORMATION.agc:966-967`

```agc
# 01201	      *	EXECUTIVE OVERFLOW - NO VAC AREAS		EXEC
# 01202	      *	EXECUTIVE OVERFLOW - NO CORE SETS		EXEC
```

> 官方告警码表里，1201 与 1202 挨在一起：一个是 VAC 区耗尽，一个是核心集耗尽。表里的星号是判断严重性的关键。

### 【源码实证】`Luminary099/ASSEMBLY_AND_OPERATION_INFORMATION.agc:1014-1021`

```agc
#	      *	INDICATES AN ABORT CODE THAT RESULTS IN A SOFTWARE RESTART.
#
#	     **	INDICATES A MORE SERIOUS ABORT CODE THAT RESULTS IN THE
#		PROGRAM GOING TO R00.
#
#	      P	INDICATES A PRIORITY ALARM.
#
#		ALL OTHERS ARE NON-ABORTIVE
```

> 源码里这段说明就是当晚判断的依据：一个星号代表会导致软件重启，双星号更严重，其余都不中止任务。1202 只有一个星号——所以它不中止任务。

### 【源码实证】`Luminary099/EXECUTIVE.agc:201-208`

```agc
NEXTCORE	CAF	COREINC
		ADS	LOCCTR
		CCS	EXECTEM2
		TCF	NOVAC3
		LXCH	EXECTEM1
		CA	Q
		TC	BAILOUT1	# NO CORE SETS AVAILABLE.
		OCT	1202
```

> 1202 就是在这里发出的：NOVAC 挨个检查核心集，全占满就走出错处理；紧跟着的 OCT 1202 就是告警码。

### 【源码实证】`Luminary099/FRESH_START_AND_RESTART.agc:281-296`

```agc
ENEMA		INHINT
		TC	STARTSB1
		TCF	GOPROG2A
GOPROG2		TC	STARTSB2
GOPROG2A	TC	LIGHTSET
		CS	RSFLGBTS	# CLEAR BITS 7 AND 14.
		MASK	FLGWRD10
		TS	FLGWRD10

GOPROG3		CAF	NUMGRPS		# VERIFY PHASE TABLE AGREEMENTS
PCLOOP		TS	MPAC +5
		DOUBLE
		EXTEND
		INDEX	A
		DCA	-PHASE1		# COMPLEMENT INTO A, DIRECT INTO L.
		EXTEND
```

> 重启的入口叫 ENEMA。重启后 GOPROG3 会逐组校验六个重启组的相位表，对不上就判定重启失败。校验通过，事先登记过的作业按各自的恢复点继续。

**要点。**

- 1202 的含义是核心集耗尽，官方告警表标为单星号，后果是软件重启。
- 重启不是从头来：关键动作事先登记了恢复点，重启后按相位表接回。
- 1201 与 1202 是同一族：一个 VAC 区耗尽，一个核心集耗尽。
- 故障处理的软件机制细节见另一册《阿波罗 11 号制导计算机源码 · 逐层拆解》。


---

## 10　更大的坐标系

*Perspective · 博学者视角. 把这台机器放回它所在的年代，会发现一件更有意思的事：它几乎是把当时最先进的理论，用当时最笨重的办法，硬生生实现了一遍。*

**当时的处境。** 从布尔代数到最优估计，从通用门到存储密度，这台机器上能找到好几条跨越几十年甚至上百年的理论线索。它们不是巧合——是有人在极端的资源约束下，把能用的理论全用上了。

### 【源码实证】`Luminary099/MEASUREMENT_INCORPORATION.agc:31-35`

```agc
# RADAR OR LANDMARK BIAS. THE OUTPUT OF THE BVECTOR ROUTINE ALONG WITH THE
# ERROR TRANSITION MATRIX (W) ARE USED AS INPU TO THE ROUTINE. THE DEVIATION
# IS OBTAINED BY COMPUTING AN ESTIMATED TRACKING MEASUREMENT FROM THE
# CURRENT STATE VECTOR AND COMPARING IT WITH AN ACTUAL TRACKING MEASUREMENT
# AND APPLYING A STATISTICAL WEIGHTING VECTOR.
```

> 误差转移矩阵加统计加权——这就是递归最优估计在代码里的样子。理论没有停留在论文上，它被写成了能在 15 位（bit）字长的机器上跑的定点运算。

### 【外部资料】`公开学术史料（Kalman 1960；NASA Ames 与 MIT 仪表实验室的应用记录）`

```agc
1960 年　Kalman 发表《A New Approach to Linear Filtering and Prediction Problems》
1960 年　NASA Ames 的 Stanley F. Schmidt 将其引入载人登月导航研究
1961 年　IBM 704 上的仿真确认该方法在精度相当的前提下更省内存与算力
　　　　 MIT 仪表实验室 Richard Battin 团队为航天器导航采用这一递推方法
　　　　 MIT 的 James Potter 提出平方根形式，使其适配阿波罗机载计算机的短字长
1969 年　阿波罗 11 号登月
```

> 这里只做交叉引用，不再重讲：Kalman 1960 年提出最优估计，到这套代码飞上月球，中间经过五步转化，本册第 5 章已按「理论→算法→数值表示→硬件与指令集→飞行软件」拆开讲过。其中专门有人为短字长做了数值稳定性改造，那是理论落进工程时最见功夫的一步。这段属外部史料，源码里查不到，单独标注。

### 【源码实证】`Luminary099/ERASABLE_ASSIGNMENTS.agc:377`

```agc
MODE		ERASE			# +1 FOR TP, +0 FOR DP, OR -1 FOR VECTOR.
```

> 连当前算的是三精度、双精度还是向量，都要专门占一个字。这种节省程度，是理解后面一切设计的前提。

**约束到底换来了什么。** 绳芯决定了代码必须一次织对。从今天的视角回看，这等于把大量验证活动放到了代码冻结与投料制造之前：交叉引用表、页码、告警码表、装订前自检——不过这是本册的归纳，不是当年团队自己的提法。3 位操作码逼着每条指令精打细算，于是长出了解释器那层虚拟机。内存只有 2K 可写，于是每一个字都要手工分配。这些都不是优雅的设计选择，是被逼出来的。但逼出来的东西有一个特点：每一处都有存在的理由，没有一处是「顺手加的」。这大概是这份代码五十年后还值得读的根本原因。

**要点。**

- 从理论到飞行中间隔了五步转化，不是「论文出来直接就用上」——详见第 5 章。
- 有人专门为它做了短字长适配——数值稳定性是理论落地时绕不开的一步。
- 绳芯存储相当于把程序在编译期固化，是今天固件与掩模只读存储器的前身。
- 3 位操作码加上换档扩展，是编码密度走到极限的样子，今天压缩指令集仍在解决同类问题。


---

### 怎么复核本册的每一条

下面几条命令可以直接粘贴执行。原始源码为公有领域，任何人都能拿到同一份底本。

```bash
git clone https://github.com/chrislgarry/Apollo-11
cd Apollo-11
git checkout 911e5c0283c629c50cb97666f34065e8c07d71a5

# 核对 1202 告警的产生点
sed -n '201,209p' Luminary099/EXECUTIVE.agc

# 核对核心集的数量与步长
grep -nE 'NO\.CORES|COREINC' Luminary099/EXECUTIVE.agc

# 核对可写内存里核心集与 VAC 区的容量注记
grep -nE '84D|220D' Luminary099/ERASABLE_ASSIGNMENTS.agc

# 核对重启初始化：三个告警格清零
sed -n '55,60p' Luminary099/FRESH_START_AND_RESTART.agc

# 核对 PRM 记法的定义
sed -n '67,73p' Luminary099/ERASABLE_ASSIGNMENTS.agc
```

- 所有「源码实证」条目都标了文件与行号。行号以 commit `911e5c0` 为准；仓库后续若有变动，请先 `git checkout 911e5c0` 再核对。
- 「外部资料」条目不能回仓库核对，都给了参考文献编号，按编号去原文查。
- 「作者推导」条目给出了完整算式，你可以自己重算一遍。若结果与本册不同，以源码为准。
- 「解释性类比」只是解释工具，不是证据，不必去源码里找。

## 参考文献

全部列出，便于复现本册的研究路径。

- **[1]** Apollo-11 源码仓库（Luminary099 登月舱 / Comanche055 指令舱）
  - chrislgarry（整理），MIT Museum 藏硬拷贝数字化（Paul Fjeld 扫描） · 源码
  - https://github.com/chrislgarry/Apollo-11，commit 911e5c0283c629c50cb97666f34065e8c07d71a5。Public domain（公有领域）。源码自身的装订记时为 16:27 JULY 14, 1969；仓库 commit 的提交时间为 2026-07-15（该日期为仓库 commit 的提交时间，与源码内容无关，可自行用 git log -1 核实）。两者相差 57 年，不要混为一谈。
  - 用于：全文所有「源码实证」条目的出处。
- **[2]** MIT Instrumentation Laboratory Report R-500：Apollo Guidance and Navigation — Part VI, Guidance Computer Design
  - MIT Instrumentation Laboratory · 一手技术报告
  - MIT，1960 年代原始设计报告（klabs.org 等处存有扫描件）。
  - 用于：指令字格式（3 位操作码 + 12 位地址）、EXTEND 与 partial codes 两种扩充手法、Block I 指令清单。
- **[3]** NASA SP-8015：Guidance and Navigation for Entry Vehicles（原稿误引条目，已更正）
  - NASA · 一手技术报告
  - NASA NTRS 19690010164（1968）。本次对 NTRS 原页核验：该号实为再入飞行器导航专册，与 AGC 无关；原稿据其引述的 AGC「通用计算机」表述，已改由 [4] 的 Appendix F 承担（该附录取自 Draper Lab Report R-700，对页核验通过）。
  - 用于：文献纠错记录。
- **[4]** Apollo GN&C System Components（Appendix F）
  - NASA · 一手技术报告
  - NASA NTRS 20230005922（NASA/TP-20230005922，2023）。Appendix F 取自 Draper Lab Report R-700；PDF p288 含 AGC「general purpose computer…priority driven operating system」原话，p292（印刷页 271）含 AGC 规格表——均已对页核验。
  - 用于：机载制导导航控制系统的职责边界描述。
- **[5]** Apollo Onboard Navigation Techniques
  - NASA · 一手技术报告
  - NASA NTRS 20090016292。
  - 用于：机载导航与地面测控的分工、滤波方法的工程化过程。
- **[6]** Apollo 11 Mission Report / 任务相关技术文件
  - NASA · 一手技术报告
  - NASA NTRS 19700008096（MSC-00171）。原稿误引的 19700014507 经 NTRS 原页核验为月球大地测量报告，与任务报告无关，已更正；表 5-I 为着陆事件时间线（含 1202/1201 序列）
  - 用于：任务时间线与测控（MSFN）定轨职责的表述。
- **[7]** Apollo 11 Lunar Surface Journal — Program Alarms（1201 / 1202）
  - NASA 历史部（ALSJ） · 史料 / 综述
  - nasa.gov 历史档案，含当事软件人员对 1202/1201 的回顾。
  - 用于：1202/1201 与 core set / VAC 耗尽的关联，及重启后恢复的口述佐证。
- **[8]** Core rope memory（含其中引用的 Ken Shirriff 等人资料）
  - Wikipedia 条目及其引用 · 史料 / 综述
  - 公开条目。注意：该条目关于存储密度的部分自身带有 citation needed 标记。
  - 用于：仅用于 LOL memory 这个行话外号。原条目给出的密度数字 72 KB/ft³ 因来源过弱已从正文删除。
- **[9]** A New Approach to Linear Filtering and Prediction Problems
  - R. E. Kalman · 史料 / 综述
  - Journal of Basic Engineering, 1960。
  - 用于：最优估计的理论起点。
- **[10]** James Potter 讣闻（MIT News）
  - MIT News · 史料 / 综述
  - news.mit.edu，2005。
  - 用于：平方根形式滤波的提出者及其在阿波罗上的作用。
- **[11]** Apollo 11 任务时间线
  - Planetary Society / 史密森尼国家航空航天博物馆 · 史料 / 综述
  - 两处公开资料。
  - 用于：第 4 章时间线。两源在地月转移点火时刻上存在约一分钟差异，正文已标明。
- **[12]** Apollo Guidance Computer 公开技术综述（Wikipedia 等）
  - Wikipedia 等 · 史料 / 综述
  - 公开条目。其中「Minuteman II 混用多种逻辑族」一句自身标有 citation needed。
  - 用于：Block I / Block II 芯片数与封装、整机外形尺寸。等级偏低，正文已单独标注；功耗重量与容量改用 NASA NTRS 20230005922 原文。
- **[13]** AGC Block II Instructions（Digital Development Memo #193）
  - Albert Hopkins，MIT Instrumentation Laboratory · 一手技术报告
  - MIT 仪器实验室内部备忘录，ibiblio.org/apollo/Documents/dd_memo_193.pdf。
  - 用于：Block II 指令集扩充的两条机制（extension 与 partial codes）及 quarter code 的位来源。
- **[14]** Apollo Guidance Computer Block II — CMC Data Cards（基本指令与操作码表）
  - F. Bernardini 整理，基于 CMC/AGC 原始手册 · 一手技术报告
  - ibiblio.org/apollo/CMC_data_cards_15_Fabrizio_Bernardini.pdf（整理稿，非 NASA 原件）。
  - 用于：基本指令的操作码八进制值（TC=00、CCS=01、CA=03、AD=06 等）与 EXTEND=0.0006。
- **[15]** Virtual AGC 项目：yaYUL 汇编器与 yaAGC 模拟器
  - Ron Burkey 等，开源项目 · 公开网页
  - github.com/virtualagc/virtualagc；项目网站 virtualagc.github.io/virtualagc/ 与 ibiblio.org/apollo。chrislgarry/Apollo-11 仓库 README 的 Attribution 表里，Assembler 一栏写的就是 yaYUL（2026-09-15 对其 raw README 逐字核对）。
  - 用于：把本册的源码实证变成可执行证据：汇编与仿真复现的工具链出处。
- **[16]** chrislgarry/Apollo-11 仓库 README 的 Attribution 表（源码来历与装订记时）
  - chrislgarry/Apollo-11 仓库 README · 源码
  - Attribution 表在 chrislgarry/Apollo-11 的 README（不是 virtualagc 仓库的 README）。2026-09-15 逐字核对：Luminary099 一栏写明 「Assemble revision 001 of AGC program LMY99 by NASA」与「2021112-061. 16:27 JUL. 14, 1969」；Comanche055 一栏为「10:28 APR. 1, 1969」。
  - 用于：装订记时、程序正式编号；汇编器为 yaYUL。

**两个日期，不要混。** 源码自身的装订记时 `16:27 JULY 14, 1969`，写在源码头部，指这份程序当年装订的那个时刻；仓库 commit `911e5c0283c629c50cb97666f34065e8c07d71a5` 的提交时间是 2026-07-15，只是仓库整理者的提交时间，与源码内容无关，可用 `git log -1 911e5c0` 自行核实。两者相差 57 年。若仓库后续变动，请以该 commit 为准核对行号。

## 术语速览

| 术语 | 一句话解释 |
| --- | --- |
| NOR 门 | 一种通用逻辑门，任何逻辑都能由它搭出来，代价是用的数量多。 |
| RTL | 电阻晶体管逻辑，早期集成电路工艺，AGC 所用芯片采用。 |
| Block I / Block II | AGC 的两个硬件版本，载人飞行用的是 Block II。 |
| EXTEND | 指令前缀，类似换档键，使下一条指令改读另一套含义。 |
| partial codes | 让操作码侵占地址字段，同一操作码在不同地址区间表示不同指令。 |
| MCT | 存储周期，AGC 用它以周期为单位计量指令耗时。 |
| 磁芯存储器 | 可写的磁性存储，用磁芯的磁化方向存 0 和 1。 |
| 绳芯存储器 | 只读存储，靠导线穿过或绕过磁芯表示 1 和 0，手工编织。 |
| 状态向量 | 描述飞行器在哪、多快、什么时刻的一组数，通常六维或九维。 |
| 惯性测量单元 IMU | 用陀螺与加速度计持续推算自身姿态与位置的装置。 |
| 测量合并 | 把新的测量值与推算值按可信度加权合并，得到更优的估计。 |
| PGNCS | 登月舱主制导导航控制系统，读作 pings。 |
| AGS | 中止制导系统，备用计算机，可从月面起飞并交会，但不能着陆。 |
| LVDC | 土星五号运载火箭上的数字计算机。 |
| 相位表 | 登记作业恢复点的表，重启后据此把作业接回原位。 |
| 核心集 Core Set | 作业的工作位。全系统只有 7 个，每个 12 个字；同时运行的作业超出发放能力就抛 1202。 |
| DPS / APS | 登月舱的下降级与上升级发动机。源码里 P40 管下降级点火，P42 管上升级点火。 |
| DSKY | 飞船上的显示与键盘，宇航员通过 Verb（动作）加 Noun（对象）与计算机对话。 |

---

**证据来源。** 源码实证来自本地 Apollo-11 仓库（chrislgarry/Apollo-11，公有领域）。外部资料来自 NASA 公开史料、MIT 原始设计报告 R-500 与公开学术文献。

**一处未决。** 地月转移点火的精确时刻，不同公开资料存在约一分钟差异，本册如实标出未取精确值。

**图片。** Wikimedia Commons（PD / CC BY-SA 3.0）／NASA（PD）。Markdown 版不含图片，图片见同名 HTML。