Apollo Command Module software (Colossus)
or Lunar Module software (Luminary)
was written in a computer language (AGC assembly language)
invented at MIT's Instrumentation/Draper lab. Software whose
source code is in "assembly language" must be processed to turn it
into a binary format ("machine language") understood by the
computer itself. The program that converts the human-written
source code into machine-readable binary code is called an
"assembler". The conversion from source code to machine code
took place prior to loading the software into the AGC, so the
assembly-language code was actually not actually run by the AGC
itself, but rather was processed by ground computers weeks or
months prior to the actual Apollo flights.
(Incidentally, for debugging purposes, the original developers had a special read-write module which could be programmed from a paper tape and then plugged into the AGC and used as if it were a core rope. While this process was apparently not easy, it was certainly more convenient than manufacturing a core rope. The assembler produced the data for creating the paper tape.)
Actually, the situation is slightly more-complex than this.
For one thing, in talking about "assembly language" above, I was
using generic programming terminology, not necessarily used by the
AGC development team. In fact, the programs were generally
in a combination of two different programming
In the second place, as the AGC hardware and the developers'
ideas changed over time, so did these programming languages, going
through various stages. In other words, the programming
language itself was not just one thing, but was several different
things over time, although it remained constant throughout all the
manned missions which actually flew.
The original AGC assembler, which turned this mixture of
programming languages into an executable program that could be
stored in core memories and run on the AGC, was called YUL (from "yuletide") because
the projected delivery date of the MOD 1A guidance computer, with
system software, was Christmas, 1959. As time went on, it
had to support all of the different "target" languages I mentioned
above, and Hugh Blair-Smith, the program's author, tells us that
YUL eventually supported the MOD 1A, MOD 1B, MOD 3S, MOD 3C, AGC4
(Block I AGC), and two versions of the final Block II AGC, which
is seven different targets by my count. In real life, YUL was eventually succeeded
by the GAP (General
Assembly Program), but "YUL" sounds much niftier than "GAP"
(which, sorry, sounds like something from Accounting), so we'll
keep calling it "YUL".
YUL, by the way, originally ran on
the IBM 650, which quickly ran out of capacity, and hence it was
ported to the more-powerful Honeywell 800. Now, I don't have
a Honeywell 800 in my pocket, so I have no way to run YUL, but I
can show you YUL's complete source code, because Hugh has allowed
us to have it scanned. If you demand the absolute highest
visual quality (by which I mean huge, huge files), you can go to our Virtual
AGC Project at archive.org and download the imagery of the
source code in various formats. However, if you're willing
to get much smaller files, which will download much quicker, but
at a slight loss in quality, we've hosted the page images here as
Before you turn up your nose at this idea, though, I'd recommend
at least looking over the "Introduction", which contains no actual
code, because you may find yourself amused at the peculiar brand
of humor you'll find there. There's also a
video of Hugh giving a talk about "Pass 0" of the assembler
at the MAPLD '04 conference. The picture above is him
showing the YUL listing to an interested attendee.
The original YUL accepted a complete program (such as Luminary or Colossus) as decks of punch-cards, and seemingly preserved the code in tape libraries; an actual assembly run therefore worked on chunks of code extracted from the tape libraries. The assembler directly outputs binary machine code. There is no linker.
|At this point, you may be
reasonably be wondering why a mere assembler would ever need
to make 10 passes through the source code. Naively,
one would expect a simple assembler to take 2 passes: one to
resolve the values assigned to address labels, and one to
generate the code. However, there is a complication, in that pseudo-ops
(see the assembly-language
manual) allow forward-references to other EQUALS pseudo-ops.
For example, consider the following code fragment:
SYMBOL5 EQUALS SYMBOL4
SYMBOL4 EQUALS SYMBOL3
SYMBOL3 EQUALS SYMBOL2
SYMBOL2 EQUALS SYMBOL1
SYMBOL1 EQUALS 42
In this example, the value of SYMBOL1 isn't known until the end of pass 1, the value of SYMBOL2 isn't known until the end of pass 2, and so on. There is no practical limit to the number of passes needed—if symbol resolution is handled in a straightforward way—because it depends on how many constructs like those above appear within the assembly-language source code. Besides, this simple-minded use of multiple passes is eerily reminiscent of certain behaviors of the original YUL assembler, as evidenced by the following amusing quote from Hugh Blair-Smith (YUL's author):
"... [the] observation about assemblies being so long that they were performed as overnight batch jobs, brings me to a confession of one thing I wish I had done better, and I really think I could have at the time. When it became clear, early in the project, that the number of words in AGC memory was going to be greater than the number of words in the assembling machine's (i.e., the Honeywell 800/1800's) memory, I gave up any attempt to retain the object program in memory and just wrote each patch of object code on tape. Then there was a "third "pass of the assembly process which sorted the object code by what is perhaps the dumbest sort algorithm possible: running that tape back and forth and writing the object code in its proper order on another tape. As long as programs were just a few thousand instructions, this went like the wind, but the full-size programs of 36000 or so instructions made Pass 3 pretty boring and frustrating to watch. We did have a hard disk drive from 1965 or 1966, so I could and should have written my object code onto that and read off the sorted code in a flash. There wasn't anything like DOS to keep disk files out of each other's hair, so this effort would have involved learning and overcoming some risks of data getting stepped on. And there were always other little enhancements that had to be done, so it wouldn't have been easy—but I still wish I'd found a way to get it done. I guess one thing that decreased the motivation was that each assembly had to be printed, in about 3 or 4 hours on the noisy 600 line-per-minute printer, so there wasn't anything the disk could do about assembly being an overnight batch process. I had no notion, at the time, of assembling modules separately and then linking the object modules, and the long and difficult history of PC linkers suggests that it wouldn't have been a good idea to try it even if I had thought of it."
This quote was taken from conference transcripts at MIT's Dibner Institute's now-discontinued History of Recent Science and Technology website.
There are some additional options available for certain specialized purposes, which you can view with "yaYUL --help".