Contents
What is YUL?
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
languages, intermixed:
- The assembly language, which was referred to as "basic"
(though having nothing whatever to do with Kemeny & Kurtz's
BASIC programming language, invented in roughly the same time
frame).
- Interpreter language, a higher-level language which was
executed by an "interpreter" written in basic.
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
Assembler Program), but "YUL" sounds much niftier than "GAP"
(which, sorry, sounds like something from Accounting), so we'll
keep calling it "YUL".
There's a pretty extensive AGC
Information
Series document covering YUL and its operation. And here's a short excerpt
from the same document, describing the punched-card format,
but with the additional enticement of a couple of images of actual
cards. These days, we also have the "User's Guide for the
General Assembler Program (GAP)", which I'm sorry to say I
did not have when I originally wrote our modern AGC
assembler and was making the initial transcriptions of the two
listings of AGC software we had back then. Without it,
everything I did back then was based on eyeballing the AGC code
rather than on a reliable description of how it was supposed to
work in principle.
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
well:
It has been pointed out to me that if this program were for the
Honeywell 800 computer, it should be in the ARGUS language:
i.e., the input language of the Honeywell 800's ARGUS
assembler. However, it is not in ARGUS
language. What's the deal with that? Well, there were
things the AGC developers wished to do that ARGUS did not support,
such as having space characters in symbols, and spreading out the
code for readability purposes. So they invented a new
format, which they called MITIGUS, and YUL is written in
MITIGUS. There was a separate program, a pre-processor,
which converted MITIGUS to ARGUS. Unfortunately, we do not
have this pre-processor, nor an exact list of rules defining the
relationship between MITIGUS and ARGUS, but have been told that
it's pretty straightforward, and hopefully won't affect your
ability to read the program (and certainly not the comments
embedded in the program!) even if you happen to be an expert in
ARGUS.
Before you turn up your nose at this idea of looking at this
code, 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.
What is
yaYUL?
Since most people do not have a Honeywell 800 on which to run YUL —
and frankly, here at this project we needed to assemble AGC code
beginning in 2003, and didn't even have a copy of YUL's program
listing until 2016 — I have created a completely new assembler,
duplicating the features of the original YUL to the extent I think important, called yaYUL. In other words, yaYUL is used to convert Luminary or Colossus source code to a binary
format usable by the yaAGC
emulator.
As I mentioned above, YUL itself would accept and assemble language
from 7 different (though related) versions of the AGC. yaYUL is not so clever as this,
and limits itself merely to the variants of Block 1 and Block 2
languages found in the versions of the AGC programs we've been able
to get our hands on. Even though YUL was succeeded by GAP, I
don't feel that "yaGAP" has quite the ring to it that "yaYUL" does,
so I feel entitled to ignore that fact.
It is important to understand that when I wrote yaYUL, there
was almost no available documentation of how the assembler was supposed to operate—i.e., of
the syntax of AGC assembly language. (Well, the manual for GAP does exist, but I'd not seen
it.) In the end, most that is known of the syntax of AGC
assembly language has been deduced from Luminary and/or Colossus
assembly listings and, frankly, some of this syntax is very
obscure. I have written down what I have learned and what I
have deduced in the assembly-language
manual. Therefore, yaYUL
is not so much an assembler for AGC assembly language (which is
fairly nebulous idea), as much as it is a utility which processes existing
Luminary and/or Colossus source-code to produce
good core-rope images for those specific programs. But we've
had good luck in feeding most AGC programs into it.
Finally, of course, yaYUL
accepts source-code files rather than punch-card decks or
source-code libraries from magnetic tape. But like YUL, yaYUL
directly outputs binary machine code, and there is no linker.
Invoking yaYUL
Running the assembler is very simple. yaYUL is a command-line program,
invoked as follows:
yaYUL [OPTIONS] SourceFile
The binary executable is automatically created if no fatal errors
have occurred during assembly. The binary file has the same
name as the input source-code file, but with ".bin" added to the end
of the filename. For example,
yaYUL Luminary131.agc
would produce a file named "Luminary131.agc.bin", which would be
directly usable by the yaAGC
program. An annotated program listing (including any error
messages) is written to the screen, or may be captured for later
viewing:
yaYUL SourceFile >ProgramListing
As of version 20050728 or later, yaYUL
also outputs a symbol-table file that can be used in conjunction
with yaAGC's "--debug"
switch. This file will have the same name as the source-file,
but with ".symtab" suffixed to it.
In the unlikely event that you choose to create and/or modify some
AGC assembly language, it is very important to understand that yaYUL requires at least one free
word in each memory bank to store the "bugger word" (checksum) for
that memory bank. You can only use 1777 words (octal) out of
each 2000-word memory bank. If you completely fill a memory
bank, the yaYUL is going to
overwrite the final word of the bank with a bugger word, and you may
or may not see an error message. (Sorry about that.)
Since nobody is likely to be developing much new software for the
AGC, yaYUL doesn't need to
have very many command-line options. (Actually, in spite of
saying there will be no new AGC software, I do provide a newly-written AGC
program in assembly language, for validating the CPU's instruction
set, and yaYUL is perfectly
adequate for assembling the validation suite.) Those options
are as follows:
--help
This causes the available options
to be listed.
--block1
(As of 20160824.) Indicates
that Block 1 assembly-language is processed rather than Block 2
assembly-language. See also the "--blk2" switch below.
--blk2
(As of 20161009.) Indicates
that the assembly target is BLK2. The topic of "assembly
targets" is confusing, and in particular you should note that
"--blk2" is not the opposite of "--block1", though the two are
indeed mutually exclusive, nor does it comprise all software for
the Block 2 AGC. It's important to understand that the
original
YUL program had to support an evolving range of
AGC computer hardware designs, and roughly corresponding to them,
an evolving range of language designs, both in terms of the basic
instructions (the assembly language) and the interpreter
language. As such,
YUL supported a variety of
"target" systems, each with a short alphanumeric designation (such
as "BLK2"), with each corresponding more-or-less to a given
hardware architecture
plus a given software
architecture. However,
yaYUL makes no effort to
support the same large range of assembly targets as
YUL,
but merely focuses on those target systems for which we have
complete AGC program listings have survived and are available to
us now. The specific targets supported by
yaYUL are:
- The AGC4 target ("--block1" command-line switch) comprises
all programs for Block 1 AGC systems, of which the only
example we have at this writing is the Solarium 055 program,
though Solarium 054 (which exists though we can't get it at
present) also falls into this category.
- The BLK2 target ("--blk2" command-line switch) comprises
programs written in an early dialect for Block 2 AGC systems,
of which the only example we have at this writing is Aurora 12
program, though Retread 44 (coming soon, according to plans)
presumably also falls into this category.
- The AGC target (the default, no command-line switch needed)
comprises all of the AGC programs in the later dialect used
for actually-flown manned missions, and most other Block 2
programs that we have in our inventory as well.
An example of a
YUL target
not supported by
yaYUL
is AGC3.
--flip=b
AGC memory-bank "bugger words" are
not necessarily unique; sometimes they are, but sometimes they are
not, and in that case there are two distinct bugger words which
could be added to a memory bank, with the self-test accepting
either of these as being valid. For one of these possible
bugger words, the memory-bank's checksum is equal to the bank
number, and for the other it is equal to the negative of the bank
number. Normally, when yaYUL adds bugger word to an
assembled memory bank, it chooses the one leading to the positive
checksum if possible, but uses the one leading to the
negative checksum if not. With the --flip=b switch,
where b is the number of a fixed-memory bank, in octal,
this behavior is reversed for memory-bank b; in other
words, for memory bank b, yaYUL will try to use
the bugger word leading to a negative checksum, and will fall back
on the one leading to a positive checksum otherwise. The
only known use of this switch is for bank b=7 of the
SUNBURST program. There are notes in the original YUL
source code highlighting bank 7 of SUNBURST as a special case, and
you are invited to read that source code if interested in this
point.
--force
Forces creation of the core-rope
image file, which is normally bypassed when fatal errors are
detected. (As of 2005-09-05, there are no known bugs left in
yaYUL that need this
switch as a workaround.)
--format
(As of 20161009.) Simply
reformat the source file into a normalized form (i.e., with
standardized alignment of columns), outputting it on stdout, and
then exit. This does rely on the input file being at least
partially formatted correctly, in the sense that labels begin at
column 1 and opcodes at column 17. Either spaces or tabs
(interpreted as moving to the next multiple of 8 spaces) can be
used in the input but at present, tabs will be converted to spaces
in the output.
--html
(20090629 and later.) Causes
creation of an HTML version of the assembly listing. The
top-level HTML filename is the same as
SourceFile, except that the .agc
filename-extension (if present) is replaced with .html. An
additional HTML file is created for every source file included by
the top-level source file, and you can browse to them through
links in the top-level file. Additionally, the HTML is
syntax-highlighted, so that it is easy to distinguish
basic-language opcodes from interpreter opcodes from line labels,
etc. Finally, the HTML contains hyperlinking from where
symbols are used to where they are defined.
It is also possible to add modern
annotations to the source code.
--ascii, --ebcdic, --honeywell
(20210420 and later.) By
default (or with --ebcdic), yaYUL sorts AGC symbol tables in the
ordering implied by an EBCDIC character encoding, which matches
the ordering of symbol tables produced by the original GAP
assembler. With the --honeywell switch, yaYUL instead sorts
according to the character encoding of the Honeywell H-800
computer system, which is the ordering that symbol tables created
by the original YUL assembler followed; the AGC programs RETREAD,
AURORA, SUNBURST, TRIVIUM, and SOLARIUM should be assembled with
the --honeywell switch. Finally, with the --ascii switch,
the native (ASCII) ordering is used; prior to the 20210420 version
of yaYUL, ASCII was the only available option.
--reconstruction
(20220422 and later.)
Provides reconstruction support in assembly-listing files.
This command-line switch could optionally be used during the
engineering process of reconstructing source code, but then should
be removed once the reconstructed AGC source code was
released. To understand what that means, the following
background info is needed.
For AGC source-code versions which are "reconstructed" rather than
transcribed from a contemporary assembly-listing printout — for
example, as of this writing, Comanche 44, 45, 45/2, and 51 are all
reconstructed versions of COLOSSUS — it is usual to add modern
##-style comments to the reconstructed code at each point where
the reconstructed code differs from a baseline version of the code
used as a starting point for the reconstruction process.
Each change is documented and justified by an added comment.
For example, Comanche 51 was reconstructed starting from Comanche
55 as a baseline, so each difference between Comanche 51 and 55 is
justified by a ##-style comment. Actually, these justifying
comments tend to be sequences of ##-style comments rather
than just a single comment line, with the very first line
containing the string "Reconstruction:" somewhere within it.
Normally, however, ##-style comments contain HTML tags in
addition to plain-text descriptions, because they are really
intended to be viewed in HTML versions of the assembly
listings. (See the --html command-line switch above.)
Therefore, ##-comments are not really very suitable for the
plain-text assembly-listing files output by yaYUL, and hence most
such comments are omitted from the plain-text assembly listings.
(Exceptions are page-numbering and file-header ##-comments, which
are always included.) Nevertheless, even though not suitable
for normal plain-text assembly listings, the reconstruction
##-style comments can be very useful tools in the plain-text
assembly listings during the actual process of reconstructing
source code. What the --reconstruction switch does,
therefore, is to add the reconstruction ##-comments into the
plain-text assembly listings, while continuing to omit all other
##-comments from them. The HTML assembly listings are not
affected, and always contain all ##-comments, regardless of the
use or absence of the --reconstruction switch.
--unpound-page
(20100220 and later.) If
--html is used, causes bypassing of "## Page ..." to be treated as
a regular AGC assembly-language comment. This may be useful
if you are debugging source-code created from a scanned assembly
listing, but probably not otherwise.
--max-passes=n
This sets the maximum number of
passes used by the assembler to the number n. The assembler will stop as
soon as it can—i.e., it won't necessarily use all of the allowed
passes, if it does not need to. For example, you might set n to 10.
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 like EQUALS (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.
|
--syntax
(As of 20161009.) Simply
check the syntax and then quit. This is useful, for example,
for checking the accuracy of transcriptions of source code, when
only portions of the code rather than the entire AGC program are
available.
There may be some additional options available for certain
specialized purposes, which you can view with "yaYUL --help".
Apollo Source-Code Naming
In the case of each of the original Apollo programs provided by this
project, the main source-code file will be named MAIN.agc, and will
be located in a directory appropriate to that particular program
(Luminary131, Colossus249, or whatever). For example, to
assemble the Luminary (rev. 131) source-code I provide, the
appropriate steps (in Linux) might be
cd Luminary131
yaYUL MAIN.agc
>Luminary131.lst
mv MAIN.agc.bin
Luminary131.bin
mv MAIN.agc.symtab Luminary131.symtab
(In MS-Windows, use "rename" rather than "mv" in the last line
above.)
AGC4
Assembly
Language
For a full explanation of the formatting of assembly-language files,
and of available AGC4 assembly-language instructions, refer to the
separately-provided assembly-language
manual. Anyone who's determined to write AGC4
assembly-language will probably also need to consult the developer-info page, which covers
important supplementary topics such as the relationships between
"i/o channels" and hardware peripherals. For the latter
information, however, comments within Luminary/Colossus
source code are the definitive references.
This page is available under the Creative
Commons
No Rights Reserved License
Last modified by Ronald Burkey on
2021-09-06