Apollo Guidance Computer

From Esolang
Jump to navigation Jump to search

The Apollo Guidance Computer (AGC) is a real computer architecture from the 1960s that was used in the Apollo moon landing missions of NASA, as well as some other space exploration missions afterwards. The AGC was developped by MIT's Instrumentation Lab.

Each of the Apollo spacecrafts contained two AGC with different programs, plus one other computer of a very different architecture.

The AGC was a pinnacle of engineering, trying to put as much functionality into a physically compact package as possible, so that the computer can be put on a spacecraft. The computer hardware and software is also built to be very resilient to errors.

Hardware

The RAM of the AGC is made of core memory, which stores data in the magnetization of sub-millimeter sized metal rings, one bit per ring, reading and writing them using thin isolator-coated address and sense wires woven through them. Core memory has the property that reading a bit zeroes it, so the computer rewrites it (or a modified value) shortly after. The RAM is persistent, keeping its content indefinitely even if power is lost. Indeed, the content of at least one RAM module was recovered by retro hardware enthusiasts decades after use.

The ROM is made of wikipedia:core rope memory, which consists of centimeter sized metal rings with wires woven through them, several bits per ring. The data is stored in which of the sense wires go inside each metal ring and which ones outside. Both types of memory are then controlled by special amplifiers made of high-power transistors to amplify the weak electric signal induced in the wires by the changing magnetic field.

Both the RAM and ROM are accessed as whole words of 16 bits at a time.

The computation logic of the AGC is built from then bleeding edge technology: integrated circuits, which contained multiple transistors packaged into a small housing with 16 legs. No printed circuit boards are used: there are sockets that hold multiple ICs in a row, each easily replacable, and their contacts are all wire-wrapped. There are apparently very few flip-flops in the AGC, so much that even the most important hardware registers are stored in special small pieces of core memory rings outside of the main RAM.

Memory and register organization

The AGC operates on words of 15 bits. The RAM and ROM both store a parity bit together with each word. The AGC has 2 kilowords of RAM and up to 36 kilowords of ROM.

Addresses are word-granular. The AGC uses bank switching, mapping the physical memory to a much smaller virtual address space. The virtual address space is 4096 words, split in the following way. The lower 1024 words of virtual address space is RAM, of which the lower 768 words have a fixed mapping while the other 256 bytes can be mapped to any of the 8 256-byte banks. The upper 3072 words are ROM, of which the upper 2048 words have a fixed mapping, while the lower 1024 words are bank-switched.

The first seven words of the virtual address space have important hardware registers mapped into them, including two words of accumulator, the instruction pointer, the subroutine return address register, a constant zero register, and three registers associated with bank switching. Accessing these special addresses is handled by special logic in the computer, rather than the main RAM.

Four special memory locations have an additional function implemented by the CPU, even though they are backed by the RAM: their value is automatically shifted in place after each access, namely rotate right by 1, signed shift right by 1, rotate left by 1, and unsigned shift right by 7 respectively.

Apart from the main memory address space, there's a separate 512 word long IO address space. This is connected to various external hardware.

Instruction set

The CPU executes instructions in sequence using a program counter. Instructions can reside in either the ROM or RAM, though they are usually in the ROM.

Instructions are normally one word long, with the upper 3 bits being an opcode and the lower 12 bits encoding the address operand. Opcodes 0, 3, 4, 6, 7 can have almost any address as their operand. Opcodes 2 and 5 implement instructions where the operand must be in the RAM, which frees two bits in the encoding, and those two bits are used as an extension to the opcode to distinguish between different instructions. Opcode 1 is split to two different instructions, one for RAM and one for ROM operands. This gives a total of 15 simple instructions. A few more instructions are mapped to certain otherwise useless combinations where the operand refers to one of the hardware registers. There is also a one-word prefix for a second opcode table, effectively adding several instructions that are encoded as two words with the first word being the constant 000006.

Most arithmetic instructions operate on signed words encoded as 1's complement. Unlike words in memory and most registers, the two words of the accumulator each have 16 bits, effectively storing the result of an addition together with an overflow. Arithmetic instructions operate on the full 16 bits, but only 15 bits of these are stored into RAM. The overflow and its sign can then be examined by a few instructions, this is used to implement double-precision or triple-precision arithmetic. There are built-in double-precision add and subtract instructions that operate on the two words of the accumulator and two adjacent words in memory, handling a value that effectively has 28 bits of mantissa, a sign bit, and, in the accumulator only, an overflow bit. There are also fast multiplication and division instructions implemented in hardware, multiplying two one-word inputs to a two-word output or dividing a two-word dividend by a one-word divisor to get a one-word result.

Many of the instructions are read-modify-write instructions that read a memory operand and immediately write a modified value there. This is probably because the core memory makes these particularly efficient to implement. Such instructions leave the full 16-bit or 30-bit result in the accumulator, but store only the reduced 15-bit or 29-bit result to the RAM. There are also swap instructions to swap one or two bytes of the RAM with the accumulator.

The second word of the accumulator can be used as an extra general purpose register when you're not doing double-precision computations, and the return address can also be used as an extra general purpose register. To facilitate this, there are instructions that swap either of these registers with a memory operand. There's a general purpose bitwise and instruction, but bitwise or and bitwise xor are only available for operands in the IO address space. However, the two extra registers are mapped to the IO address space, thus letting you use these bitwise instructions for general purpose computations.

There is a special indexing instruction that loads an operand from memory and adds its value to the next instruction as that instruction is executed. This is usually used to change only the operand, but occasionally also to change the opcode. This is the main way for indirect memory address. As if this wasn't enough, there are a few more rare instructions that let you execute a computed instruction word.

The instruction mnemonics are unusual to our modern ears. Instead of a memory load to the accumulator, we have CA for clear and add instruction. The unconditional jump/branch instruction is called TCF for transfer control to fixed instruction (fixed memory is what they call the ROM), the call subroutine instruction is called TC for transfer control with TCR for transfer control with return as an alias.

Interrupts and “unprogrammed sequences”

The CPU has a full interrupt system. Interrupts are triggered by timers expiring or by certain hardware inputs. Interrupt requests are stored in an IRQ mask and handled when possible. Interrupts can only occur between instructions, and even then only if certain conditions are satisfied. The program can disable interrupts using special instructions, and interrupts are normally disabled during an interrupt. Interestingly interrupts are also disabled while the accumulator has an overflow, because it would be difficult for the interrupt routine to restore such a value. Interrupts only save the value of the instruction pointer, the interrupt routines themselves have to save the accumulator, banks, and any other state that they wish to modify. The programs ran on AGC use one of the timers to implement non-cooperative multitasking.

In addition to normal interrupts, the CPU also interrupts normal execution to handle so-called “unprogrammed sequences”. These last for only one clock cycle, they do not change the instruction pointer, and so can be executed even while interrupts are disabled. Instead of transferring control to an interrupt routine, unprogrammed sequences have their effect hard-wired into the CPU, usually incrementing or decrementing a memory-mapped counter. Five of the unprogrammed sequences increment one of the five timer registers, then trigger an interrupt request if it overflows. Other unprogrammed sequences are connected to the gyroscopes and accelerometers that measure the movement of the spacecraft. These also simply increment or decrement a memory cell by 1, the memory cell storing the current orientation or position of these instruments. Apparently hardware counters were considered so expensive that timers and analog input devices had to be implemented this way, even though this takes up a significant quantity of the precious CPU execution time.

Legacy

Retrocomputing enthusiasts have built simulators for the AGC on modern computers, acquired and studied software running on it in detail, and later repaired most of an AGC to working condition.

Links