Home
AGS
LVDC
Gemini
Download
Document library
Change log
Bug and issues
Developer info
Virtual AGC — AGS — LVDC — Gemini

Launch Vehicle Digital Computer (LVDC)
Saturn IB and Saturn V Rockets

FAQ
yaAGC
yaYUL
yaDSKY
yaOtherStuff
Luminary
Colossus
Language Manual
Physical Implementations

Please enable javascript in your browser to see a site-search form here.

Contents

What is the Launch Vehicle Digital Computer (LVDC)?

The Launch Vehicle Digital Computer (LVDC) was a computer that resided in the Instrument Unit (IU) that perched above the Saturn IVB that was the second stage in a Saturn IB rocket and the third stage in a Saturn V rocket.  The LVDC was a completely separate computer system from the AGC, with a different architecture, different instruction-set, and different runtime software.  The purpose of the LVDC was to precisely control the Saturn from shortly before liftoff until the point at which the Saturn was discarded by the CSM. 

Factoid
People generally think that the guidance computer (AGC) of the command module controlled the Saturn rocket, but it isn't true.  During burns of the S-II and S-IVB rocket stages, it was possible for the CSM's AGC to control the steering, as a backup to the LVDC.  This was not possible during burns of the first stage (S-IB or  S-IC).  On the CSM's DSKY, the crew could see a display of various measurements taken by the rocket's sensors.  I don't think the backup capability was ever used in a mission.  Correct me if I'm wrong, please!

The LVDC has a less-visible role in people's eyes than the AGC, not only because it was used for only a very small portion of the individual missions, but also because it had no user interface as such.  In other words, it was a black box that responded to inputs from sensors in the Saturn and to ground telemetry, but there was no panel into which astronauts could enter commands or get feedback from it.  One might well call the LVDC "The Forgotten Computer", even more so that the computer of the LM's Abort Guidance System.  Nevertheless, the LVDC's importance is great, because you need to actually get the Command Module and Lunar Module into space and headed toward the moon if you expect any landings to occur!  As I understand it, the folks that actually worked on the Saturn referred to the Instrument Unit as "The Brain", and that term might as well be applied to the LVDC, since it was the brain of The Brain.







The LVDC was developed by IBM, rather than by the MIT Instrumention Lab that developed the AGC, so there was no overlap in development personnel between the LVDC and AGC systems.  Furthermore, there was almost no overlap in engineering technique, other than that both groups of necessity were generally constrained by the technology available at the time.  For example, both needed to use memory based on ferrite-core technology.  Moreover, there was no interaction between the LVDC and AGC systems.

Actually, there was some interaction between the development groups, in the sense that at some point in 1963 or before the idea arose that the LVDC might be used in place of the AGC in the CM and LM, and that this move might save some time and money.  In fact, IBM produced a 300+ page report detailing the differences between the two systems with the apparent object of arguing this point, and the MIT Instrumentation Labs' autobodies flooded in to destroy the invader with critiques and reports negative of the report.  In the end, the Instrumentation Lab won this particular battle, relegating the LVDC to the relatively small share of public attention that it presently enjoys.



Peripheral Devices

As with any of the other computer systems we cover here at Virtual AGC, the LVDC does not stand alone and do its computing in a computing vacuum (so to speak).  The subsystems involved are:
At the end of the preceding section was an illustration of a very simplified logical view of the interconnection of the LVDC to various peripherals.  Here is a somewat more complete illustration for the Saturn IB:


and for the Saturn V:

LVDC Documentation

Sadly, documentation we've been able to collect for the LVDC lags far behind that of the AGC or even that of the Abort Guidance System.  What little survives that we have been able to access can be found in our Document Library.

Evolution of the Flight Software

No information about any of the following topics has yet been uncovered:
I have received second-hand anecdotal accounts that the flight software was created by "the Germans"—i.e., the German scientists such as Rudolf Drecher and Walter Haeussermann who were engaged in creating the rockets—in the form of a FORTRAN program.  Of course, "the Germans" may simply have directed the coding of the FORTRAN program rather than having done it themselves, but I have no information about who may have coded that FORTRAN program, nor what the program may have been called.  Subsequently, young (American) programmers just out of college were then employed to manually compile the FORTRAN program into the assembly language of the embedded LVDC CPU, and presumably to make whatever other adjustments are needed when you pass from the computing environment of a large computer to a smaller embedded system.

In some sense, the LVDC may be thought of as a descendent of the ASC-15 guidance computer used in the Titan II rocket used for launching Gemini spacecraft into orbit.  However, the ASC-15 was a very different sort of beast than the LVDC.  It was based on magnetic-drum memory rather than an array of ferrite cores.  Since drum memory is designed to be read sequentially, it is not very efficient for software based on it to branch or call subroutines, or to react to conditional tests.  In other words, a drum-based machine is closer to being a sequencer that executes an invariable set of steps in sequence, rather than being a general-purpose computer like the LVDC.

In a deeper sense, the LVDC is a descendent of the onboard computer used in the Gemini spacecraft, which is to say the Gemini equivalent of the AGC.  While the Gemini computer is certainly different than the LVDC, there are striking similarities as well that point to a family resemblance.

Architecture of the LVDC

References

Unlike the AGC or AGS/AEA, there is no single document or couple of documents that pull together the complete details of how the LVDC operates.  Therefore, the information in this section is pieced together from a variety of documents in our document library, none of which were originally intended as documentation for developers, as follows:
  1. 1 October 1963:  Apollo Study Report, Volume II, which was part of IBM's feasibility study for using the LVDC in place of the AGC in the LM and CM.
  2. 31 October 1963:  IBM's Saturn V Guidance Computer, Semiannual Progress Report.
  3. 30 November 1964:  Laboratory Maintenance Instructions: Saturn V Launch Vehicle Digital Computer, Simplex Models, Volume I: General Description and Theory.  This is IBM's documentation for the LVDC "breadboard model II" system.  (I'm not presently aware of any existing documentation of the production "TMR" LVDC.)  Cross-checking was done against the IBM documents titled, and   The documents aren't 100% consistent, though they are very close, so I've had to use my imagination in places; where there are discrepancies, the former document wins, since it is approximately a year later than the latter documents.
  4. 1 February 1966:  "The Astrionics System of Saturn Launch Vehicles" by Rudolf Decher.
  5. 1 November 1968:  Astrionic System Handbook, Saturn Launch Vehicles, chapters 11 and 15.
  6. 1 November 1968:  Saturn Flight Manual, SA-503, chapter VII, particularly data on interrupts and i/o.
  7. 30 September 1972:  Skylab Saturn IB Flight Manual, chapter VI, again for data on interrupts and i/o.
Among these, it would be fair to state that reference #3 was used primarily, and the others were used to cross-check or to provide guidance or information missing from reference #3.  (In retrospect, however, I would recommend reference #4 as a better starting point to those readers who don't find my musings amusing.)  Where there were discrepancies between earlier documents and later documents, the later documents were treated as definitive.

General Characteristics of the Computer



The illustration above shows a simplified block diagram of the LVDC.  The device itself was designed and manufactured by IBM.  Mechanically, the LVDC had dimensions of about 29.5"×12.5"×10.5", and weighed about 72.5 pounds.  A number of different power supplies were needed:  +6V, -3V, +12V, and +20V, at roughly 150W. 

However, the LVDC and the Launch Vehicle Data Adapter (LVDA) really operated as a pair, and neither is of use without the other, so in considering the mechanical and electrical characteristics of the LVDC one really needs to include those of those of the LVDA into their thinking.  The LVDA had dimensions of about TBD"×TBD"×TBD", and weighed about 214 pounds.  It's electrical budget was about 320W and it accepted +28V power.  The purpose of the LVDA was basically to intermediate between the LVDC and the remainder of the rocket.

In computer terms, LVDC had the following characteristics:
The CPU had the following additional registers not addressable as normal memory:
There are some memory words in the "residual sector" (see below) that are real memory (unlike 0775), but nevertheless have special purposes and so should be avoided for general usage:
Finally, address 000—I believe, in module 0 sector 0 but am not sure—stores a HOP Register code loaded at reset.

Layout of Memory Words




The illustration above depicts the data organization within a memory word.   For numeric data, there is a sign bit (designated "S" in the illustration), with the bit labeled "1" being the most-significant bit and the bit labeled "25" being the least-significant bit.  For non-numeric data, the bits were designated instead as "1" through "26", with no overlap between the designation of the bits for numeric data.  A very curious system indeed, in modern thinking!

The situation is even curiouser, to paraphrase Alice, when considering instructions stored in the syllables in place of numeric data.  In those cases the bits are interpreted as in the following illustration:


The instruction in Syllable 0 is processed first, and the instruction in Syllable 1 is processed second.  In most cases, the bits labeled OP1-OP4 contain an instruction code and the bits A1-A9 contain an address in the range 0-511 on which the instruction operates.  There are, however, a few instructions in which A9 and/or A8 also form a part of the instruction code, in which case the addressable range is smaller.  Note that bits A1-A9 are neither in consecutive order, nor are they in an order which would be consistent with the ordering of bits in data words.

These oddities in bit-ordering are due to the fact that memory was read serially into the CPU, so the ordering of the bits is optimized to mimic the order in which the CPU needed to use them.

For the purpose of executing instructions, memory is considered as being divided into "sectors" of 256 words each.  Address bits A1-A8 select an offset into a sector, while A9 (known as the "residual bit") selects which sector is being addressed.  When A9 is 0, the currently-selected sector is being addressed, while when A9 is 1 a special sector called the "residual sector" is being addressed.  The "residual sector" is always sector 017 (octal) in the current memory module.  Incidentally, the "residual sector" can only be used for addressing memory, and there's no way to access instructions in it unless it happens to be the currently-selected instruction sector as explained in the paragraph that follows.  In essence, the "residual sector" is good for storing global variables whilst the currently-selected data sector is good for storing local variables.

Memory-sector selection and the "residual sector" become clearer when contemplating the HOP Register mentioned earlier:



The meanings of these fields are probably clear to you, but just in case they are not:
Upon reset, the CPU loads the HOP Register with the value stored at address 000 (presumably in memory module 0 sector 0), and this determines where program execution starts.

Some instructions, of course, do not address memory at all, and in those cases the An bits are not interpreted as addresses. 

CPU Instructions



Mnemonic

A
8

A
9
O
P
4
O
P
3
O
P
2
O
P
1
Timing
(computer
cycles)


Description of the instruction
HOP
X
X
0
0
0
0
2 (?)
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 CDS and TRA.
MPY
X
X
0
0
0
1
1
(results
available after 4)
This is a multiplication instruction.  It multiplies two 24-bit numbers to produce a 26-bit product.  The accumulator provides the address of one operand, and the address embedded in the instruction points to the other operand.  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.  A partial product (24 bits from the addressed memory times the 12 less-significant bits from the accumulator) can be fetched from the P-Q Register (0775 octal) on the 2nd instruction (or more accurately, two computer cycles) following MPY, though there is no need to do so if that value isn't desired by the program.  The full product is available from the accumulator or from the P-Q Register on the 4th instruction (more accurately, 4 computer cycles) following MPY.  However, the result will remain in the P-Q register until the next MPH, MPY, or DIV
SUB
X
X
0
0
1
0
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.
DIV
X
X
0
0
1
1
1
(results
available
after 8)
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 in the P-Q Register (0775 octal) on the 8th instruction (more accurately, 8 computer cycles) following the DIV.  However, the result will remain in the P-Q register until the next MPH, MPY, or DIV.
TNZ
X
X
0
1
0
0
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 offset within the currently selected 256-word instruction sector, while bit A9 gives the syllable number within that word.   The "residual sector" cannot be accessed.  See also TMI.
MPH
X
X
0
1
0
1
5
This is a multiplication instruction.  It is exactly like MPY except that the program "holds" until the multiplication is complete, so that the product is available from the accumulator or from the P-Q Register at the next instruction following MPY.  However, the result will remain in the P-Q register until the next MPH, MPY, or DIV.
AND
X
X
0
1
1
0
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".
ADD
X
X
0
1
1
1
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".
TRA
X
X
1
0
0
0
1
This is an unconditional jump instruction, which branches to the address embedded in the instruction.  Bits A1-A8 of the embedded address represent the new offset within the currently selected 256-word instruction sector, while bit A9 gives the syllable number within that word.   The "residual sector" cannot be accessed.
XOR
X
X
1
0
0
1
1
Logically exclusive-ORs 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".
PIO
X
X
1
0
1
0
1
Reads or writes an i/o port.    Bits A1-A9 select the source and destination of the i/o.   A table of the i/o ports vs. addresses is given in the following section.
STO
X
X
1
0
1
1
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 following addresses are special:
  • 0775 (octal) stores into the Product-Quotient register rather than to normal memory.
  • 0776 (octal) stores the contents of the multiplicand-divisor register (rather than the accumulator) to address 0776.
  • 0777 (octal) stores the contents of the multiplicand-divisor register (rather than the accumulator) to address 0777.
TMI
X
X
1
1
0
0
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-A8 of the embedded address represent the new offset within the currently selected 256-word instruction sector, while bit A9 gives the syllable number within that word.   The "residual sector" cannot be accessed.  See also TNZ.
RSU
X
X
1
1
0
1
1
Same as SUB, except that the order of the operands in the subtraction is reversed.
CDS
X
0
1
1
1
0
1
Change the currently-selected 256-word data sector.  For this instruction, A9 forms a part of the instruction itself, so only A1-A8 are significant.  The partially overwrite the HOP Register as follows:



See also HOP.
SHF
0
1
1
1
1
0
1
Performs a logical shift operation on the accumulator.  For this instruction, bits A8 and A9 form a part of the instruction itself, but of the remaining bits only A1, A2, A5, and A6 are actually used, as follows:

A1
A2
A5
A6
Description of operation
0
0
0
0
Clears the accumulator
1
0
0
0
Shift one position towards in the less-significant direction
0
1
0
0
Shift two positions towards in the less-significant direction
0
0
1
0
Shift one position towards in the more-significant direction
0
0
0
1
Shift two positions towards in the more-significant direction

EXM
1
1
1
1
1
0
1 + cycles needed for target instruction (?)
"Execute modified".  This instruction takes an instruction stored at a specified memory location, forms a modified A1-A9 field for that instruction, executes that instruction, and then continues with the next instruction following the EXM (unless the program counter has been modified).  For this instruction, A8 and A9 form a part of the instruction code, so only A1-A7 are significant.  Only 4 different target words are allowed, 0600, 0640, 0700, and 0740, and they are all in the "residual sector".  Many of the bits in A1-A7 represent various types of modifications to the embedded address at the target address rather than being address bits themselves.   Here are the interpretations of bits A1-A7 in the EXM instruction:
  • A1-A4 modify the address embedded in the target instruction as described below.
  • A5 indicates the syllable in which the target instruction resides.
  • A7,A6 selects the target address, as follows:
    • 0,0 for target address 0600
    • 0,1 for target address 0640
    • 1,0 for target address 0700
    • 1,1 for target address 0740
When the target instruction is executed, its A1-A9 bits are formed as follows:

  • A1-A2 come from A1-A2 of the EXM instruction.
  • A3 is the logical OR of the A3 of the target instruction and A3 of the EXM instruction.
  • A4 is the logical OR of the A4 of the target instruction and A4 of the EXM instruction.
  • A5-A8 come from A5-A8 of the target instruction.
The data sector used when the target instruction is executed is also changed for the duration of that one instruction, as determined by bits A1, A2, and A9 of the unmodified target instruction, as follows:

A2
A1
A9
Data Sector
0
0
0
004
0
0
1
014
0
1
0
005
0
1
1
015
1
0
0
006
1
0
1
016
1
1
0
007
1
1
1
017 ("residual" sector)

In baseball terms, this is the "infield fly rule" of the LVDC: it clearly does something, but it's hard to grasp exactly what it does.
CLA
X
X
1
1
1
1
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".

I/O Ports (For PIO Instruction)

I don't really know yet what all these i/o ports do, but I'll post additional info here when I have it.  In general, i/o ports are defined in LVDA, IU, or Saturn documentation rather than in LVDC-specific documentation.

Address Field from PIO Instruction
Data Source
Data Destination
Purpose of the i/o port
Comments
A9
A8
A7
A6
A5
A4
A3
A2
A1
X
0
B
B
B
B
B
0
X
Accumulator Register
Telemetry Register BBBBB (?)

For all of these operations, it is also possible to use main memory or residual memory as the Data Source.  For main memory, use A9,A8=0,1 and for residual memory use A9,A8=1,1.

The selection of the specific address offset within memory of the Data Source word in this case is TBD.
X 0
0
0
0
0
1
1
0
Accumulator Register
Mode Register

X 0
0
0
0
1
0
1
0
Accumulator Register Discrete Output Register (Reset)

X 0
0
0
0
1
1
1
0
Accumulator Register Discrete Output Register (Set)

X 0
0
0
1
0
0
1
0
Accumulator Register Internal Control Register (Set)

X 0
0
0
1
0
1
1
0
Accumulator Register Internal Control Register (Reset)

X 0
0
0
1
1
0
1
0
Accumulator Register Interrupt Register Reset

X 0
0
0
1
1
1
1
0
Accumulator Register Switch Selector Register (Load)
This register is used by the the LVDC to issue commands to specific vehicle devices such as the fuel valve controls.  The register has a 15-bit capacity.
X 0
0
1
0
0
0
1
0
Accumulator Register Orbital Checkout

X 0
0
1
0
1
0
1
0
Accumulator Register Switch Selector & Discrete Output Registers (Read)

X 0
0
1
1
0
0
1
0
Accumulator Register Switch Selector Interrupt Counter

X 0
0
1
1
0
1
1
0
Accumulator Register COD Error (Read)

X 0
0
1
1
1
0
1
0
Accumulator Register Interrupt Inhibit
Interrupts can be programmatically masked or unmasked with PIO to Interrupt Inhibit.  By setting a bit in Interrupt Inhibit corresponding to the interrupt whose masking is desired, that interrupt is thereby masked.  Any combination of bits can be set, so any combination of interrupts can be masked.  To reenable the interrupt, a 0 is written to the corresponding bit in Interrupt Inhibit.
X 0
0
1
1
1
1
1
0
Accumulator Register Minor Loop Timed Interrupt Counter

X 0
1
1
0
0
1
1
0
Accumulator Register Ladder No. 1

X 0
1
1
0
1
0
1
0
Accumulator Register Ladder No. 2

X 0
1
1
0
1
1
1
0
Accumulator Register Ladder No. 3

X 0
1
1
1
0
0
1
0
Accumulator Register Ladder No. 4

X 0
1
1
1
0
1
1
0
Accumulator Register Ladder No. 5

X
0
0
0
1
0
0
1
1
Error Monitor Register
Accumulator Register

X
0
0
1
0
0
0
1
1
Command Receiver or RCA-110
Accumulator Register

X
0
0
1
0
1
0
1
1
Discrete Input Spares
Accumulator Register

X
0
0
1
1
0
1
1
1
Telemetry Scanner
Accumulator Register

X
0
0
1
1
1
1
1
1
Switch Selector
Accumulator Register

X
0
1
0
0
0
0
1
1
Real Time
Accumulator Register

X
0
1
0
0
0
1
1
1
Accelerometer Processor X
Accumulator Register

X
0
1
0
0
1
1
1
1
Accelerometer Processor Z
Accumulator Register

X
0
1
0
1
0
1
1
1
Accelerometer Processor Y
Accumulator Register

X
0
1
0
1
1
1
1
1
Interrupt Storage
Accumulator Register

X
1
0
0
0
0
1
1
1
Spare No. 6
Accumulator Register

X
1
0
0
0
1
1
1
1
Computer COD Counter Start
Accumulator Register

X
1
0
0
1
0
0
1
1
Fine Gimbal No. 1
Accumulator Register

X
1
0
0
1
1
0
1
1
Coarse Gimbal No. 3
Accumulator Register

X
1
0
0
1
1
1
1
1
Computer COD Counter Start
Accumulator Register

X
1
0
1
0
0
0
1
1
Coarse Gimbal No. 1
Accumulator Register

X
1
0
1
0
0
1
1
1
Horizon Seeker No. 1
Accumulator Register

X
1
0
1
0
1
1
1
1
Spare No. 3
Accumulator Register

X
1
0
1
1
1
1
1
1
Spare No. 4
Accumulator Register

X
1
1
0
0
1
0
1
1
Fine Gimbal No. 4
Accumulator Register

X
1
1
0
0
1
1
1
1
Spare No. 1
Accumulator Register

X
1
1
0
1
0
0
1
1
Horizon Seeker No. 3
Accumulator Register

X
1
1
0
1
0
1
1
1
Horizon Seeker No. 2
Accumulator Register

X
1
1
0
1
1
0
1
1
Coarse Gimbal No. 4
Accumulator Register

X
1
1
0
1
1
1
1
1
Spare No. 5
Accumulator Register

X
1
1
1
0
0
0
1
1
Coarse Gimbal No. 2
Accumulator Register

X
1
1
1
0
1
0
1
1
Fine Gimbal No. 3
Accumulator Register

X
1
1
1
0
1
1
1
1
Spare No. 2
Accumulator Register

X
1
1
1
1
0
0
1
1
Fine Gimbal No. 2
Accumulator Register

X
1
1
1
1
0
1
1
1
Horizon Seeker No. 4
Accumulator Register

Subroutine Linkage

While the LVDC is executing an instruction, it is also forming the HOP constant of the next instruction in sequence—i.e., on the assumption that no branch occurs—and this HOP constant is available to the next instruction that executes.  In most cases, this means that an instruction can find out its own address (which isn't very interesting), but if the previous instruction was a branch then it means that the current instruction can determine the address of the instruction in sequence that followed the branch instruction, and thus can use this information for settting up returns from subroutines.  The instruction for fetching that HOP constant and saving it is either STO 0776 or STO 0777.  Only those special addresses work.  So a typical subroutine linkage would look like this:

    TRA     MYSUB
        ... return to here ...

        ...

MYSUB   STO     0776    # or, STO 0777
        ... do stuff ...
        HOP     0776    # or, HOP 0777

Interrupts

There are up to 12 external interrupt sources, buffered by the LVDA.  Upon any of these becoming active, the LVDA generates a master interrupt signal to the LVDC.  When the LVDC receives the master interrupt signal, assuming that interrupts have not been programmatically inhibited, the following actions occur:
  1. The LVDC automatically masks that particular interrupt from occurring again until explicitly reenabled (at step 9 below).
  2. The LVDC allows any instruction, multiplication, or division in progress to complete.
  3. The LVDC performs a HOP 0400, thus transferring control to an interrupt-service routine—or, as the original documents refer to it, an "input-output subprogram".  Recall that this does not jump to address 0400, rather it loads the HOP Register from the value stored at address 0400, and this can be used to jump to a location, set the current memory module and sector, etc.  (Early non-flight hardware seemingly used a HOP 0776 instead of HOP 0400.)
  4. The first instruction executed by the interrupt service routine must be either STO 0776 or STO 0777 to store the pre-interrupt value of the HOP Register at either address 0776 or 0777.  (There is some ambiguity as to whether 0776 and 0777 are really separate memory words, or whether they represent a single memory word with two separate addresses.  I will suppose the former until more information becomes available.  If location 0777 is used, compatibility with earlier hardware documentation is assured.)
  5. The interrupt service routine should then save any registers or common memory locations that were going to be altered into local storage.  In almost all cases, one would suppose that the accumulator needed to be stored.  If multiplications or divisions would be used, the P-Q Register would also need to be saved, presumably with a pair of instructions like CLA 0775 followed by STO somewhere.
  6. The interrupt service routine should do a PIO from the Interrupt Storage input port to determine which of the 12 interrupt sources are active, so that it can vector to an appropriate service routine for it.
  7. The interrupt service routine should then do whatever computations it needed to do.
  8. The interrupt service routine should restore the registers it had saved (CLA somewhere followed by STO 0775 to restore the P-Q Register, if necessary, followed by a restoration of the accumulator).
  9. The interrupt service routine should do a PIO to the Interrupt Register Reset output port, with just the specific bit set corresponding to the interrupt type being processed, to reenable that specific interrupt.  The particular flavor of PIO performed should, of course, take the Data Source from memory rather than from the accumulator, since at this point the accumulator has already been restored to its pre-interrupt condition.
  10. The return from interrupt is either HOP 0776 or HOP 0777, depending on which location the HOP constant had been stored on entry to the interrupt service routine.
Interrupts can be programmatically masked or unmasked with PIO to Interrupt Inhibit.  By setting a bit in Interrupt Inhibit corresponding to the interrupt whose masking is desired, that interrupt is thereby masked.  Any combination of bits can be set, so any combination of interrupts can be masked.  To reenable the interrupt, a 0 is written to the corresponding bit in Interrupt Inhibit.

The available interrupts, and their bitwise positioning in the i/o registers mentioned above, differed for the Saturn IB rocket (Apollo 7, ASTP, Skylab) vs. the Saturn V rocket (Apollo 8-17).  The Saturn IB and Saturn V descriptions below were taken from different documents (namely, Skylab Saturn IB Flight Manual p. 6-21 and Saturn Flight Manual, SA-503 p. 7-21, respectively), and if one accounts for the differences in language between the two documents, the interrupts are almost entirely the same. I've marked the ones in red that seem different to me, as well as any other points of particular difficulty for me.

LVDC Data Word Bit Position
Description of function in Saturn IB
Description of function in Saturn V
Are these actually the same thing?
Comments
11
RCA-110A interrupt
Command LVDA/RCA-110A interrupt
Probably.
The RCA-110A is the ground-control computer.  This interrupt implies that a command word has been received via digital uplink and is ready to be processed.  See section 6.2.3 of Astrionic System Handbook, Saturn Launch Vehicles.
10
S-IB low-level sensors dry "A"
S-IC inboard engine out "A"
If interpreted as "first stage engine out", yes.
9
RCA-110A interrupt
Program re-cycle (RCA-110A) interrupt
Probably.
The RCA-110A is the ground-control computer.  The following is partly speculation, so take it with a grain of salt: I believe that this interrupt may occur when a special uplink command ("Terminate") is received.  The purpose of the "Terminate" command is to halt an operation from a previously uplinked command (see the 2nd line above) and to return the LVDC flight program to normal operation.  Since the "command LVDA/RCA-110A" interrupt would be disabled until that processing is completed, a separate interrupt for the "Terminate" command is needed, and that is the "Program re-cycle" interrupt.
8
S-IVB engine out "B"
S-IVB engine out "B"
Yes.

7
S-IB outboard engines cutoff "A"
S-IC propellant depletion/engine cutoff "A"
If interpreted as "first stage engine cutoff", yes.
6
Manual initiation of S-IVB engine cutoff "A"
S-II propellant depletion/engine cutoff
Both refer to the second stage, but ... don't know!

5
Guidance reference release
Guidance reference release
Yes.

4
Command decoder interrupt "A" or "B"
Command receiver interrupt
Probably.
I think this interrupt comes from the decoder that interprets uplinked data (see the two RCA-110A interrupts above), but it's unclear to me what the purpose is, or how "A" and "B" differ.
3
Simultanous memory error
Temporary loss of control
Yes.
"Simultaneous memory error" refers to simultaneous parity errors in a single address mirrored in duplexed memory modules.  This is also known by the acronym TLC, and thus is obviously the same as "temporary loss of control".
2
Spare
Computer interface unit interrupt
No.

1
Internal to the LVDC
Switch selector interrupt
Probably.
The switch-selector interrupt and the minor-loop interrupt are generated internally by the LVDC/LVDA.
S
Internal to the LVDC
Minor loop interrupt

Telemetry

TBD

LVDC Assembly Language

"Forbidden Planet" is really about the mysterious Krel, who were so advanced technologically they were able to gain control over the very essence of their material bodies. The mystery of why they left no record of their physical appearance only makes the irony of their destruction by the evil of "The Mindless Primitive" within even more interesting.
—G. D. Garduno (2007), on the movie Forbidden Planet

This web page is about the mysterious LVDC, which was so advanced technologically that it could guide the hurtling of a montrously large rocket toward the moon. The mystery of why no record was left of the computer software or even of its visual appearance only makes the irony of its destruction by the evil of "The Mindless Budget-Cutters" even more interesting.
—Ron Burkey (2009), on LVDC assembly language

As the second quote above alludes, not a single scrap of LVDC assembly language has been left behind by its developers ... or at least, not in any place where we've so far been able to find it.  And I refer here not merely to the flight software, but to any code sample at all!  So even though we know what all of the assembly-language opcodes do and what their mnemonics are, and even though we understand the architecture of the computer, we have no idea what the syntax of the assembly language was.  For example, there must have been some pseudo-ops that allowed assembly of constants into memory locations.  There must have been some other pseudo-ops to set the program origin and to select memory modules or memory pages.  Must have been, yes, but we have no clue what they were like.

Well, I exaggerate.  Like the Krel, with their triangular doorways and what-not, some indirect traces of LVDC syntax still remain.  And those indirect traces come from ... drumroll, please! ... the MIT Instrumentation Labs, which had no involvement whatever in the development of the LVDC and indeed was somewhat at odds with IBM over it. 

How it came about was this.  When IBM proposed that the LVDC be used in place of the AGC in the CM and LM, in 1963, it produced a big, two volume report (here and here) to support their proposal.  The Instrumentation Labs fired back their own critiques, shredding IBM's report to the extent possible.  (And they were right, the LVDC would never have worked in the LM and CM.  It was simply too slow.)  And in one of those critiques, we have a few precious gems of LVDC assembly language, as written by the Instrumentation Labs personnel rather than by IBM. 

Whether it's good LVDC code or bad, or whether it even has the appropriate syntax, who knows?  But it's all we have, so here are is what it looked like.  The '#' characters indicate the beginnings of comments; the comments were added by me, and weren't present in the samples originally.

# Sum of two double-precision vectors A and B to produce  vector C.
         CLA     A
         ADD     B
         STO     C
         CLA     A + 1
         ADD     B + 1
         STO     C + 1
         CLA     A + 2
         ADD     B + 2
         STO     C + 2
         ...

# Purportedly, subroutine linkages to call functions to perform vector addition.
         CLA     ADRESA
         STO     VCAADR
         CLA     * + 2
         HOP     VCALINK
         HOPCON  * + 1
         CLA     ADRESB
         STO     VADADR
         CLA     * + 2
         HOP     VADLINK
         HOPCON  * + 1
         CLA     CADRES
         STO     VTSADR
         CLA     * + 2
         HOP     VTSLINK
         HOPCON  * + 1
         ...

# Integration during accelerated flight. If you want to see the equations being
# implemented, look at page 7 of the critique.
AVERAGEG STO     EXITHOP
         HOP     HOPSET1
AVG1     CLA     WK
         SHF     R1
         ADD     HGK/2
         ADD     VK
         MPH     H
         ADD     R
         STO     R
         MPY     R
         HOP     THISEC1
AVG4     CLA     HOPWD1
         ADD     ONE
         STO     HOPWD1
         CLA     PQ
         ADD     DOTSUM
         STO     DOTSUM
HOPWD1   HOP     HOPSET1
AVG2     CLA     DOTSUM
         STO     SQRTARG
         CLA     * + 2
         HOP     SQRTLINK
         HOPCON  * + 1
         CLA     SQRTANS
         MPY     DOTSUM
         CLA     -MUH/2
         NOOP
         NOOP
         DIV     PQ
         HOP     THISSEC2
AVG5     CLA     HOPSET1
         STO     HOPWD1
         CLA     HOPSET2
         STO     HOPWD2
         NOOP
         NOOP
         NOOP
         CLA     PQ
         STO     DOTSUM
         HOP     HOPSET2
AVG3     CLA     R
         MPY     DOTSUM
         CLA     HGK/2
         ADD     W
         ADD     V
         STO     V
         CLA     PQ
         STO     HGK/2
         ADD     V
         STO     V
         HOP     THISSEC3
AVG6     CLA     HOPWD2
         ADD     ONE
         STO     HOPWD2
         HOP     HOPSET2
HOPSET1  HOPCON  AVG1, XCOMP
         HOPCON  AVG1, YCOMP
         HOPCON  AVG1, ZCOMP
         HOPCON  AVG2, XCOMP
HOPSET2  HOPCON  AVG3, YCOMP
         HOPCON  AVG3, ZCOMP
EXITHOP  ( exit hop con )
STRTLINK HOPCON  SQRT, XCOMP
THISSEC1 HOPCON  AVG4, AVG4
THISSEC2 HOPCON  AVG5, AVG5
THISSEC3 HOPCON  AVG6, AVG6

# Compute a double-precision square root.
SQRT     STO     RETURN
         CLA     ZERO
         STO     NORMCNT
         CLA     ARG
NORMTEST AND     HIGH3
         TNZ     NORMDUN
         CLA     NORMCNT
         ADD     ONE
         STO     NORMCNT
         CLA     ARG
         SHF     L2
         STO     ARG
         TRA     NORMTEST
HIGH3    DEC     -.75
1/2      DEC     .5
SLOPELO  DEC     .4162
BIASLO   DEC     .1487
SLOPEHI  DEC     .2942
BIASHI   DEC     .2046
NORMDUN  AND     1/2
         TNZ     ARGHI
         CLA     ARG
         MPY     SLOPELO
         SHF     R1
         STO     ARG
         CLA     BIASLO
         ADD     PQ
         TRA     NEWTON
ARGHI    CLA     ARG
         MPY     SLOPEHI
         SHF     R1
         STO     ARG
         CLA     BIASHI
         ADD     PQ
NEWTON   STO     BUF
         CLA     ARG
         DIV     BUF
         ADD     ZERO
         ADD     ZERO
         ADD     ZERO
         ADD     ZERO
         ADD     ZERO
         ADD     ZERO
         ADD     ZERO
         CLA     PQ
         SHF     R1
         ADD     BUF
         STO     BUF
         CLA     ARG
         DIV     BUF
         ADD     ZERO
         ADD     ZERO
         ADD     ZERO
         ADD     ZERO
         ADD     ZERO
         ADD     ZERO
         ADD     ZERO
         CLA     BUF
         SHF     R1
         ADD     PQ
         STO     ARG
CLANORC  CLA     NORMCNT
         TNZ     POSTSQRT
         CLA     ARG
         SHF     R1
         STO     ARG
         TRA     CLANORC

# Calling sequence for SQRT (or similar for any other unary subroutine).
         CLA     X
         STO     ARG
         CLA     REHOP
         HOP     SQRTLINK
RETURN   CLA     ARG
         ...
REHOP    HOPCON  RETURN
SQRTLINK HOPCON  SQRT

So what do we learn from these indirect clues?  Well,
Or not.  Many of the observations above could be just as easily explained if the Instrumentation Labs developers who wrote this sample code knew no more than we about LVDC language syntax, and simply reused the AGC syntax with which they were familiar.  But until something better comes along, let's just assume the Instrumentation Labs guys (and it's clear stylistically that there were at least two of them working on this sample code) knew what they were doing here!

yaLVDC, the LVDC CPU Emulation

The inclusion of this section is an act of pure optimism.  :-)  Since no existing copy of the flight software has yet been uncovered, we have little use for a CPU simulation.



An interesting aspect of the LVDC is that since it is essentially a "black box" that outputs real-time control signals in response to real-time inputs, it is possible to create a reasonably satisfactory behavioral simulation for it in the absence of the original software, if one simply knows the guidance equations relating the outputs to the inputs.  While creating behavior simulations is not an objective of the Virtual AGC project as far as the Apollo CPUs are concerned, there are people engaged in creating such simulations for the Orbiter NASSP project and elsewhere.

Something that would be more interesting and have a slightly higher degree of realism from my personal viewpoint would be to try and implement the guidance equations in LVDC assembly language, so that it could be run in yaLVDC.

yaASM, the LVDC Cross-Assembler

Because of the tremendous similarity between the LVDC and Gemini OBC computers, the Gemini OBC assembler yaASM is used for both assembly languages.  When assembling LVDC code, the command-line switch "--lvdc" is added.

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 LVDC 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:

Homage

Part of our purpose here is to pay homage to the original LVDC developers, including the developers of "the FORTRAN program" and the test & checkout software.  I do not know any of their names, nor do I have any information about them, so I'm not making much progress on the homage front.   So if you know any of the developers or their relatives or friends, please have them contact me.  The anecdotes of a developer would be interesting, even if no notes or documents had been retained.

By the way, any information on this page that doesn't come directly from the surviving documentation is largely due to conversations with Barry Silverman, who has made a significant effort to find and talk to original LVDC developers.



Last modified by Ronald Burkey on 2009-08-21.

Virtual AGC is hosted by ibiblio.org