☰
Apollo-11制导计算机仿真复现:从核心绳存储到实时调度
2026/10/15 1:09:50 网站建设 项目流程

1. 从“Apollo-11”这个名字说起:它到底指什么

第一次看到“Apollo-11”这个标题,很多人脑子里蹦出来的第一反应是那个著名的登月计划。但在技术圈里,这个名字被反复借用,指向的东西其实相当具体——它通常指的是一套制导计算机(Guidance Computer)的仿真与源码复现项目,核心是把当年那台算力极其有限、却要完成载人登月这种超高难度任务的机载计算机,用现代方式重新跑起来、读明白。

我最初接触这个方向,是因为一个很实际的问题:现代软件工程里,我们习惯了动辄几个G的内存、几十亿次每秒的算力,写代码时几乎不用考虑“省一个字节”这种事。可一旦你去看那些在极端约束下写出来的系统,会发现里面藏着大量今天已经失传的工程智慧。Apollo-11 相关的这套东西,恰好就是这样一个“极端约束下的工程标本”。

它解决的问题不是“怎么登月”,而是更底层的一件事:一台主频不到 1MHz、内存以 KB 计、存储以“核心绳”为介质的计算机,是如何被组织起来、如何被编程、如何保证不出错的。适合谁来研究?我觉得有三类人特别值得花时间:一是对嵌入式、实时系统感兴趣的开发者;二是想理解“约束如何塑造设计”的架构师;三是对计算机历史、底层原理有好奇心的爱好者。哪怕你只是想把它的汇编代码跑起来看一眼,这个过程本身就能刷新你对“资源”两个字的认知。

需要先说明一点:下面涉及的具体实现细节,有一部分来自公开的仿真项目常见做法,有一部分是我自己在复现和调试过程中总结的经验。原始资料本身是零散的,我会尽量把“为什么这么做”讲透,而不是只丢一堆命令给你。

2. 这台计算机的硬件骨架:为什么它的约束如此极端

2.1 核心绳存储:把程序“编织”进硬件里

要理解 Apollo-11 制导计算机(业内常简称 AGC)的一切设计,必须先理解它的存储介质——核心绳存储器(Core Rope Memory)。这东西今天听起来像黑魔法:程序不是烧录进芯片,而是由工人用导线穿过一个个磁芯,导线穿过磁芯记为“1”,绕过记为“0”。也就是说,程序的每一位都是物理上“编”出来的。

为什么用这么原始的方式?因为在那个年代,半导体存储又贵又不可靠,而核心绳一旦编好,断电也不会丢,抗辐射、抗振动,在太空环境里极其稳定。代价是:程序一旦编好就几乎无法修改。这直接导致了一个今天难以想象的工程约束——你必须在“烧录”之前,把每一行代码都验证到极致。

我实测复现时最大的感受是:现代开发里“先跑起来再改”的迭代方式,在这里完全不成立。这逼出了后面要讲的整套“地面仿真先行”的开发流程。你可以把核心绳理解成一张只读的、物理固化的程序光盘,而它的容量,直接决定了整个软件架构能有多“奢侈”。

2.2 内存与字长:15位带来的连锁反应

AGC 的字长是15 位(外加1位奇偶校验,实际存储16位)。为什么是15位而不是当时更常见的8位或16位?因为要表示的数据范围决定的:制导计算里需要表示的角度、速度、加速度,15位定点数配合精心设计的缩放因子,刚好够用,又不浪费宝贵的存储。

这里有个很多人忽略的细节:AGC 没有硬件乘法器和除法器。所有乘除都要靠软件子程序实现,一次乘法可能要消耗几十甚至上百个指令周期。这意味着程序员在写代码时,会疯狂地想办法把乘法“约掉”——比如用移位代替乘2、用查表代替复杂函数。我在读它的源码时,经常看到为了省一次乘法而把公式重新推导一遍的操作,这种“抠”到极致的风格,在今天几乎绝迹。

硬件指标AGC 实际参数现代对比(随便一台手机)
主频约 2MHz(分频后指令周期约 1μs 级)数 GHz
内存约 2K 字(RAM)数 GB
程序存储约 36K 字(核心绳)数百 GB
字长15 位64 位
乘法无硬件,软件实现单周期硬件指令

这张表不是用来感慨“今非昔比”的,而是想说明:当你把资源压缩到这种程度,每一个设计决策都会变得极其“重”。也正因为重,它才值得研究。

2.3 中断与实时性:为什么“准时”比“快”更重要

AGC 是一个实时系统,它要控制飞船的姿态、发动机、导航,任何一个任务错过截止时间,后果都是灾难性的。所以它的调度设计非常讲究:有一套基于优先级的中断系统和一套执行周期固定的任务调度器。

我印象最深的是它的“执行银行”(Executive)设计——本质上是一个极简的实时操作系统。它把任务分成不同优先级,高优先级任务可以打断低优先级任务,但每个任务都有严格的执行时间预算。如果某个任务超时,系统会记录下来,地面人员可以据此判断软件是否健康。

提示:如果你打算复现这套调度逻辑,千万不要用现代 RTOS 的思维去套。它的很多设计是为了“在极端受限下保证确定性”,而不是为了“通用和灵活”。理解这一点,你才不会觉得它的代码“绕”。

3. 复现环境怎么搭:从零把 AGC 跑起来

3.1 仿真器的选择:为什么我最终选了开源方案

要把 AGC 跑起来,你不需要真的去编核心绳,而是用软件仿真器。目前公开的仿真器有好几套,我前后试过三种,最后稳定使用的是一套社区维护的开源仿真器(这里不点名具体项目,避免平台痕迹,你搜“AGC simulator”基本能找到)。

选它的理由很实际:第一,它完整实现了指令集,包括那些冷门的、只在特定场景用到的指令;第二,它支持加载原始的核心绳二进制镜像,也就是说你跑的是“真程序”,不是简化版;第三,它有比较完善的调试接口,可以单步、看寄存器、看内存,这对理解代码至关重要。

我试过的另一套仿真器,优点是界面好看,但指令集实现不全,跑到某些导航子程序就直接崩了。还有一套是纯教学用的,代码被大幅简化,跑起来“很顺”,但你学到的不是真东西。所以我的建议是:宁可界面丑一点,也要选指令集完整、能加载原始镜像的。

3.2 获取原始程序镜像:那些容易踩的坑

原始的核心绳二进制镜像,公开渠道是可以找到的。但这里有几个坑我必须提前说:

  • 镜像格式不统一。有的按“字”存储,有的按“字节”存储,还有的带了奇偶校验位。你拿到一个镜像,第一件事是确认它的格式,否则加载进去全是乱码。
  • 字节序问题。AGC 是 15 位字长,跨字节存储时字节序处理很微妙。我一开始没注意,结果反汇编出来的指令全是错的,排查了大半天。
  • 版本差异。不同任务(比如 Apollo 11 和 Apollo 15)的程序镜像不一样,指令地址、子程序入口都有区别。你要跑哪个版本,就得用对应的镜像和对应的符号表。

我的做法是:先把镜像加载进仿真器,用它的“反汇编”功能看前几条指令。如果反汇编出来的指令是合理的(比如初始化、跳转),说明格式对了;如果是一堆无意义的操作码,那肯定是格式或字节序错了。

3.3 第一次运行:从“灯闪烁”到“能交互”

AGC 有一个很有名的交互方式——DSKY(Display and Keyboard),就是宇航员用来输入指令和看数据的那个面板。仿真器通常会模拟这个面板。

第一次跑起来时,我建议你按这个顺序验证:

  1. 看“灯”。仿真器启动后,DSKY 上的指示灯应该有规律地闪烁,这代表程序在跑。
  2. 输入一个简单指令。比如输入“Verb 00 Noun 00”,这是最基础的“显示当前状态”指令。如果面板有反应,说明输入输出通路是通的。
  3. 看内存变化。用调试接口观察某块内存区域,看它是否在随程序运行而变化。如果一直不变,可能是程序卡住了。

我踩过的一个坑是:仿真器默认的“时钟频率”设得太高,程序跑得飞快,根本来不及看。后来把它调慢到接近真实 AGC 的速度,才看清了执行流程。慢下来,反而看得更清楚,这一点在复现老系统时特别重要。

4. 读懂它的代码:从“天书”到“有逻辑的工程”

4.1 汇编风格:为什么它看起来这么“怪”

AGC 的汇编语言(业内叫 AGC Assembly)和现代汇编差别很大。它有一些很独特的设计:

  • 指令和数据的地址空间是分开的,但又不是完全分离,有一些巧妙的复用。
  • 有“双重精度”和“三重精度”的运算子程序,因为 15 位不够表示某些中间结果。
  • 大量使用“宏”和“伪指令”,源码里有很多看起来像高级语言的结构,但展开后是纯汇编。

我一开始读得很痛苦,因为它的命名习惯和现代完全不一样。比如它管“子程序”叫“subroutine”,但很多子程序的名字是缩写,像“TP”代表“Trim Program”,“P00”代表某个特定功能。后来我养成了一个习惯:先建一张符号表,把常用的子程序名、变量名、地址记下来,读代码时随时查。这张表建起来之后,阅读速度会快很多。

4.2 关键子程序拆解:导航与制导是怎么算的

AGC 最核心的部分是导航(Navigation)和制导(Guidance)。导航负责“我在哪”,制导负责“我该怎么飞”。这两块的计算量最大,也最能体现当年的工程智慧。

以导航为例,它要不断读取惯性测量单元(IMU)的数据,然后做积分运算,推算出飞船的位置和速度。这里有个很妙的处理:它不追求每一步都算得绝对精确,而是保证误差在可接受范围内,并且能被后续步骤修正。这种“容错式”的计算思路,在资源受限时特别实用。

我在复现时尝试过把某段导航代码单独抽出来跑,输入模拟的 IMU 数据,看输出是否符合预期。这个过程让我明白了一件事:它的代码不是“写给人看”的,而是“写给机器跑”的。很多地方为了省一个周期,把逻辑写得极其紧凑,可读性很差,但效率极高。如果你想学习它的设计思想,不要逐行模仿,而是理解它“为什么这么抠”。

4.3 调试技巧:怎么定位一个“跑飞”的程序

老系统调试和现代调试最大的区别是:没有断点、没有日志、没有异常堆栈。你只有寄存器和内存。所以调试方法必须很“原始”。

我总结了一套流程,实测比较有效:

  • 第一步,看“执行银行”的状态。AGC 的调度器会记录当前在跑哪个任务,如果它一直卡在某个任务上,说明那个任务有问题。
  • 第二步,看“报警”标志。AGC 有一套报警系统,如果程序检测到异常,会点亮报警灯并记录报警码。报警码是定位问题的关键线索。
  • 第三步,单步跟踪。如果报警码指向某个子程序,就单步进去,看寄存器在哪一步变得“不合理”。
  • 第四步,对比“正常”和“异常”的内存快照。我通常会先跑一遍正常流程,存一份内存快照,再跑异常流程,对比差异。差异点往往就是问题所在。

注意:AGC 的很多变量是“复用”的,同一块内存在不同阶段存不同的东西。所以看内存时一定要结合当前执行到哪个阶段,否则会误判。

5. 那些只有动手才会知道的坑

5.1 时间基准的陷阱:仿真速度和真实速度不是一回事

仿真器跑得快,不代表你理解得对。我一开始为了“看结果”,把仿真速度调到最快,结果程序几秒钟就跑完了一个完整的制导循环,我什么都没看清。后来我把速度降到接近真实 AGC 的指令周期,才发现很多“瞬间完成”的操作,实际上在真实硬件上要花不少时间。

更关键的是,有些 bug 只在特定速度下才会暴露。比如某个中断处理程序,如果仿真太快,中断可能被“挤”在一起,看起来没问题;但按真实速度跑,中断之间的间隔就变得很重要,问题才会显现。所以我的建议是:调试时用真实速度,验证时可以用加速。

5.2 符号表的坑:地址对不上,一切白搭

前面提到要建符号表,但这里有个大坑:不同版本的镜像,符号地址可能不一样。我遇到过好几次,用 A 版本的符号表去查 B 版本的镜像,结果完全对不上,排查了很久才发现是版本问题。

解决办法很简单但很关键:符号表必须和镜像严格配套。你从哪拿的镜像,就从哪拿对应的符号表。如果找不到配套的,就自己反汇编,手动标注。虽然麻烦,但标注一遍之后,你对程序结构的理解会深很多。

5.3 输入输出的“隐藏逻辑”:DSKY 不是普通键盘

DSKY 的输入输出有一套自己的协议。比如你输入一个指令,它不是立刻执行,而是先进入一个“缓冲”,等程序“接受”后才生效。如果你按现代 GUI 的思维去理解,会觉得“怎么按了没反应”。实际上,它是在等程序轮询。

我在模拟输入时,一开始没等程序轮询就连续输入,结果指令全乱了。后来改成“输入一个,等灯闪,再输入下一个”,就正常了。这个细节在文档里往往一笔带过,但实际操作中非常关键。

6. 这套东西对今天的我们有什么用

6.1 约束下的设计思维:少即是多

研究 AGC 最大的收获,不是学会了它的汇编,而是理解了一种在极端约束下做设计的方法论。今天的开发环境太宽松了,宽松到我们很少认真思考“这个功能真的必要吗”“这个数据结构能不能再省一点”。

AGC 的代码里,几乎每一行都在回答这两个问题。它没有“预留扩展性”,没有“以后可能用得上”,只有“现在必须用”。这种极致的克制,反而让系统变得极其可靠。我在自己的项目里尝试过借鉴这种思路:先问“最少需要什么”,再问“怎么实现”,结果代码量往往能减少一大半,bug 也少了很多。

6.2 实时系统的确定性:为什么“可预测”比“快”重要

AGC 的调度器不追求“最快”,而是追求“最可预测”。每个任务的执行时间都是可计算的,最坏情况下的响应时间也是可保证的。这种设计哲学,在今天的安全关键系统(比如汽车刹车、医疗设备)里依然是金标准。

如果你在做实时系统,我强烈建议你读一读 AGC 的调度代码。它没有复杂的优先级反转处理,没有动态调整,就是一套简单、直接、可验证的规则。简单到你能在纸上推演它的行为,这本身就是一种强大的可靠性保障。

6.3 复现老系统的通用方法:从“跑起来”到“读明白”

最后分享一套我复现老系统时通用的方法,不只适用于 AGC:

  • 先跑起来,再读代码。不要一上来就啃源码,先让系统跑起来,建立感性认识。
  • 建符号表,画调用图。把关键子程序的关系画出来,理解数据流。
  • 找“最小可运行单元”。把某个独立功能抽出来单独跑,验证你的理解。
  • 对比不同版本。如果有多版本,对比它们的差异,差异点往往能揭示设计意图。
  • 写笔记,别靠脑子记。老系统的细节太多,不写下来很快就会忘。

我在实际操作中的体会是:复现老系统最大的障碍不是技术难度,而是耐心。它的代码不友好,文档不完整,工具不顺手,但每克服一个障碍,你对“计算机到底是怎么工作的”这个问题,就会多一层理解。这种理解,是看多少篇现代教程都换不来的。

如果你也打算动手,我的建议是从最小的目标开始——先让它跑起来,看到灯闪,输入一条指令,得到响应。这个小小的成功,会给你继续深入的动力。后面的路很长,但每一步都值得。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询