Apollo Guidance Computer
The Apollo Guidance Computer (AGC) was the first recognizably modern embedded system. It was developed for the Apollo program by the MIT Instrumentation Laboratory under Charles Stark Draper, with hardware design led by Eldon C. Hall. Based upon MIT documents, early architectural work seems to come from J.H. Laning Jr., Albert Hopkins, Ramon Alonso, and Hugh Blair-Smith. The actual flight hardware was fabricated by Raytheon.Each flight to the moon had two AGCs. They ran the inertial guidance systems of both the command module and lunar module.
Each moon mission also had two additional computers: a flight computer on the Saturn V booster instrumentation ring called the LVDC--a serial computer built by IBM Federal Systems Division. The other computer was a small machine in the lunar module used for the Abort Guidance System (AGS; built by TRW), used in the event of failure of the AGC. The AGC was part of the lunar module's Primary Guidance System, called PNGS.
The Apollo flight computer was the first to use integrated circuits. The Block I version used 4,100 ICs, each containing a single 3-input NOR gate. The later Block II version used dual 3-input NOR gates in a flat-pack; appoximately 5,600 gates in all. They were interconnected by a technique called wire wrap, in which the circuits are pushed into sockets, the sockets have square posts, and wire is wrapped around the posts. The edges of the posts bite the wire with tons of pressure per square inch, causing gas-tight connections that are more reliable than soldered PC boards. The wiring was then embedded in cast epoxy plastic.
The computer's RAM was magnetic core memory and ROM was core rope memory. Both cycled in 12 microseconds. The memory word length was 16 bits, 15 bits of data and 1 odd-parity bit. The internal data format was 14 bits of data, 1 overflow bit, and 1 sign bit (1's complement representation).
The AGC had four 16-bit registers for general computational use. These were called the "central registers":
Register A: The Accumulator register, used for general computation.
Register Z: The program counter, which contained the address of the next instruction to be executed.
Register Q: Used to hold the remainder in the DV instruction, and to hold the return address after TC instructions.
Register LP: Held the lower product after MP instructions.
The instruction format was 3 bits for opcode, 12 bits for address. Block I had 11 instructions: TC, CCS, INDEX, XCH, CS, TS, AD, MASK, SU, MP, and DV. The first 8, called "basic instructions", were directly accessed by the 3-bit op code. The last 3 were called "extracode instructions" because they were accessed by performing a special type of INDEX instruction (called EXTEND) immediately before the instruction.
The Block I AGC instructions consisted of the following:
TC (Transfer Control): An unconditional branch to the address specified by the instruction. The return address was automatically stored in the Q register, so the TC instruction could be used for subroutine calls.
CCS (Count, Compare, and Skip): A complex conditional branch instruction. The A register was loaded with data retrieved from the address specified by the instruction. The "Diminished Absolute Value (DABS)" of the data was then computed and stored in the A register. If the number was positive, the DABS decrements the value by 1; if the number is negative, it increments it by 1, so that the DABS moves the number toward zero. Because the AGC uses 1's compliment notation, there are two representations of zero. When all bits are set to zero, this is called "plus zero". If all bits are set to one, this is called "minus zero". Therefore, when the AGC performs the DABS function, positive numbers will head toward plus zero, and negative numbers will head toward minus zero. The final step in CCS is a 4-way skip, depending upon the result in register A after the DABS. If register A is greater than 0, CCS skips to the first instruction immediately after CCS. If register A contains plus zero, CCS skips to the second instruction after CCS. Less than zero causes a skip to the third instruction after CCS, and minus zero skips to the fourth instruction after CCS.
INDEX: Add the data retrieved at the address specified by the instruction to the next instruction. INDEX can be used to add or subtract an index value to the base address specified by the operand of the instruction that follows INDEX. This method is used to implement arrays and table look-ups, or to modify the op code in a following (extracode) instruction.
RESUME: A special instance of INDEX (INDEX 25). This is the instruction used to return from interrupts. It causes execution to resume at the interrupted location.
XCH (Exchange): Exchange the contents of memory with the contents of the A register. If the specified memory address is in fixed (read-only) memory, the memory contents are not affected, and this instruction simply loads register A.
CS (Clear and Subtract): Load register A with the one's compliment of the data referenced by the specified memory address.
TS (Transfer to Storage): Store register A at the specified memory address. TS also corrects for overflows.
AD (Add): Add the contents of memory to register A and store the result in A.
MASK: Perform a bit-wise (boolean) AND of memory with register A and store the result in register A.
MP (Multiply): Multiply the contents of register A by the data at the referenced memory address and store the high-order product in register A and the low-order product in register LP.
DV (Divide): Divide the contents of register A by the data at the referenced memory address. Store the quotient in register A and the remainder in register Q.
SU (Subtract): Subtract (one's complement) the data at the referenced memory address from the contents of register A and store the result in A.
Instructions were implemented in groups of 12 steps, called timing pulses. The timing pulses were named TP1 thru TP12. Each set of 12 timing pulses was called an instruction subsequence. Simple instructions, such as TC, executed in a single subsequence of 12 pulses. More complex instructions required several subsequences. The multiply instruction (MP) used 8 subsequences: an initial one called MP0, followed by a MP1 subsequence which was repeated 6 times, and then terminated by a MP3 subsequence.
Each timing pulse in a subsequence could trigger up to 5 control pulses. The control pulses were the signals which did the actual work of the instruction, such as reading the contents of a register onto the bus, or writing data from the bus into a register.
Block I AGC memory was organized into 1024 word banks. The lowest bank (bank 0) was eraseable memory (RAM). All banks above bank 0 were fixed memory (ROM). Each AGC instruction had a 12-bit address field. The lower bits (1-10) addressed the memory inside each bank. Bits 11 and 12 selected the bank: 00 selected the eraseable memory bank; 01 selected the lowest bank (bank 1) of fixed memory; 10 selected the next one (bank 2); and 11 selected a BANK register that could be used to select any bank above 2. Banks 1 and 2 were called "fixed-fixed" memory, because they were always available, regardless of the contents of the BANK register. Banks 3 and above were called "fixed-switchable" because the selected bank was determined by the BANK register.
The Block I AGC initially had 12K words of fixed memory, but this was later increased to 24K.
The AGC transfered data to and from memory through the G register in a process called the "memory cycle." The memory cycle took 12 timing pulses (12 microseconds). The cycle began at timing pulse 1 (TP1) when the AGC loaded the memory address to be fetched into the S register. The memory hardware retrieved the data word from memory at the address specified by the S register. Words from erasable memory were deposited into the G register by timing pulse 6 (TP6); words from fixed memory were available by timing pulse 7. The retrieved memory word was then available in the G register for AGC access during timing pulses 7 through 10. After timing pulse 10, the data in the G register was written back to memory.
The AGC memory cycle occurred continuously during AGC operation. Instructions needing memory data had to access it during timing pulses 7-10. If the AGC changed the memory word in the G register, the changed word was written back to memory after timing pulse 10. In this way, data words cycled continuously from memory to the G register and then back again to memory.
The AGC had 5 vectored interrupts. One interrupt (DSRUPT) was reserved for updating the user display (DSKY). Another interrupt (KEYRUPT) signaled a keypress from the user's keyboard. Another interrupt (T3RUPT) updated the AGC's real-time clock.
The AGC also had 20 involuntary counters. These were memory locations which functioned as up/down counters. The counters would increment or decrement in response to internal inputs. The increment (PINC) or decrement (MINC) was handled by a brief sequence of microinstructions inserted between the regular instruction stream during timing pulse 12.
AGC software was written in AGC assembly language. There was a real-time operating system consisting of the EXEC, a batch job-scheduling system that could run up to 8 'jobs' at a time using non-preemptive multi-tasking (each job had to periodically surrender control back to the EXEC). There was also a interrupt-driven component called the WAITLIST which could schedule multiple timer-driven 'tasks'. The tasks were short threads of execution which could reschedule themselves for reexecution on the WAITLIST, or could kick off a longer operation by starting a 'job' with the EXEC.
The EXEC jobs were priority-based. The lowest priority job, called the dummy job, was always present. It did diagnostic checks and ran a green "COMPUTER ACTIVITY" light on the DSKY display. When the dummy job was running, the computer had nothing better to do, so the COMPUTER ACTIVITY light was turned off. When the dummy job exited, there was some higher priority job, so the COMPUTER activity light was illuminated.
The AGC also had a sophisticated software interpreter that implemented a virtual machine with more complex and capable instructions than the native AGC. Interpreted code could be mixed with native AGC code.
A set of interrupt-driven user interface routines called PINBALL provided keyboard and display services for the jobs and tasks running on the AGC. A rich set of user-accessable routines were provided to let the operator (astronaut) display the contents of various memory locations in octal or decimal in groups of 1, 2, or 3 registers at a time. "Monitor" routines were provided so the operator could initiate a task to periodically redisplay the contents of certain memory locations. Jobs could be initiated. The PINBALL routines performed the rough equivalent of the UNIX shell.
The user interface was called the DSKY (display/keyboard); an array of numerals and a calculator-style keyboard (electronic calculators were unknown at the time--slide rules were used). Commands were entered numerically as two digit "prog", "verb" and "noun" numbers. The numerals were green high-voltage fluorescent displays arranged in an array of seven segments per numeral to display numbers. The segments were driven by electromechanical relays, which limited the display update rate. Three 5-digit numbers could also be displayed in octal or decimal. Input was by pushbuttons. This "calculator-style" interface was the first of its kind, the prototype for all similar interfaces.
The command module (CSM) had 2 DSKYs; one located on the main instrument panel and another located in the lower equipment bay near a sextant used for aligning the inertial guidance platform. Both DSKYs were driven by the same AGC. The lunar module (LM) had a single DSKY.
A Block II version of the AGC was designed in 1966. It retained the basic Block I architecture, but increased eraseable memory from 1K to 2K. Fixed memory was expanded from 24K to 36K. Instructions were expanded from 11 to 34 and I/O channels were implemented to replace the I/O registers on Block I. The Block II version is the one that actually flew to the moon. Block I was used during the unmanned Apollo 4 and 6 flights, and was slated for the ill-fated Apollo I.
The decision to expand the memory and instruction set for Block II, but to retain the Block I's restrictive 3-bit op code and 12-bit address had interesting design consequences. Various tricks were employed to squeeze in additional instructions, such as having special memory addresses which, when referenced, would implement a certain function. For instance, an INDEX to address 25 triggered the RESUME instruction to return from an interrupt. Likewise, INDEX 17 performed an INHINT instruction (inhibit interrupts), while INDEX 16 reenabled them (RELINT). Shift and rotate right and left instructions were implemented by writing to memory locations 20-23. Other instructions were implemented by preceeding them with a special version of INDEX called EXTEND with arithmetically modified the 3-bit op code by employing the sign bit to extend it. The address space was extended by employing a BANK register, so the only memory that could be addressed at any given time was the current bank, plus the small amount of fixed-fixed memory and the eraseable memory. All across-bank subroutine calls had to be initiated from fixed-fixed memory through special functions to restore the original bank during the return.
It's not widely known, but the system failed during the first lunar descent, with a "1201 alarm" and "1202 alarm" (tasks not finished) because the terminal approach (docking) radar was left on and unexpected radar returns from the moon overloaded the CPU. This almost caused a mission abort. The software failed safe, shedding unnecessary tasks, and the inertial guidance tasks continued to operate reliably.
External Links