Home
yaAGS et al.
Download
Links
Change log
Bug and issues
Developer info
FAQ
Virtual AGC and AGS
AGC Assembly-Language Programmer's Manual
v0.51 draft, 2004-09-25  

yaAGC
yaYUL
yaDSKY
yaOtherStuff
Luminary
Colossus
Language Manual
Physical Implementations

Contents


Introduction

This manual covers AGC4 assembly-language, as accepted by the yaYUL assembler program.  Additionally, AGC4 interpreter-language is covered.

For those who can tolerate such talk, this document serves as the requirements for processing of machine language by the yaAGC program, as well as for the assembly language accepted by the yaYUL program, and that's why this document is versioned.

The original Apollo documentation from which the information presented here was derived, in roughly descending order of importance, is:
  1. E-2052:  AGC4 Basic Training Manual, Volume I, by Bernard Savage and Alice Drake, January 1967. 
  2. AGC4 Memo #9, Block II Instructions, by Hugh Blair-Smith, July 1966.
  3. E-1077:  Preliminary MOD 3C Programmers Manual, by R. Alonso, J. H. Laning, Jr., and H. Blair-Smith, November 1961.
  4. Keyboard and Display Program and Operation, by Alan I. Greene and Robert J. Filene, June 1, 1967.
  5. Block II AGC Self-Check and Show-Banksum, by Edwin D. Smally, December 1966.
  6. Luminary 131 (1C) assembly listing,  December 19, 1969. 
  7. Colossus 1A (build 249) assembly listing, October 28, 1968.
Where referenced below, I'll denote references 1 and  2 as "Savage&Drake" and "Blair-Smith", respectively.  Where I make statements that I believe to be true, but which I don't think are fully supported by the original Apollo documentation, I will color the text green to indicate uncertainty.

The Interpreter vs. the CPU

If all of the software-provided functionality required for the moon missions had been written straightforwardly in AGC assembly language---i.e., in the native language of the AGC's CPU---more memory would have been needed for program storage than was actually physically provided within the AGC.  It is important to realize that the AGC had no capability of loading programs into memory at runtime, except for extremely tiny code fragments (keyed in manually by the astronauts or uploaded via telemetry uplink). All of the software needed for the mission was encoded in the "core ropes", and these had to be manufactured and hermetically sealed within the computer unit. In other words, all of the software needed to fit within the 38,912 15-bit words of core memory.

To solve this problem, the designers of the AGC chose to use part of the precious core memory to implement a virtual computer-within-the-computer---in much the same way as yaAGC is a virtual computer within another computer. This virtual computer, the "interpreter", was a subprogram (within the larger Colossus or Luminary program) which when activated, read its own instructions from memory and executed them. Because each of the interpreter's instructions represented many AGC assembly-language instructions, a larger amount of functionality could be fitted into the same amount of core memory, even accounting for the fact that software was needed to implement the interpreter. The drawback was that implementing any particular functionality in interpretive language required far more execution time than implementing the same functionality directly in AGC assembly language. But as long as the program ran "fast enough", that didn't matter very much.

The interpreted code is in some ways much more elegant and useful than the pure AGC assembly language.  For example, the interpreter allows for a linear address space (which the pure assembly language does not), and has many "high-level" instructions for doing things like operating on position vectors or state vectors and performing trigonometric operations.  (Thanks to Onno Hommes for pointing out that I wasn't giving as much credit to the developers of the interpreter language as they deserved.)

It is important also to understand that yaAGC has no special support for the interpreter: yaAGC simply runs AGC4 machine code and, as far as it is concerned, the interpreter is just like any other subprogram within Luminary or Colossus. It "just works" with interpreter code.

yaYUL, on the other hand, does require special support for AGC interpreter language.  Interpretive instructions are simply intermixed with assembly-language instructions within a source-code file.  Typically, you'll find a block of assembly-language instructions, followed by a block of interpretive instructions, followed by a block of assembly-language instructions, and so on.  Between an assembly-language block and an interpretive block there will be a call (in assembly language) to the interpreter subroutine.  In other words, the interpreter subroutine expects to find the code it is going to interpret following the assembly language instruction which called it.  Similarly, a block of interpretive code ends with a specific interpreter instruction meaning "stop interpreting and jump to the next location in memory".

Because of this intermixing, this manual describes both AGC assembly language and AGC interpretive language.


General Formatting Information

The format of source code accepted by yaYUL differs slightly from that accepted by YUL. This is partly because without documentation for YUL, determining the exact format required by it requires more effort than I care for; but also, formatting restrictions based on strict column alignment---which make a lot of sense with punch-cards---make little sense now that punch-cards have gone to their final resting place.  (But see the MOD 3C Programmer's Manual, which though covering an earlier, incompatible version of the AGC, does give some information on how YUL was used.)

Here are the principles used in formatting yaYUL source files, along with my stylistic preferences:
These principles are perhaps best understood by viewing actual source-code listings, such as ALARM_AND_ABORT.s from the Luminary 131 source code.

Data Representation

Bit Numbering

AGC memory "words" are 15 bits in size---or rather 15 data bits, plus an odd-parity bit used only by the hardware for error-detection purposes, and not accessible to software. The original AGC documentation referenced the individual bits within a word as

15, 14, 13, 3, 2, 1, P,

where bit 15 is numerically the most significant bit, and bit 1 is the least significant bit.  For yaYUL and yaAGC, the parity bit is not used and is always equal to 0.  Thus, if you were able to inspect the data being used internally by yaAGC or yaYUL, you would often find that it is shifted one bit further to the left than you would otherwise expect.  However, all data in source listings, in yaAGC's --debug mode, etc., eliminate the parity bit (rather than setting it to 0), and therefore symbolically appear exactly as one would expect. 

Single-Precision (SP, 1's-complement) Format

Most arithmetic operations by the CPU use the 15-bit Single Precision (SP) data-type, which is a variant of 1's-complement notation.

In SP binary format, bit 15 is the sign and bits 14-1 represent the data.  If bit 15 = 1, the magnitude is negative and is represented as the one's complement of the positive magnitude (discussed below). Bit 14 is the high order bit (highest value) and bit one is the low order bit (lowest value). For arithmetic purposes the value in bits 14-1 is thought of as a fraction. That is, the binary point is between the sign and bit 14. For instance, a one in bit 14 is equivalent to 1/2 . From a programmer's point of view, the programmer must keep track of the "imaginary" point's position within the word in accordance with the appropriate scaling.

Notice that from this definition, zero has two different representations---as "+0" and as "-0".

Some examples:
To represent an SP number within the assembly-language source code, the constant---i.e., a constant representing a real number---has an optional +/- sign, 0 or more decimal digits, an optional decimal point, and more decimal digits.

In some circumstances, numerical constants may optionally be scaled by factors that are powers of 10 or of 2. To scale by factors of 10, the option field "En" would be added, where n is a decimal integer such as "-1" or "9". This scaling field is separated from the decimal number by whitespace.

Similarly, to scale by factors of 2, the option field "Bn" would be added.

These options may be intermixed on the same line of code. For example, "+656.0 E-4 B3" has the numerical value  656×10-4×23 .  The net result, however, must always be a value whose absolute value is less than 1.0.

In rare cases, the original source code (for example, of Luminary) has a mutilated form of this syntax, of which a typical example would be "+656.0E -4B3". While YUL may have been forgiving of this, yaYUL is not; the spacing of the options needs to be corrected in such a case.

Double-Precision (DP) and Triple-Precision (TP) Format

The fourteen magnitude bits of the SP format do not always allow us sufficient precision. To overcome this, we may represent data in a Double Precision (DP) quantity within two adjacent words of memory.   Since each single precision word has 14 magnitude bits, the combined quantity has 28 bits with which to represent the magnitude.   Bits 14-1 of word 1 represent the more-significant bits and bits 14-1 of the second word represent the less-significant bits.

Bit 15 of the first word contains the sign of the word, and usually of the value itself (unless, of course, the first word is +0 or -0). Bit 15 of the second word will normally be the same as bit 15 of the first word but may differ in certain cases.   When the signs of the two words agree, the words add together; when the signs differ, the words subtract.  Every DP value in which the signs of the words differ can be converted to a representation in which the signs agree, though the reverse is not true.  Some examples may clarify these points:
You may wonder why a situation ever arises in which the sign bits of the words of a DP value don't match, but I do not know the answer.

For even greater accuracy, a quantity may be contained within 3 adjacent words and is called a Triple Precision (TP) quantity.  In essence, we combine 14 additional low order bits so that we have 42 bits to represent the magnitude. Again, the signs of the 3 words may not match, and therefore the individual words may add or subtract to/from each other.  There are no CPU instructions that work with TP quantities, so TP quantities are used mostly by the interpreter.

Vectors

Another Interpreter convention (rather than a format recognized by the CPU)  is that the x,y,z  components of a vector can be represented by three consecutive DP values.

Unsigned-Integer (2's-Complement) Format

There are some cases, such as the CDU counters described in the next section, where the AGC CPU uses 2's-complement values rather than the 1's-complement SP and DP values described above.  2's-complement is used by most computers these days, and in particular, is used by personal computers.  Some examples should suffice to show how an unsigned integer is represented in 2's-complement:
Double-precision unsigned integers are formed simply by using two  consecutive single-precision unsigned integers, with the more-significant 15 bits preceding the less-significant 15 bits in memory.

Integer constants within the assembly-language source code are written either in decimal or in octal form.  In some cases, the context determines which format (octal or decimal) is used; for example, the OCT pseudo-op accepts an octal constant.  In other cases, the structure of the constant itself determines whether it is octal or decimal:
Notice that there is some overlap betweed this definition and that of Single-Precision (SP) constants above. For example, "12345" could be either an octal integer constant or a real constant (but not a decimal integer constant). The difference is determined from context.


CPU Architecture (Registers)

All CPU registers are memory mapped (see the next section).  The registers at addresses 00-23 (octal) are central to CPU operations, from the point of view of the instruction set. 

The registers at addresses 24-61 are generically referred to as "counters".  While the counter registers can be modified under program control, they are typically only set up by the program and are then subsequently automatically incremented or decremented by events such as electrical pulses.  The TIME1-TIME6 registers are even more specialized, in that the "pulses" that increment them are actually provided by an oscillator, so that these counters act as timers.  Many of the counters can be used to trigger interrupts upon overflow, so that the CPU can use them to detect various hardware conditions or events without having to continuously poll the hardware.

A reader familiar with the operation of counter/timer registers in modern CPU types may suppose that incrementing or decrementing the counter/timer registers is entirely a hardware operation having no effect on program flow other than that caused directly by reading the counter/timer registers or by the interrupts generated by the counter/timer registers.  This is not so.  Incrementing or decrementing the counter/timer registers is (and was) actually implemented by the use of "unprogrammed sequences", which are similar to CPU instructions, but which cannot be directly used by the programmer.  The unprogrammed sequences have names like PINC, MINC, PCDU, and so on.  When an electrical pulse occurs that is supposed to affect a timer, the CPU selects an appropriate unprogrammed sequence (such as PINC), waits until a safe opportunity appears to execute the unprogrammed sequence, and then executes the unprogrammed sequence.  For example, an unprogrammed sequence cannot be executed until a regular instruction or an unprogrammed sequence already in progress has completed.  This is significant because it has two side-effects that may be observable:
  1. Counter/timer registers are updated shortly after the hardware pulses associated with them occur ... but not necessarily immediately after the hardware pulse occurs.  The exact length of time before updating the counter/timer is unpredictable and, in theory, could be as little as 1 machine cycles up to a large number (like 20) of machine cycles.  A machine cycle is 11.7 microseconds, and thus it is possible for the time-jitter in updating a counter to be near 0.2 ms.  Since the fastest counters are updated about every 0.3 ms., this jitter can be very significant.  On the other hand, the average delay is much shorter and most counters are updated much less rarely, and stackup of the delays is a very rare event, so this effect can usually be ignored.
  2. Incrementing a counter/timer takes CPU time.  Each of the unprogrammed-sequence instructions which update counters actually take exactly one CPU cycle to execute.  Therefore, the amount of time used by the CPU exceeds the time needed to execute the assembly-language instructions.  Because there are so many counter/timer registers, the CPU time required by the unprogrammed sequences is not necessarily negligible.
It should also be noted that there are two additional timer-counter registers, HISCALAR and LOSCALAR, which appear as i/o channels rather than as memory-mapped CPU registers, and therefore are not listed in the following table.
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:
  1. 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
  2. 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.

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.

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).  Changes to the EB register are immediately automatically mirrored in the BB register, and vice-versa.
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 6th 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 don't actually exist within the AGC, and so it is mere supposition on my part that they would be selected.

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).  Changes to the FB register are immediately automatically mirrored in the BB register, and vice-versa.

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.  Changes in the EB and FB registers are immediately automatically mirrored in the BB register, and vice-versa.  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 transfer of data back and forth between A (16 bits) and ARUPT (15 bits) does not result in loss of overflow indications.
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
(spares)

15
ZRUPT
This register stores the return address 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.   Actually, the contents of the bits 8-15 in the edited result are undefined, as far as I can tell, and making them zero is my own requirement.

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.  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 5 ms. out of phase with incrementing TIME4, so if their respecitve interrupt service routines don't take longer than 4 ms. to execute, 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 5 ms. out of phase with incrementing TIME4, so if their respecitve interrupt service routines don't take longer than 4 ms. to execute, 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.  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 sequenceThere 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:
  1. 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.
  2. Enable the counter with bit 15 of i/o channel 13 octal.
  3. 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.

I assume these counters are incremented or decremented with PINC or MINC unprogrammed sequences, but I haven't found any documentation for this conjecture yet.
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.
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.  I have no idea at all what the OUTLINK register is used for, unless it is somehow used in the downlink process, but not actually accessed by the flight software.
60
ALTM
LM only.


Memory Map

The memory map of the AGC is tricky (to say the least!), and it is necessarily to thoroughly understand the memory map before code can be reasonably written or even understood.

Memory may be categorized in several ways.  Firstly, it may be read-only ("fixed", in AGC terminology) or it may be read-write ("erasable").  Both fixed memory and erasable memory were implemented using magnetic-core technology, but (obviously) using the cores in very different ways.  The AGC also had a memory-like space called "i/o channels", which could not be used for general purposes, but which was used to convey commands or data between the CPU and peripheral devices like the DSKY.

Secondly, the memory (but not the i/o channels) can be categorized as directly addressable via an address ("unswitched") or as addressable only via an address plus a bank number ("switched").  This situation resulted from the fact that 10-bit addresses for erasable memory and 12-bit addresses for fixed memory were built into the AGC instruction set, but that the actual amount of memory required eventually increased far beyond these puny limitations, until eventually 16-bit addressability was required.  With each successive increase in the amount of supportable memory, the methods for supporting the additional memory became more and more ponderous.  The CPU registers EB, FB, and BB, and i/o channel 7 (sometimes denoted FEB) were added for no other reason than to support memory-bank selection.

With these facts in mind, we note that there are 5 basically different types of memory:
But wait (you ask), what about the BB register?  I say it is used for bank selection, but I've not mentioned any functionality for it.  Well, the BB ("both banks") register combined and duplicated the functionality of the EB ("erasable banks") and FB ("fixed banks") registers.  In other words, if the EB and FB registers were completely eliminated, the same bank-selection effects could be obtained by working only with the BB register.  Changes to the BB register are automatically, immediately reflected in changes to the EB/FB registers, and vice-versa.

As if this scheme is not complicated enough, there is yet another complication:  Small areas of some of these memory spaces overlap, so that there is actually not as much memory present in the system as it would seem from the description above.

Interrupt Processing

The AGC has 11 interrupt types.  Interrupts are triggered by external events, but usually not directly so.  Various external signals affect the counter registers (see above), and underflow/overflow of certain of these counters then trigger the actual interrupts.

An interrupt-vector table appears at address 4000 octal in fixed-memory, with table entries spaced at intervals of 4 words.  Each interrupt type vectors to its dedicated address in the vector table.

Vector  Address  (octal)
Interrupt  Name
Trigger Condition
Description
4000
(boot)
Power-up or GOJ signal.
This is where the program begins executing at power-up.
4004
T6RUPT Counter-register TIME6 decremented to 0. The digital autopilot (DAP) for controlling thrust times of the jets of the reaction control system (RCS).
4010
T5RUPT Overflow of counter-timer TIME5.
Used by the autopilot.
4014
T3RUPT Overflow of counter-timer TIME3. Used by the task scheduler (WAITLIST).
4020
T4RUPT Overflow of counter-timer TIME4. Used for various DSKY-related activities such as monitoring the PRO key and updating display data.
4024
KEYRUPT1 Keystroke received from DSKY.
The DSKY transmits codes representing keystrokes to the AGC.  Reception of these codes by the AGC hardware triggers an interrupt.
4030
KEYRUPT2 Keystroke received from secondary DSKY.
In the CM, there was a second DSKY at the navigator's station, used for star-sighting data, in conjunction with the Alignment Optical Telescope (AOT).  There was no 2nd DSKY in the LM, but the interrupt was not re-purposed.
4034
UPRUPT Uplink word available in the INLINK register.
Data transmitted from ground-control for the purpose of controlling or monitoring the AGC is in the form of a serial data stream which is assembled in AGC INLINK counter-register.  When a word has been assembled in this fashion, an interrupt is triggered.
4040
DOWNRUPT The downlink shift register is ready for new data (output channels 34 & 35).
Used for telemetry-downlink.
4044
RADAR RUPT Overflow in the counter-register RNRAD. Data from the rendezvous radar is apparently assembled similarly to the uplink data described above.  When a data word is complete, an interrupt is triggered.
4050
RUPT10 (LM)
TBD Used for LM landing guidance, but details are TBD
HANDRUPT (CM)
TBD Used for CM hand control, but details are TBD


There is a master interrupt-enable mask, and when interrupts are disabled the interrupt-vectoring described above does not take place.  Interrupts are globally enabled by the RELINT instruction (see below), and are globally disabled by the INHINT instruction.

Enabling interrupts globally does not necessarily cause an interrupt to immediately occur even if one has been requested.  Other conditions which defer processing of interrupts include:
When an interrupt request is processed, the following steps are taken:
  1. The current contents of the program counter (Z register) is saved into the ZRUPT register.
  2. The instruction appearing at the memory location pointed to by the program counter is saved into the BRUPT register.
  3. Control passes to the appropriate vector-table location, as listed above.
  4. Execution then continues (with interrupts inhibited) until the interrupt-service routine returns using the RESUME instruction.
It should also be pointed out that since an interrupt service routine preserve the values of all memory locations not specifically allocated to it, including the central registers, it is necessary for an interrupt-service routine to specifically save all registers which it intends to use, and then to restore them before returning.  The registers ARUPT, LRUPT, QRUPT, and BBRUPT are provided for the specific purpose of temporarily storing the A, L, Q, and BB registers during interrupt processing.


Instruction Representation

Assembly-Language Instructions

By original design, every instruction in the AGC instruction set occupied precisely one word of memory (including operand), and consisted of 15 bits as follows:

CCC AAA AAA AAA AAA

The 3-bit field CCC represents the instruction type (the "code"), while the 12-bits AAAAAAAAAAAA represent a memory address.  With this simple scheme, there are at most 8 instruction types, each of which can operate on any memory location (assuming that memory consists of 4096 words).  However, as the number of required instruction types ballooned, more complex instruction encoding was introduced, and several different new types of encoding appeared.  The required memory also ballooned but (as described above), the introduction of banking allowed continued use of 12-bit addressing in the instruction encoding.
It is also worth noting that when an instruction operates on double-precision (DP) values, it necessarily addresses a pair of words in memory rather than a single memory word.  In these cases, the address field points to the second word of the pair.  For example consider the "double exchange" instruction DXCH, which has Code=5 (CCC) and QC=1 (QQ).  The instruction "DXCH K", where (say) K is the program label associated with address 70 octal.  This instruction would exchange the contents of the A,L register pair with the values stored at addresses 70 and 71.  The address field AAAAAAAAAA would be encoded as 00071 rather than 00070.  The instruction itself would be encoded as the octal value 52071.  This is, of course, handled automatically by the assembler and is not usually something of direct concern to the programmer.

Interpretive Instructions

TBD


AGC4 Instruction Set

AD

Description:
The "Add" instruction adds the contents of a memory location into the accumulator.
Syntax:
AD K
Operand:
K is the label of a memory location.  It must assemble to a 12-bit memory address.
Extracode: This is not an extracode, and therefore cannot be preceded by an EXTEND instruction.
Timing:
2 MCT (about 23.4 µs)
Flags:
The Overflow depends on the result of the operation, and can be positive, negative, or none.  The Extracode flag remains clear. 
Editing:
Editing is done upon writing to K, if K is CYR, SR, CYL, or EDOP.
Octal:
60000 + K
Notes:
The accumulator is not overflow-corrected prior to the addition.  The contents of K are added to the accumulator, which retains any overflow that resulted from the addition.

A side-effect of this instruction is that K is rewritten after its value is written to the accumulator; this means that if K is CYR, SR, CYL, or EDOP, then it is re-edited.

Note that the normal result of AGC arithmetic such as (+1)+(-1) is -0.

For the special case "AD A", refer instead to the DOUBLE instruction.

ADS

Description:
The "Add to Storage" instruction adds the accumulator to an erasable-memory location (and vice-versa).
Syntax:
ADS K
Operand:
K is the label of a memory location.  It must assemble to a 10-bit memory address in erasable memory. 
Extracode: This is not an extracode, and therefore cannot be preceded by an EXTEND instruction.
Timing:
2 MCT (about 23.4 µs)
Flags:
The Overflow is set according to the result of the addition.  The Extracode flag remains clear. 
Editing:
Editing is done upon writing to K, if K is CYR, SR, CYL, or EDOP.
Octal:
26000 + K
Notes:
The contents of the accumulator and K are added together, and the result is stored both in the accumulator and in K.  The accumulator is neither overflow-corrected prior to the addition nor after it.  However, the sum is overflow-corrected prior to being saved at K if K is a 15-bit register.  If K is a 16-bit register like L or Q, then the sum is not overflow corrected before storage.

Note that the normal result of AGC arithmetic such as (+1)+(-1) is -0.

If the destination register is 16-bits (L or Q register), then the non-overflow-corrected values added.

AUG

Description:
The "Augment" instruction increments a positive value in an erasable-memory location in-place by +1, or a negative value by -1.
Syntax:
AUG K
Operand:
K is the label of a memory location.  It must assemble to a 10-bit memory address in erasable memory. 
Extracode: This is an extracode, and therefore must be preceded by an EXTEND instruction.
Timing:
2 MCT (about 23.4 µs)
Flags:
The Overflow is set according to the result of the operation.  The Extracode flag is cleared.
Editing:
Editing is done upon writing to K, if K is CYR, SR, CYL, or EDOP.
Octal:
24000 + K
Notes:
If K is a 16-bit register like A, L, or Q, then arithmetic is performed on the full 15-bit value (plus sign).  Otherwise, only the available 14-bit value (plus sign) is used.

If the contents of K before the operation is greater than or equal to +0, it is incremented by +1.  On the other hand, if it is less than or equal to -0, it is decremented.

If K is one of the counter registers which triggers an interrupt upon overflow, then an oveflow caused by AUG will trigger the interrupt also.  These registers include TIME3-TIME6.  Furthermore, if K is the TIME1 counter and the AUG causes an overflow, the TIME2 counter will be incremented.  Some of the counter registers such as CDUX-CDUZ are formatted in 2's-complement format, but the AUG instruction is insensitive to this distinction and always uses normal 1's-complement arithmetic.

BZF

Description:
The "Branch Zero to Fixed" instruction jumps to a memory location in fixed (as opposed to erasable) memory if the accumulator is zero.
Syntax:
BZF K
Operand:
K is the label of a memory location.  It must assemble to a 12-bit memory address in fixed memory.  (In other words, the two most significant bits of address K cannot be 00.)
Extracode: This is an extracode, and therefore must be preceded by an EXTEND instruction.
Timing:
1 MCT (about 11.7 µs) if the accumulator is plus zero or minus zero, or 2 MCT (about 23.4 µs) if the accumulator is non-zero.
Flags:
The Overflow is not affected.  The Extracode flag is cleared.  The Q register is unaffected.
Editing:
The CYR, SR, CYL, and EDOP registers are not affected.
Octal:
10000 + K
Notes:
If the accumulator is non-zero, then control proceeds to the next instruction.  Only if the accumulator is plus zero or minus zero does the branch to address K occur.  The accumulator (and its stored overflow) are not actually modified.

Note that if the accumulator contains overflow, then the accumulator is not treated as being zero, even if the sign-corrected value would be +0 or -0.

This instruction does not set up a later return.  Use the TC instruction instead for that.

Indirect conditional branch:  For an indirect conditional branch, it is necessary to combine an INDEX instruction with a BZF instruction.  Refer to the entry for the INDEX instruction.

BZMF

Description:
The "Branch Zero or Minus to Fixed" instruction jumps to a memory location in fixed (as opposed to erasable) memory if the accumulator is zero or negative.
Syntax:
BZMF K
Operand:
K is the label of a memory location.  It must assemble to a 12-bit memory address in fixed memory.  (In other words, the two most significant bits of address K cannot be 00.)
Extracode: This is an extracode, and therefore must be preceded by an EXTEND instruction.
Timing:
1 MCT (about 11.7 µs) if the accumulator is zero or negative, or 2 MCT (about 23.4 µs) if the accumulator is positive non-zero.
Flags:
The Overflow is not affected.  The Extracode flag is cleared.  The Q register is unaffected.
Editing:
The CYR, SR, CYL, and EDOP registers are not affected.
Octal:
60000 + K
Notes:
If the accumulator is positive non-zero, then control proceeds to the next instruction.  Only if the accumulator is plus zero or negative does the branch to address K occur.  The accumulator and its stored oveflow are not actually modified.

Note that if the accumulator contains +overflow, then the accumulator is not treated as being zero, even if the sign-corrected value would be +0.  If the accumulator contains negative overflow, then the value is treated as being negative non-zero, so the jump is taken.

This instruction does not set up a later return.  Use the TC instruction instead for that.

Indirect conditional branch:  For an indirect conditional branch, it is necessary to combine an INDEX instruction with a BZMF instruction.  Refer to the entry for the INDEX instruction.

CA (or CAE or CAF)

Description:
The "Clear and Add" (or "Clear and Add Erasable" or "Clear and Add Fixed") instruction moves the contents of a memory location into the accumulator.
Syntax:
CA K
or
CAE K
or
CAF K
Operand:
K is the label of a memory location.  It must assemble to a 12-bit memory address.  The CAE or CAF variants differ from the generic CA, only in that the assembler is supposed to display error messages if K is not in erasable or fixed memory, respectively.
Extracode: This is not an extracode, and therefore cannot be preceded by an EXTEND instruction.
Timing:
2 MCT (about 23.4 µs)
Flags:
The Overflow is cleared, unless K is the accumulator or the Q register.  The Extracode flag remains clear. 
Editing:
Editing is done upon writing to K, if K is CYR, SR, CYL, or EDOP.
Octal:
30000 + K
Notes:
A side-effect of this instruction is that K is rewritten after its value is written to the accumulator; this means that if K is CYR, SR, CYL, or EDOP, then it is re-edited. 

Note that if the source register contains 16-bits (like the L or Q register), then all 16 bits will be transferred to the accumulator, and thus the overflow will be transferred into A.  On the other hand, if the source register is 15 bits, then it will be sign-extended to 16 bits when placed in A.

For the special case "CA A", refer instead to the NOOP instruction.

CCS

Description:
The "Count, Compare, and Skip" instruction stores a variable from erasable memory into the accumulator (which is decremented), and then performs one of several jumps based on the original value of the variable.  This is the only "compare" instruction in the AGC instruction set.
Syntax:
CCS K
Operand:
K is the label of a memory location.  It must assemble to a 10-bit memory address in erasable memory.
Extracode: This is not an extracode, and therefore cannot be preceded by an EXTEND instruction.
Timing:
2 MCT (about 23.4 µs)
Flags:
The Overflow is set according to the result of the operation.  The Extracode flag remains cleared.
Editing:
The contents of K is edited if K is one of the special registers CYR, SR, CYL, or EDOP.
Octal:
10000 + K
Notes:
The operation of this instruction is rather complex:
  1. The "Diminished ABSolute value" of the contents of memory-location K is loaded into the A register.  The diminished absolute value is defined as DABS(x)=|x|-1 if |x|>1, or +0 otherwise.   (If K is a 16-bit register like A, L, or Q, then its contents may contain + or - overflow; overflow correction is not performed prior to the operation.)
  2. After computing the contents of the accumulator, the contents of K is "edited", if K is one of the registers CYR, SR, CYL, or EDOP, but is otherwise unchanged from its original value. 
  3. A jump is performed, depending on the original (unedited) contents of K:  If greater than +0, execution continues at the next instruction after the CCS.  If equal to +0, execution continues at the 2nd instruction after the CCS.  If less than -0, execution continues at the 3rd instruction after the CCS.  If equal to -0, execution continues at the 4th instruction after the CCS.   (If K is 16 bits, then the original contents may contain + or - overflow; in this case, the value is treated as + or - non-zero, even if the sign-corrected value would have been 0.)
A typical use of this instruction would be for loop control, with "CCS A".

Note that the net effect of the way overflow is treated when K is A, L, or Q is to allow 15-bit loop counters rather than mere 14-bit loop counters.  For example, if A contains +1 with +overflow, then CCS A will place +0 with +overflow into A, and another CCS A will place 037777 without overflow into A, and thus no anomaly is seen when decrementing from +overflow to no overflow.

The overflow of the accumulator will generally be cleared by this operation except in the kinds of cases decribed in the preceding paragraph.

COM

Description:
The "Complement the Contents of A" bitwise complements the accumulator
Syntax:
COM
Operand:
This instruction has no operand.
Extracode: This is not an extracode, and therefore cannot be preceded by an EXTEND instruction.
Timing:
2 MCT (about 23.4 µs).
Flags:
The Overflow is unaffected. The Extracode flag remains clear. 
Editing:
The editing registers CYR, SR, CYL, or EDOP are unaffected.
Octal:
40000
Notes:
All 16 bits of the accumulator are complemented.  Therefore, in addition to negating the contents of the register (i.e., converting plus to minus and minus to plus), the overflow is preserved.

This instruction assembles as "CS A".

CS

Description:
The "Clear and Subtract" instruction moves the 1's-complement (i.e., the negative) of a memory location into the accumulator.
Syntax:
CS K
Operand:
K is the label of a memory location.  It must assemble to a 12-bit memory address.
Extracode: This is not an extracode, and therefore cannot be preceded by an EXTEND instruction.
Timing:
2 MCT (about 23.4 µs)
Flags:
The Overflow is cleared, unless K is the accumulator.  The Extracode flag remains clear. 
Editing:
Editing is done upon writing to K, if K is CYR, SR, CYL, or EDOP.
Octal:
40000 + K
Notes:
A side-effect of this instruction is that K is rewritten with its original value after the accumulator is written; this means that if K is CYR, SR, CYL, or ED