Address (octal)

Name

Description



00

A

The "accumulator". Almost every AGC instruction uses or modifies the accumulator in some way. The accumulator differs from all other memory or i/o locations addressed by the CPU, in that it is a 16-bit register rather than a 15-bit register. In most cases this is transparent to the programmer, because the 16th bit is not directly observable or modifiable, and because data within the accumulator is automatically adjusted to 15 bits before most uses of it. The 16th bit is present in order to allow detection of arithmetical overflow or underflow.



Internally, when there is no overflow, the 16th bit of the accumulator is a duplicate of the 15th (sign) bit. When a value is loaded into the accumulator from memory, the value is sign-extended from the 15th bit to the 16th bit. In other words, for positive values the 15th and 16th bits are both 0, while for negative values they are both 1. When overflow occurs, however, the 15th and 16th bits differ: After an operation that causes positive overflow, the 16th bit is 0 and the 15th bit is 1. After an operation that causes negative overflow, the 16th bit is 1 and the 15th bit is 0.



Various CPU instructions can detect overflow and alter their actions somewhat upon finding it. The TS (transfer to storage) instruction is notable in this regard, because it can actually be used to provide a branch upon detection of overflow.



In most cases, when data is transferred out of the accumulator to a true 15-bit register, it is overflow-corrected . Overflow-correction implies:

The 16th bit of the accumulator is assumed to be the correct sign bit, and is copied into the 15th bit of the destination location; and The positive data and negative data are (separately) converted to a range of 0 to 214-1. For example, if we were incrementing +16383, we would find that a positive overflow had occurred and that we had wrapped around to +0. Similarly, if we were decrementing -16383, then a negative overflow (an underflow) would occur, and the data would wrap around to -0. (On the other hand, incrementing -0 would take us to +1 and decrementing +0 would take us to -1, without underflow or overflow.) The wraparound of under/overflowed data is very different from that which programmers of most modern computers using 2's-complement arithmetic would expect, since they would expect that incrementing the maximum positive integer would give the "biggest" negative integer.



01

L

Like the accumulator, this is a 16-bit register rather than a 15-bit register. This means, for example, that like the accumulator you can generate overflow conditions with instructions like ADS L ; also, the overflow can be transferred between the accumulator and L with instructions like XCH L or LXCH A . For a dozen years, the L register was described as being in this space as being a 16-bit register like the accumulator, our AGC simulator treated it as such, and our "validation suite" of AGC software did so too. An intrepid correspondent (thanks Mike Stewart!) recognized that while it may be a 16-bit register, the 16th bits is in fact discarded and cannot be queried by software. Consequently, for software versions 2016-08-23 and later, the L register is now 15 bits, as the AGC programming gods apparently intended.



This is the "lower product register". This is a general-purpose register, but many instructions pair it with the accumulator in cases where double precision (DP) operations are performed. In these cases, the A register holds the more-significant word, and the L register holds the less-significant word.



Note that erasable-memory location 01 is automatically duplicated as i/o channel 01, and vice-versa.



02

Q

Like the accumulator, this is a 16-bit register rather than a 15-bit register. This means, for example, that like the accumulator you can generate overflow conditions with instructions like ADS Q ; also, the overflow can be transferred between the accumulator and Q with instructions like XCH Q or QXCH A .



This register is intended to store return addresses of called procedures. Note that the AGC CPU has no hardware stack, and provides only a single memory location (the Q register) for storing return addresses. Therefore, it is not possible to have nested procedure calls unless the contents of the Q register are stored prior to calling a procedure and then restored after the procedure returns. The CPU's instruction TC is used to call a procedure, and the instruction automatically updates the Q register; similarly, the RETURN instruction returns from a called procedure by placing the contents of the Q register into the program-counter register (technically it does an indirect jump through Q, but the net effect is the same).



Note that erasable-memory location 02 is automatically duplicated as i/o channel 02, and vice-versa.



03

EB

The "erasable bank register". This register contains a 3-bit field that determines which of the 8 banks of erasable memory (see "Memory Map" below) is mapped into the address range 1400-1777 (octal). The 15 bits of the EB register are arranged as follows:

000 0EE E00 000 000

where EEE are the bank-selector bits.



Note that the EEE field of the EB register is duplicated into the BB register (see below). Internally, the two point to the same set of flip-flops, and simply provide different means of accessing them.



04

FB

The "fixed bank register". This register contains a 5-bit field that determines which of the 36 banks of fixed memory (see "Memory Map" below) is mapped into the address range 2000-3777 (octal). 5 bits are not, of course, adequate for selecting among 36 banks, so these 5 bits are supplemented by a 7th bit (the "super bank" bit) from i/o channel 7. In most cases, the superbank bit is 0, and so the 5-bit field in the FB register simply selects from among banks 0-37 (octal). When the superbank bit is 1, on the other hand, the 5 bits of the FB register actually select from among banks 0, 1, ..., 27, 40, 41, ..., 47; i.e., bank-selection is the same as when the superbank bit is 0, except that banks 40-47 are used instead of 30-37. Banks 44-47, however, do not exist. Though the AGC can internally calculate addresses in this range, the rope selection circuitry gives up and decides to select no rope at all when given such an address. The appropriate strands are still cycled, and a read is still attempted, but we can only guess as to what sort of data would be returned with no ropes selected. Presumably they would read all 0 or all 1, and trip the parity fail alarm, causing a reset.



The 15 bits of the FB register are arranged as follows:

FFF FF0 000 000 000

where FFFFF are the bank-selector bits.



Note that the FFFFF field of the FB register is duplicated into the BB register (see below). Internally, the two point to the same set of flip-flops, and simply provide different means of accessing them.



Refer also to i/o channel 07.



05

Z

The program-counter register. This 12-bit register always indicates the next instruction to be executed. It is always updated prior to executing the instruction, so that an instruction which saved the value of the Z register would actually be the address of the next instruction in memory.



Obviously, a 12-bit register cannot address all of memory. Full addresses are formed by combining the 12-bits of the Z register with the 3 bits of the EB register, the 5 bits of the FB register, and the superbank bit of i/o channel 7. (Refer to "Memory Map" below, and to the descriptions of the EB and FB registers above.) 12 bits can represent values from 0-7777 (octal), and these are interpreted as follows:

0000-1377 (octal). These addresses are used as-is, and refer to an area of memory known as "unswitched erasable" memory.

1400-1777 (octal). These addresses must be combined with the EEE field of the EB register, and refer to one of the memory banks in "switched erasable" memory.

2000-3777 (octal). These addresses must be combined with the FFFFF field of the FB register and (in some cases) to the superbank bit of i/o channel 7, and refer to one of the memory banks in "common fixed" memory.

4000-7777 (octal). These addresses are used as-is, and refer to an area of memory known as "fixed fixed" memory.



06

BB

The "both banks register". This register contains a 3-bit field duplicating the EEE field of the EB register, and a 5-bit field duplicating the FFFFF field of the FB register. Internally, it points to the same flip-flops as the EB and FB registers, so changing it directly changes the other two. The bits are arranged within the register as follows:

FFF FF0 000 000 EEE



Refer also to i/o channel 07.

07

(no name)

This location is not associated with core memory, but is hardwired to 0. In other words, it always contains the value 00000. It is very useful as a source of zeroes, because most AGC instructions have no "immediate" addressing mode. (In other words, you can't use a specific numerical value as an operand, but can only use the address of a memory location as an operand.)



10

ARUPT

This register is provided as a convenient location for storing the value of the A register during an interrupt service routine. However, vectoring to the interrupt does not automatically load this register, nor does returning from the interrupt-service routine restore the A register from ARUPT. These actions must be done under program control by the interrupt service routine. Interrupts are automatically disabled while overflow is present in the accumulator, so the fact that overflow would be lost by writing A to ARUPT is not a concern.



11

LRUPT

This register is provided as a convenient location for storing the value of the L register during an interrupt service routine. However, vectoring to the interrupt does not automatically load this register, nor does returning from the interrupt-service routine restore the L register from LRUPT. These actions must be done under program control by the interrupt service routine.

12

QRUPT

This register is provided as a convenient location for storing the value of the Q register during an interrupt service routine. However, vectoring to the interrupt does not automatically load this register, nor does returning from the interrupt-service routine restore the Q register from QRUPT. These actions must be done under program control by the interrupt service routine.

13-14

SAMPTIME

These registers store copies of TIME1 and TIME2, respectively, as sampled in the waitlist interrupt service routine. They are used for Noun 65 displays.



15

ZRUPT

This register stores the return address, plus one, of an interrupt service routine. When the CPU vectors to an interrupt service routine, it automatically transfers the value of the Z register (the program counter) into the ZRUPT register. When the interrupt-service routine returns, using the RESUME instruction, the value of ZRUPT is automatically transferred back into the Z register.



16

BBRUPT

This register is provided as a convenient location for storing the value of the BB register during an interrupt service routine. However, vectoring to the interrupt does not automatically load this register, nor does returning from the interrupt-service routine restore the BB register from BBRUPT. These actions must be done under program control by the interrupt service routine.

17

BRUPT

( Note : As of 20050820, I no longer perform the instruction substitution described below. The internal mechanics of yaAGC are sufficiently different from the true AGC CPU that it should not been needed. I may restore it later.)



This register stores the value stored at the return address of an interrupt service routine. In other words, it is the instruction (not the address of the instruction) which will be executed when the interrupt-service routine returns. When the CPU vectors to an interrupt service routine, it automatically loads this register. When the interrupt-service routine returns, using the RESUME instruction, the value found in the BRUPT register will be used as the next instruction.



It may seem from this description that an interrupt service routine can return to a position in memory from which the interrupt vector occurred, but can arrange to execute an entirely different instruction than what is found at that address. I believe that this statement is true, and obviously such a feature would need to be used with great care. (However, I don't believe that the BRUPT register was really provided for this purpose; I believe that the BRUPT register exists for the purpose of holding instruction which have been altered by a preceding INDEX instruction, as described below under the discussion of the instruction set. The true AGC allowed interrupts to occur between an INDEX instruction and the instruction affected by the INDEX instruction, and so this provision was necessary. However, yaAGC does not allow such interrupts, and conflicts between INDEX and the interrupt system do not arise in yaAGC .)



20

CYR

The "cycle right register", which is one of the four so-called "editing" registers. When a value is written to this register, the value is automatically cycled right (with the least significant bit, bit 1, wrapping into bit 15). For example, if the software attempted to write the following bits to the CYR register,

abc def ghi jkl mno

then the value actually stored in the CYR register would be

oab cde fgh ijk lmn



21

SR

The "shift right register", which is one of the four so-called "editing" registers. When a value is written to this register, the value is automatically shifted right (with the most significant bit, bit 15, being duplicated into bit 14,and the least significant bit, bit 1, being discarded). For example, if the software attempted to write the following bits into the SR register,

abc def ghi jkl mno

then the value actually stored in the SR register would be:

aab cde fgh ijk lmn



This operation corresponds arithmetically to division of a single-precision (SP) value by 2, as it automatically sign-extends the result.



22

CYL

The "cycle left register", which is one of the four so-called "editing" registers. When a value is read back from this register, the value is automatically cycled left (with the most significant bit, bit 15, wrapping into bit 1). For example, if before readback the CYL register contained the bits

abc def ghi jkl mno

then the value actually stored in the CYL register would be:

bcd efg hij klm noa



23

EDOP

The "edit polish opcode register", which is one of the four so-called "editing" registers. This register is used mainly by the interpreter for decoding interpreted instructions (which are packed two to a word), and has little value for other purposes. When a value is written to this register, it is automatically shifted right 7 positions, and the upper 8 bits are zeroed. Though the zeroing of these bits is undefined in the reference documentation, it nevertheless was the behavior of the hardware.



For example, if the software attempts to write the following bits into the EDOP register,

abc def ghi jkl mno

then the value actually stored in the EDOP register would be:

000 000 00b cde fgh

24

TIME2

TIME1 is a 15-bit 1's-complement counter which is incremented every 10 ms. TIME1 by itself overflows every 214*10 ms., or 163.84 seconds. Upon overflow of TIME1, the 14-bit counter TIME2 is automatically incremented. Thus, the two counters together form a 28-bit value which can keep track of time for up to 228*10 ms., or just over 31 days. The TIME1/TIME2 register pair acts as a master clock for the AGC. yaAGC internally clocks this counter.



25

TIME1



26

TIME3

TIME3 is a 15-bit 1's-complement counter which is incremented every 10 ms. It is incremented synchronously with TIME1. Upon overflow, it requests an interrupt (T3RUPT), which results in vectoring to the interrupt service routine at address 4014 (octal). This interrupt is used by the "wait-list" for scheduling multi-tasking.



Incrementing TIME3 is 7.5 ms. out of phase with incrementing TIME4 (i.e., TIME4 increments 7.5ms after TIME3). Thus, if the TIME3 interrupt service routine doesn't take any longer than 6ms. or so, the interrupts for the two will not conflict. Software typically uses this counter by having the interrupt service routine reload the counter with a value chosen to insure that the interrupts occur at a desired rate. For example, to make an interrupt occur once per second, at every interrupt the counter would be reloaded with 214-100=16284 (decimal). Because 10 ms. is usually much longer than the amount of time needed to vector to the interrupt service routine, it is unnecessary in such calculations to account for the time taken by the interrupt vectoring.



yaAGC internally clocks this counter.



27

TIME4

TIME4 is a 15-bit 1's-complement counter which is incremented every 10 ms. Upon overflow, it requests an interrupt (T4RUPT), which results in vectoring to the interrupt service routine at address 4020 (octal). The T4RUPT program services the DSKY's display. (It does not service DSKY keypad.)



Incrementing TIME3 is 7.5 ms. out of phase with incrementing TIME4 (i.e., TIME4 increments 7.5ms after TIME3). Thus, the TIME4 interrupt service routine doesn't take any longer than 2 ms. or so, the interrupts for the two will not conflict. Software typically uses this counter by having the interrupt service routine reload the counter with a value chosen to insure that the interrupts occur at a desired rate. For example, to make an interrupt occur once per second, at every interrupt the counter would be reloaded with 214-100=16284 (decimal). Because 10 ms. is usually much longer than the amount of time needed to vector to the interrupt service routine, it is unnecessary in such calculations to account for the time taken by the interrupt vectoring.



yaAGC internally clocks this counter.



30

TIME5

TIME5 is a 15-bit 1's-complement counter which is incremented every 10 ms. It is incremented 5 ms. out of ph ase with TIME1 and TIME3. Upon overflow, it requests an interrupt (T5RUPT), which results in vectoring to the interrupt service routine at address 4010 (octal). This is used by the digital autopilot (DAP)



Software typically uses this counter by having the interrupt service routine reload the counter with a value chosen to insure that the interrupts occur at a desired rate. For example, to make an interrupt occur once per second, at every interrupt the counter would be reloaded with 214-100=16284 (decimal). Because 10 ms. is usually much longer than the amount of time needed to vector to the interrupt service routine, it is unnecessary in such calculations to account for the time taken by the interrupt vectoring.



yaAGC internally clocks this counter.



31

TIME6

TIME6 is a 15-bit 1's-complement counter which is updated every 1/1600 second by means of a DINC unprogrammed sequence. There is a CPU flag which can mask counting of TIME6 on or off. By writing 1 to bit 15 of i/o channel 13 (octal), TIME6 counting is enabled; conversely, by writing 0 to that bit, the TIME6 counting is disabled. Upon reaching ±0, the counter requests an interrupt (T6RUPT), which results in vectoring to the interrupt service routine at address 4004 (octal), and then turns off the T6RUPT counter-enable bit.



The T6RUPT is used by the digital autopilot (DAP) of the LM to control the jets of the reaction control system (RCS).



Thus a typical use might be:

Load TIME6 with a desired time interval for firing a jet, in 1600ths of a second. The maximum allowable count is 37777 octal, or just a little more than 10 seconds. Enable the counter with bit 15 of i/o channel 13 octal. After the desired time has passed, a T6RUPT occurs, and bit 15 of i/o channel 13 (octal) is reset. yaAGC internally clocks this counter.



32

CDUX

These counters are used to monitor the orientation of the spacecraft. Three Control Data Units (CDUs) are dedicated to measuring the 3 gimbal angles in the Inertial Measurement Unit (IMU). CDUX refers to the "inner" gimbal angle, CDUY refers to the "middle" gimbal angle, and CDUZ refers to the "outer" gimbal angle.



The CDUs are like analog-to-digital converters, and convert the analog angles to digital data comprehended by the CPU. The IMU provides a measurement platform which is stable with respect to the fixed stars, and maintains its orientation with respect to the stars even while the spacecraft itself rotates. The platform is physically mounted on gimbals, and by measuring the gimbal angles, the orientation of the spacecraft with respect to the IMU's stable platform can be deduced by calculation. (Because only 3 gimbals were used, it was possible for the spacecraft to rotate into positions beyond which the stable platform could no longer maintain its stability with respect to the fixed stars, and would thus begin to rotate with the spacecraft. This condition, "gimbal lock", resulted in an inability to continue monitoring spacecraft orientation and acceleration, and required re-entry of all orientation, position, and velocity data into the computer system. A 4th gimbal would have prevented gimbal lock, but was not provided for some reason.)



These counters contain 15-bit 2's-complement unsigned values, and therefore can take values ranging from 0 to 32767 (decimal). The counters are processed with the PCDU unprogrammed sequence (see below) in order to increase the angles by one unit, and are processed with the MCDU unprogrammed sequence to decrease the angles by one unit. The units of measurement are quoted as 40" of arc in Savage&Drake, but actually they were 39.55078125" of arc, making the full range come out to exactly 360 degrees.

33

CDUY



34

CDUZ



35

OPTY

These counters are used to monitor the orientation of the optics subsystem (i.e., the line of sight) or LM rendezvous radar with respect to the spacecraft. Two Control Data Units (CDUs) are dedicated to measuring these relative angles. OPTY refers to the trunnion angle, whereas OPTX refers to the shaft angle. The CDUs are like analog-to-digital converters, and convert the analog angles to digital data comprehended by the CPU.



These counters contain 15-bit 2's-complement unsigned values, and therefore can take values ranging from 0 to 32767 (decimal). The counters are processed with the PCDU unprogrammed sequence (see below) in order to increase the angles by one unit, and are processed with the MCDU unprogrammed sequence to decrease the angles by one unit. The units of measurement are quoted in Savage&Drake as 10" of arc for the optical trunnion angle, or 40" of arc for the radar trunnion angle or optical or radar shaft angles; but they were actually 9.887695312" and 39.55078125" of arc, respectively, making the full range come out to exactly 90 or 360 degrees.



36

OPTX



37

PIPAX

"PIPA" stands for "Pulsed Integrating Pendulous Accelerometer". There are 3 PIPAs mounted on the stable platform of the Inertial Management Unit (IMU). Since the PIPAs are "integrating", they measure changes in velocity (i.e., "delta-V") rather than acceleration, and the counters PIPAX, PIPAY, PIPAZ thus monitor the velocity of the spacecraft (as long as gimbal lock has not occurred). Savage&Drake quote the units as 5.85 cm./sec or 1 cm./sec., but do not state the conditions under which the two different units are used.



These counters are incremented or decremented with PINC or MINC unprogrammed sequences.



40

PIPAY



41

PIPAZ



42

Q-RHCCTR

(RHCP)

"Pitch"

LM only. Each of these registers holds a count in 1's-complement format, indicating the displacement of the rotational hand controller (RHC) in the pitch, yaw, or roll axes. The way this is supposed to work is as follows: There is a deadband near the detent, where the count is supposed to be zero. When outside of the deadband, the counter is supposed to continually update to correspond to the angular displacement. The count begins to be non-zero after the angle has reached about 2°, is calibrated to a count of 42 at 10° (which is the nominal full-scale position), and increases until reaching a mechanical stop at 13°. The counts are supposed to update only if the RHC counts are enabled (bit 8 of output channel 013 set) and when the count is requested (bit 9 of output channel 013 set). In other words, the flight software must enable the counters and then request new data whenever it wants new data. Furthermore, the fact that the RHC is out of detent is reported to the CPU by clearing bit 15 of channel 031 to zero.



In practice, of course, people will be using 3D joysticks intended for games, rather than the actual LM RHC, so there's no way the yaACA program that manages all this can enforce these angles. So the way it actually works is this: yaACA assumes that the usable range in each axis, as reported by the joystick driver, is -127 to +127. (Any values outside this range are simply forced to be -127 or +127.) A raw value of 13 or less appears in the counter register as 0, a raw value of 97 appears in the counter register as 42, and all other values are scaled linearly from these reference points. The formula is Counter = (Raw - 13)/2. The maximum possible count is thus 57. For negative deflections, of course, the same formula applies but is simply negative. This formula is based partially on the characteristics of the LM RHC, but is also partially based on being able to translate from raw joystick values to RHCCTR registers relatively elegantly.



It is, of course, possible to use MINC and PINC commands to alter the value of these register, but in the interest of reliablity, yaACA reports the count to yaAGC via fictitious input channels, 0170 (roll) or 0167 (yaw) or 0166 (pitch). The value in the input channel is a 1's-complement value in the range -57 to +57, and is placed directly in the counter by yaAGC .



43

P-RHCCTR

(RHCY)

"Yaw"



44

R-RHCCTR

(RHCR)

"Roll"



45

INLINK

This register is used to receive digital uplink data from a ground station. After the incoming data word is deposited in the register, the UPRUPT interrupt-request is set. Correct data is in one of two forms: the value 0 (which the ground station may uplink for error-recovery purposes) or the triply-redundant bit pattern cccccCCCCCccccc , where CCCCC is meant to be the logical complement of ccccc , which is always a DSKY-type keycode. Other patterns will be interpreted by the flight software as corrupted data.



46

RNRAD





47

GYROCTR

(GYROCMD)

These registers are used during IMU fine alignment to torque the gyro to the the precise alignment expected by the AGS. (The tolerance of fine alignment is approximately ±80" of arc.) This register is written by the flight software with counts (in AGC 1's-complement format) that represent the desired drive on the currently selected axis. Only one axis can be selected at any given time—namely, +X, -X, +Y, -Y, +Z, or -Z—using bits 7-9 of output channel 014. Each count represents ±0.617981" of arc. Actual torquing of the gyro does not begin until bit 10 of output channel 014 is set. (For completeness, note also that bit 6 of channel 014 is supposed to be set at least 20 ms. prior to any of the other stuff just mentioned.)



If the torque is supposed to be 1-16383 counts, it should be achieved in a single burst. However, if it is greater than that, it should be achieved by bursts of 8192 counts each, with bursts separated by 30 ms. If you examine the Luminary131 software, you'll see that it does exactly this.



Upon detecting a non-zero value in the GYROCTR register while the gyro activity bit (10) in channel 014 is set, the true AGC would emit a stream of electronic pulses at a rate of 3200 pulses per second, with a pulse-count equal to the register value. yaAGC behaves simularly, except that it emits fictitious output channels 0174-0176 , each one of which can contain multiple pulses, scheduled to roughly correspond to the 3200 pps. timing. As soon as yaAGC has read the GYROCTR register, it resets it to zero. I have no idea if the actual AGC did this or not. As soon as yaAGC has read the GYROCTR register, it resets it to zero. I have no idea if the actual AGC did this or not.



50

CDUXCMD

These registers are used during IMU coarse alignment to drive the IMU stable platform to approximately the orientation expected by the AGC. (The tolerance of coarse alignment is approximately ±1.5°.) These registers are written by the flight software with counts (in AGC 1's-complement format) that represent the desired drive in each axis. Each count represents ±0.04375°. (192 counts represent ±8.4 degrees.) The drive sequence does not actually commence until the corresponding drive-enable bit is set in output channel 14 (octal). Bit 15 (the most significant bit) of channel 14 must be set to drive in the X axis, bit 14 in the Y axis, and bit 13 in the Z axis. yaAGC does not perform this operation instantly, but instead simulates the true AGC timing (which emits a burst of 192 count-pulses every 600 ms. when active), using the fictitious output channel 0177. Notice that all three axes can be slewed simultaneously if multiple drive bits are set in channel 014.



yaAGC zeroes the CDUxCMD registers as soon as it has read them while the corresponding drive-bit in channel 014 is set. I have no idea if the actual AGC behaved this way or not.



51

CDUYCMD



52

CDUZCMD



53

OPTYCMD







54

OPTXCMD



55

THRUST

LM only.



56

LEMONM

LM only.



57

OUTLINK

One might suppose that since the INLINK register is used for digital uplinks, then the OUTLINK register is used for digital downlinks. Actually, output channels 013, 034, and 034 are used for digital downlinks, and OUTLINK apparently was not used at all, at least according to the description of it in the symbolic information listing document (p. 33). That document says

Not used. Originally intended for use to provide "crosslink" capability for serial binary data to cell 0045 8 of another computer ....

and then proceeds with a lengthy explanation of exactly how to use the "unused" register that I won't bother to cover here.

