Contents

What is the Gemini Spacecraft Computer (OBC)?

The Gemini spacecraft computer is, as the name implies, the onboard computer of the Gemini spacecraft.  The computer seems to have been referred to variously as the "spacecraft computer", the "digital computer", or the "On-Board Computer" (OBC).   It was the Gemini equivalent of Apollo's AGC, though with more limited capabilities and functionality.  Its basic use was in the post-launch phases of missions (orbit phase, retrograde phase, re-entry phase), because the Titan II rocket which carried the Gemini spacecraft into orbit was guided by its own (separate) ACS-15 guidance computer, but there was provision also for switchover to the Gemini computer for backup guidance if the need arose.  Interestingly, the OBC could be used for automatic attitude control of the spacecraft, but not automatic velocity control; rather, it performed necessary calculations for maneuvers such as orbital insertion or re-entry, and the pilots then performed the manual chores of actually adjusting the spacecraft velocity appropriately.

The OBC was designed and manufactured by IBM's Federal Systems Division, in Owego, New York, just as Apollo's Launch Vehicle Digital Computer (LVDC) was.  The OBC and the LVDC are extraordinarily similar at the CPU level.


The Gemini VIII OBC, with cover removed
(Smithsonian National Air & Space Museum)


Location of the OBC in the spacecraft

Peripheral Devices

This section contains a general overview of the OBC's peripheral devices, but many of them are discussed in much greater detail in later sections.

From a user standpoint, the most visible of the OBC's peripheral device was the Manual Data Insertion Unit (MDIU)—the Gemini equivalent of the Apollo DSKY—which comprised the Modular Display Keyboard (MDK) and the Modular Display Readout (MDR).


Modular Display Keyboard (MDK)

Modular Display Readout

These were on the Pilot's (as opposed to the Command Pilot's) side of the control panel, at the lower right in the drawing below.  The small image below is from the familiarization manual, but if you click on it you'll get a much bigger, much more detailed drawing from the Gemini 5 Mission Report.



A basic inventory of the guidance sub-systems includes:
The diagram below shows a very simplified block diagram of the guidance system, but if you click it you'll get a (different) more-detailed block diagram.



The IMU is the usual gimballed stable platform with accelerometers and angular resolvers as in Apollo, except for a key difference that the Gemini IMU had four gimbals rather than the three gimbals of Apollo.  This means that it was not subject to the phenomenon of "gimbal lock", and hence the software used to adjust spacecraft alignment could be simpler than with three gimbals.  The value of the 4th gimbal can be appreciated when considering incidents like the mishap in Gemini VIII in which an uncontrolled roll occurred.  (If the IMU had had only three gimbals, my understanding is that gimbal lock would have occurred when the roll angle was too great.)  On the other hand, at that point the spacecraft was under manual control anyway, and I'm sure that the notion that the IMU would have to be realigned later would have been the least of Neil Armstrong and Dave Scott's worries.

Gemini Documentation

Sadly, documentation we've been able to collect for the OBC lags far behind that of the AGC or even that of the Abort Guidance System (AGS).  What little survives that we have been able to access can be found in our Document Library.  There's a lot of unique stuff there contributed by original Gemini developers.

Of particular note are the portions of the Gemini Operations Handbook, for spacecraft 7 and 10, and especially subsection 2.5.7 of those handbooks.  These provide user instructions for the flight-computer software, and in the case of spacecraft 10 are particularly detailed.  For example, in the case of spacecraft 10, there's a complete list, with explanations, scope, and format, of all of the memory variables (addresses 0-162) accessible from the MDIU/DCS.

Evolution of the Flight Software ... or, "Everybody Loves Math Flow 7" ... or, "What is software, my man?  What is software?"

Information about the Gemini OBC software is hard to come by.  Useful information we don't have includes any actual OBC software that's contemporary to the Gemini project itself, and that's a lot not to know.  But the situation isn't all bad, partly because the development method of the Gemini OBC software causes us to question what the notion of having the original software even means.  I'll explain more about that shortly, but there's an important sense in which we actually do have significant portions of the software at our disposal.

But before turning our attention to such lofty matters, let's begin with some of the more-mundane details.  Firstly, as far as naming is concerned, the flight software seems to have been called simply the "operational program".   On the subject of versioning of the operational program, we have only partial information, from the familiarization manual, from James Tomayko's Computers in Spaceflight, Chapter 1, section 4, and from this short memo.  (Where there's any discrepancy, I personally believe in the memo.)

The operational programs were characterized in terms of something called the "Math Flow".  In brief, the Math Flow is the complete design of the software, expressed in Gemini as a series of very detailed flowcharts.  The development of the Math Flow eventually went through 7 major versions, designated MF-1 through MF-7.  But there were differing revisions for each of the major versions as well.

The overall software design was partitioned into several different areas of basic functionality. In math-flow MF-1 through MF-6, these functional areas were integrated into a single operational program.  (Though for some missions, unneeded functionality could be omitted. Thus, Catch-up & Rendezvous were omitted in spacecraft GT-3, GT-4, and GT-7.)  In MF-7, the code was refactored into 6 different high-level "Program Modules", which could be loaded into memory from the Auxiliary Tape Memory (ATM) when needed during specific mission phases, though Module I was in memory at all times and didn't need to be loaded from the ATM.  The modules were as follows:
Module
Basic Functionality
MOD I
Executor
Pre-Launch
Diagnostics
Computational subroutines (SINCOS, SQROOT, etc.)
ATM-read
MOD II
Ascent (with abort capability)
Catch-up (without radar)
Re-entry for ascent-abort
MOD III
Catch-up (with radar)
Rendezvous
MOD IV
Touchdown-predict
Re-entry
Re-entry initialization
MOD V
Simplified functions as backup for ATM failure:
Ascent (without abort capability)
Catch-up and Rendezvous (without self-test)
MOD VI
Orbit-predict
Orbit-navigation
Orbit-determination

And here's a more-detailed breakdown if the evolution and usage of these modules on math-flow by math-flow basis:


The astronauts used the Computer Mode rotary switch on the Pilots' Control and Display Panel to select from amount the following mission phases to indirectly affect the active functionality areas:  Pre-launch, Ascent, Catch-up, Rendezvous, or Re-entry.

All of these functionality areas are self-explanatory, except "Executor".  Executor is the interface that interrelates the other software modules and allows them to interact with each other, as well has implementing certain common functionality among them.

Here's another breakdown, this time mine:



Spacecraft
Mission
Designation
Math Flow
version
Program
number,
revision


Comments
GT-1
Gemini 1
n/a
n/a
Unmanned mission.  Since Gemini I was apparently intended principally as a structural test of the spacecraft, it may not have had a computer onboard.
n/a
n/a
MF-1
-

n/a
n/a
MF-2
-

n/a
n/a
MF-3
6444540, B Flowcharts that we have!  Seemingly, one minor revision prior to the software flown in the Gemini 2 unmanned mission.  You'll notice, though, that the first manned missions (Gemini 3 and 4) still used MF-3, though in a later minor revision.  It's useful to know that:
  • Rendezvous begins on p. 1
  • Gimbal Angle and CLOCK subroutines are on p. 8
  • SINCOS and ARCTAN subroutines are on p. 9
  • Re-entry begins on p. 10
  • SHIFT, SQRT (also computes arcsin), and LOG subroutines are on p. 15
  • MDIU subroutine is on p. 16
  • Ascent guidance begins on p. 17
  • Fast-loop ascent guidance begins on p. 19
  • Root sum subroutine begins on p. 22
  • Executor, Accelerometer, DCS, and DAS are on p. 23
  • MDIU scaling stuff starts on p. 24
  • AGE is on p. 26
  • Standby, TRS, and I/O subroutines are on p. 27
n/a
n/a
MF-3(?)
62-564-0020, B
(Ascent Guidance and
Fast Ascent Guidance only)

Flowcharts that we have!  See pp. 2-3 of the linked document.  The document contains a lot of other helpful stuff like detailed explanations of the variables, some additional theory, and source code of a FORTRAN implementation.

I'm not really clear where this goes in the development chronology, merely that it is a few months later than the corresponding elements from the Detailed Math Flow in the preceding entry.
GT-2
Gemini 2
MF-3
6444541, C Unmanned mission.
GT-3
Gemini III
MF-3
6444566, C First manned mission.
GT-4
Gemini IV
MF-3
6444909, C

n/a
n/a
MF-4
-
Work stopped prior to "sell off".
n/a
n/a
MF-5
-
Work stopped prior to release or sell off.
GT-5
Gemini V
MF-6
6444871, B

GT-6
Gemini VI-A
MF-6
6444871, D

GT-7
Gemini VII
MF-6
6444871, D
GT-8 (backup)
n/a
MF-6
6444871, E

GT-8
Gemini VIII
MF-7
MOD I: 6449856, C
MOD II: not used
MOD III: not used
MOD IV: 6449864, B
MOD V: 6449812, B
MOD VI: not used
The principal difference between MF-6 and MF-7 was the reworking of the integrated operational program into 6 individual Modules (here referred to as MOD I through MOD VI) that were treated as independent programs, loadable into main memory at runtime from the new Auxiliary Tape Memory (ATM).  One consequence is that each of the 6 Modules in MF-7 now had its own individual program number and revision.
GT-9
Gemini IX-A
MF-7
MOD I: 6449856, C
MOD II: not used
MOD III: not used
MOD IV: 6449864, B
MOD V: 6449812, B
MOD VI: not used
 
n/a
n/a
MF-7
MOD III: 6449883 Flowcharts that we have!  Later than any Module III flown prior to the ATM, and therefore presumably algorithmically mature, but preceding (by some unknown number of revisions) the first use of Module III as an integrated program loaded from the ATM in Gemini X and therefore presumably relatively immature in terms of its implementation in OBC assembly language.  But remember, we don't have any of the original OBC assembly language, and it's only the algorithmic correctness that concerns us.

Incidentally, this scan derived from a microfilm retrieved from a wastebasket prior to the project's move from the Washington, D.C., area in mid-1966.  Obviously, we're always trying to find better sources of material.  (If you happen to have any wastebaskets from that era that are still loaded with microfilm, be sure to let us know.)
GT-10
Gemini X MF-7
MOD I: 6449856, C (?)
MOD II: 6449816, A
MOD III: 6449895
MOD IV: 6449864, B (?)
MOD V: 6449812, B (?)
MOD VI: 6450027

GT-11
Gemini XI
MF-7
?

GT-12
Gemini XII
MF-7
?


Finally, let's return to odd question of whether or not we're in possession of any of the original flight software.  This question is related to the serious if somewhat facetiously-phrased question asked in this title's heading, namely:  "What is software?"  In the context of the Virtual AGC project --- and I think in the minds of most currently-active computer programmers (2011) --- the question "What is software?" is very easily answered:  If you have the source code of the program (and some way of compiling or assembling that code) or if you have the binary executable of the program (and some way to execute it), then you have the software.  If you have all of the instructions for how to compile/assemble it, so much the better.  But the OBC software developers had a somewhat different view of this question, and their view is bound up in the method used to develop the software.

The most important thing to understand about the software-development process for the OBC software is that it was very heavily dependent on design as opposed to coding.  What I mean by that is the following:
  1. Great attention was given to deriving the mathematics needed for achieving the objectives, and great attention was given as well to verifying the correctness of that mathematics.
  2. Then (and only then), great attention was given to developing the "Math Flow".  To repeat what I said earlier, the Math Flow was a series of a flowcharts specifying the algorithms to be implemented in very great detail.  The flowcharts described the algorithms in such detail that the programmer had very few options left open to him in actually coding that software into a form that could be compiled or assembled.
  3. Then (and only then), software was coded.  But the coding was almost entirely a slavish detail-by-detail translation of the flowchart into computer source-code form.
It was interesting (and at first frustrating) for me to discuss the matter of existence of the software with OBC developers, because from my point of view the software (source code) seemingly no longer existed, while from the point of view of the OBC developers the software did still exist to the extent that the flowcharts still existed ... because to them the software is the flowchart and not the source code.  The source code could always be reproduced from the flowchart, albeit with great effort, and not necessarily byte-for-byte identical to the original.  When viewed from this perspective, it makes little difference how the flowchart is translated into computer language—whether into FORTRAN as was done for simulation purposes or into OBC assembly language for the mission computer—because regardless, it's the same flowchart so it's the same program.

Now, in the preceding paragraph I probably exaggerated the OBC developers' somewhat in order to make my point, but I think there is nevertheless a lot of validity in the viewpoint that was expressed:  If we have the Math Flow charts, then we have the software.  You'll notice from the table above that we do have some of the Math Flow charts, though the validity of what we have could be debated.

I'll leave it as an exercise for the reader to decide whether or not we actually have any of the software, or whether or not we're rationalizing.

OBC Architecture and Interfacing

References

The principal known sources of information about the computer itself are the "Guidance and Control" sections (Section VIII) of the Project Gemini Familiarization Manual, Volume 1 and Volume 2, and most of the information on this web-page was extracted from those sources.  If you find my re-digesting of the material too poor, you may want to read the Manual instead.  However, any simulation software, assemblers, etc., will be based on my understanding and hence on the content of this web-page, so please bring any errors to my attention.

Also, I should state that there's a lot of information on this page that comes from personal communications with original OBC developers, and can't be found in any other reference that's going to be available to the reader ... or probably, to anyone.  While I present a general acknowledgements and "homage" to the original OBC developers in general at the very end of this web-page, let me mention here the OBC developers who have been so directly helpful to me.  In no particular order:

General Characteristics of the OBC

The OBC measured 18.9"(H)×14.5"(W)×12.75"(D), and weighed 58.98 pounds.  OBC power was supplied by the IGS Power Supply, which was itself powered from the spacecraft's main +28VDC bus or (for very brief main-power outages or brownouts) the Auxiliary Computer Power Unit (ACPU).  The OBC required various voltages (+27.2VDC, +9.3VDC -27.2VDC, +20VDC, +28VDC, and 26VAC, but the existing documentation is inconsistent on the exact voltages used), and itself supplied the MDIU (+25VDC, -25VDC +8VDC) and these latter three voltages were what was actually used internally by the OBC itself.

The computing characteristics were:

Layout of Memory Words

I should make it clear that in this section I'm describing my perspective on the organization of OBC memory, in terms of how the original OBC programmers would have worked with it, in terms of how one would work with it using the tools I've created for this site, and in terms of what I think would be the thinking of "modern" programmers at the time I'm writing these words (2011).  I'm not slavishly reproducing here the material on memory organization from the most-complete documentation available to us, namely the "Guidance and Control" sections (Section VIII) of the Project Gemini Familiarization Manual, Volume 1 and Volume 2, because that documentation seems to me to conflict with what I've been told by actual OBC programmers.  The specific area of difficulty is bit-ordering within memory words.  You see, the memory was accessed by a kind of serial interface, and the natural hardware view is in terms of the time-order in which the bits are shifted in and out ... whereas the natural software or mathematical view is in terms of which bits are the most-significant or least-significant—or as normally represented, which bits are on the "left" and which are on the "right".  So I'll adopt the latter perspective, but if you wish to explore what the documentation says on the topic of bit-ordering, feel free to do so.

In all cases, when I show you binary or octal representations of OBC memory, it will use the notation common today, in which the least-significant bits or octal digits are on the right and the most-significant bits or octal digits are on the left.

As mentioned earlier, memory words are 39 bits, comprising three 13-bit "syllables".  In most ways, the syllable is really the natural memory unit, and not the word.  Except in one specific case, storing and retrieving 26-bit data, syllables within a memory word are completely unrelated to (and independent of) each other.  So you're really best served by thinking of memory as a set of syllables rather than a set of words.

Not all syllables are created equal.  In the normal operating mode of the OBC at mission time, the following rules apply:
(There's also a less-common operating mode called "half-word mode" which has somewhat different rules, but this mode has limited usage so we'll return to it later rather than diverting the main discussion.)

Now let's look at some common syllable or double-syllable formats.

Every CPU instruction consists of a single syllable, in the following bit layout:

PPPPAAAAAAAAA

where PPPP is a 4-bit code identifying the specific CPU instruction (the "op code") and AAAAAAAAA is a 9-bit code (3 octal digits) identifying (in a way that varies by instruction type) the operand for the instruction.  Conventionally, OBC programmers name the individual bits like so:
In most instruction types, A1-A8 select a particular memory word.  Since there are only 8 bits, only 256 different words are accessible.  Recall, moreover, that memory consists of 16 sectors of 256 words each of 3 syllables each.  So the instruction is able to select a specific word address, but the sector containing the word and the syllable within the word can't be selected ... those have to be known by other means, which we'll discuss later; for now, just realize that at any time there's some "current sector" and "current syllable", and that whatever the CPU is doing operates within that current selection.  When A1-A8 is interpreted in this way, A9 can be used to override the current sector and instead to do a one-time selection of sector 0, which is referred to as the "residual sector".  A9=0 means to use the current sector and A9=1 means to use the residual sector.  But there's no way to select a different sector or a different syllable on an individual-instruction basis.

Several instructions use a scheme in which the field consisting of bits A1-A3 is given the name "X" and A4-A6 are given the name "Y", thus giving the instruction two independent parameters.  In those cases, A7 and A8 are unused, and A9 may or may supply additional functionality

For normal 26-bit data, recall that a standard 2's-complement format is used.  OBC programmers conventionally refer to the sign bit (i.e., the most-significant bit if interpreting the data as an unsigned integer) as S, to the most-significant non-sign bit as M25, and to the least-significant bit as M1. Therefore, in a word containing such data, syllable 1 will contain S and M25-M14; syllable 0 will contain M13-M1.

Numerical data can be interpreted in two different ways, depending on the interpretation of the software.  Obviously, the data could be interpreted as a simple 2's complement integer.  It can also be interpreted as a fractional value with absolute value less than 1.0.  In the latter interpretation, there is some scaling factor needed to relate the actual value of the number to the binary value that's stored in memory. The OBC and its software have no method for dealing with scaling factors, and it was up to the programmer to understand which interpretation was used, as well as to explicitly scale values during computations to avoid overflow and loss of significant bits.

An important variation in which 26 bits of data aren't numerical in nature is the so-called "HOP constant".  A "HOP constant" is used by a dedicated CPU instruction (HOP)  to change things such as the currently-selected memory sector and syllable by loading a hidden CPU register that can't be accessed by other means. The layout of a HOP constant is as follows:

xxxxxxxxHxSSxPPPPAAAAAAAAA

In this scheme:
You may wonder what half-word mode is good for?  Well, originally, it seems to have been intended for testing purposes.  Later, when the flight-program outstripped the size of available memory, it became necessary to add the ATM and use it to overlay programs at runtime.  In that case, I guess, it's useful to be able to run a program entirely within syllable 2 (which is read-only) without fear that the ATM can overlay it.  But you know, I'm not really sure.

Instruction Sequencing

You may naïvely suppose (I did!) if you did not read the preceding section in great detail, that the everyday usage of the words "word" and "syllable" applies similarly in stepping through the OBC instructions.  In proceeding through a sentence of natural language like English, you use up all of the syllables in a word before proceeding to the next word.  So you might suppose that OBC instructions would sequence in a manner something like the following:  word N syllable 0, word N syllable 1, word N syllable 2, word N+1 syllable 0, word N+1 syllable 1, and so on.  In fact, this is not the case at all, and (as you may infer from the instruction definitions in the following section) would have caused insuperable difficulties.  So get the naïve interpretation right out of your head!

Instead, the instruction sequencing was like this:

word 0 syllable N
word 1 syllable N
word 2 syllable N
etc.

so that the syllable number never changed automatically as you progressed through the program.  But you could always change the syllable manually by executing an instruction (HOP)  and a HOP constant specifically designed to change the syllable number. 

In retrospect, from an outsiders point of view, it would perhaps have been less confusing in terms of instruction sequencing if the OBC hardware designers had used the word "paragraph" rather than "syllable".  Alas! it's a bit late to worry about that now.  The OBC programmers I've consulted seem to think that this is a perfectly natural scheme, and don't seem to have experienced any confusion over the concept of "syllables". 

CPU Instructions

If you're interested in Gemini, you may not be very interested in Apollo's LVDC instruction set.  But there are so many similarities between the two that I'll probably not be able to resist the temptation to point out some of the differences as I proceed.  A difference not pointed out in the table below is that the LVDC instructions MPH, XOR, and CDS, EXM are not present in the OBC.

Note that in what follows, a name representing a location of memory holding an instruction is called a "left-hand symbol" in the parlance of the Gemini OBC programmers, and I will continue to call it that (or LHS for short) rather than adopting more-current terminology.

Finally, when I talk below about the assembly-language syntax of the instructions, I'm referring to the syntax supported by my own yaASM assembler presented as a download on this website.  This syntax is very similar to the original OBC assembler's syntax but we can't be sure it's identical because no documentation for the original assembler has been located up to this point in time.



Mnemonic
Opcode
(OP1-OP4)
in octal
Timing
(140 μs
cycles)


Description of the instruction
HOP
00
1
This instruction combines an unconditional jump instruction with various other configuration options, such as memory-sector selection.  The way it works is that the address A1-A9 points to a memory word that contains a "HOP constant", and the HOP instruction transfers that HOP constant into the HOP register.  Recall that A1-A8 select the offset within a 256-word sector, and A9 is the "residual bit" that selects between the current sector and the "residual sector".  There is no provision for a partial HOP constant, and the full HOP constant needs to be given every time a HOP instruction is used.  See also TRA.

However ... the fact that HOP operates on HOP constants rather than on the left-hand symbols that are the labels for locations in the code as actually understood by the programmers, is not very convenient.  The simple act of HOPping to a location would have to look something like this:

HTARGET   HOPC    TARGET    # Set up a HOP constant for the target location.
          ...
          HOP     HTARGET   # HOP to the target location
          ...
TARGET    ...               # Location we want to HOP to.


This is pretty cumbersome.  The assembler therefore provides a special feature in that if the operand of a HOP is a left-hand symbol for a code location, which would otherwise be illegal, the assembler silently allocates and initializes a HOP constant of the same name, but enclosed in parentheses, and then it pretends that the operand of the HOP was really the newly-created HOP constant.  Therefore, in assembly language, the following becomes legal even though seemingly illegal in machine code:

          HOP      TARGET   # HOP to the target location
          ...
TARGET    ...               # Location we want to HOP to.

But what the assembler really outputs in this case is the same as in the first example (with the HOP constant named "(TARGET)" instead of "HTARGET").

The assembler performs a similar service for the CLA and STO instructions (see below). There are some drawbacks to this special feature as well, namely:
  • Any left-hand symbols used as targets of HOPs in this way must be 6 characters or less rather than 8.
  • The assembler always creates the implicit HOP constants in the residual sector 17, syllable 0.
  • Since there are no explicit allocations for the implicit HOP constants, it's easy for the programmer to overlook that they're being created, and therefore to be less aware of the rate at which memory is being used up.
  • There's no provision for half-word mode.
Fortunately, there's no drawback here that can't be worked around by explicitly defining any troublesome HOP constants needed, as in the first example.
DIV
01
1
(results
 available
after 6)
This is the division instruction.  The contents of the accumulator are divided by the operand pointed to by the address A1-A9 embedded within the instruction to produce a 24-bit quotient.  Recall that A1-A8 select the offset within a 256-word sector, and A9 is the "residual bit" that selects between the current sector and the "residual sector".  The quotient is available via the SPQ instruction from the 5th instruction following the DIV.  In other words, 4 other instructions not involving multiplication or division can be performed in the interval between DIV and SPQ.

To illustrate the assembly-language syntax, let's divide the integer 56 by 3 and store the result in a variable:

RESULT                     # Allocate variable for output.
K56      DEC     56        # Provide dividend as a constant.
K3       DEC     3         # Provide divisor as a constant.
         CLA     K56       # Load divisor into accumulator.
         DIV     K3        # Start the division.
         NOP               # The result won't be available
         NOP               # for a while, so kill some time.
         NOP
         NOP
         SPQ               # Fetch quotient into accumulator.
         STO     RESULT    # Save it!

PRO
02
1
Inputs or outputs an i/o "signal" into or from the accumulator.  (In the AGC these are called "channels".  In current terminology, we'd probably usually refer to them as "ports".)  Whether or not an input or an output is performed depends on the particular signal chosen.  The X (A1-A3) and Y (A4-A6) operand fields are used for signal selection.  A9 is used as well.  For an output operation, it determines if the accumulator should be cleared after the output (A9=1) or preserved (A9=0).   For an input operation, it determines if the data should be loaded into the accumulator (A9=1) or logically OR'd with the accumulator (A9=0).  A table of the i/o signals vs. addresses is given in the following section.  (The PRO instruction is essentially equivalent to the LVDC PIO instruction, but the selection of i/o signals is different.)

The documentation does not explain this, but I think that when the PRO instruction is accessing a single-bit signal, only the accumulator's sign bit is used as the output or the input.  (I'm not sure what the effect on other bit-positions should be on input.)

There are several allowable assembly-language syntaxes for this instruction:

PRO    YX    # If A9=0
PRO    0YX   # Same as "PRO YX"
PRO    4YX    # If A9=1

(Or, you could just look at it as having a literal octal constant as operand, and that constant was placed directly into the bits A9-A1.)  For example, to read MDIU keystroke data, X=3 and Y=4, so

PRO    43
RSU
03
1
Same as SUB (see below), except that the order of the operands in the subtraction is reversed.

Assembly-language example to compute RESULT=3-56:

RESULT                     # Allocate variable for output.
ARG1     DEC     56
ARG2     DEC     3
         CLA     ARG1
         RSU     ARG2
         STO     RESULT
ADD
04
1
Adds the contents of the accumulator with the contents of the address embedded within the instruction and places the result in the accumulator.  Recall that A1-A8 select the offset within a 256-word sector, and A9 is the "residual bit" that selects between the current sector and the "residual sector".

Assembly-language example to compute RESULT=56+3:

RESULT                     # Allocate variable for output.
ARG1     DEC     56
ARG2     DEC     3
         CLA     ARG1
         ADD     ARG2
         STO     RESULT 
  
SUB
05
1
Subtracts the contents of a word pointed to by the address embedded within the instruction from the accumulator, and puts the result back into the accumulator.  Recall that A1-A8 select the offset within a 256-word sector, and A9 is the "residual bit" that selects between the current sector and the "residual sector".  See also RSU.

Assembly-language example to compute RESULT=56-3:

RESULT                     # Allocate variable for output.
ARG1     DEC     56
ARG2     DEC     3
         CLA     ARG1
         SUB     ARG2
         STO     RESULT
CLA
06
1
Store a value to the accumulator, from the memory word at the address embedded within the instruction.   Recall that A1-A8 select the offset within a 256-word sector, and A9 is the "residual bit" that selects between the current sector and the "residual sector".

Assembly-language example to load the accumulator with decimal 56:

K56      DEC     56
         CLA     K56

Note that as with the HOP instruction, the assembler allows seemingly meaningless usages like "CLA LHS", where LHS is the left-hand symbol of a code location rather that the name of a variable or constant.  What the assembler does in this case is automatically, silently to create a HOP constant in memory called "(LHS)", and then to substitute the "CLA (LHS)" for the original instruction.  See the notes accompanying the HOP instruction for full details.
AND
07
1
Logically ANDs the contents of the accumulator with the contents of the address embedded within the instruction and places the result in the accumulator.  Recall that A1-A8 select the offset within a 256-word sector, and A9 is the "residual bit" that selects between the current sector and the "residual sector".

Assembly-language example to compute RESULT=037&052 (i.e., to logically AND together octal 37 and octal 52):

RESULT                     # Allocate variable for output.
ARG1     OCT     37
ARG2     OCT     52
         CLA     ARG1
         SUB     ARG2
         STO     RESULT
MPY
10
1
(results
available after 3)
This is a multiplication instruction.  It multiplies two 24-bit numbers to produce a 26-bit product.  The accumulator provides the address of one multiplication factor, and the address embedded in the instruction points to the other factor.  Recall that A1-A8 select the offset within a 256-word sector, and A9 is the "residual bit" that selects between the current sector and the "residual sector".  In both cases, the most-significant 24-bits of the operands are used, and the least-significant 2 bits of the operand are ignored.  The result is available via the SPQ instruction on the 2nd instruction following MPY.  Any other instruction not involving multiplication or division can be performed between the MPY and the SPQ.

To illustrate the assembly-language syntax, let's multiply the integer 56 by 3 and store the result in a variable:

RESULT                     # Allocate variable for output.
K56      DEC     56
K3       DEC     3
         CLA     K56
         MPY     K3        # Start the multiplication.
         NOP               # The result won't be available
         NOP               # for a while, so kill some time.
         SPQ               # Fetch product into accumulator.
         STO     RESULT    # Save it!

TRA
11
1
This is an unconditional jump instruction, which branches to the address embedded in the instruction.  Bits A1-A9 of the embedded address represent the new offset within either the currently-selected sector or the residual sector.  Note that the syllable remains the same, so if (for example) the TRA is itself in syllable 1 of the current program counter, then the next instruction executed will be at syllable 1 in the new program counter.  (This differs from the behavior of the corresponding LVDC instruction, in that the LVDC instruction allows selection of the target syllable via A9, but does not allow the new program counter to be in the residual sector.)

See also the description of shorthands for various instructions.

Assembly-language examples:

# Branch from location START to location FINISH.
START    TRA     FINISH
         ...

FINISH   ...
# Branch from location START2 to FINISH2, but use
# relative addressing rather than the left-hand
# symbol FINISH2.  The NOP instructions below
# could be anything --- the point is simply that
# FINISH2 is 3 words in memory after START2.
START2   TRA     *+3
         NOP
         NOP
FINISH2  ...


The operand for TRA is either an existing left-hand symbol for an instruction (rather than for a variable or constant), or else an expression of the form "*+N" or "*-N", where N is any number from 1 to 7.
SHF
12

Performs a logical shift operation on the accumulator.  For this instruction, only bits A1-6 are actually used, as follows:

X
(A1-3)
Y
(A4-6)

Description of operation
1
2
Shift "right" one position
0
2
Shift "right" two positions
X
3
Shift "left" one position
X
4
Shift "left" two positions
(Other)
Clears the accumulator

But what do "left" and "right" mean?  Fortunately, "left" implies multiplication by powers of two, and "right" division by powers of two, just as modern programmers are accustomed to.

For the left-shifts, 0 is shifted into the least-significant bit at the right.  For the right-shifts, the sign-bit is duplicated into the most-significant bit at the left.

For illegal X,Y combinations, the accumulator is zeroed.

Note that this instruction is similar to the corresponding LVDC instruction, but differs in details.

See also the description of shorthands for various instructions.

There assembly-language syntax for this instruction is:

SHF    YX

(Or, you could just look at it as having a literal octal constant as operand, and that constant was placed directly into the bits A6-A1.)  For example, to shift right one position, X=1 and Y=2, so

SHF    21
TMI
13
1
This is a conditional jump instruction, which branches to the address embedded in the instruction if the accumulator is less than zero, but simply continues to the next instruction in sequence if the accumulator greater than or equal to zero.  Bits A1-A9 of the embedded address represent the new offset within the currently selected 256-word instruction sector or the residual sector.  See also TNZ.  (This differs from the behavior of the corresponding LVDC instruction, in that the LVDC instruction allows selection of the target syllable via A9, but does not allow the new program counter to be in the residual sector.)

Assembly-language examples:

# Branch from location START to location FINISH
# because VALUE is negative:
VALUE    DEC     -129
START    TMI     FINISH
         ...              # Never gets here!
FINISH   ...              # But does get to here!
# Don't branch from START2 to FINISH2, because
# VALUE2 is not negative:
VALUE2   DEC     127
START2   TMI     FINISH2
         ...              # Comes to here!
         TRA     BAILOUT
FINISH2  ...              # Never comes to here!
BAILOUT  ...

The operand for TMI is either an existing left-hand symbol for an instruction (rather than for a variable or constant), or else an expression of the form "*+N" or "*-N", where N is any number from 1 to 7.  The usage of the latter relative-addressing forms isn't illustrated in the code example for TMI, but you can look at the code example for TRA instead; it works exactly the same for TMI.
STO
14
1
Stores the contents of the accumulator in the word indicated by the address embedded within the instruction.  Recall that A1-A8 select the offset within a 256-word sector, and A9 is the "residual bit" that selects between the current sector and the "residual sector".   The accumulator retains its value.

Assembly-language example:

RESULT                    # Allocate a variable
         STO     RESULT   # Store accumulator value in the variable.

Note that as with the HOP instruction, the assembler allows seemingly meaningless usages like "STO LHS", where LHS is the left-hand symbol of a code location rather that the name of a variable or constant.  What the assembler does in this case is automatically, silently to create a HOP constant in memory called "(LHS)", and then to substitute the "STO (LHS)" for the original instruction.  See the notes accompanying the HOP instruction for full details.
SPQ
15
1
Store a product or quotient (computed with MPY or DIV) into the word indicated by the address embedded within the instruction.  Recall that A1-A8 select the offset within a 256-word sector, and A9 is the "residual bit" that selects between the current sector and the "residual sector".   The accumulator retains its value.  (This instruction is somewhat similar to the LVDC instruction CLA 0775, though quite different in detail.)

For assembly-language examples, see MPY or DIV above.
CLD
16
1
A discrete input (i.e., a single bit) selected by the operand address is read into the accumulator.  The entire accumulator is overwritten so that every bit position has the value of the discrete input bit, and consequently will be either 000000000 or else 377777777 octal.  A test of either TMI or TNZ thereafter can thus branch on the basis of the bit value.  A table of the allowed discrete inputs follows later.  (This instruction does not exist in the LVDC.)

See also the description of shorthands for various instructions.

There assembly-language syntax for this instruction is:

CLD    YX

(Or, you could just look at it as having a literal octal constant as operand, and that constant was placed directly into the bits A6-A1.)  For example, to read the MDIU data-ready bit, X=1 and Y=0, so

CLD    01
TNZ 17
1
This is a conditional jump instruction, which branches to the address embedded in the instruction if the accumulator is not zero, but simply continues to the next instruction in sequence if the accumulator is zero.  Bits A1-A8 of the embedded address represent the new word address within the sector, while bit A9 selects between the current sector vs. the residual sector.  (In the LVDC, A9 instead selects the syllable within the current sector, which is possible since the LVDC has only 2 syllables.) See also TMI.

Assembly-language examples:

# Example 1: Branch to location IS129 if accumulator is
# equal to 129 and to ISNOT129 if accumulator is not
# equal to 129:
K129     DEC     129
         SUB     K129
         TNZ     ISNOT129
         TRA     IS129
         ...
IS129    ...
         ...
ISNOT129 ...
# Example 2: A simple loop with 10 iterations:
LOOPCTR                    # Variable for counting loop iterations.
K1       DEC     1
K10      DEC     10
         CLA     K10       # Setup for the loop.
         STO     LOOPCTR
LOOP     ...               # Do stuff
         CLA     LOOPCTR   # Decrement and test loop counter
         SUB     K1
         TNZ     LOOP
         ...               # Done!

The operand for TNZ is either an existing left-hand symbol for an instruction (rather than for a variable or constant), or else an expression of the form "*+N" or "*-N", where N is any number from 1 to 7.  The usage of the latter relative-addressing forms isn't illustrated in the code example for TNZ, but you can look at the code example for TRA instead; it works exactly the same for TNZ.

I/O Signals (For PRO Instruction)

Note that in assembly language, in the operand for a PRO instruction, the Y operand field would proceed the X operand field.  So, for example, if X=3 and Y=4, the instruction would be PRO43.  That's the opposite of present ordering of the columns in the table below and could be confusing, for which I apologize, but I'm too lazy to completely rewrite the table.

Operand
Input /
Output
Signal
Comment
X (A1-A3)
Y (A4-A6)
0
0
In
Digital Command System shift pulse gate
Causes a 24-bit word buffered in the Digital Command System (DCS) to be read into bits M1-M24 of the accumulator.  Or, reads data from the Rendezvous Radar (if any).
0
1
Out
Data Transmission System control gate
Used to output a data word to the Instrumentation System (IS) for digital downlink.
0
2
In/Out
Time Reference System data and timing pulses
The action of this signal seems pretty complex.  Please read the section on the Time Reference System (TRS) for my conclusions as to what it's actually supposed to do.
0
3
Out
Digit magnitude weight 1
Used in conjunction with "Digit magnitude weight 2", "Digit magnitude weight 4", and "Digit magnitude weight 8" to write a particular digit to an MDR position previously selected using the "Digit select weight X" outputs.  The weights derive from a BCD value of the digit whose display is desired.

I haven't seen any explanation of how to clear a digit so that it's blank ... perhaps there was no such feature, though it seems to me that it would make data-entry very confusing if so.  There are a number of ways this might have been done.  Until I understand it better, the yaPanel MDIU emulator handles this as follows:
  • Using any combination of magnitudes that doesn't form a BCD (i.e., something in the range 0-9) will clear the selected digit to be blank.
  • Pressing the MDR's CLEAR button will make all of the digits blank.
0
4
Out
Reset data ready, enter, and readout
When zeroed, signals the MDIU to reset its internal buffer so that a numerical keystroke subsequently be collected.  It is unclear if this needs to be returned to a non-zero state later.  The CLD inputs associated with the ENTER and READ OUT keys also are cleared as a result.
0
5
Out
Digit select weight 1
Used in conjunction with "Digit select weight 2" and "Digit select weight 4" to select the next digit position to which a display value will be output to the MDIU.  It is not really explained how these work, but I think that they are used to form an index from 0-7 in the obvious way, and that the leftmost address digit is 0, the 2nd address digit is 1, the leftmost message digit is 2, and so on.
0
6
Out
Memory strobe
I believe that this signal is used only in conjunction with the AGE for testing purposes.  When the accumulator is negative, it seems to enable a hardware mode called "marginal early" may help in determining how robust the memory access is with respect to marginal timing.  When the accumulator is positive or zero, it disables this diagnostic feature.
1
0
Out
Computer ready
Signal to the Digital Command System (DCS) that the OBC wishes to read a buffered uplinked data word.  Also used to tell the Rendezvous Radar, if any, that radar data is required.  In the latter case, a 20 ms. delay must occur afterward before polling the radar-ready discrete input (CLD00).
1
1
Out
Drive counters to zero
For setting a delta-V display on the IVI to zero.  First do PRO11 with the accumulator negative, then (see "Select X counter") select the X, Y, or Z axis, then do PRO11 with the accumulator positive or zero to return to the normal state.  CLD31, CLD25, and CLD26 can be subsequently used for feedback that the displays are actually at zero.
1
2
Out
Enter
When inactive, the Time Reference System (TRS) is capable of receiving timing data (like TR or TX) from the ODC.  When active, the ODC can receive timing data (like ET or TR) from the TRS. 
1
3
Out
Digit magnitude weight 2
See Digit magnitude weight  1
1
4
Out
Display device drive
The "display device drive", as far as I can see, is what's used to turn the physical wheel on which the MDIU display-digits are inscribed to the proper position for display.  In other words when the drive is off (i.e., PRO41 output a zero) the last-selected digit continues to be displayed, while when the drive is on (PRO41 output non-zero) the display wheel will be turned if necessary.  Therefore, the drive is normally off, but is turned on briefly when a digit is being changed.  The full procedure is as follows:
  1. Use the digit-select weights to choose the display-position which is supposed to be changed.
  2. Turn on the display device drive.
  3. Use the digit-magnitude weights to determine what digit is driven into the selected display position.
  4. Wait 0.5 seconds.
  5. Turn off the display device drive.
1
5
Out
Digit select weight 2
See Digit select weight 1
1
6

Autopilot scale factor

2
0
Out
Pitch resolution
Controls the range switch for Pitch Error (or down range error) output.  If the sign bit is positive, then there is a 6-to-1 attenuation applied; if the sign bit is negative, there is no attenuation.
2
1
Out
Select X counter
Used along with "Select Y counter" to select one of the IVI's delta-V displays to receive additional commands, as follows:
  • X-axis:  PRO12 with accumulator negative, PRO13 with accumulator positive or zero.
  • Y-axis:  PRO12 with accumulator positive or zero, PRO13 with accumulator negative.
  • Z-axis:  PRO12 with accumulator negative, PRO13 with accumulator negative.
2
2
Out
Aerospace Ground Equipment data link
For outputting a single data bit to the dedicated AGE data link.
2
3
Out
Digit magnitude weight 4
See Digit magnitude weight  1
2
5
Out
Digit select weight 4
See Digit select weight 1
2
6
In
Reset start computation
From the PCDP's RESET switch.
3
0
Out
Yaw resolution
Controls the range switch for Yaw Error (or cross-range error) output.  If the sign bit is positive, then there is a 6-to-1 attenuation applied; if the sign bit is negative, there is no attenuation.
3
1
Out
Select Y counter
See "Select X counter".
3
2
Out
Aerospace Ground Equipment data clock
Provides a data clock, one pulse at a time, for reading data on the dedicated AGE data link.
3
3
Out
Digit magnitude weight 8
See Digit magnitude weight 1
3
4
In
Read Manual Data Insertion Unit insert data
Reads a keystroke that has been buffered in the MDIU.  This operation should be done only in response to a separate discrete "Data ready" input via CLD.  The BCD value of the digit is stored into bits M1-M4 of the accumulator.  A PRO40 should be performed afterward to clear the MDIU buffer and allow the next keystroke to be collected, and additional PRO instructions should be used to display the digit on the MDIU.
3
6
Out
Reset radar ready
Sent to the Rendezvous Radar, if any, to reset its discrete input buffer.
4
0
Out
Roll resolution
Controls the range switch for Roll Error output.  If the sign bit is positive, then there is a 6-to-1 attenuation applied; if the sign bit is negative, there is no attenuation.
4
1
Out
Elapsed time control and Time Reference System control reset / ATM wind-rewind reset
Signal to the Time Reference System (TRS) that the data about to be fetched from the TRS with PRO20 commands is the elapsed time (ET).  This output should persist for 9-15 ms. before being returned to the normal state.  It also apparently acts to reset the TRS control circuitry.

(Units with ATM only.) It has additional functionality for the Auxiliary Tape Memory (ATM), in that it commands the ATM to stop winding or rewinding.  I believe that it also turns off the ATM ERROR lamp.  (I don't know how to select between the TRS/ATM functions, or if it always performs both simultaneously.)
4
3
Out
Computer malfunction
To the PCDP's MALF light.
4
4
Out
ATM verify/repro command
Send a command to the Auxiliary Tape Memory (ATM) to begin data output.  I assume that the accumulator is negative to begin the output and zero or positive to end it.
4
6
TBD
Second stage engine cutoff
TBD
5
0
Out
Computer running
To the PCDP's COMP light.
5
1
In?/Out
Time to start re-entry calculations control / ATM wind command
The use for "time to start re-entry calculations" is TBD.

(Units with ATM only.)  Initiates winding of the ATM.  I assume that the value in the accumulator should be negative, however, I don't think that outputting a positive or zero value stops the winding.  Instead, use PRO14.  (I don't know how to select between the timing and ATM functions, or if it always performs both simultaneously.)
5
2
Out
Time to reset control / ATM rewind command
Signal to the Time Reference System (TRS) that transfer of time-to-equipment-reset (TX) data is desired.  This output should persist for 9-15 ms. before being returned to the normal state.

(Units with ATM only.)  Initiates rewinding of the ATM.  I assume that the value in the accumulator should be negative, however, I don't think that outputting a positive or zero value stops the rewinding.  Instead, use PRO14.  (I don't know how to select between the TRS/ATM functions, or if it always performs both simultaneously.)
5
3
Out
Write output processor
For incrementally adjusting the delta-V displays of the IVI.  First, the X, Y, or Z display is selected (see "Select X counter" above).  No more than 1 ms. later, PRO35 is used to begin the update.  The value in the accumulator comprises the sign bit and M1-M12, so the maximum change is -4096 to +4095.  Since the displays are actually -999 to +999, in theory the adjustment range is more than full.  In practice, only very small adjustments would be made.  My understanding of what the hardware actually does is to increment or decrement the displays by 1 every 21.5 ms., and that it will not be ready to process another delta-V until the count has reached zero.  For example, trying to change the display by 25 would take about half a second, and no other outputs to the IVI should take place in that interval.  The "Velocity error count not zero" discrete (CLD22) can be polled to determine when the increment/decrement pulses have all been sent to the display and the counter has reached zero.
5
4
In
Read delta velocity
This port is used to read the change in velocity from the platform electronics, and to zero the reference velocity for the next readings.

A single PRO45 instruction reads the ΔV from all three axes into the accumulator.  Documentation is unclear as to how the data appearing in the accumulator is packed, but my nearest guess as to what it's trying to tell us is that each of the X, Y, and Z axis readings is a 4-bit 2's-complement value (thus being in the range -8 to +7), and that they are packed into the accumulator as follows:

XXXXYYYYZZZZ00000000000000

Even if correct, the units are TBD.
5
5
TBD
Input processor time
TBD
5
6
Out
Time to retrofire control
Signal to the Time Reference System (TRS) that transfer of time-to-retrograde (TR) data is desired.  This output should persist for 9-15 ms. before being returned to the normal state.
6
3
In
Read pitch gimbal
These ports are used for reading gimbal angles from the inertial platform.  The units used are TBD, as the documents discussing them speak only of phase-shifted 400 cps voltages rather than true angles.

15-bit values are provided, including the sign bit and the 14 most-significant bits.  The 11 least-significant bits are zeroed.  Each of the PRO commands associated with these ports both reads a previously-measured value and begins accumulating a new measurement, so these ports must be accessed in a very specific procedure to get a complete set of readings, as follows:
... at least 5 ms. from last read of gimbals ...
PRO36    # Must ignore the first value received.
... wait >= 5 ms. ...
PRO46
STO PITCH
... wait >= 5 ms. ...
PRO56
STO ROLL
... wait >= 5 ms. ...
PRO36
STO YAW
# The total time must be <=30 ms.
6
4
In
Read roll gimbal
6
5
In
Read yaw gimbal
7
0
Out
Pitch error command
For the re-entry mode, the outputs are down-range error rather than pitch error, and cross-range error rather than yaw error.

These are values which are expected to be output at intervals of 50 ms. or less, and feed into a 7-bit digital-to-analog converter for driving the Flight Director Indicator (FDI).  The output comes from the accumulator sign bit and from bit-positions M8-M13.  The analog outputs also feed into range switches which can attenuate the signals, and are controlled by PRO02, PRO03, and PRO04.
7
1
Out
Yaw error command
7
2
Out
Roll error command

Discrete Inputs (For CLD Instruction)

Note that in assembly language, in the operand for a CLD instruction, the Y operand field would proceed the X operand field.  So, for example, if X=3 and Y=4, the instruction would be CLD 43.  That's the opposite of present ordering of the columns in the table below and could be confusing, for which I apologize, but as I said above, I'm too lazy to rewrite the table.

Operand
Signal
Comment
X (A1-A3)
Y (A4-A6)
0
0
Radar ready
Indicates that data from the Rendezvous Radar (if any) is ready.
0
1
Computer mode 2
From the PCDP's COMPUTER mode selector rotary dial.  The rotary dial has 7 positions, encoded onto 3 discrete inputs, "Computer mode 1", "Computer mode 2", and Computer mode 3".  The encoding is:

Computer
Mode 1
Computer
Mode 2
Computer
Mode 3
Mode
0
0
0
TBD
0
0
1
Pre-launch
0
1
0
Ascent
0
1
1
Catch-up
1
0
0
Rendezvous
1
0
1
Re-entry
1
1
0
TBD
1
1
1
TBD
0
2
Spare

0
3
Processor timing phase 1

0
4
Spare

1
0
Data ready
From the MDIU.  It indicates that a digit-keystroke has been buffered within the MDIU and is ready to be read.
1
1
Computer mode 1
See "Computer mode 2".
1
2
Start computation
From the PCDP's START switch
1
3
X zero indication
Indicates that the IVI's X-velocity display is at zero.
1
4
ATM clock
(Units with ATM only. Otherwise, spare.) See the ATM section.
2
0
Enter
From ENTER key of MDIU
2
1
Instrumentation System sync
From Instrumentation System (IS), to trigger beginning of a new downlink cycle every 2.4 seconds.
2
2
Velocity error count not zero
From the IVI.  It is an indicator that a prior "Write output processor" (PRO35) has reached completion.
2
3
Aerospace Ground Equipment request
From the AGE.  Becomes active (accumulator negative) when a word is available on the dedicated AGE data link.
2
4
Spare

3
0
Readout
From READ OUT key of MDIU
3
1
Computer mode 3
See "Computer mode 2".
3
2
Spare

3
3
ATM on
(Units with ATM only. Otherwise, spare.) See the ATM section.
3
4
ATM data channel 2
(Units with ATM only. Otherwise, spare.) See the ATM section.
4
0
Clear
From CLEAR key of MDIU
4
1
ATM mode control 1
(Units with ATM only. Otherwise, spare.) See the ATM section.
4
2
Simulation mode command

4
3
ATM end of tape
(Units with ATM only. Otherwise, spare.) See the ATM section.
4
4
ATM data channel 3
(Units with ATM only. Otherwise, spare.) See the ATM section.
5
0
Time to start re-entry calculations
This is a signal from the Time Reference System (TRS) that its TR (time to retrograde) counter has reached zero.
5
1
ATM mode control 2
(Units with ATM only. Otherwise, spare.) See the ATM section.
5
2
Y zero indication
Indicates that the IVI's Y-velocity display is at zero.
5
3
ATM data 1
(Units with ATM only. Otherwise, spare.) See the ATM section.
5
4
Spare

6
0
Digital Command System ready
This is a signal from the Digital Command System (DCS)—i.e., the digital uplink from ground control—that data is available for the OBC to read.  In general, it is expected that this signal be polled at 50 ms. intervals or shorter.
6
1
Fade-in discrete
From the PCDP's FADE-IN.  This is a signal from a relay, but anything beyond that is TBD.
6
2
Z zero indication
Indicates that the IVI's Z-velocity display is at zero.
6
3
Umbilical disconnect

6
4
Spare

7
0
Instrumentation System request

7
1
Abort transfer
From the PCDP's ABORT switch.  The software should poll it during ascent mode, and switch from ascent mode to re-entry mode if the input becomes active.
7
2
Aerospace Ground Equipment input data
Reads a single data bit on the dedicated AGE data link.
7
3
Spare

7
4
Spare

Subroutines

As weird as it may seem in modern terms, the Gemini OBC CPU had no mechanism for easily implementing subroutines.  Further, the assembly-language source code for the OBC slavishly implemented what is basically a state machine, using the separately designed "math flow" as a pattern.  Therefore the OBC software developers had little need for subroutines.  You may think I'm wrong about this, but I've pursued this question with several OBC developers to an extent they probably consider tiresome—fortunately, they've been very patient!—and I think that this is an inescapable conclusion.  Therefore, while the OBC may have been a splendid mechanism for developing state machines, it would have been very tiresome for developing general-purpose software without any easy subroutine mechanism.

Now, there were a few subroutines, but they weren't created willy-nilly during development as we often do today.  Indeed, the full list (give or take a few due to errors), including some explanation of how to set up the inputs and retrieve the outputs of the subroutines, can be found in the Gemini Programming Manual.  In modern terms, we'd probably think of these as library routines, but in Gemini they were the only subroutines.  I'll return to this topic of library routines at the end of the section.

Naturally, since there were some subroutines, there had to be some software workaround for the fact that the CPU itself didn't support subroutines, and it seems to have been this:
In terms of the native capabilities of the machine code, it's actually very cumbersome to accomplish all of this, since it's necessary to set up several HOP constants (one for the subroutine entry point and one for each potential return address), each of which has names that must be distinct from the names of the subroutine and return points themselves.  But you may have noticed from the earlier descriptions of the HOP, CLA, and STO instructions that the assembler implements a feature for them in which left-hand symbols can be used as their operands (which would otherwise be illegal), and the assembler simply automatically creates HOP constants as necessary.  Therefore, even though what's going on behind the scenes is somewhat more complex, the assembly language for the subroutine linkage as described above simply looks like this:

        CLA    RETADR    # Set up the return address.
        HOP    SUBROU    # HOP to the subroutine.
RETADR  ...              # Subroutine returns to here.
        ...
RSUBROU                  # Variable to hold SUBROU's return address.
SUBROU  STO    RSUBROU   # Enter SUBROU, store return address.
        ...              # Do stuff inside of SUBROU.
        HOP    RSUBROU   # Return from SUBROU.

There are several HOP constants used here ("(SUBROU)" and "(RETADR)"), but the assembler creates them transparently, and the programmer doesn't have to know about them unless he suddenly finds himself out of memory.  In this example, RSUBROU also holds a HOP constant, but is nevertheless just a normal variable that hasn't been handled in any special way by the assembler.  (A construct like "CLA *+2" seems like it would be useful here, since it would have eliminated the need to explicitly define the symbol RETADR. But the OBC developers haven't mentioned doing anything like that, so I haven't bothered to implement it.  This makes sense in light of the Math Flow diagrams from which the code was created, because they include the detail of setting up the return addresses.  Hence to conform to the Math Flow, the coders would have explicitly set up the return addresses anyway.)

I suppose I should make it clear that I'm not honestly sure that the original OBC assembler worked in this way.  But multiple OBC developers have made it clear to me that this is the way they recall handling subroutines, even though the explanation of why it was legal to do so (in light of the contradictory machine-code characteristics) has been lost in the ensuing decades.  So I see little alternative to supposing that the original assembler did indeed have a similar feature.

Before leaving the subject of subroutines, let me just briefly return to the list of existing subroutines on pages 21-24 the Gemini Programming Manual that I mentioned earlier.  One of the most important subroutines is I/O, which seems to be rather mysterious and we're unfortunately told little about it; it appears to be an exception in that no return address was supposed to be supplied to it.  The most complete information is available for the subroutines listed on page 22 of the manual, since for those routines there's actually some documentation about how to set up the inputs and how to fetch the outputs of the subroutines.  I've collected a little additional information on some of those routines not covered by the manual, and will present that info here just for the sake of completeness:
Sadly, I'm not aware of what most of the other routines actually did.  Though not a subroutine as such, the code identified as the "Executer" was very important and deserves some special attention.  Also known as the executive program (commonly called Hard Core), it was assigned to sector 00 and contained code common to all mode programs (Pre-Launch, Ascent, Catch-up, Rendezvous, Re-entry), such as:
The Executer and whatever mode program happened to be active functioned somewhat like coroutines.  After each pass through a mode program, there was always a return to the beginning of the executive program, where the discrete outputs were set, time was read again, and so forth.  After the Executer pass, control was passed back to the mode program again, and this process of cycling back and forth between the Executor and the mode program continued.

There's also a little information available on placement of some of these subroutines (and other programs) in memory ... though, other than the Executer and MDIU programs, I'm told that the placement of the various subprograms in memory may not have been terribly important.  As of early 1963, prior to the ATM and in-flight swapping of programs in and out of memory, the following is known about memory placement (thanks to notes by Alden Minnick):

Program
Starting address
Rendezvous
01-2-007 ... but I've also been told 02-2-105, 01-2-105, 06-2-007, 03-2-306.
Catch Up
01-2-105
Reentry
06-2-000
Sin Cos
05-2-000
Square root, Arcsine
05-2-325 ... but I've also been told 05-2-000
MDIU
11-0-060
Ascent Guidance
13-2-002
Executor
00-0-000
Standby
00-1-023

But I suspect these allocations changed a lot after that as, for example, I'm also told that at some point the MDIU was assigned to sector 17 (octal) rather than 11 (octal).

Telemetry

Uplink

It was possible to digitally uplink data from ground control to the OBC, via the Digital Command System (DCS).  The procedure for fetching a single word from the DCS is as follows:
  1. Poll CLD06 at intervals of 50 ms. or less to determine if data is ready.
  2. When data is ready:
    1. PRO01 to tell the enable the DCS to send the data.
    2. PRO00 to fetch the 24-bit data word into the accumulator bits M1-M24.
In the fetched word, bits M1-M18 contain a data value, while bits M19-M24 contain an address in the range 000-077.  The flight software is expected to store the data at the specified address.

The obvious limitations here are that full 26-bit data words are not provided and that the address-range covered is limited.  As a variation, there is an "extended" protocol that transmits word pairs rather than single words.  The extended protocol allows 26-bit data words and slightly extends the covered address range.  It works as follows:

Downlink

Conversely, telemetry data could be digitally downlinked from the OBC to ground control.  The flight software output 21 data words to the Instrumentation System (IS) for downlinking every 2.4 seconds.  The flight software would snapshot the values of 21 memory locations (dependent on the operational mode) into a memory buffer, and then to output the contents of that buffer for transmission.  Specifically, the way it works is that:
  1. CLD07 is polled at 50 ms. or less intervals.  When it becomes active (accumulator negative), the steps below are taken.
  2. CLD12 is tested.

Rendezvous Radar

For those spacecraft having a Rendezvous Radar, the following procedure is used to fetch data from it:
  1. PRO63 is used to reset the radar's discrete input buffer.
  2. PRO01 is used to tell the radar that the OBC wants data.
  3. Wait 20 ms.
  4. Test if data available using CLD00.
  5. If data is ready (i.e., if accumulator is negative), perform a code-sequence like the following:
PRO00
STO     RANGE   # 15 BITS
PRO00
STO     SINAZI  # SINE OF AZIMUTH, 10 BITS
PRO00
STO     SINELEV # SINE OF ELEVATION, 10 BITS

The Range data is positive (being a magnitude),  and is stored in accumulator bits M8-M24.  The least-significant bit (M25) is thus not used.  If M8-M11, the 4 most-significant bits, are all 1, then the data should be discarded.  The two sine values are stored in M15-M24.

Aerospace Ground Equipment (AGE)

The AGE provides a dedicated data link from the OBC to (as implied by the name) aerospace ground equipment, and provides a way of performing tests or other diagnostic activities by connecting special equipment.  The technique of reading a word from the AGE is as follows:
  1. Poll CLD32 until active (accumulator negative).
  2. Fetch an 18-bit word by repeating the following 18 times:
    1. PRO23 with accumulator negative.  (Starts a pulse on the AGE data clock.)
    2. Wait 2.5 ms.
    3. PRO23 with accumulator positive or zero.  (Ends the clock pulse.)
    4. Wait 1.5 ms.
    5. CLD27.  (Reads the data bit.)
    6. Wait 1.5 ms.
Assuming that what the software does with this data is to pack it into bits M1-M18 of a data word, with the first bit read going into M1 and so forth, M4-M1 will contain an operation code. The operation-code bits specify the requested operation as follows:

Mode Bits
Mode
M4
M3
M2
M1
0
0
0
0
None
0
0
0
1
Read words from memory.  (See below.)
0
0
1
0
Set marginal early.  The software should use PRO60 to enable the "marginal early" memory-accessing mode.
0
0
1
1
Set computer malfunction on.  The software should use PRO34 to turn the MALF light on.  (It's unclear how the MALF light gets turned off.  Probably the astronaut is supposed to do it manually by pressing the RESET button on the PCDP.)
0
1
0
0
Set marginal late.  The software should use PRO60 to disable the "marginal early" memory-accessing mode.
0
1
0
1
Set pitch ladder output.  (See below.)
0
1
1
0
Set yaw ladder output.  (See below.)
0
1
1
1
Set roll ladder output.  (See below.)
1
0
0
0
Set all ladder outputs.  (See below.)

As you can see, one of these commands causes a memory word to be read and reported back through the interface, while the others are supposed to trigger the OBC software to perform some operation.

When data is being read back (operation 0001), the data word read from the AGE link is interpreted as follows:  M5-M12 will contain a data address (A1-A8), M13 (A9) will contain a bit related to AGE internal clock pulse timing, M14-M17 will identify the sector (S1-S4) of the requested data, and S5 will identify the syllable of the requested data.  (By selecting S5=0, the data is taken from syllables 0,1.  By selecting S5=1, the data is taken from syllable 2 with an implied but fictitious syllable 3 that is entirely 0.)  The first bit transmitted is the most-significant bit of higher selected syllable and the last bit transmitted is the least-significant bit of lower selected syllable.  The actual transmission technique is to repeat the following 26 times, in most-significant to least-significant bit order:
  1. Load the accumulator so that the bit to be sent is the sign bit.
  2. PRO22 to output the bit.
  3. Wait 2.5 ms.
  4. PRO23 with accumulator negative.  (Start AGE data clock pulse.)
  5. Wait 2 ms.
  6. PRO23 with accumulator positive or zero.  (End clock pulse.)
  7. Wait 2 ms.
  8. PRO22 with accumulator positive or zero.  (Put AGE datalink line back to its normal resting state.)
  9. Wait 1 ms.
(The manual states that specifically that "there is a delay of 4.5 ms. between resetting clock 18 and setting clock 19".  I cannot fathom any meaning in this statement, so I simply report it as written.)

As far as the "Set XXX ladder outputs" operations are concerned (0101, 0110, 0111, and 1000), the data word read from the AGE is interpreted as a sign bit at M18 and a 6-bit data word (D1-D6) at M12-M17.  What is done with this data is TBD.

Time Reference System (TRS)

The Time Reference System (TRS) keeps track of elapsed time from lift-off, and provides count-down times to retrograde and to equipment reset.  It counts in 1/8-second increments.  The timings being tracked can be transferred to the OBC or set from the OBC, and they can be set by other means such as manual entry and digital uplink from the ground.

The TRS can be accessed by the OBC in one of two modes:  "readout mode", which is activated by PRO21 with the accumulator negative, and "enter mode", which is activated by PRO21 with the accumulator positive or zero.  In readout mode, the elapsed time (ET), the time until retrograde (TR) or the time until equipment reset (TX) is transferred from the OBC to the TRS.  In enter mode, the transfer is instead from the TRS to the OBC.  If TR reaches zero, then a discrete from the TRS which can be read with CLD05 becomes active, and the software is generally expected to poll this discrete so that it can know when to begin retrograde.

The TRS has three internal 24-bit counter-buffers in which times are counting upward or downward, and a separate 24-bit buffer used to transfer data to/from the OBC. 

In order to make sense of the procedures documented in the familiarization manual, the PRO21 instruction must have some unusual behavior, such as the following:

Readout Mode

Here's how the OBC can write data to the TRS.
  1. PRO21 with accumulator negative to select readout mode.
  2. Load the accumulator with 24-bit data for the TRS.  The data should be in accumulator bits M2-M25.
  3. Repeat the following 24 times:
    1. PRO20 to output accumulator's M1 to the TRS.
    2. SHR1 to discard M1 from the accumulator and move the other accumulator bits downward.
  4. With the accumulator negative use (only) one of PRO14, PRO65, or PRO25 to strobe the TRS transfer buffer into one its ET, TR, or TX counter, respectively.
  5. Delay 9-15 ms.
  6. Use the same PRO instruction from step 4, but with the accumulator zero or positive.

Enter Mode

Here's how the OBC can read data from the TRS.
  1. PRO21 with accumulator zero or positive to select enter mode.
  2. With the accumulator negative use (only) one of PRO14, PRO65, or PRO25 to load the TRS ET, TR, or TX counter value, respectively, into its transfer buffer.
  3. Delay 9-15 ms.
  4. Use the same PRO instruction from step 2, but with the accumulator positive or zero.
  5. 25 repetitions of the following steps.  (Yes, that's 25 repetitions, even though only 24 bits are involved.)
    1. PRO20 to get the next bit from the TRS into the accumulator's M1 bit.
    2. SHR1 to logically right-shift the accumulator by one place.
  6. Notice that after the 25th step above, the first bit that was read will have been shifted out of the accumulator entirely, so only the bits from the 2nd through 25th reads will remain.

Auxiliary Tape Memory (ATM)

At some point in the evolution of the operational program, feature creep caused the size of the operational program to overrun the total amount of memory provided by the ferrite array.  For Gemini VIII through XII, the approach taken was to modularize the software in a way that allowed it to be reloaded into the OBC during the mission with software that was specialized for the current phase of the mission.  So even though we talk (for example) about the "software for Gemini X", the software for Gemini X was really several different programs that were loaded just during the mission phases in which they were used.  The programs were stored in the Auxiliary Tape Memory (ATM) and then transferred to the OBC.  We are told by the Gemini Familiarization Manual that
The Auxiliary Tape Memory (ATM) is a self-contained magnetic tape recording system. It is used in spacecraft eight through twelve to provide additional program storage for the digital computer. It has a total storage capacity of over 85,000 thirteen-bit words. This is about seven that of the computer core memory. The ATM is mounted on a cold plate in the adapter section of the spacecraft ...
From the Familiarization Manual's ATM specifications, we can figure out about how long a program load from the ATM into the OBC must have taken.  With a total tape length of 525 feet and a read/write speed of 1.5 inches/second, the total tape could be read or written in 525×12/1.5 = 4200 seconds = 70 minutes.  (If a tape rewind were needed, the full operation would also require a rewind at 8× speed, adding a maximum additional 8.75 minutes to the total operation.)  Since the tape has a 7× capacity relative to the OBC core-memory capacity, any individual load, ignoring tape wind/rewind, would then be about 70/7 = 10 minutes.  Since not all of the memory could be overwritten, and since syllable 2 of the 39-bit memory words couldn't be changed in flight anyway, the actual loads would have taken less time, and is estimated at about 7 minutes.

Loading software from the ATM into the OBC is actually a software operation rather than a hardware-only operation, so it requires that some software—namely, the software that does the software loading—remain always in the OBC without being overwritten.  That invariant portion of the software is known as "Module I".  There were six modules in all, and I've already described them above.

I can't tell you (yet) how many separate software loads occurred during the missions, nor which modules were loaded during these loads, but that is probably information we can find or deduce at some point in the future.  I believe, however, that loads occurred during the pre-launch phase after diagnostics had been completed, in orbit prior to rendezvous, and after rendezvous but prior to re-entry.

The documentation does not precisely describe how data is read from the ATM.  But the following is my best guess as to how the actual OBC/ATM interface works. 

Various of the PRO/CLD instructions mentioned below are repurposed from interfacing to other peripherals like the TRS.  The image at right, showing the pilot controls for the ATM, came from the Gemini XII Mission Report. (I was obliged to replace all of the text to make it legible for presentation here.)  In the AUTO mode, it appears as though data could be written to the tape using the Aerospace Ground Equipment (AGE), but only the STDBY, REWIND, WIND, and PROG modes seem to have been useful during the mission. 
The ERROR lamp seems to have been directly controlled from the ATM rather than from the OBC.  The 3-bit data frames mentioned above were actually 4 bits each, with the 4th bit being a parity bit, so the ERROR lamp was lit when a parity error was detected.  Moreover, the data was triply redundant as well, so a voter circuit could detect an error if there was a mismatch between the redundant data.  Finally, the data checks occur even during wind/rewind operations, so the ERROR light can potentially be lit during those activities.  On a similar note, it may have been possible to read data from the ATM during a tape wind/rewind operation, but I have no data on that subject.  I believe that a PRO14 will extinguish the lamp if it is lit. 

The RUN lamp is also controlled directly by the ATM, and indicates that the tape is in motion; it lights 5 seconds after receiving any command that sets the tape in motion.  It will be automatically extinguished if the beginning or end of the tape is reached.

During an ATM search operation, the IVI was used to show the tape position (in 13-bit words) on the left/right display, and the module words on the fore/aft display.

As far as how the data is actually encoded on the tape—i.e., how the 3-bit frames are recombined into 39-bit memory words, and where those words are placed in memory—I have, as of yet, found no clue in the documentation.

OBC Assembly Language

I've given a number of examples of OBC assembly-language above, particularly where describing the various CPU instructions, but I'd like to devote this section and its sub-sections to describing the assembly language and its syntax a little more generally.  I'll try to describe the original language used by the OBC developers to the extent possible, but since no documentation of the language or the assembler other than the names of the instructions is known to survive, nor any examples of OBC assembly-language contemporary to Gemini, you can't assume that my description is completely correct. 

On the other hand, my information has been gleaned from a lot of communications with OBC developers, and by some rather extensive modern (2011) recreations of sample code by OBC developers.  You can find the sample code here:
This sample code was produced with the intent of showing the coding style that was employed, and was developed similarly to the way that the original OBC code was developed: namely, by "slavishly" duplicating the extremely detailed flowcharts known as the "math flow".  (I got the description "slavish" here from OBC developer Don O'Neill, who was in charge of the assembler program.)  So I think that there's a pretty high degree of authenticity.  On the other hand, you have to recognize that the sample code was developed 45 years after the end of Gemini, and that Alden and Charlie had (at the time of creating the samples) neither an assembler nor an OBC simulator, so you have to expect that there's going to be some degree of inconsistency and unavoidable error as well.  Charlie has passed along the following additional brief notes that he wrote while creating his own code snippet that I think give a much fuller picture not merely of the production of the sample code, but of the method by which the original OBC software was produced ... not that all of the original developers necessarily worked the same way, of course!
Here also is a far briefer sample and explanation by Charlie of coding a simple formula in OBC assembly language, slightly massaged by me for typos:

I will start out with a simple equation like: Y=MX + B. Here goes:

Let's assume the numbers are small as that we won't have to do any fixed point scaling.

Let's define B as a constant with the decimal value of +3. The 24 bit memory in binary word would be as. (0 00 000 000 000 000 000 000 011) There is no actual spaces between the binary zeros - it makes it easier for me count the bits and look at the sign bit! The sign bit was the most significant bit while the the least significant bit was the 1.

Let's also assume the program is in sector (00) - in octal (zero). There were 16 sectors in octal that you could program in. To change sectors you had to execute a HOP instruction.

The first bit of constant (+3) in memory is the sign bit of zero which represents a positive number. A negative number would have a 1 bit.

The Gemini symbolic instructions on punch cards fed in to the Assembler would look like this:

CLA X       Variable Comment
MPY M       Slope Comment
SPQ Temp1   Store the product in a memory location Temp1 comment
ADD B       Constant (+3) comment
STO Y       Store result in Variable Y memory location

To a certain extent, I have tried to get around some of the problem of having no feedback for detecting coding errors by developing a recreated version of the OBC assembler, which I call yaASM, and an OBC CPU emulator, which I call yaOBC.  At this point, these programs are very much works in progress, and I don't claim that they are fully debugged or even that they will run on your computer.  For this reason, they have not made their way into the official Virtual AGC software source or binary distribution.  But for now you can download the cutting-edge binaries from the temporary Gemini download section on this page.

Finally, before starting, let me note that in contemplating the original OBC assembly language, there was a small set of features which (from a modern standpoint) seem to be absolutely necessary to the language, but which don't seem to have existed originally; perhaps they truly existed in some form but have simply been forgotten over time.  In those cases, I have taken the liberty of adding those features to yaASM and to the assembly-language syntax.  In the description that follows, I have color coded in this brown color any aspects of the language that seem to me to be newly-added and not to have existed in this exact form in the original OBC assembly language.

General format

The format of an individual line of code, corresponding to a single punch-card from the point of view of the original OBC developers or to a line of a source file from the current perspective, is

LHS OPERATOR OPERAND COMMENT

Note that these fields are not aligned on an particular column, and are simply separated by white space of any kind.  The total number of characters in a line was originally limited to punch-card length (80 characters), as the assembler did not allow for continuation cards, but the current assembler extends that limit to 132 characters.  Moreover, since it's a little easier to compose source-code these days (without having to use punch-cards), with newly-written code I think it's nicer to align the columns attractively.
The original OBC developers, I told, formatted the code for submission to the assembler as follow:
  1. A list of all variables used, where a "variable" is the name a memory location whose value can be changed at runtime.  In these lines, LHS is present but OPERATOR and OPERAND are not.  yaASM treats such a line as an allocation for an uninitialized variable named LHS, as the original OBC assembly language doesn't seem to have had any other method of making such an allocation.  I'm not sure, but I think that lines of the form "LHS SYN REFLHS COMMENT" might be included in this section.
  2. A list of all constants used, where a "constant" is the name of a memory location assigned a value at assembly-time.  They're not really "constant", though, since there's nothing to stop the runtime program from changing the values later.  In modern terms, it's probably best to think of these as allocations of initialized variables.  To my understanding, the OBC programmers used a naming convention in which if the name of the constant began with 'K', the program was not supposed to alter the value.  (Interestingly, the original assembler did not have a concept of a symbolic constant that was used only at assembly time without corresponding to a memory location.  The pseudo-op EQU which would be used for that purpose in many current assembly languages is, in fact, used for something else.)  In section, OPERATOR is generally DEC, OCT, EQU, or HOPC.
  3. Instructions.
Curiously, I've been unable to ascertain how the original assembler was told what areas of memory were to be used for assembly of instructions or data.  Perhaps each memory region was assembled separately, along with job-control directives giving the memory region, and all of the little pre-assembled chunks were merged together later into a single executable image.  At any rate, to overcome this, I've found it necessary to invent my own syntax for such things. The following directives for that purpose are completely new in yaASM and didn't exist in this form originally:

Directive
Description
HALF
Tells the assembler that the half-word memory access mode is in effect in following block of code.  This remains in effect until a NORM directive is encountered.
NORM
Tells the assembler that the normal memory access mode is in effect in following block of code.  This remains in effect unti a HALF directive is encountered that overrides it.
CODE M-PP-S-WWW
Tells the assembler that the next instruction encountered should be assembled at address M-PP-S-WWW, where M is the module,  PP represents two octal digits giving the memory sector, S is the syllable, and WWW represents three octal digits giving the word number.  The word number is incremented by the assembler on each successive instruction encountered, but assumptions about the selected sector and syllable are never changed until another CODE directive is encountered.

The term "module" (M) refers to the program modules (I, II, III, IV, V, and VI) that can be loaded at runtime from the Auxiliary Tape Memory, thus overlaying each other.  Module I, however, was intended to always be present.  yaASM allows 8 modules numbered 0-7.  Module 0 corresponds to program module I, 1 corresponds to II, and so on.

yaASM expects to assemble a complete set of program modules as a single operation, rather assembling the program modules separately and merging them afterward ... which, I gather, was the original procedure in Gemini itself.  This makes it easier for all program modules to be aware of the same set of global variables. As a consequence of this feature, however, yaASM requires that program modules do not redefine left-hand symbols or variable/constant names from one module to the next.  So (for example) if you had a variable named X in module I, you couldn't define a different variable X in module II, even though you could continue using X from module I within module II, as long as module II hadn't actually overlaid the portion of module I where X was defined.  yaASM has no way of detecting runtime problems where code or data are accessed that aren't actually loaded, so it is the responsibility of the programmer to avoid it. 

One situation that may arise is that some memory location may be used as a variable with two different interpretations in two different modules, and therefore it's desirable to assign two different symbolic names to it.  For example, we might desire a specific address to be the variable PHI in module II and the variable EPSILON in module III.  Using multiple names for the same address causes no problems if module II and module III use the same region of memory and hence don't coexist.  In this case, the SYN pseudo-op could be used to define PHI and EPSILON as synonyms; module II would use only the symbol PHI and module III would use only the symbol EPSILON.  The same situation could occur with left-hand symbols as well; for example, if there were two modules for the exact same area of memory, and the entry points for both were at the same address, then two different left-hand symbols would refer to the same address but in two different modules.  But generally in this latter situation, the left-hand symbols are all defined naturally just by assembling the code, and therefore no explicit SYN is needed.
DATA M-PP-S-WWW
Tells the assembler that the next variable or constant declaration encountered should be assembled at address M-PP-S-WWW.  See the CODE directive for more detail.

These directives, with whatever operands they may have, are expected to be placed on lines by themselves, without any left-hand-symbol or comment.  However, any desired white-space can be added to make them look pretty.   Note that CODE and DATA are completely separate and independent, so that they can logically be use together or separately.  I'd think that the most normal usage, though, would be to issue both directives together, like so:

CODE M-PP-2-000
DATA M-PP-0-000
... all of the code, variables, and constants for sector PP ...

Because of the existence of these directives,
yaASM has no need to enforce the original-OBC division into sections (VARIABLE/CONSTANT/CODE) described earlier, and expects that variable- and constant-specifications can be intermixed at random with instructions.  However, it is required that blocks of source code be preceded by the appropriate directives HALF/NORM/CODE/DATA describing the memory being used.  It's very important to understand that the directives only affect the assembler's assumptions, but don't have any effect at runtime.  While the assembler can help to keep the assemble-time assumptions consistent with the runtime conditions, it's still possible for the programmer to fool the assembler and generate code that won't actually execute. For example, for HOP constants generated with HOPC, the runtime effect of a HOP will generally be consistent with the assembler's assumptions about memory use; for HOP constants generated instead by OCT, there's no such expectation.  It's ultimately up to the programmer to insure consistency.

In order to allow relatively clean organization of source code, yaASM allows an OBC source file to include the complete contents of another OBC source file within it by placing the name, preceded by the character '$', by itself on a line, like so:

...
$IncludeThisFile.obc
...

Multiple include-files can be used in a single source file, and include-files can include other files.  This feature could be used, for example, to organize a program in terms of pages in its math-flow diagram by putting each page in a separate source file. 

Shorthands for some instructions

Shorthand
Description
SHR 1
Same as an SHF with X=1, Y=2.
SHR 2
Same as an SHF with X=0, Y=2.
SHL 1
Same as an SHF with Y=3.  The value of X doesn't matter in this case, but our assembler will use X=0.
SHL 2
Same as an SHF with Y=4.  The value of X doesn't matter in this case, but our assembler will use X=0.
NOP
A no-operation instruction that simply advances to the next instruction in sequence.  The assembler translates this to "TRA *+1".  The existence of NOP.

In discussions or in documentation you'll often see references to things like "SHR1" or "PRO43" — in other words, to things that look like SHR, SHL, SHF, PRO, or CLD instructions+operands, but without any space between the operator and operand.  Indeed, you'll find references like that on this web page.  It remains unclear to me whether the original OBC assembler accepted constructs of this kind, but the yaASM assembler does not: yaASM expects the instruction and operand to be delimited by space(s) in all these cases.  Until/unless actual OBC source code is found so that it can be fed into the assembler, the point is (of course) not of overwhelming concern.

Pseudo-ops

Pseudo-op
Description
Example
DEC
Assembles a decimal constant into memory.  It can assemble either integer values or else fractional values.  The allowed range of values is -33554432≤Operand≤+33554431.  As with all data, in normal mode the data was stored in syllables 0,1, while in half-word mode it was stored in syllable 2.

If the literal decimal constant is an integer (i.e., if it has no decimal point in it), then it is converted much as you might expect: for example, a decimal 3 is stored as a binary 11. 

But in converting fractional values in which the literal decimal constant contains a decimal point, the value is auto-scaled by whatever power-of-2 is required to make the most-significant data bit (other than the sign) 1; in other words, the value is left-shifted to maximally fill the range -1.0<ScaledOperand<+1.0.  There is no convention for storing values in memory with the binary point at any location other than fully to the left or fully to the right of all the bits; it's up to the programmer to understand these conventions and explicitly apply scaling to deal with it as the computation progresses.

ANINT DEC -12345678
PI DEC 3.14159
OCT
Assembles an octal constant into memory.  Its operand is a set of octal digits.  The allowed range of values is 0 to 377777777.  As with all data, in normal mode the data was stored in syllables 0,1, while in half-word mode it was stored in syllable 2.  ANOCT OCT 1234567
SYN
Creates a symbol referring to the same memory address as a different symbol ... i.e., causes symbols to be synonyms for each other.  This is useful in cases where different programs which never run simultaneously are sharing the same memory locations for variable storage. Since the different programs would have different interpretations for these same memory locations, they'd naturally want to assign different symbolic names to them. (I believe that the OBC programmers referred to such variables as "timeshared" variables.)  In yaASM, SYN can be used to create a synonym for instruction left-hand-symbols as well, though I'm not sure if that feature was present in the original assembler or would have had any use there.
A SYN B
EQU
Creates a variable having the same initial value as a different variable (presumably created by OCT or DEC).  In the example shown at right, two variables (A and B) are allocated, each having the same initial value of 21, but they're at two different memory locations and may have different values later in the program's execution.
A DEC 21
B EQU A
HOPC
Creates a HOP constant from an existing left-hand symbol for an instruction.  The constant is stored in the currently-active DATA section at the position where the HOPC pseudo-op is encountered, but the constant itself is constructed using the CODE and HALF/NORM settings which exist at the location of the left-hand symbol being targeted, which is exactly what's required to make the constant usable.  It's possible alternatively to create a HOP constant manually using OCT, but it's frankly difficult and error-prone to do so, and creates a constant that's easily broken by future code changes.

Because of the assembler's feature of implicitly creating HOP constants when it finds code left-hand symbols used as operands for HOP, CLA, or STO instructions, it actually turns out that there's little need to explicitly use HOPC except in odd cases which the assembler would handle implicit HOP constants incorrectly, like half-word mode.
HLAB HOPC LAB
...
LAB ... code ...

Software Examples

Above, you've seen various code snippets of OBC assembly-language generated by me or original OBC developers in the absence of any OBC programming manual or actual examples of OBC code contemporary to Gemini to work from.  You may also find the short programming example created by John Pultorak instructive.  (In John's document, "SGSC" refers to a Gemini-related project of his own, and not to anything that actually existed in the true Gemini project.)  Unfortunately, John is in the same boat as I am, and is working without genuine code or code samples.

Our "Modern" OBC Development Tools

In the foregoing sections I've talked about the characteristics of the Gemini OBC itself.  In this section I discuss simulation software provided by the Virtual AGC project to process OBC source code and emulate the OBC.  Some of the software discussed below exists, but some of the description below is speculation about software that I might create in the future, and how I might go about doing it. I apologise for that.  Nevertheless some significant software is available already.

Downloads

As mentioned earlier, I have created a new version of the OBC assembler, which I call yaASM, and an OBC CPU emulator, which I call yaOBC

In brief, yaASM is a command-line tool which:
while yaOBC is a command-line tool which:
More-detailed explanations are available in the sections specifically devoted to yaASM and yaOBC below, but at its most basic, here are the commands you'd use to assemble the test OBC assembly-language source-code file, using sample OBC code provided in the file Test.obc, and then run the assembled program in the emulator/debugger from the command-line in Windows:

yaASM --input=Test.obc >Test.lst
yaOBC --binary=yaASM.bin --symbols=Test.lst

The commands above will present you with a debugger interface in which you can do things like examine or modify OBC memory, set breakpoints, run or single-step through the OBC test program, etc.  You can also view the assembly listing, Test.lst, in any convenient text editor you happen to have handy, such as Notepad or Wordpad.

By the way, I follow the convention that OBC source files have names of the form *.obc, OBC executables have names of the form *.bin, and OBC assembly-listings have names of the form *.lst.  These conventions are not enforced by yaASM and yaOBC, though, and you're free to do as you like.

The Gemini Catch-Up and Rendezvous Simulation Program

Background

This is an actual existing program described in this report, with the full FORTRAN source code in Appendix A of the report.  The program was used by the original Gemini developers to verify algorithms for the catch-up and rendezvous flight phases.  It is a behavioral simulation of the flight code, rather than being flight code itself.  The actual flight code was apparently developed by handing the validated FORTRAN source code to programmers, who recoded it to something usable directly in the Gemini OBC.  It is therefore the closest thing we have at the present time to actual flight code.  The report was contributed by Gemini developer Eugene Mertz, and scanned by his son Dave.  Thanks, Gene and Dave!

Although the report is dated slightly after the Gemini 7/6 mission, Gene recollects that it was actually prepared a few weeks before the mission, which was the first rendezvous maneuver of manned spacecraft.  In other words, it's reasonable to suppose that the FORTRAN code corresponds to the Gemini 7/6 mission. 

Gene comments, "The FORTRAN code seems to be complete since it had to simulate the flight code.  The coding style is archaic, to say the least.  Today's techniques (and newer languages) would produce better code!  But, hey, the system worked to perfection despite problems that cropped up in equipment other than the computer (example:  the plug falling out at 2 inches off the pad!) I believe the version was FORTRAN IV since this was the language of choice at the time for the IBM 7094.  I recall one problem that we had running the binary deck after it sat dormant for several months.  The problem arose because one of the FORTRAN programmers used an 'undocumented instruction' that IBM decided to change to make it better.  I put one chad in the offending hole and duplicated the deck.  The chad stayed in long enough to read the 'fix' into memory.  After that, no problem!  (Also, no voting machine was involved.)"

Two separate application programs are actually provided, though using much of the same underlying machinery.  Both a batch-oriented program (capable of receiving a bunch of input data and quickly generating corresponding output data for the mission) and a dynamic simulation program that operates in real-time are provided.

Source Code

The source code for Report #4 described above has been extracted from the report and is available in the Virtual AGC software source tree under the directory yaAGC/GeminiCatchUpandRendezvousProgram/.

The original program was really combined FORTRAN II and IBM 7090/7094 assembly-language.  Both the original FORTRAN II and the assembly code did things which simply cannot be performed with any modern version of FORTRAN, so the original source wouldn't have been directly compilable and (if somehow it compiled) the executable would not have worked as expected on any computer other than an IBM 7090/7094.  The theory of operation section explains some of the problems involved.  Therefore, the source code in the Virtual AGC source tree has necessarily been modified from the original to be buildable and portable.

In general, the following modifications have been made:

Building the Catch-Up and Rendezvous Simulation Program

In a general Virtual AGC program build, the catch-up and rendezvous simulation program is built automatically.  But if you just want to build the Gemini simulation and none of the rest of Virtual AGC, you can do this:

cd yaAGC/GeminiCatchUpandRendezvousProgram
make

This requires:
Although the Makefile has provisions for using the earlier GNU g77 in place of gfortran, but it's best not to use it because I've found that with g77 the program will appear to compile but the executable will not be fully functional.  If you adapt for other compilers, let me know the details.  Note: At build-time, the Makefile dynamically transforms the FORTRAN II to a more-modern FORTRAN dialect (*.f → *.for), since the FORTRAN II code cannot be directly compiled with a modern compiler.  This transformation behavior must therefore also be mimicked if changing to a different toolset.

Running the Catch-Up and Rendezvous Simulation Program

The batch-oriented simulation program, referred to in Report #4 as the "static environment", is created as the executable named BENCH7.  The dynamic simulation program, referred to in Report #4 as the "dynamic environment", is created as MAIN7.  Neither has any command-line arguments, but both expect input files to be available.  (The nature of the input files and output files is discussed in the next section.)
Both programs may also print some status messages on stderr, due to my alterations rather than to any intention of the original programmers.

Data for the Catch-Up and Rendezvous Simulation Program

The input-data files needed to run the simulation program(s) are described in Report #4.  Actually generating such data is TBD.

Gene's comments: "The problem is that there is no 'environment' FORTRAN program to generate the radar inputs to the OBC (range, azimuth, and elevation to the target), the platform inputs to the OBC (gimbal angles and accelerations), horizon sensor angles, and astronaut inputs (thrusting, switch position selections, etc.) required for a complete simulation of rendezvous flights.  Without that, the executable just loops through the equations and logic waiting for dynamic inputs to arrive.  As I recall, the 'environment' simply had the target moving in a constant, 'circular' orbit around an oblate Earth whose gravitational field was defined by a six-term series potential function.  Time (one second increments) was common to both the 'environment' and the OBC FORTRAN programs.  I believe the astronaut switch inputs were originally simulated using the 7090 (or 7094) console keys.  Today, mouse clicks would do the trick.  Thrusting and attitude were closed-loop from the OBC results using rates approximating the actual spacecraft capability.  The 'environment' development is being left to the student at this time.  Data were communicated between FORTRAN programs through judicious use of COMMON arrays."

Theory of Operation and Porting-Problems for the Catch-Up and Rendezvous Simulation Program

As mentioned above, the original source code from Report #4 is incompatible with modern FORTRAN—or indeed, any modern high-level computer language—in various fundamental ways.  Therefore, significant code alterations had to be made to produce a portable, working program; yet, every attempt was made to preserve the original source in as much detail as possible, and to preserve its "look and feel" otherwise.  Those problems and fixes are described in this section, along with some theory of operation of the original code in order to understand the nature of the problems.

TBD

yaOBC, the OBC CPU Emulation

Invoking yaOBC

yaOBC is a software-based emulator for the OBC CPU.  It is simply a command-line program for Linux, Windows, or Mac OS X.  It has no user-interface as such, except for a debugger interface which can be used to perform such operations as examining emulated memory, single-stepping through instructions, setting breakpoints, and so on.  However, it can optionally be used to connect to other programs like yaPanel (not yet available!) which do provide a user interface; if not so connected, it simply uses the CPU instructions PRO and CLD (which would otherwise be used to communicate with peripheral devices) to read and write to a dedicated memory area separate from the regular OBC memory, and therefore remains usable for software debugging even without peripheral devices.

The command-line syntax for yaOBC is as follows:

yaOBC [OPTIONS]

By default, yaOBC treats OBC memory as persistent, and thus to have the same contents whenever yaOBC starts as it had on the last occasion yaOBC stopped.  It accomplishes this by means of an auxiliary file it creates called yaOBC.bin, but in order to do this effectively requires an orderly shutdown process by means of the debugging interface it provides, in order to insure that yaOBC.bin is actually saved.  (More on this later.)  However, if no such file as yaOBC.bin exists, it instead requires a replacement file—generally created by yaASM, since both programs use the same file format—to be specified by means of its OPTIONS.

The presently-accepted OPTIONS are:

--help
Displays the available OPTIONS and exits.

-v
Increases the verbosity of messages displayed by yaOBC.  Multiple -v switches can be used.  At present, the maximum verbosity that has any observable effect is "-v -v -v -v -v -v".

--binary=Filename
This specifies the name of a binary file containing the complete contents of memory/ATM at startup, along with the starting value of the HOP constant.  Typically, this file would be created by yaASM, but it could be a snapshot of the OBC system status created earlier by yaOBC as well.  If present, it overrides the default yaOBC.bin file.

--symbols=Filename
This is the name of a listing file produced by yaASM.  If this option is used, then it gives yaOBC knowledge of the source code and symbol table associated with the OBC binary being used, and allows symbolic debugging of the OBC program ... i.e., it allows memory to be inspected or modified by variable/constant name rather than just addresses, allows breakpoints to be put at left-hand symbols rather than just addresses, allows source code to be displayed when single-stepping or reaching a breakpoint (merely than being disassembled from the contents of memory), and so on.

--run
By default, yaOBC starts in a paused state at the starting HOP constant specified by the input binary file.  In other words, by default, no OBC instruction will be executed until explicitly commanded via the debugging interface.  If the --run switch is used, it instead causes OBC program execution to begin in real time without further intervention.

--ports=Port
Specifies the port number of a network socket by which additional emulation programs such as yaPanel can connect to the CPU emulation and interact with it.  By default, we use "--port=19653" ... because the first Gemini mission was in March 1965 (in case you wondered).  Because network sockets are used, peripheral-emulating programs such as yaPanel can reside on entirely different computers from the one running yaOBC, as long as there's a network connection between them.

--method=Peripheral,Driver
This switch relates to the method by which emulated or physical peripheral devices connect to the emulated CPU. In essence, it allows different types of device drivers to be used for different XY ranges for the PRO and CLD instructions of the CPU.  The Peripheral field selects the XY range by the designator of a specific peripheral device, as follows:
The Driver field specifies the the data-transport method for the XY ranges associated with Peripheral, as follows:
The default is "--method=ALL,MEM".  Note that regardless of the driver type, all PRO/CLD ends up in the memory array, so all drivers ultimately build atop the MEM driver.

--io=Filename
When the MEM driver (see --method above) is used, the dedicated memory area used for emulating the PRO/CLD instructions defaults to being all zeroes at startup, or else is populated with values from the preceding run of yaOBC.  It's possible instead to load that area with different values using the --io switch.  Filename represents a simple ASCII file that can be created in any text editor.  The file has 128 lines, each of which is of the form "PRO yx value" or "CLD yx value".  The first 64 lines are for PRO and the last 64 are for CLD. Each of the two areas is in YX order: 00, 01, 02, ..., 77.  So while it may appear that you can rearrange the lines of the file however you like, you actually cannot: the "PRO yx" and "CLD yx" portions of the lines are present simply to make it easier for you to know which value is which, but cannot actually be changed and only the value fields should be edited.  The easiest way to get such a file to edit is to start from the yaOBC.io file of a prior yaOBC run, since such a file is automatically created when yaOBC shuts down.  (This is the file which is loaded, if it exists, at yaOBC startup unless overridden by --io.)  You can also manually create such a file during a yaOBC run via the COREDUMP command debugging interface as described below.

--com1=ComportName, --com2=ComportName, etc.
Optionally used with the --method switch.  The defaults are "--comN=COMN", but those defaults are meaningful only in Windows.  On Linux, the comport names are generally one of the following instead:  /dev/ttyS0, /dev/ttyS1, ..., /dev/ttyUSB0, /dev/ttyUSB1, .....  So in Linux, you'd need switches like "--com1=/dev/ttyS3", "--com2=/dev/ttyUSB1", and so forth, depending on your setup.  I don't know what they're typically called in Mac OS X, but they'd be /dev/something as well.

Debugging Interface of yaOBC

General Information About the yaOBC Debugger
The yaOBC debugging interface is a method of controlling, examining, or altering the emulation process at runtime by entering textual commands from a command-line.  The debugging interface is always present, whether or not you choose to use it.  By default, yaOBC starts in a paused state, so that the emulation won't even start unless you manually start it with (for example), the debugger's RUN command; however, you can override this behavior and start yaOBC in a running state by using its "--run" command-line switch.  If you do the latter, and if there are physical or emulated peripheral devices attached to the the CPU, you never need to use the debugging interface at all.  Conversely, if you have no attached peripheral devices, you can never observe the behavior of the emulation unless you use the debugger.

At startup in a paused state, the yaOBC command line will display something of this nature:

HOP=000100000 (ADR=0-00-2-000 HWM=0 VAL=06400)  ACC=000000000  PQ=000000000 (TMR:0)
Cycles=0 (0.00000 seconds)
0-00-2-000    START    CLA  KZERO                # Get 0 into accumulator
OBC debugger paused>

It may not look exactly like this, but I'll describe some of what's here just to give you the general idea.  The first line shows the values of various CPU registers:
The second line shows the total number of instructions executed so far, and the amount of real time those instructions would have taken.  Realize that yaOBC cannot maintain the exact timing of 140 μsec. of the original OBC, since even though the computer on which it is running is far, far faster than the OBC, it is nevertheless not an embedded system and yaOBC must share resources with other software running on the computer.  So yaOBC merely tries to maintain the same average instruction rate in a manner that's hopefully transparent to the user.  Under normal circumstances, the total time listed by the debugger should correspond closely with the actual real time consumed, except when the emulator is explicitly commanded to run the emulation faster or slower than real time.

The third line shows the source code of the line at which the emulation is currently paused.  This source line is taken from the yaASM listing file, where available, in which case it will be include left-hand symbols, show the operand by name, and show comments.  If the listing file is not available, or the location is somehow absent from the listing file, what will instead be shown is a disassembly of the current location, which in the case of this example would be:

0-00-2-000             CLA  400

Another interesting factoid about source-code lines is that since the complete OBC software consists not only of program modules loaded into main memory, but also program modules residing on the ATM but not yet loaded, the source-code line associated with any given address in memory is ambiguous: several different program modules may use the same addresses for different purposes and associate different source code with them.  Unfortunately, the debugger has no way of knowing which program modules are loaded or are associated with which addresses.  So it tries to match the value stored at the address with the value that each of the program modules think should be stored at that address, and then displays the first source-code line that actually matches.  But this method can still be wrong and the wrong source-code line could be displayed sometimes.  The address printed with the source line will show the module which the debugger thinks the source line is from (for example "1-00-2-000") even though the code is actually being run from main memory ("0-00-2-000") rather than from the ATM directly.

Finally, the fourth line is the debugger's prompt, and which is where commands you input would appear.  If yaOBC starting in a running state instead of a paused state, you'd have only this prompt, and wouldn't have any of the other three lines.  (By the way, any user input to the debugger discards anything from an '#'  character to the end of the line.  This isn't of much interest under normal circumstances, but can be useful if input is piped into the debugger from the command line from a prewritten script, since it allows the addition of comments to such scripts.)

When the emulation is in a running state, any command (legal or illegal, or even just hitting the Enter key) at the debugger prompt will pause the emulation.  The emulation remains paused until commanded otherwise.
Commands Recognised by the yaOBC Debugger
The commands which can be entered at the prompt are the following.  Items in brackets (like so: [Stuff]) are optional.  The commands themselves are not case-sensitive.
Notice that while no way is provided to directly do something like jump to a given location and begin executing there, you can indirectly achieve that by doing things such as "EDIT HOP ExistingLeftHandSymbol" and then "RUN".
Treatment of Program Modules by the Debugger
The assembler, yaASM, expects to assemble a complete set of program modules as a single operation, and hence the binary file loaded by yaOBC contains not only the contents of main memory but also the contents of all program modules on the ATM but not yet loaded into main memory.  This is why the debugger treats full addresses as being of the form "Module-Sector-Syllable-Word".  A numbering system is used in which Module=0 corresponds to Program Module I, Module=1 corresponds to Program Module II, and so on.

However, this idealized numbering scheme pertains only to the situation immediately after assembly and before any ATM modules have been loaded into main memory, because the debugger really interprets Module=0 as being "the contents of main memory" and not merely as Program Module I.  Therefore, as time progresses and various program modules are loaded from ATM into main memory, Module=0 becomes a mashup of not only Program Module I, but also a lot of other program modules as well.  However, Module=1-7 will always continue to be the pure contents of ATM.
Location-Field Parsing by the Debugger
Several of the debugger's commands (BREAK, DELETE, PRINT, EDIT) have a Location field that represents a location at which an operation is supposed to be performed.  For simplicity, the debugger uses the same parser for this field in all cases, whether or not all possibilities necessarily make sense for all commands.  The Location field can be any of the following:

Communications Protocol for yaOBC

If, perchance, you are familiar with the socket protocol use for Apollo-related software provided by the VirtualAGC project, such as yaAGC, yaAGS, yaDSKY, etc., you'll find the protocol and external tools used for the Gemini-related software very different.  There's no particular reason for this, other than present convenience for me, though the new method does have some points in its favor as compared to the old. 

As mentioned above, yaOBC supports both network sockets or comports (RS-232, USB) for connecting the emulated CPU to emulated or physical peripherals.  The protocol I envisage is basically the same in either case, and is as follows:
For example:  Part of the process of downlinking telemetry data is outputting a data word via "PRO 10" to the Instrumentation System (IS).  For the sake of argument, we'll suppose that the word in the accumulator is octal 123454321, and that the PRO instruction will be the 666'th instruction executed.  The message emitted by the CPU is "P10 123454321 666".

The optional usage of the enetHost program is very simple:  To start a server, do "enetHost --server"; only one server can be running on any given port, so if yaOBC or another instance of enetHost is running on the same port, this operation will fail.  To start a client, just "enetHost" (or "enetHost --client", if you prefer).  Up to 32 clients can connect to one server, as presently configured.  The switch "--port=PortNum" can be used to select a port other than the default 19653.  Message data which is supposed to be sent is accepted on stdin, without any supplemental data.  Received-message data is output on stdout, accompanied by some helpful information:
Additional information of a less-useful nature, like information on connects and disconnects, user prompts, and so on, is output on stderr.  In theory, one could construct a Gemini peripheral emulator from a language with no bindings for the enet library, such Tcl/Tk or some other interpreted language, by using enetHost as a backend and redirecting/interpreting stdin/stdout/stderr appropriately.

yaASM, the OBC Cross-Assembler

yaASM has been discussed above quite a bit, but a few unexplored details remain.  This program is presently functional for OBC, though not necessarily debugged or tested.

yaASM is an assembler for Gemini OBC assembly language files, outputting a binary executable suitable for being used with yaOBC simulation software.  The assembly language for OBC is as defined above.

By convention, but not by any requirement of the assembler, Gemini OBC source-code files have the filename extension .obc.  This convention arises from the existence (or potential existence) of CPU-specific syntax highlighters when viewing such source code.  The assembler does not care what the filename extensions are.

Note that at present, yaASM simply aborts with an error message upon the first source-code error it detects.  I personally don't like that behavior—I'd like to get a complete list of all errors—but I may or may not be too lazy to ever change it.

The command-line syntax for yaASM is as follows

yaASM [OPTIONS] --input=SourceFilename >OutputListing

The assembled executable binary is always put into a file called yaASM.bin.

The presently-defined OPTIONS are:

--help
Displays the available OPTIONS and exits.

--hwm
Equivalent to putting the directive HALF at the top of the input source file to set half-word mode.  The default is NORM to set normal mode instead.  The --hwm switch (or lack thereof) can be overridden by the directives within the source file itself.

--code=M-PP-S-WWW
Equivalent to putting the directive "CODE M-PP-S-WWW" at the top of the input source file.  The default for OBC is "CODE 0-00-2-000".  Can be overridden by the directives within the source file itself.

--data=M-PP-S-WWW
Equivalent to putting the directive "DATA M-PP-S-WWW" at the top of the input source file.  The default for OBC is "DATA 0-00-0-000".  Can be overridden by the directives within the source file itself.

The format of the binary output file is as follows:
There's no attempt by the assembler to make this binary file portable to other computers, so if you assemble such a binary file on a computer with a little-endian format (such as so-called 'x86 CPUs have) and try to emulate it on a computer with a big-endian format (such as PowerPC), or vice-versa, you will find that it doesn't work.  However, if you stay within the 'x86 family of computers, there should be no problem passing such files around among Linux, Windows, and Mac OS X computers at will.

yaPanel, the Control Panel Emulation

Unlike the Apollo spacecraft (plural), the Gemini spacecraft had a simple enough control panel that it makes sense to simulate the complete control panel on a single computer screen.  Of course, since we won't simulate all of the Gemini peripherals, many of the controls and readouts won't be functional.  Recall that the MDIU comprises the MDR readout unit and the MDK keypad unit, as seen in the photo at right, to provide a simple display and keypad interface to the OBC. 

yaPanel
software would provide a simulated MDIU interface to the yaOBC simulated-OBC software ... if yaPanel existed.  Right now, it's merely a fairly-distant gleam in my eye.

Operation of the OBC via the MDIU follows a simple set of conventions, as follows:
Control of the OBC via the MDIU is very similar to control of the Apollo AGS via its DEDA.  Here are the operations which can be performed by the astronaut using the MDIU:
The relationship of the "addresses" 1-99 to actual physical memory addresses is TBD.  (There is no reason logically why they can't map to any 99 memory locations.  However, for efficiency of coding, it's reasonable to suppose that they were actually contiguous.  It's also reasonable to suppose that they resided in the residual sector, so that they could be immediately accessed by code in any memory sector.)

As another example, yaPanel would provide a simulated Pilots' Control and Display Panel (PCDP).  The additional controls provided by the PCDP are:


Then too, consider the Incremental Velocity Indicator (IVI) from the command-pilot's control panel, as depicted at right.  The IVI has a set of three 3-digital displays that show the current velocity of the spacecraft relative to a previously-set zero reference.  (It can also be used to show data related to the Auxiliary Tape Memory, if any.)  The OBC sends pulses to the IVI that increment or decrement the displays whenever the velocity changes.
  1. Forward-direction indication lamp.  When lit, indicates that the delta-V value shown on the forward-aft display device (2) is in the forward direction.
  2. Forward-aft display device.  Displays the magnitude of the forward or aft delta-V from the previously-set zero point, in ft./sec.
  3. Left-direction indication lamp.  When lit, indicates that the delta-V value shown on the left-right display device (4) is in the left direction.
  4. Left-right display device.  Displays the magnitude of the leftward or rightward delta-V from the previously-set zero point, in ft./sec.
  5. Right-direction indication lamp.  When lit, indicates that the delta-V value shown on the left-right display device (4) is in the right direction.
  6. Up-down display device.  Displays the magnitude of the upward or downward delta-V from the previously-set zero point, in ft./sec.
  7. Up-direction indication lamp.  When lit, indicates that the delta-V value shown on the up-down display device (6) is in the up direction.
  8. Down-direction indication lamp.  When lit, indicates that the delta-V value shown on the up-down display device (6) is in the down direction.
  9. Down-up rotary switch.  Can be used to manually zero or otherwise adjust the up-down display device (6).  Spring-loaded to return to the neutral position.
  10. Left-right rotary switch. Can be used to manually zero or otherwise adjust the left-right display device (4).  Spring-loaded to return to the neutral position.
  11. Aft-forward rotary switch. Can be used to manually zero or otherwise adjust the forward-aft display device (2).  Spring-loaded to return to the neutral position.
  12. Aft-direction indication lamp.  When lit, indicates that the delta-V value shown on the forward-aft display device (2) is in the aft direction.
yaPanel also provides some simulated control-panel indicators related to the Time Reference System (TRS), which relate to passage of real time rather than being controlled by the OBC.  These displays include three separate clocks and a stop-watch function.  We don't provide a simulated TRS as such, but yaPanel is obviously aware of the passage of real time, and consequently it can provide these simulations itself.  The operation of these simulated devices should be pretty self-explanatory.



Plea for Data

As you will have noted if you've read this far, there are some pretty serious gaps in the publicly-accessible data about the Gemini computer and its software.  If you know where to find any more information, please tell me about it.  Examples of some of the things that would be interesting to have include:
Another interesting possibility is to locate a tape from the Gemini Aux Tape Unit.  Since the Aux Tape Unit was used to load software for some mission phases in flight, it is possible such a tape could still hold actual executable OBC software.

Reminiscences and Factoids from the Original Developers

In this section, I provide distilled/edited material from personal correspondence I've had (directly or indirectly) with original OBC developers.  The following are thus not direct quotes, and you should attribute errors to me rather than to my correspondents.

From Eugene Mertz:

I worked on the Gemini project at IBM in Owego, NY, and Bethesda, MD, from about 1962 through 1968, basically from the beginning to the end of the project, and was responsible for the in-orbit software applications of the onboard computer system.  The Gemini software team was organized by function (ascent, rendezvous and in-orbit navigation, and reentry).  My responsibilities encompassed the rendezvous and in-orbit, autonomous navigation functions.  Our rendezvous group consisted of five people:  two analysts, two simulation programmers, and one on-board computer programmer.  The other groups were similarly organized.

Many things were new in the 50s, 60s and 70s.  In the late 50s, I participated in a panel discussion on local TV to explain to the public what space, satellites, Sputnik, Vanguard, etc., were all about.  Looking back on that experience, I believe it was done to alleviate small-town public fear that something bad was about to happen soon.  I'm not sure we succeeded.

The transcendental equations of relative motion between the Gemini spacecraft and its target vehicle included a series expansion of the Earth's gravitational field (without the South Atlantic Anomaly).

The transcendental equations were written by an IBM engineer, Connie McClure, who was a professor formerly at GW University (I believe) in Washington, DC.  He also taught orbital mechanics to the team very early in the project.  It was a tough course.  I wish I had kept all his notes.  The series expansion was verified and derived by a number of analysts at IBM, other contractors and sub-contractors, and probably NASA.  As I recall, the values of the constants were determined by tracking satellites that were already in orbit.  The constants were to change from time to time but finally settled down to those selected in the OBC.  All equations were checked and re-checked by project members several times to be sure they were accurate.  Some equations were adapted to the in-orbit Autonomous Navigation function.  Many computer hours were expended on IBM mainframes (7090/7094) simulating all mission aspects to "man-rate" the Gemini system.

Our mainframe Fortran simulator had a converter that allowed plugging in the actual Gemini flight code to replace the Fortran version in the 7094 simulation.  This, of course, was used to check the actual flight code for closed-loop timing or other problems.  A Mylar punched tape was used to load the Gemini computer memory itself (except for the programs that were stored on the Auxiliary Tape Unit) prior to launch.  I recall a situation where the tape reader was lifted up the outside of the launch tower, connected to the Gemini computer (which was already installed in the spacecraft), and a program fix loaded to correct a radar hardware problem.  This would NEVER be done today!

We started out with FORTRAN II running on the 7090, but when our computer was upgraded to the 7094, I believe we quickly switched to FORTRAN IV.  IBM was never shy when they pushed for adopting standards.  After all, if their version of the standards was adopted, they had a foot in the door.  The switch from FORTRAN II to FORTRAN IV occurred, but it could have been as early as 1963-64, in time for Gemini 7/6.  Our facility was always on the forefront of technology.  I don't recall the exact date of the switchover.  The version used for the catch-up and rendezvous simulation program could have been FORTRAN II.  The key is whether or not there are no "machine-dependent features" included in the listing.  I can't tell for sure.  I know we used punched cards for loading the program, a 1401/1403 for printing, and a special plotter on the "other side of the wall" to show relative trajectories.  Wow!  What power. [Ed.: There are machine-dependent features, it seems, so the program must either have been FORTRAN II or a mix of II and IV.]

The 7094 rendezvous simulator could also accept telemetry data to drive the guidance in open-loop fashion (post flight) to show what really (?) happened during the mission.  Closed-loop computer control in flight proved to be the most efficient mode (only 5% above maneuvering fuel plan). 

Here are a few tidbits which I believe are accurate:

  • A translator was used to generate the flight computer code which was then punched into wide (2-inch?) Mylar tape for use in a memory loader.  But I don't recall exactly what the translator encompassed.  Perhaps someone else will come forward with clarification.
  • A lot of coordinate system transformations were performed, especially during rendezvous.
  • Changing the flight software required a big shoehorn.  Installing a code change might have meant using 300 memory locations.  Subsequently removing the change would save only 200.
I'm beginning to learn things about the Gemini memory I wish I had known in the 1960s.  For example, after many divide instructions were executed in a row (I don't know how many), the memory cores heated up and you would get the wrong answer in the accumulator.  This problem was controlled by inserting a no-op instruction between the divides, thus keeping the cores cool enough to always give the right answer.  Wow!  If I had known this, maybe I would have structured the guidance equations differently.  But we had smart OBC programmers who could figure out ways to get around hardware problems, both in the OBC and in external equipment (such as the on-board radar).  There were lots of lessons learned in the early days of space flight.  And there wasn't much time to spend figuring out how to fix problems.

The MARS [type of memory element used] inventor was probably Al Vinal I recall the core device as being called Multi-Aperture Reluctance Switch.Making the MARS devices was an art, not a science.  They were made using an "aspirin press" and fired in an oven, a tray at a time.

The OBC code listings were run through a detailed manual check by a team of OBC programmers and hardware experts, instruction by instruction.  All team members had to agree 100%. 

I recall (?) there was a processing module that used input from OBC compiled instructions and created a punched Mylar output tape.  This tape was run on the memory loader [6' x 19" rack of equipment!] to program the OBC.


(On finding a memo describing the three-term gravitational potential function describing the oblate Earth while looking for material for this website.)It surprised me to find the equation. Three
terms were used for the rendezvous mode, two terms used for the orbital navigation mode, and up to six terms were used for the "environment"simulation and accuracy comparisons. Obviously (?), the OBC couldn't handle six terms along with everything else in memory, or the speed required. We needed the power of a modern TV remote.
:-)   

(On the subject of recreating the complete OBC assembly-language source code from Math Flow diagrams.)
Charlie Leist, Alden Minnick, and I discussed the possibility of recreating the complete reentry and rendezvous modules but, as a group, rejected the idea because the effort to do so would have been too great.  Instead, Alden and Charlie each chose a section of code they felt comfortable (?) coding.  Comfort was relative because neither was sure he could recall all the details.  A lot of reading of the programming manual and discussion was necessary to recall what it all meant.  That's why it took so long to complete the snippets.  Further, the I/O other subroutines were missing.  They would have had to be "reinvented."  We just had the names of the subroutines, not the actual code.


Consider this \96 the OBC was the first attempt (to my knowledge) by the company to develop a digital computer to fly men into space.  The memory device, the same as was used in OAO, was designed basically for collection of data from the telescope, storing it until it could be sent via telemetry to a ground station.  No real computer involved — until Gemini.

I met Wally Schirra in Washington, DC, almost 25 years to the day after the historic first rendezvous on December 16, 1965.  I recall his words, "I remember you."  The mission was Gemini 7/6.

The photos below have nothing to do with Gemini.  They depict a Vanguard tracking station using a MiniTrack Mark II installation.  I am the middle figure, and to the left and right are L. Passage and K. Watson, respectively.  To my knowledge, they were not involved in Gemini.  The right-hand photo shows a partially completed half of the antenna, which consisted of two 8-dipole arrays spaced 500 feet apart.  It was all, including frequency converters, etc., constructed by hand by volunteers.  Yes, that is snow on the ground. The photos were taken about four years prior to the Gemini project (following the first successful launch of Vanguard 1 on March 17, 1958).  We worked together on some terrestrial projects in the 1950s.  Many of us were members of the radio club, K2ERQ, and we tracked sightings for Echo (100-foot Mylar balloon) and other satellites.  The tracking program was written in FORTRAN by unknown persons at Brown University.  We ran the program on an IBM 650 computer (drum machine, probably FORTRAN I).  I believe the club's interest in satellite tracking and space in general announced that the company was ready, willing, and able to enter the space development.  At least, we believe so (according to club lore).

Gene and friends at Vanguard tracking
                              station
Partially-completed antenna for the
                              tracking station.


From Charlie Leist:
The ATM magnetic tape was 550 feet long and about 1 inch wide. The magnetic tape was loaded using test equipment run in the IBM Owego test lab that read a 2000 ft mylar tape with punched holes that contained the memory load information for each program module. The operational program modules had to be placed on the magnetic tape twice in sequence just in case there was a malfunction in loading a program module. The second half of the magnetic tape contained the same memory load information as the first half of the tape. The tape header for each program module was unique so there would be no confusion on what program module to load into the Gemini computer memory.

It was my job to generate the 2000 ft punch tape after each module programmer had tested and peer code inspected their operational program module. I do not remember ever having to change a magnetic tape from wear or breakage on a tape unit for any of the flight programs in the test lab. This tape unit was sealed and the magnetic tape not easily changed.

The peer code inspection included a scheduled meeting in a conference with the appropriate system engineers and operational programmers.

The inspection process included the following reviews:
  1. A comparison of every block on a system math flow diagram (developed by the system engineer) with every corresponding block on a detailed math flow diagram (developed by a programmer).
  2. A comparison of every program instruction (assembly listing generated on the IBM 7090 computer by the programmer) with every block on the detail flow diagram.
When no errors were found the program module was deemed ready for flight by the inspection team of system engineers and programmers.

This process took several days and was always successful since to my knowledge no flight operational program problems were ever reported.

The time to generate a 2000 ft punch tape took several hours and I spent many long nights in the 7090 computer room being sure that no problems occurred in the hole punching equipment.

I have often wondered how IBM assembled this team of dedicated Gemini people that came together and did so many creative things.

On no-operation (NOP), memory overheating when the wrong instruction sequence is used, and waiting for multiplications or divisions to complete:
I will give you an example of coding to prevent overheating of memory. Lets say the equations required the programmer to make 3 divides in a row ( A=B/C, D=E/F, G=H/I). Conceptually, it would be programmed as:
 
CLA    B    Load the accumulator
DIV    C    Start the division
SPQ    A    Save the computed quotient
NOP         NOP did not use any memory locations and thus would not heat up the memory.
CLA    E
DIV    F
SPQ    D
NOP         Again no heat up of the memory
CLA    H
DIV    I
SPQ    G
NOP         Again no heat of the memory
 
You could do as many divides in a row as you wanted as long as you put the NOP instruction after the SPQ instruction. Those extra NOPs kept the memory from heating up.
 
Now, the real interesting thing about the DIVide instruction is that the answer was only available to the memory location specified by the SPQ instruction after 4 instructions were executed after the DIV instruction.  So the code snippet above wouldn't actually have worked.  The example was really programmed as below:
 
CLA    B
DIV    C
NOP
NOP
NOP
SPQ    A
NOP          Cool memory
CLA    E
DIV    F
NOP
NOP
NOP 
SPQ    D
NOP          Cool Memory
CLA    H
DIV    I
NOP
NOP
NOP
SPQ    G
NOP          Cool memory
 
Later on in the Gemini Program, Jim Condell noticed that the 3 NOP instructions between the DIV and SPQ were not doing any useful work and asked Pat Mooney if we the programmers could use them for something other than NOPs. Pat checked with the Computer designers and they said YES! This was an Atta Boy for Jim on memory use saving!!

On scaling of numerical values during calculations:  Scaling is something the programmer did by hand calculations. You got no help from the assembler on this topic. Fixed point scaling of numbers in Gemini made the programmer always, always, always remember where the decimal point and binary point was at ALL times. Scaling was a most difficult task in Gemini programming.

The assembler read and processed one 80 column punch card (from the punch card deck) at a time that card contained (Left Hand Symbol, operation instruction, instruction address, and comment preceded by a # sign). There was not a second card that contained more information for a single 80 column card just read by the assembler.
 
The assembler provided a lot of pre and post processed tables before and after the coded program was assigned the binary 39 bit code for each instruction.
 
A program listing generated by the assembler for Re-entry and Ascent (just examples) would be about 3 inches thick  each and contained: Pre and Post processed tables for Constants, Variables, Constants and Left hand symbols ( I showed this in my code Snippets)
 
A symbolic card deck (punched from a key punch machine) for either of these programs would contain a complete box of IBM cards for each program (80 columns per card);
 
On power up of the Gemini Computer the first instruction executed would always start at 00-0-00 (sector zero, instruction zero and address zero).
 
In my Gemini Re-entry mode and Touch Predict mode coding in the Sixties (1962 to 1966), I did not hardly ever use comments and probably is why I did use the # in front my Comments in the code Snippets. This was added programming work in key punching and I did see the value added comments. On the other hand, Al was an excellent programmer and used many comments for one to use in following his coding techniques and the use of many Temp01, 02, 03, 04, 05 and 06 variables!! When I was reviewing Al's code Snippets it took me 2 1/2 hour for just one pass through the code!

(On Don O'Neill, the OBC assembler guru.) When we (the less than 10 OBC programmers) were working coding the operational programs in Owego you could always count on Don stopping by your desk at any time with Assembler in hand. He would stay as long as he thought necessary to be sure you knew another part of the Assembler and its interface with the Gemini Simulator. He told us it was necessary to know every part of the Assembler and how it worked. He said we would be better programmers if we knew how every part of the Assembler operated on your code!!

From Dick Fisher:
The OAO Program, the Gemini computer, and the Apollo Program were such exciting space ventures that you had to feel privileged to be working on them.  I have never been on a program again like Apollo where you were working with so many other companies and you were cheering them on for their successes.

I joined IBM in Harry Branning's Dept. in 1956.  Al Vinal was there working on the MARS device.  I didn't have much to do with him then as I was in the digital circuits group under Bob Hildenbrandt.  Bob had left for Glendale [an IBM lab located near Endicott, NY] by 1960 when we bid on the OAO so I was the senior circuits guy then in that dept.  The OAO was to last a year in orbit and there was no technology with that kind of reliability.  Bob Urquhart and I came up with a new circuit technology we called quad-redundancy.  Grumman won the spacecraft contract but NASA made them take our design for the memory system instead of Westinghouse, who had bid the memory system with Grumman and made Radiation Inc. (who won the communications part) use our design concept. After I finished the digital circuits design Harry put me on the design of all the memory circuits for Al Vinal.  The last time I had checked on the status of the OAO in orbit, it was still performing after three years.  I used that same design concept on the switch selector for the Saturn Launch Vehicle in Huntsville as the switch selector had to have the highest reliability as there were four of those boxes on each rocket, one for the Instrument Unit and one in each of the three stages of propulsion and all commands for gimballing of the engines for control of the rocket and for stage separation and ignition of the next stage from the control computer were sent thru the switch selector.  IBM got about a 5 million dollar contract from that and I got an OCA.  I had often wondered where Al Vinal was and what he was doing since the Gemini program.  Its hard to believe he's been dead for the past 16 years [as of 2011] and he died so young.   I think the last I had heard of him he and Connie something were working on a new theory of relativity.  He was a very bright guy and very patient to work with as I knew nothing of the MARS devices when I first started working with him.

From Don O'Neill:
(In response to "How much programming could you do with 16 instructions and 39 bits?")  As much as a Turing Machine and more! Limits were imposed only by the lack of an interrupt mechanism, sector addressability, the lack of floating point, and 25-bit plus sign precision. Some may recall when Jim Joachim demanded an interrupt mechanism and the shoe banging imitating the Nikita Kruschev action at the UN.

(On the question of "left-hand symbols" vs. "labels" for naming lines of code.) 
Left-hand symbols were used for navigation through the code. Variables and constants were named. Left-hand symbols, variable symbol, and constant symbols (preceded with a K signifying a constant that was not to stored into memory altered) might be called labels, but the term label was not used at the time.

Overall the contemporary criteria for coding standard of excellence can be found in the Software Inspections checklists I have sent you.  [The checklists mentioned were ones Don developed while working on SEI at CMU; I don't care to reproduce them here, but if you're familiar with SEI you'll get the idea.]  Ron, you might want to conduct a software inspection on one of your procedures [alas! so wise and yet so wrong!] to see how you stack up against the standard of excellence or to see how the standard of excellence stacks up as an actual quality threshold.

(On the question of very limited use of subroutines in OBC code.)
I do not recall a subroutine mechanism. A number of people on the Gemini Project worked on the XB70 bombing and navigation computer, a drum computer whose instructions were read and executed from a rotating drum so there was no subroutine mechanism possible. In addition, the slavish attention to the Math Flow, literally a flow chart, reinforced linear, sequential thinking. This was reinforced by the fact that there was no interrupt on the Gemini computer. All this was literally a deterministic state machine.

From Pat Mooney:
(In response to being presented by Charlie Leist and Jim Condellwho had worked for himwith the Gemini Programming Manual in 2011, rather than the 1960's when it was written.) "Charlie and Jim, I told you two guys to write this manual and to bring it back to me for comment and sign off. I always wondered why you did not follow my direction and how did you get it out of Owego with out my signature? ... Charlie, I am going to review this document, make comments and sign off on it. I expect you fix the errors I find!!"

From various unidentified team members:
The memory element was a non-destructive readout (NDRO) device invented for use in the Orbiting Astronomical Observatory (OAO).  The design was based on the Multi-Aperture Readout Sensing (MARS) principle.  The MARS device principal used a two-hole core (as opposed to single-hole "donut" then commonly used in memory designs).  The new principle was based on sensing the logical state of a core at one of the holes, and restoring the state by electrically pulsing the second hole (ed. that's my limited understanding) thus achieving the equivalent of non-destructive readout -- a critical requirement for space applications.

The 7090 had a fixed point add, subtract, etc.  So, one could program the Gemini OBC equations in assembly language and execute them on the 7090 using a simulator.  But you had to mask off all 7090 bits over 26 to contain the computation to the Gemini OBC 26-bit format.  We did that to check function and accuracy.

Computational step size in the simulation was controlled using 7090 console keys.  A family of results could be run to determine if the Gemini OBC timing was adequate.



Homage

Part of my purpose on this web-page is to pay homage to the original Gemini flight-software developers.  I have little information about them, so if you know things about them, feel free to pass your information to me.   What I do know follows: 




This page is available under the Creative Commons No Rights Reserved License

Last modified by Ronald Burkey on 2023-05-30.

Virtual AGC is hosted
              by ibiblio.org