AGC Code Learning Notes

Intro

1969 年 7 月 20 日,人类首次踏上月球。下面是当年的一张照片,站在一大摞打印的代码边上的这位是 Margaret Hamilton,她带领团队开发阿波罗计划所需要的软件。

Hamilton in 1969, standing next to listings of the software she and her MIT team produced for the Apollo project

不久前,我们已经可以在 Github 上下载到阿波罗 11 号制导计算机 (AGC) 中的指令模块和登月模块的代码,并且也看到了这个仓库里很多无营养的中文 issue,反正有这么一波人就是来凑个热闹。毕竟这是 1969 年的代码,当时这样的工程还不被叫做软件工程,C 语言也是到 1972 年才诞生的。

Downloading

在 Google 搜索 “github agc” 会看到两个仓库,一个就是上述代码仓库,叫做 chrislgarry/Apollo-11,这位名为 Chris Garry 的 github 用户前几年是 NASA 的见习工程师;另一个是 virtualagc,我们稍后再介绍。

在 Apollo-11 代码仓库中,除了各种语言的 README 和 CONTRIBUTING 文件外,有两个文件夹,分别名为 Comanche055 和 Luminary099,其内部各自包含许多以 .agc 结尾的文件。之所以有两个文件夹,是因为阿波罗 11 号上有两个制导计算机。在看代码之前,先了解一下飞船的整体构造。

Terminology

根据维基百科的描述:

装载着阿波罗11号的土星5号火箭于当地时间1969年7月16日9时32分(13时32分UTC)在肯尼迪航天中心发射升空,12分钟后进入地球轨道。环绕地球一圈半后,第三级子火箭点火,航天器开始向月球航行。30分钟后,指令/服务舱从土星5号分离,在转向后与登月转接器中的登月舱连接。此后航天器进入地月转移轨道,前往月球。

Saturn V & Apollo 11

如上图所示,阿波罗 11 号装载于火箭最顶端。它主要由三部分构成:指令模块 Command Module (CM)、服务模块 Service Module (SM) 和登月模块 Lunar Module (LM 或 LEM)。其中 CM 是宇航员待在里边时间最长的地方,包括从发射开始到旅行全程及返回地球的整个过程。SM 是最大的一个区域,但也是最简单的,是阿波罗登月及返回的引擎,提供燃料,储存水、氧气和电能等供宇航员维持生命所需的东西。CM 和 SM 组合起来称之为 CSM (the command and service module)。LM 是实际登陆月球表面的部件,并会再次将宇航员带离月球表面。

简单描述一下整体流程:一开始三个部件是连在一起的,三位宇航员,Neil Armstrong、Michael Collins 和 Edwin (“Buzz”) Aldrin 都在 CM 里面。当到达月球轨道之后,Buzz Aldrin 和 Neil Armstrong 就到 LM 里边,LM 与其他部件分离并着陆于月球表面,而 Michael Collins 则留在 CSM 里。两位宇航员在月球上处理完事情之后,便回到 LM 内,LM 再次与阿波罗号剩余部件对接。待两名宇航员回到 CM 里,LM 就完成了所有工作,并被丢弃。在回地球的最后阶段,CM 会单独分离,成为最终着陆地球的唯一模块。

再回过头来看之前下载到的代码。里边的两个文件夹,Comanche055 是 CM 的代码,Luminary099 是 LM 的代码。CM 和 LM 内各带有一个制导计算机,而 SM 没有单独的制导计算机,它由 CM 来控制。两个文件夹内有许多相似的地方,且有许多相同的代码,但毕竟两者要做的事情还是有所差别,所以代码并不完全一致。

The Language

上述两个文件内含有许多扩展名为 .agc 的文本文件,用 Visual Studio Code 或者 Sublime Text 打开的话,都可以安装相应的扩展来获得代码高亮。原版的几千页代码并不是按照这个 git 仓库里的文件来组织的。现在这种文件拆分和命名方式只是为了方便我们浏览。

这些 .agc 文件里的代码所使用的语言是汇编 (assembly) 语言。撇开现在的高级编程语言不说,即使开发者有过汇编语言的开发经验,也并不代表能完全看懂 AGC 所使用的汇编语言。我们在开发 JavaScript 应用的时候,现在都流行一次编写,各端运行。但汇编语言的话,必须是针对某个硬件架构来定制开发的。

所以这里的指令会细到把某个值从内存的这个位置挪到那个位置,开发者也就必须了解硬件的内存映射 (memory mapping) 的工作原理,然后就牵扯到处理器的中的寄存器 (register) 了。因为 AGC 的处理器是直接连接到阿波罗飞船的诸如陀螺仪、平衡环、引擎等硬件上的,这意味着开发者可以编写一系列汇编语言指令把数据传递给寄存器,达到类似关闭引擎等效果。

assembly instructions to turn off engine

就算开发者在 PC 或者 iPhone 上用过汇编语言,到这里也是看到完全不一样的内容了。

下面是一个超级简单的代码摘录解读,代码摘自 Comanche055/AGC_BLOCK_TWO_SELF-CHECK.agc

an excerpt explained

所以我作为一个只用面向对象编程语言的开发者,这是一个让我感觉很不友好的语言。

Comments

当然,大多数的代码看不懂不要紧,这里还有很大一片比较好玩并且看得懂的东西,就是注释。

从 github 下载过来的每一个 .agc 文件顶部的注释是将纸质代码转为电脑版本的时候加上的,简要叙述了我们现在在网上下载到这些代码的来历,并提供了扫描版的线上地址

以前面摘录代码的 Comanche055/AGC_BLOCK_TWO_SELF-CHECK.agc 文件为例

# Copyright:	Public domain.
# Filename:	AGC_BLOCK_TWO_SELF-CHECK.agc
# Purpose:	Part of the source code for Colossus 2A, AKA Comanche 055.
#		It is part of the source code for the Command Module's (CM)
#		Apollo Guidance Computer (AGC), for Apollo 11.
# Assembler:	yaYUL
# Contact:	Ron Burkey <[email protected]>.
# Website:	www.ibiblio.org/apollo.
# Pages:	1394-1403
# Mod history:  2009-05-10 SN   (Sergio Navarro).  Started adapting
#				from the Colossus249/ file of the same
#				name, using Comanche055 page images.
#
# This source code has been transcribed or otherwise adapted from digitized
# images of a hardcopy from the MIT Museum.  The digitization was performed
# by Paul Fjeld, and arranged for by Deborah Douglas of the Museum.  Many
# thanks to both.  The images (with suitable reduction in storage size and
# consequent reduction in image quality as well) are available online at
# www.ibiblio.org/apollo.  If for some reason you find that the images are
# illegible, contact me at [email protected] about getting access to the
# (much) higher-quality images which Paul actually created.
#
# Notations on the hardcopy document read, in part:
#
#    Assemble revision 055 of AGC program Comanche by NASA
#    2021113-051.  10:28 APR. 1, 1969
#
#    This AGC program shall also be referred to as
#            Colossus 2A

# Page 1394
# PROGRAM DESCRIPTION				DATE  20 DECEMBER 1967
# PROGRAM NAME - SELF-CHECK			LOG SECTION  AGC BLOCK TWO SELF-CHECK
# MOD NO -  1					ASSEMBLY SUBROUTINE UTILITYM REV 25
# MOD BY - GAUNTT

因为电脑上通常以字母表升序来排列文件,要快速将这里的文件和原版顺序对上号,可以打开 Comanche055/README.md 文件查阅。

这样我们就知道其实原版的开头应该是 CONTRACT_AND_APPROVALS.agc 文件里的内容,并且知道 Margaret Hamilton 和她的团队是来自 MIT 的,而不是 NASA 雇员。AGC 项目是与 NASA 签约后在 MIT 仪器实验室里开发的。

现在很多开发者喜欢在自己的代码里留一些有意思的注释,当年的项目也是如此。

例如 Luminary099/LUNAR_LANDING_GUIDANCE_EQUATIONS.agc 的这个地方,就跟现在在我自己好几年前的代码里发现 TODO 注释一样

I hope it works

再如 Luminary099/THE_LUNAR_LANDING.agc,这是即将登月的代码,里边有如下内容

check antenna before landing

有没有看美国科幻电影时候那种感觉?

上面代码准备点火着陆的时候,跳转到的代码叫做 BURNBABY。上世纪 70 年代中期有一首歌叫 Disco Inferno,歌词开头就是 burn, baby, burn。不过阿波罗登月比这首歌早得多了。实际上打开 BURNBABY 所在的代码,即 Luminary099/BURN_BABY_BURN--MASTER_IGNITION_ROUTINE.agc 文件,在开头的注释里解释了这段背景,跟一个 DJ 曾经说过的话以及 1965 年发生在洛杉矶的黑人骚乱有关系。

# Page 731
## At the get-together of the AGC developers celebrating the 40th anniversary
## of the first moonwalk, Don Eyles (one of the authors of this routine along
## with Peter Adler) has related to us a little interesting history behind the
## naming of the routine.
##
## It traces back to 1965 and the Los Angeles riots, and was inspired
## by disc jockey extraordinaire and radio station owner Magnificent Montague.
## Magnificent Montague used the phrase "Burn, baby! BURN!" when spinning the
## hottest new records. Magnificent Montague was the charismatic voice of
## soul music in Chicago, New York, and Los Angeles from the mid-1950s to
## the mid-1960s.
# BURN, BABY, BURN -- MASTER IGNITION ROUTINE

在刚才的代码截图中,还有一个蓝色框标注的代码指令,转向 GOTOP00H 代码块。这里 00 是两个阿拉伯数字 0,代表 Program 00,不过发音和 pooh 一样,即 /puː/。P00 的作用是让 AGC 进入空闲状态。因为不像现代操作系统,在 AGC 里操作完一段指令后,系统需要开发者明确告知进入空闲状态才行,所以在代码仓库中能搜到很多 P00 或者 P00H。如果你还不知道 Pooh 是什么就自己去查字典吧。

这里还有更进一步的,如果是要完全重启,也就是要把 pooh 彻底清理干净,那就要灌肠 (enema) 了,哈哈哈。在 Comanche055/FRESH_START_AND_RESTART.agc 里,就能搜到 # ENEMA SOFTWARE RESTART 了,并且说得很形象。

enema

好奇他们当时在 code review 时候的场景。

Verbs, Nouns, Error Codes, and DSKY

最后再了解下宇航员是怎么和 AGC 交互的。在 Comanche055/ASSEMBLY_AND_OPERATION_INFORMATION.agc 文件里,一开始罗列了许多子程序的名称,接着是动词 (VERB) 表,再后面试名词 (NOUN) 表。这些词都有相应的编码。例如

接近文件尾部的地方有一系列错误代码,例如

在阿波罗 11 号即将登月着落的时候,就发生了这两个错误,即执行溢出。在阿波罗号上有 2 个雷达,一个是着陆雷达 (Landing Radar),另一个是交会雷达 (Rendezvous Radar)。在着陆期间,只需要开启着陆雷达,但实际上当时交会雷达也处于开启状态。在着陆时,AGC 就因为数据量增大,又浪费了资源在监控不需要的交会雷达,便开始报错。不过 AGC 的程序设计就是考虑过这个情况的,会自动抛弃低优先级的任务,此时就会显示上面这两个错误码。而 MIT 的工程师在实验室模拟过登月操作,知道此时发生这个错误时正常的,所以在决定是否终止登月计划的关键时刻,地面的飞行控制指挥官下令继续登月,最终飞船成功在月球着陆。

这些操作代码和错误代码,都显示在一个 DSKY 的设备上,看起来容易念成 D Sky,正确发音是 /ˈdɪskiː/,即 display and keyboard。宇航员也通过 DSKY 来输入指令与 AGC 进行交互。

DSKY

在阿波罗 11 号上有两个 DSKY,你可以在 Smithsonian 的站点上看到其整个内部结构,并且有 VR 设备的话还能体验 VR 效果。

在文章一开始提到的 virtualagc,就是在网页上模拟 DSKY 的。你可以打开这个网站来操作。这个模拟器是给予阿波罗 9 号飞船的,不过和我们现在看到这个仓库的说明代码也很接近的。

前面提到 VERB 35 是测试灯光的,我们可以在模拟器上依次点击“VERB”、“3”、“5”、“ENTR”来测试灯光。

有的指令是要动词和名词组合操作的,例如 VERB 16 MONITOR DECIMAL IN R1 OR R1,R2 OR R1,R2,R3 是用来显示某个名词所返回的值,我们依次点击“VERB”、“1”、“6”、“NOUN”、“6”、“5”、“ENTR” 就能看到 AGC 模拟器从启动到现在的时间。因为 NOUN 65 SAMPLED AGC TIME 会返回 AGC 运行的时间。

还有的操作是在输入并确认动词之后,等待一个参数的输入,例如之前让程序转到空闲 P00H 的指令,就可以依次点击“VERB”、“3”、“7”、“ENTR”、“0”、“0”、“ENTR”。因为 37 CHANGE PROGRAM (MAJOR MODE)是用来切换程序的。

所有在 DSKY 上的操作,都会由一个名为 PINBALL 的程序来处理,它的代码在 Comanche055/PINBALL_GAME_BUTTONS_AND_LIGHTS.agc 文件。这和街机上的弹珠台游戏 (就是 Windows xp 里三维弹球那种游戏)没啥关系,人家就是这么命名的。

Wrapping Up

这篇文章并不是说大家应该都去学习登月飞船的代码,而是可以去发现一下里边很多有趣的内容,了解些许历史。

最后以阿波罗 11 号飞船上,宇航员写在飞船 CM 里的一段话作为结尾:

Spacecraft 107 - alias Apollo 11 - alias “Columbia”. The Best Ship to Come Down the Line. God Bless Her. – Michael Collins, CMP