Contents copyright Tom Jennings 1999-2002
Operators Manual
for the
Universal Machine
(preliminary design draft)
15 December 2001
Tom Jennings
World Power Systems
1 February 2001
CONTENTS
NOTES ON THE PRELIMINARY DRAFT 3
OPERATORS CONTROL PANEL 4
Indicators 4
Control switches 5
Examine circulator contents 6
Modify circulator contents 6
Examine drum sector 7
Modify drum sector 7
Stepping orders
THE VIRTUAL MACHINE 9
High speed storage 10
Drum organization 10
Optimum coding 13
Flip-flops Cy and Z 14
Order word format 14
Order execution 15
Order types 16
MACHINE ORDER DESCRIPTIONS 18
Drum operand orders 18
Literal orders 20
Other digit manipulation orders 22
Skip orders 23
Machine control orders 25
THE AUTOMATIC COMPILER 26
Teletype characters 27
Orders 29
Constants and numbers 29
Named variables 29
Meta-orders 30
PROGRAMMING CONVENTIONS 32
POWER CONTROL PANEL 33
LIBRARY ROUTINES 34
APPENDIX A: Order codes
APPENDIX B: Teletype characters 41
APPENDIX C: Powers of two 43
APPENDIX D: Initial orders 44
NOTES ON THE PRELIMINARY DRAFT.
This is the functional description of the logical machine. The peculiar writing style is entirely intentional; it is an unapologetically revisionist crib of Wilkes' 1951 Preparation of Programs for an Electronic Digital Computer, with a few major deviations, all of which are to take advantage of a half-century of computer culture and experience: logical and physical concepts are entirely separated; the modern notion of a 1970's-style "assembly language" is built-in; now-routine (pun intended) and natural-seeming linkage of subroutines are not treated as so dificult and abstract as they seemed in 1950. Wilkes' system is very hard to follow with modern eyes, since he has entangled his cobbled-up teletype code with machine definitions (of course this is no criticism of Wilkes' groundbreaking work of programming technique on the world's first fully-functional stored-program computer, though he did benefit from the organizational theft of Turing's work).
Also note that the cultural-assumption gulf from then til now is huge, for items small and large. With a few notable exceptions (eg. today a non-linear memory organization would get chapter to itself; in this machine the ramifications are barely hinted at; (the concept of a "character" vs. a teletype "letter", long since settled with character code standards), any anachronisms that cropped up were disposed of in favor of modern constructs, because it doesn't matter how nifty it is if no one can understand it.
The very existence of the "automatic compiler " (aka assembler) is an anachronism, as such things were not widely considered a good idea in 1955, even, and the two-pass assembler here is very1975.
Further, many of the sections are simply incomplete. This version is not intended to be complete, but only to impart the flavor of the final project, though it does in fact represent more or less what is currently the "final" design.
--tomj 20 June 2001
OPERATOR'S CONTROL PANEL
The control panel on the front of the Machine directs the initial and overall operation of the machine. The control panel is used to initiate program loading, both manually and from tape, into the main drum store, and may be used for manually examining and modifying drum contents, and for running programs one order at a time to isolate problems within a program.
The control panel contains switches with which the operator manipulates the workings of the machine, and indicators that respond to events and status within the machine, both manually instigated and during automatic operation.
INDICATORS
The RUN and STOP lamps indicate whether or not the Machine is executing orders. The Machine remains in the STOP state until the RUN switch is depressed (presumably a program has already been loaded, as described in later sections). Once running, the machine will stop when the STOP switch is depressed or a HALT order is encountered.
The LAMP REGISTER, containing 18 lamps corresponding to the 18 digits in a word, displays the contents of either circulator A, C or K, or the drum sector whose address is contained in circulator C, depending on the position of the LAMP REGISTER FUNCTION switch. (The latter is labeled "D" on the switch.)
Additional lamps indicate the internal state of the Machine during the operation of a program or routine. For every order encountered, the Machine passes through four discrete states in turn:
FETCH:SEARCH The drum location containing the order is found.
FETCH:LOAD The order is read from the drum and decoded.
EXECUTE:SEARCH If required, drum location containing operand found.
EXECUTE:RUN The order is executed.
The FETCH lamp is lit when the machine is in either of the first two states, when an order is being located on the drum or loaded into machine. (It will be lit more brightly when the machine is stopped.)
The EXECUTE lamp is lit when the machine is executing an order or locating a drum-stored operand, eg. when the machine is in the RUN state.
The MEMORY-SEARCH lamp lights during the first or third states, when the drum is searching for the order to execute or the operand possibly required by the previously-fetched order. The third state is skipped (more accurately, it becomes one digit-time in duration rather than one minor cycle in duration) if the most recently fetched order does not indicate a drum operand is required.
The CARRY and ZERO lamps directly display the current state of the Cy and Z flip-flops, respectively. The of these flip-flops are covered in other sections of this manual.
Each subassembly of the Machine has its own set of indicators that display more detailed status of program and machine operation that may be of use to the skilled operator, but these are outside the scope of this manual. Please refer to the Hardware Reference manuals for details.
CONTROL SWITCHES
Manual control switches provide direct manipulation of the Machine, sufficient to manually enter initial orders, provide input to running programs, or to examine and modify errant programs.
The STOP toggle switch, when raised, halts an executing program after the current order is complete, leaving the machine in the STOP state. Raising STOP does not modify the state of the machine nor any circulator contents, therefore, raising STOP switch can be considered an arbitrarily long pause in program execution, if followed by pressing the START switch. Raising the STOP switch has no effect if the machine is in the STOP state.
The START momentary switch initiates continuous program operation (if the STOP toggle is in the lowered position) or a single order is executed (STOP toggle in the raised position). In either case the first, or only, order executed is the drum location indicated by the contents of register C. If a running program was stopped with the STOP switch it may be restarted at any time with the START switch. Please note that if any changes were made to drum contents or any of the circulators it may not be possible to resume a paused program without manually restoring the contents of the A and C circulators.
The RESET switch, operable only when the machine is in the STOP state, clears all circulators to zeros, resets the Cy and Z flip-flops, sets the teletype output digit to the marking state, etc. It does not modify drum contents.
The SWITCH REGISTER FUNCTIONrotary determines what is displayed in the LAMP REGISTER, either register A, C, K, or the contents of the drum sectors whose address is the contents of C, labelled "D" on the front panel. This switch has no effect on the operation of the machine and may be changed at any time. The operator may find this less than useful while a program is running.
The SWITCH REGISTER consists of 18 switches which correspond to the 18 digits in a word. It can control execution of running programs with the use of the SWA order, or when the machine is in the STOP state, used to specify new contents for circulators A or C, or the drum sector whose address is contained in circulator C, when the STORE-A, STORE-C, STORE-D switches, respectively, are pressed. The most-significant 6 digits of the switch register are ignored when modifying register C.
When the SWITCH REGISTER is used as programmatic input, it is generally convenient to first execute a HALT order to stop the machine at the point at which it is desired to read the switch register; instructions to the operator then consist of making the appropriate settings on the switch register then pressing START.
EXAMINE CIRCULATOR
At any time the LAMP REGISTER FUNCTION rotary switch can be used to examine the contents of circulators A, C, or K, causing them to be written to the LAMP REGISTER. This is mostly useful when the machine is stopped.
MODIFY CIRCULATOR
The STORE-A, STORE-C, and STORE-D momentary switches cause the contents of the SWITCH REGISTER to be written into the circulator A or C, or D, the drum location specified by C. The machine must be in the STOP state for these switches to be functional. PLEASE NOTE that modifying D leaves circulator A in an indeterminate state; if the contents of A must be maintained it must be done so manually by the operator.
The INCREMENT-C momentary switch causes one to be added to the current contents of the C circulator, when the machine is in the STOP state. This is useful when examining or modifying sequential drum locations.
EXAMINE DRUM SECTOR
It is assumed that the machine is in the STOP state.
Set the SWITCH REGISTER to the track and sector address to be examined.
Press STORE-C to place this address into the C register.
The drum sector is searched for and displayed in the LAMP REGISTER.
Pressing INCR-C advances the C register by one, and therefore the particular drum sector displayed on the LAMP REGISTER.
MODIFY DRUM SECTOR
It is assumed that the machine is in the STOP state.
Set the SWITCH REGISTER to indicate the drum track and sector address to be modified.
Press STORE-C to place this address into the C register.
The drum sector is searched for and the current contents are displayed on the LAMP REGISTER.
Set the SWITCH REGISTER to the value to be stored into this drum sector.
Press STORE-D to write this value to the drum sector. The LAMP REGISTER will display the new contents.
Pressing INCR-C advances the C register by one, and therefore the particular drum sector displayed on the LAMP REGISTER. These final three steps may be repeated as necessary.
PLEASE NOTE that this operation modifies the A circulator; if its contents must me maintained (eg. A program is being repaired before it is restarted) the contents of A must be recorded and restored manually.
STEPPING ORDERS
The high speed of program execution sometimes paradoxically interferes with identifying and repairing problems within programs. The control panel provides a single-order-step function to help with location logical problems within programs.
With the Machine in the STOP state:
Leave the STOP/STEP switfch in the STOP/STEP position.
Press the RUN switch once.
With each pressing of the RUN switch thus, one order only will be executed. Registers and drum may be examined as necessary. Please note that the operator must restore the contents of any circulators modified, and the accumulator if drum contents are modified.
Additionally, the operator may find it useful to place HALT orders in strategic locations throughout a program under development; after examining registers and drum contents, and possibly modifying these, pressing the RUN switch will continue executing the program beginning with the order following the HALT order, unless otherwise modified.
A further technique might involve reading the SWITCH REGISTER with the SWA order, and conditionally executing the HALT order as above, or instead other orders convenient for testing.
THE OPERATOR'S VIRTUAL MACHINE
[This is an utter anachronism, this "virtualized" machine, a far too modern view of things, but really, without which the major point of this project (making the obscure more visible) would be incomplete.]
The basic machine organization is that of a single rotating magnetic drum comprising the sole store, and a logical control that executes orders stored on the drum. A teletype and paper tape reader and punch provide input/output facilities and program storage.
From the operator's point of view the machine consists of the following:
Twenty-six one-address machine orders.
Three circulators comprising the high-speed store:
The accumulator, A, 18 binary digits in size.
The command counter, C, 12 binary digits in size.
The constant register K, 12 binary digits in size.
A single main store of approximately 4096 18-digit words, contained in N tracks.
Two flip-flops, Z and Cy, and their complements, NZ and NCy.
One binary digit each of input and output, for communicating with a teletype.
A control panel containing lamps and switches for directing the overall operation of the Machine.
ONE ADDRESS ARCHITECTURE
This machine provides 26 unique orders that operate on the high-speed and main store and other machine facilities. The orders and their format is described in detail in the ORDER WORD FORMAT section.
This machine uses a one-address order code, and each order contains a 12-digit field that may refer to a drum store location. The location of the "next order" to execute is taken to be the current location plus one, unless directed to a different location by machine orders themselves. (The address of the current/next order is contained in the C circulator.)
Order execution is covered in more detail in later sections.
HIGH-SPEED STORAGE
There are three circulators and two flip-flops that provide high-speed storage for symbols, known by their single-letter names:
Most significant digit Least significant
A: |17|16|15|14|13|12|11|10|09|08|07|06|05|04|03|02|01|00|
C: |11|10|09|08|07|06|05|04|03|02|01|00|
K: |11|10|09|08|07|06|05|04|03|02|01|00|
Z: |00|
Cy: |00|
The numbers indicate both the relative position of each digit in this document as well as the power-of-two exponent for that digit's position.
All of the machine orders operate upon one or more of these high-speed storage components, as described in the MACHINE ORDERS section below. The circulators have a maximum access time equal to the minor cycle time; there is no additional rotational latency incurred.
Please note that the K circulator is somewhat of an abstraction, being in fact the K field of the order code. It cannot be modified during order execution, though it can be modified while the encompassing order is stored on the drum, before it is executed, using the STA or STO orders.
DRUM ORGANIZATION
The sole store for orders and data is the rotating drum memory of [approximately 4096] 18-bit words, stored on N drum tracks. The drum rotates on its axis, and a row of electromagnetic read/write heads are fixed along the length of the drum. As the drum rotates, a circumferencial track of the drum passes under each fixed read/write head. This drum track is logically considered as 64 radial sectors, each of which contains one storage word. An index mark inscribed elsewhere on the drum determines the 0th sector on all tracks.
There are no "read-around" issues or other limitations on how the main store is accessed.
Drum track and sector comprise a unique address for each sector, and are packed into the address field of each order as follows:
12 0
M 0
T T T T T S S S S S S S
|<------constant----->|
T Specifies the track number, 0 - N
S Specifies the sector number, and runs 0 to 63
[NOTE: IF SECTORS PER TRACK IS NOT A POWER OF TWO:] Note that if the last sector of a track contains an order, that order must be a JUMP to another sector address, and the second-last order should not be a SKIP.
Sectors are not in fact numbered sequentially within each track, but with an increment of 4, so that sequential access to every sector within a given track, (eg. 0, 1, 2, 3, 4, ...63) requires 4 complete revolutions of the drum. The reason for this is that the minimum order execution time is three minor cycles to complete; therefore for those orders that do not refer to a drum-located operand, the "next" order (as indicated by the contents of the C circulator) is just reaching the drum read head in time for its execution. (One minor cycle is required for the address comparison, hence the skew factor is 4, not 3.)
However, for most practical purposes, the drum sectors can be considered as sequential with a location-to-location access time of 4 times the drum rotation time:
Minimum main store access time = 800 microseconds
This obviously implies that orders that refer to a drum operand incur additional delays locating the operand, which may in fact be placed anywhere on the drum's surface, at the convenience of the operator. The sector skew table in the OPTIMUM CODING section should be referred to to determine optimum coding locations.
The actual delay can be calculated as follows:
(|S - C + 1| * 800 uS + T) + (|C - S| * 800 uS + T)
where
C is the contents of the C circulator,
S is the contents of the operand field, sector adress
T is 0 if the operand is located in the same track as the current order,
else 20mS if the operand is contained in a different track.
Clearly it is in the operator's interest to keep frequently-accessed drum locations on the same track wherever possible. However rotational latency cannot be completely overcome, though it can be minimized through careful design.
OPTIMUM CODING
Due to the serial nature of the drum storage mechanism, unless the operator takes painstaking care in laying out his program around the drum, programs will execute quite slowly, with an average order execution time of ½ a drum revolution period. This can be objectionably slow but with care can be markedly improved with optimum coding.
Optimum coding is the technique of placing orders and temporary storage locations in strategic sectors within a track, and in general arranging orders to account for rotational latency. For example, the Gill Test for this Machine was improved by more than a factor of 20 in execution speed merely by placing variable storage in optimum sectors.
To facilitate these calculations, please refer to the following sector skew table. Many organizations of this table are possible; this one lists the logical sector numbers in physical order starting with the 0th sector (which is un-skewed). For example, for an order at location 24 (decimal) the "next" sector (mimimum latency) is sector 4; the next-least latency, 1000 uS, is sector 21, etc.
Skew table, 64x4, decimal
00: 0 16 32 48
04: 1 17 33 49
08: 2 18 34 50
12: 3 19 35 51
16: 4 20 36 52
20: 5 21 37 53
24: 6 22 38 54
28: 7 23 39 55
32: 8 24 40 56
36: 9 25 41 57
40: 10 26 42 58
44: 11 27 43 59
48: 12 28 44 60
52: 13 29 45 61
56: 14 30 46 62
60: 15 31 47 63
Skew table, 64x4, octal
00: 0 20 40 60
04: 1 21 41 61
10: 2 22 42 62
14: 3 23 43 63
20: 4 24 44 64
24: 5 25 45 65
30: 6 26 46 66
34: 7 27 47 67
40: 10 30 50 70
44: 11 31 51 71
50: 12 32 52 72
54: 13 33 53 73
60: 14 34 54 74
64: 15 35 55 75
70: 16 36 56 76
74: 17 37 57 77
[This section to be greatly expanded.]
FLIP-FLOPS CY AND Z
There are two flip-flops that can be used to direct order execution. Each is set (equal to value of 1) or reset (equal to a value of 0) by intentional side effects of certain arithmetical and logical orders. Other orders may then use the state of the flip-flops as implicit operands or to control the order execution order conditionally upon the value of either flip-flop.
The Z flip-flop is modified during the execution of certain arithmetical/logical orders such that it is set to "1" when all digits of A are zero, and reset to "0" if any one or more digits of A contain 1. It is specifically not modified by any other orders.
The CY flip-flop is modified similarly by the arithmetic orders, being set to "1" if there is arithmetic overflow during addition, or cleared to "0" otherwise. The RLC order shifts the most-significant digit of the accumulator into the CY flip-flop. CY is cleared to zero by certain other logical orders.
ORDER WORD
FORMAT
17 11 0
W M 0
X O O O O O K K K K K K K K K K K K
|<order>| |<------constant----->|
or
17 11 0
W M 0
X O O O O O T T T T T T S S S S S S
|<order>| |<---drum location--->|
The order field is a 5-digit field that defines the order code, described below. The most-significant digit, 17, of an order is undefined and may take any value, 0 is generally is assumed.
The meaning of bits 0 through 11 depend on the particular order. They can contain a literal unsigned constant operand in the range of 0 through 4095, the drum address of the order's operand, or it may be undefined. When used as a drum address it is takes the form defined in the DRUM ORGANIZATIONsection. Orders that refer to an operand stored on the drum have a variable execution time, as the time needed to access the specified drum location depends on the current and desired drum addresses.
NUMBERS
When the contents of circulators and drum storage locations are treated as a numerical value, the following conventions are assumed, especially as they pertain to the arithmetical operations of the machine. These are of course only conventions for the convenience of discussion, and these assumptions can be modified in any way consistent with the operation of the machine.
All arithmetic operations assume operands to be positive, unsigned integers, with the least-significant digit to be the right-most digit when written on paper in the conventional manner. All machine operations on storage or circulator words begin with the least significant digit, proceeding to the most-significant, and during addition, propagating carry from the previous (lesser) digit's addition.
Subtraction and negative numbers in general can be done using two's-complement conventions. Addition of the two's-complement 'subtrahend' (made with the COM n order) effectively subtracts, with borrow indicated by the Cy flip-flop.
ORDER EXECUTION
Orders are executed sequentially as they are read from the drum unless the sequence is modified by orders themselves, as is often the case. The initial starting location is determined by manual setting of the machine's switch panel (see the OPERATOR'S CONTROL PANEL section), programs traditionally starting afresh from track 0 sector 0. Once a program is started, the program itself is in complete control of order execution (including unintentional errors).
The location of the 'next' order to execute is held in the C circulator. During the execution phase of each order, the contents of circulator C increases by one. There are orders that directly modify the contents of the C circulator.
When it is time to execute the next order, wherever it might be on the drum, the control circuitry selects the desired drum track (delaying as necessary for the control circuitry to catch up) and waits for the desired sector to rotate under the read/write head of that track. The amount of time required to locate the target sector depends on the angular distance from the current sector; it can be as little as four minor cycles (four word times), or nearly one major cycle, or one full drum revolution.
Therefore, order execution time depends on the distance the drum must rotate and is quite variable, and must be taken into account when designing time-sensitive programs. The use of per-track sector layout sheet (and a lot of practice) makes this task easier. Please refer to the OPTIMUM CODING section for more details.
ORDER TYPES
It is occasionally useful to group orders by the type of functions they perform. Note that many orders allow for side effects, intentional or otherwise, that can be exploited to achieve goals not necessarily defined here. [The subject of backwards compatibility and exploitation of "undocumented" effects actually deserves a paragraph unto itself, or even a whole history.]
Arithmetic and logical orders
Arithmetic and logical operations are performed on the accumulator and either a drum word or a literal operand contained in the order (K). The results of the operation are always placed in the accumulator, and may modify the Z or Cy flip-flops, depending on the particular order. When a drum location is the operand the drum track and sector specified in the order must be searched for; therefore the execution time of the order is dependent on the difference between the current track/sector and the desired location; as little as four minor cycles or nearly one major cycle. If the operand is literal then the order execution time is fixed at four minor cycles.
Skip and jump orders
Seven orders are provided that can be used to modify order execution sequence. The JUMP order modifies the contents of C and therefore causes orders to be next executed at a specified drum address. Six instructions modify order execution by incrementing the C circulator by one, thereby skipping the order immediately following the skip order: four dependent on the state of one of the Cy or Z flip-flops, and two dependent on the current state of the teletype input line.
Drum-access orders
The only way to modify drum contents under program control is with the STO or STA order, which write all 18 or the least-significant 12 bits of a drum location, respectively. Drum contents can be read, explicitly with the LDM order or implicitly with the xxxM arithmetical/logical orders.
Z and Cy flip-flops
The Z and Cy flip-flops are modified by the arithmetical and logical orders, and indicate the result the most-recently-performed arithmetical and logical order. Either flip-flop may be subsequently 'tested' with other orders and used to determine program execution, and in some cases their numeric value (0 or 1) can be incorporated into calculations directly. Z and Cy remain unchanged until the next arithmetical and logical order.
Z is set when the result of an arithmetical and logical order results in all digits of the A circulator equal to zero. Orders that modify program execution depending on the state of Z are SZ andSNZ. Orders SC and SNC can be used to modify program execution depending on the state of Cy, or Cy can be incorporated into calculations directly with the RLC, ADC, ADCM orders.
MACHINE ORDER DESCRIPTIONS
The following paragraphs define the individual machine orders, and provide a complete description of the effects and side-effects of each order.
DRUM OPERAND ORDERS
For the following orders digits 0 through 11 contain the packed track:sector address of the operand stored on the drum. Execution times for these orders are therefore dependent on the track displacement and rotational distance between the order location and that of the desired location.
LDM address
17 11 0
W M 0
X 1 0 1 1 1 T T T T T S S S S S S S
|<order>| |<---drum location--->|
The contents of the specified drum sector are written into the acumulator. Z and Cy are unaffected.
ADDM a
17 11 0
W M 0
X 1 0 0 1 0 T T T T T S S S S S S S
|<order>| |<---drum location--->|
Add the contents of the specified drum sector plus A and place the result in A. Sets Z and Cy modified as described in the text.
ADCM a
17 1 0
W M 0
X 1 0 0 1 1 T T T T T S S S S S S S
|<order>| |<---drum location--->|
Add the contents of specified drum sector plus Cy plus A and place the result in A. Sets Z and Cy as described in the text.
ORM a
17 11 0
W M 0
X 1 0 1 1 0 T T T T T S S S S S S S
|<order>| |<---drum location--->|
Merge the contents of the accumulator with the specified drum sector contents such that there is a 1 in every digit position of the accumulator where there is a 1 in the same digit position of either or both of the accumulator and the drum location. Sets Z accordingly, Cy is always cleared.
ANDM a
17 11 0
W M 0
X 1 0 1 0 1 T T T T T S S S S S S S
|<order>| |<---drum location--->|
Merge the contents of the accumulator and the specified drum location contents such that there is a 0 in every digit position of the accumulator where there is a 0 in the same digit position of either or both of the accumulator and the drum location. Sets Z accordingly, Cy is always cleared.
STO a
17 11 0
W M 0
X 1 1 0 1 0 T T T T T S S S S S S S
|<order>| |<---drum location--->|
Write the contents of the accumulator into the specified drum sector. Z and C are unaffected.
STA a
17 11 0
W M 0
X 1 1 0 0 1 T T T T T S S S S S S S
|<order>| |<---drum location--->|
Write the least -significant 12 digits of the accumulator into the least-significant 12 digits (address, K) of the specified drum sector, leaving the most-significant 6 digits unmodified. The intent is that the specified memory location contains an order whose address field is being modified. Z and Cy are unaffected.
LITERAL ORDERS
For the following orders K is a literal unsigned operand, in the range of 0 to 4095 (digit positions 0 through 11). K is extended to 18 bits with zeroes. The drum is not referenced, therefore execution time for these orders is fixed at four minor cycles.
LD k
17 11 0
W M 0
X 1 0 0 0 1 K K K K K K K K K K K K
|<order>| |<------constant----->|
Write value K to the accumulator. Z and C are unaffected.
ADD k
17 11 0
W M 0
X 0 1 1 1 0 K K K K K K K K K K K K
|<order>| |<------constant----->|
Add constant K plus A and place the result in A. Sets Z and Cy as described in the text.
ADC k
17 11 0
W M 0
X 0 1 1 0 1 K K K K K K K K K K K K
|<order>| |<------constant----->|
Add constant K plus Cy to A and place the result in A. Sets Z and Cy.
OR k
17 11 0
W M 0
X 1 0 0 0 0 K K K K K K K K K K K K
|<order>| |<------constant----->|
Merge the contents of the accumulator with constant K such that there is a 1 in every digit position of the accumulator where there is a 1 in the same digit position of either or both of the accumulator and the drum location. Sets Z accordingly, Cy is always cleared.
AND k
17 11 0
W M 0
X 0 1 1 1 1 K K K K K K K K K K K K
|<order>| |<------constant----->|
Merge the contents of the accumulator with constant K such that there is a "1" in every digit position of the accumulator where there is a "0" in the same digit position of either or both of the accumulator and the drum sector. Sets Z accordingly, Cy is always cleared.
JUMP k
17 11 0
W M 0
X 1 0 0 1 0 K K K K K K K K K K K K
|<order>| |<------constant----->|
The constant value K is written to circulator C, therefore the next program order executed will be from that drum location. While this order takes only four minor cycles to execute, the fetch of the next order will be as calculated for the drum-addressing orders above. Z and Cy unaffected.
LDA k
17 11 0
W M 0
X 1 1 0 0 0 K K K K K K K K K K K K
|<order>| |<------constant----->|
This order is exactly identical in operation to LD. LDA exists solely to allow differentiating constant-K orders from constant-address orders in order to facilitate automatic programming techniques. Z and Cy are unaffected.
OTHER DIGIT-MANIPULATION ORDERS
The following orders perform various logical and arithmetical operations on the accumulator.
SR k
17 11 0
W M 0
X 0 1 0 0 0 K K K K K K K K K K K K
|<order>| |<------constant----->|
The contents of circulator A are first divided by two, then summed with K, the result then placed in circulator A. Z is set if the result in A is zero, and Cy is always cleared (since overflow due to the addition is not possible). When K is zero, this causes the accumulator to be simply shifted right one place.
RLC
17 11 0
W M 0
X 0 0 1 1 1 X X X X X X X X X X X X
|<order>| |<------constant----->|
The contents of the accumulator are modified as follows: all digits are shifted one position to the left; the contents of the Cy flip-flop is placed in the right (least-significant) position; the previously most significant digit shifted off the left (most significant) end is placed in the Cy flip-flop. In other words, the accumulator and Cy flip-flop are treated as a 19-bit ring counter that is shifted one position counterclockwise. Z and Cy are set accordingly.
COM k
17 11 0
W M 0
X 0 1 0 0 1 K K K K K K K K K K K K
|<order>| |<------constant----->|
Invert all of the bits in the accumulator (0's become 1's, 1's become 0's) and add K, placing the result in the accumulator. If K is 0, then this instruction performs a one's complement; if 1 then it performs a two's complement. Z and C are set accordingly.
SKIP ORDERS
The following orders modify the sequence of order execution under influence of the program itself, by meeting specified states of the Z and Cy flip-flops or the state of the teletype input line. The Z, Cy and teletype input line remain unaffected. For these orders the k field is undefined.
SZ
17 11 0
W M 0
X 0 0 0 1 1 X X X X X X X X X X X X
|<order>| |<------constant----->|
SNZ
17 11 0
W M 0
X 0 0 1 0 0 X X X X X X X X X X X X
|<order>| |<------constant----->|
SC
17 11 0
W M 0
X 0 0 1 0 1 X X X X X X X X X X X X
|<order>| |<------constant----->|
SNC
17 11 0
W M 0
X 0 0 1 1 0 X X X X X X X X X X X X
|<order>| |<------constant----->|
These orders cause 1 to be added to the C circulator if the specified condition is met, causing the next order to be skipped. The conditions are:
Z the last arithmetic order left all bits of the accumulator clear
NZ the last arithmetic order left at least one bit set in the accumulator
C(y) the last arithmetic order generated an overflow condition
NC(y) the last arithmetic order did not generate an overflow condition
[IF SECTORS/TRACK NOT A POWER OF TWO:] It is recommended that skip instructions not be executed in the last sector on a track.
STZ
17 11 0
W M 0
X 0 1 0 1 0 X X X X X X X X X X X X
|<order>| |<------constant----->|
STNZ
17 11 0
W M 0
X 0 1 0 1 1 X X X X X X X X X X X X
|<order>| |<------constant----->|
Adds 1 to the C circulator if the condition is met, causing the next program order to be skipped. The condition is teletype input false (STZ) or true (STNZ). This order is the basis for the entire IO structure; it is strenuously recommended that the library routines provided with the machine be used unless very careful consideration is given to the consequences. Serial data appearing at the interface is thereby made procedural, the serial data is reconstructed by orders before and after this order.
AND 0 # clear the acumulator,
STNZ # if data asserted,
OR 1 # recreate it here.
MACHINE CONTROL ORDERS
These orders control or are influenced by various hardware aspects of the Machine.
TTO
17 11 0
W M 0
X 0 1 1 0 0 X X X X X X X X X X X X
|<order>| |<------constant----->|
Asserts the least-significant digit of A onto the teletype or paper tape punch output flip-flop. This is the sole output mechanism. Teletype word assembly and timing is done by careful placement of words around a dedicated track. It is strongly recommended that the teletype routines provided with the machine be used.
SWA k
17 11 0
W M 0
X 0 0 0 0 1 K K K K K K K K K K K K
|<order>| |<------constant----->|
The 18 switches of the operator's console SWITCH REGISTER are written to the accumulator, a 1 being written in digit positions where the switch is in the "up" position, otherwise a zero. Z and Cy are not affected.
HALT k
17 11 0
W M 0
X 0 0 0 0 1 K K K K K K K K K K K K
|<order>| |<------constant----->|
General machine control order. TBD.
THE AUTOMATIC COMPILER
[DRAFT notes: aka the assembler, currently there is only the Perl assembler, which is undoubtedly a superset of any native compiler, should such a thing get written. Also at this time the binary loader and loader format is TBD.
[To be inserted here also is a complete explanation and justification for 30 years of base-level assumptions about line-oriented input (unless it becomes tootedious).]
The Automatic Compiler is the primary way to produce sequences of orders for solutions to problems using the Universal Machine. It accepts as input a sequence of teletype characters arranged as described in this section that describe machine orders, drum storage locations, constants and variables, and meta-orders that control the interpretation of the stream of characters from the input tape; this arrangement of teletype characters thus becomes an abstract description of a program of orders to perform any function.
The end result of a successful run of the automatic compiler against an input tape is the production of an output tape that contains the actual machine orders to perform the functions abstractly described by the programmer.
In addition, programs can be assembled using libraries of previously worked-out and tested routines stored on one or more input tapes. Further, the machine is provided with standardized drum-resident routines for commonly used functions such as teletype I/O, printing, and arithmetical routines.
[DRAFT note: a whole section tying the above summary to a sample input tape, including teletype-printable representation, etc, will be inserted here. Mainly the rest of this section is devoted to documenting the Perl assembler functions. I know that you know how to use an ordinary1970-style two pass assembler.]
TELETYPE CHARACTERS AND THEIR MEANINGS
As the input tape is read, the Compiler interprets the characters read one by one. The meaning of each character depends entirely on the current state of the internal turing machine and characters previously read. At each Compiler state, certain characters cause the Compiler to change state, possibly punching other characters to the output tape. Please refer to Appendix A for a complete list of teletype characters and their representations in the Universal Machine.
The arrangement of these internal states causes the Compiler to maintain a perceptible set of semantic and syntactical rules which the programmer must follow. Luckily, most of these resulting rules follow an "english-like" form as to make for easy memorization. [This is obviously swiped from Knuth, especially as embodied in TeX -- even though the Perl compiler is the usual atrocity and in no way is the code this elegant.]
Characters are considered to be in the following groups:
Letters: A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
Digits: 0 1 2 3 4 5 6 7 8 9
Separators: space ,
Specials: - ' ! : ( ) + # ? . /
Formatting: cr lf bs nul bel wru figs ltrs
Whether a given character is allowed depends entirely on the current state of the Compiler's internal turing machine. The current state can be understood by referring to figure XXX, below, which represents a series of example characters from the input tape:
[picture of punched tape here]
Fig. XXX
Perforations on a fragment on that sample input tape might contain:
cr lf nul nul sp sp sp A N D sp sp 3 1 sp sp sp sp # r e t a i n sp t h e sp ... sp A cr lf nul ...
which produces the following when printed on the teleprinter:
Printed result: | AND 31 # retain the 5 least digits of A |
Machine state: 0 1 2 3 4 5 0
The "state" number indicates what the compiler will allow on the input tape without producing an error. As you can see the states correspond reasonably to formatted text:
STATE EXPECTS
0 separator(s), or a label (described below)
1 order or number
2 separator(s)
3 value, if required by order (described below)
4 separator(s), if a value follows an order
5 program note
State becomes 0 when a cr or lf is read from the tape; an error results if a required state (eg. 3) is missed. The # character causes the compiler to ignore all input characters until the next CR or LF is read.
In this document we will refer exclusively to the convenient representation of characters as displayed on a teleprinter, though it is assumed that the programmer recognizes the underlying tape contents.
ORDERS
Machine orders are represented by names composed of letters, as described in the MACHINE ORDERS section. Many orders require an operand, which must follow the order name, separated by one or more separator characters. An operand may be a number, character constant, or named variable, or an expression containing any or all of the above.
NUMBERS
All numbers are treated by the compiler as unsigned integers, in the range of 0 to 262144, expressed on the input tape in one of three input radix as indicated by a leading character. Further, the allowed digit-characters depends on the radix character that proceeds them:
0 100 77777 262144 decimal values
$0 $100 $77777 $777777 octal values
.100 .111111111111111111 binary values
CHARACTER CONSTANTS
Often it is convenient to use a teleprinter character in an expression, and the following has been provided to do so:
'X
This refers to the numeric value of the letter X, represented as a six-digit code, where the lower five digits are the standard teleprinter character code, and the sixth, most-significant digit is "1" for characters in the FIGS case, and "0" otherwise; in this example the result is decimal 29. Please refer to Appendix A for a complete list of character codes.
NAMED VARIABLES
The compiler provides a mechanism for assigning numerical values to arbitrary six-character named symbols, which can be used anywhere a number or character constant is required. In fact there are a number of ways in which values are assigned to names, designed for the programmers convenience.
First, symbols can be defined explicitly by the EQ meta-order, described below. Secondly, it is often convenient to assign the "current" order (drum) location to a variable for later reference in a program (eg. For programmatic looping); this is done by starting a symbol name with the first character following the CR or LF ending the previous line of input, where the Compiler would otherwise be expecting state "0". Third, the machine orders themselves are in fact simply variables, pre-defined by the Compiler, and can be used as numbers (this is of dubious value). And last, the "current" drum location is always referenced by the reserved variable name C.
In fact the use of symbols by the compiler is very simple. The compiler maintains a table of named variables and their values, and any time a a letter appears where a number (or radix indicator) is expected, the letter and the characters that follow it are looked up in the table. If a match is found, the value associated with that name is assumed. If the name is not found in the table, an error is assumed. Note that this useful trick may produce surprising results when typing mistakes are made.
Note that this scheme places limitations on the characters allowed in symbol names: they must begin with a letter, but may then contain letters and or digits, up to six positions.
META-ORDERS
In addition to the symbolic machine orders listed in previous sections, the compiler provides the following meta-orders that direct how the compiler treats subsequent orders. They may assign numeric values to symbolic names, or determine into which drum location orders or data is to be stored.
Meta-orders, like orders, must be preceeded by at least one space character [IS THIS TRUE?]. If an order requires or accepts additional parameters they must follow the order/meta-order by at least one space character.
TRACK n
Specifies the track into which subsequent orders or data will be stored. The track must physically exist or an error will result.
SECTOR n
Specifies the initial sector n within a track into which subsequent orders and data will be stored. Thereafter orders/data are stored sequentially, up to the maximum sectors in a track. The compiler produces an error if the maximum sector would be exceeded.
SYMBOL EQ n
SYMBOL: [Maybe eliminate this]
These two meta-orders assign a numeric value to a named variable. [The first form ]explicitly assigns n to the symbol. Note that n in turn may itself be a symbol, but it must already be defined when this meta-order is encountered or an error will result.[The second form assigns to the name the "current" drum location, usually to symbolically render a specific order within a program sequence, and in general is equivalent to "SYMBOL EQ C". ]
TEXT /ijklmn/
TEXT "abc"
TEXT "s", 8, 4
TEXT n m o p q ...
[Note: This meta-order will be reexamined, and probably simplified.]
This meta-order stores packed character data into drum locations, three six-bit characters per word, starting with the right-most six bits of the location. As many drum locations as necessary are used to contain the data given. If the the character data provided is not a multiple of three, the unused "characters" in the drum word are filled with NUL (0's). If the number of characters is a multiple of three, an additional drum word of all zeros is added.
For the first two forms the initial character is used to bracket the character data; the initial character itself therefore cannot appear within, hence the definition of two allowable initial characters. For the first two forms only printable teletype characters can appear between the marker characters, specifically not CR, LF, BEL, etc. The third form can be used to enter characters of this type, where n m o p q are numbers or other allowable literal values.
Note further that the TEXT meta-order accepts any number of arguments, including intermixes of all three syntactical types.
See Appendix A for a complete list of teletype character codes.
STORAGE n
This meta-order is used to set aside a sequence of drum storage locations. The drum locations are not modified. Essentially, the compiler adds n to the the "current" sector value. An error is produced if there is not enough sectors remaining on the track.
PROGRAMMING CONVENTIONS
Subroutine linkage
The machine provides an order to support a modification of the EDSAC type "Closed A" subroutine linkage mechanism, supported by the automatic compiler.
To call a subroutine only the following orders are required:
r LDA (r + 2) # A is now equal to C + 2
r + 1 JUMP s # transfer control to subroutine s
r + 2 ... # next order to be executed upon return
After the execution of the LDA order in drum location r the accumulator contains (r + 2). The JUMPinstruction then transfers control to the subroutine.
The subroutine itself provides return linkage in the following manner:
s STA s + n # save the return address
s + 1 ... # intervening subroutine orders
s + n JUMP 0 # 0 address overwritten before execution
The subroutine, if it is to use the accumulator, must first store the return address passed to it; in general the most convenient is in the address (k) field of a JUMP order that will become the return linkage; the STA order has been provided for this purpose. After storing the return address the subroutine executes whatever orders it must, which may include other subroutines. To return to the calling routine, the address field of the JUMP order at drum location (s + n) already contains address (r + 2) and after execution the main routine will continue.
POWER CONTROL PANEL
[The controls and indicators relating to power on, power sequencing, standby, and any drum power requirements will be located on the POWER CONTROL PANEL elsewhere on the machine, and will remain TBD until engineering is done, but essentially there will be a power-sequencing regimen to avoid filament damage, restricted ambient temperature range, mechanisms to avoid problems (power-fail detection, etc). This will be at least partly automated with a microcontroller and solid-state power supplies.]
LIBRARY ROUTINES
The subroutine library consists of commonly used subroutines assigned fixed locations on the drum, as well as subroutines meant to be included into programs symbolically, as needed.
The fixed routines are actually only jump instructions to the actual routines, so that the routines themselves can be modified or improved without requiring already-written programs to be modified to match.
PASS 1
PASS 2
00:000 000000 # SOFTWARE LIBRARY ROUTINES FOR THE UNIVERSAL MACHINE.
00:000 000000 # MRU 2 JULY 2001
00:000 000000 # 25 JAN 2001
00:000 000000
00:000 000000 # NOTE! THIS PRELIMINARY CODE IS NOT OPTIMALLY CODED!
00:000 000000
00:000 000000
00:000 000000 RETURN EQ 0 # place-holder for return addresses
00:000 000000 POINTER EQ 0 # place-holder for runtime pointers
00:000 000000 VAR EQ 0 # place-holder for runtime variables
00:000 000000
00:000 000000 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00:000 000000 # STANDARD JUMP TABLE LOCATION.
00:000 000000
00:000 000000 track 0
00:000 000000 sector 0
00:000 000000
00:000 225400 start: jump test # program entry
00:001 220001 ttyo: jump ttyo # (simulated)
00:002 220002 ttyi: jump ttyi # (simulated)
00:003 221015 ttyow: jump ttyowx # print packed chars
00:004 221000 ttyos: jump ttyosx # print string
00:005 221411 ttyod: jump ttyodx # print decimal
00:006 222000 ttyoo: jump ttyoox # print octal
00:007 220436 multUS: jump multUx # mult unsigned single
00:010 220400 multUD: jump multUDx # mult unsigned double
00:011 220061 m10: jump m10x # single mult by 10
00:012 000000
00:012 000000 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00:012 000000 track 0
00:024 000024 sector 20
00:024 000000
00:024 000000 ttchar: VAR # ttyxx argument
00:025 000000 ttarg: VAR # ttyxx argument
00:026 000000 ttopt: VAR # ttyxx options
00:027 000000 zschar: VAR # zero-suppress
00:030 000000 errno: VAR # subr status
00:031 000000 Mper: VAR # multiplier
00:032 000000 Mcand: VAR # multiplicand or LSW
00:033 000000 Mcandh: VAR # multiplicand MSW
00:034 000000 Mtest: VAR # mult. routine
00:035 000000 MQ: VAR # quotient or LSW
00:036 000000 MQh: VAR # quotient MSW
00:037 000000
00:037 777777 minus1: -1 # constant
00:040 777772 minus6: -6 # constant
00:041 000000
00:041 000066 digtbl: '0 # table of digits
00:042 000067 '1
00:043 000063 '2
00:044 000041 '3
00:045 000052 '4
00:046 000060 '5
00:047 000065 '6
00:050 000047 '7
00:051 000046 '8
00:052 000070 '9
00:053 000003 'A
00:054 000031 'B
00:055 000016 'C
00:056 000011 'D
00:057 000001 'E
00:060 000015 'F
00:061 000000
00:061 000000 # ---------------------------------------------------------------
00:061 000000
00:061 000000 # Unsigned single-precision fixed multiply Mcand by 10.
00:061 000000
00:061 310072 m10x: sta m10r
00:062 270032 ldm Mcand
00:063 200000 or 0 # clear carry
00:064 070000 rlc # times two,
00:065 320032 sto Mcand # save that,
00:066 070000 rlc
00:067 070000 rlc # times eight,
00:070 240032 addm Mcand # times ten,
00:071 320032 sto Mcand
00:072 220000 m10r: jump RETURN
00:073 000000
01:073 000001 track 1
01:000 000000 sector 0
01:000 000000
01:000 000000 # Unsigned double-precision multiply Mcand by Mper
01:000 000000 # leaving the result in MQ (ls word) and MQh
01:000 000000 # (ms word). Destroys Mcand and Mper. Sets errno
01:000 000000 # if overflow out of MS digit.
01:000 310434 multUDx: sta mdlr
01:001 170000 and 0
01:002 320035 sto MQ
01:003 320036 sto MQh # initialize
01:004 210001 ld 1
01:005 000000
01:005 320034 mdl1: sto Mtest # m'per digit tester
01:006 250031 andm Mper # test m'per digit
01:007 040000 snz
01:010 220422 jump mdl2 # add in Mcand if 1
01:011 270032 ldm Mcand # Mcand lo
01:012 240035 addm MQ # + MQ lo
01:013 320035 sto MQ # = MQ lo
01:014 270033 ldm Mcandh # Mcand hi
01:015 230036 adcm MQh # + MQ hi + carry
01:016 320036 sto MQh # = MQ hi
01:017 000000
01:017 210000 ld 0
01:020 230030 adcm errno # remember overflow error
01:021 320030 sto errno
01:022 000000
01:022 270032 mdl2: ldm Mcand
01:023 200000 or 0 # clear carry
01:024 070000 rlc # shift multiplicand
01:025 320032 sto Mcand # Mcand * 2
01:026 270033 ldm Mcandh # double precision
01:027 230033 adcm Mcandh #
01:030 000000
01:030 270034 ldm Mtest
01:031 200000 or 0 # clear carry
01:032 070000 rlc
01:033 040000 snz # if no more bits
01:034 220000 mdlr: jump RETURN # done.
01:035 220405 jump mdl1
01:036 000000
01:036 000000
01:036 000000 # Unsigned single-precision multiply Mcand by Mper
01:036 000000 # leaving the result in MQ. Destroys Mcand.
01:036 000000 # Sets errno if overflow out of MS digit.
01:036 310464 multUx: sta mslr
01:037 170000 and 0
01:040 320035 sto MQ
01:041 210001 ld 1
01:042 000000
01:042 320034 msl1: sto Mtest # m'per digit tester
01:043 250031 andm Mper # test m'per digit
01:044 040000 snz
01:045 220454 jump msl2 # add in Mcand if 1
01:046 270032 ldm Mcand # Mcand
01:047 240035 addm MQ # + MQ
01:050 320035 sto MQ # = MQ
01:051 000000
01:051 210000 ld 0
01:052 230030 adcm errno # remember overflow error
01:053 320030 sto errno
01:054 000000
01:054 270032 msl2: ldm Mcand
01:055 200000 or 0 # clear carry
01:056 070000 rlc # shift multiplicand
01:057 320032 sto Mcand # Mcand * 2
01:060 000000
01:060 270034 ldm Mtest
01:061 200000 or 0 # clear carry
01:062 070000 rlc
01:063 040000 snz # if no more bits
01:064 220000 mslr: jump RETURN # done.
01:065 220442 jump msl1
01:066 000000
01:066 000000 # -------------------------------------------------
01:066 000000
02:066 000002 track 2
02:000 000000 sector 0
02:000 000000
02:000 000000 # Output a string of packed characters.
02:000 000000 #
02:000 311010 ttyosx: sta ttysr
02:001 270024 ldm ttchar # ptr to string
02:002 000000
02:002 311003 tts0: sta tts1 # set string pointer
02:003 270000 tts1: ldm POINTER # load text word,
02:004 320024 sto ttchar
02:005 301007 lda C+2
02:006 221015 jump ttyowx # output one word,
02:007 040000 snz
02:010 220000 ttysr: jump RETURN # exit if end of string
02:011 271003 ldm tts1
02:012 160001 add 1 # advance string ptr,
02:013 221002 jump tts0
02:014 000000
02:014 000000 # -----------------------------------------------------
02:015 000015 sector 13 # OPTIMUM 64x5
02:015 311027 ttyowx: sta ttwr
02:016 270024 ldm ttchar
02:017 321047 sto ttwv1 # optimum storage
02:020 211024 ld ttw1 # reset table ptr,
02:021 000000
02:021 311023 ttw0: sta ttwj2
02:022 270024 ldm ttchar # A=char,
02:023 220000 ttwj2: jump POINTER # jump into table,
02:024 221036 ttw1: jump ttw3 # LS char,
02:025 221030 jump ttw2 # 2nd char,
02:026 221030 jump ttw2 # 3rd char,
02:027 220000 ttwr: jump RETURN # return
02:030 000000
02:030 000000 # Shift right one character, output it.
02:030 100000 ttw2: sr 0
02:031 100000 sr 0
02:032 100000 sr 0
02:033 100000 sr 0
02:034 100000 sr 0
02:035 100000 sr 0
02:036 000000 # Output the LS character, advance the pointer to
02:036 000000 # the next character in the word in ttchar.
02:036 320024 ttw3: sto ttchar
02:037 301041 lda C+2
02:040 220001 jump ttyo # output a char,
02:041 040000 snz # if it was a NULL,
02:042 221027 jump ttwr # exit
02:043 271023 ldm ttwj2 # current table ptr,
02:044 160001 add 1 # increment,
02:045 221021 jump ttw0 # loop.
02:046 000000
02:047 000047 sector 39 # OPTIMUM 64x5
02:047 000000 ttwv1: VAR
02:050 000000
02:050 000000 # -----------------------------------------------------
02:050 000000
02:050 000000
02:050 000000 # -----------------------------------------------------
02:050 000000
03:050 000003 track 3
03:000 000000 sector 0
03:000 000000
03:000 000000 # Output TTARG as a decimal number. Leading zero's are
03:000 000000 # handled according to ZSFLAG:
03:000 000000 # '0' displayed as 0
03:000 000000 # ' ' displayed as space
03:000 000000 # 0 suppressed.
03:000 000000 # Modifies TTARG, TTCHAR.
03:000 000000
03:000 474540 ttddk1: -100000 # table of divisors
03:001 754360 -10000
03:002 776030 -1000
03:003 777634 -100
03:004 777766 -10
03:005 000000 0 # end of table marker
03:006 000000 ttzchr: 0 # zero-suppress character
03:007 000000 ttddr: RETURN # return address
03:010 000000 ttddr2: RETURN # subr return address
03:011 000000
03:011 321407 ttyodx: sto ttddr # save return addr,
03:012 270027 ldm zschar
03:013 321406 sto ttzchr # copy of zero-supp char
03:014 211463 ld ttdd7 # ptr to decade char output
03:015 321410 sto ttddr2 # inside loop
03:016 211400 ld ttddk1 # init ptr to divisors
03:017 000000
03:017 311421 ttdd0: sta ttdd1 # top of outer loop,
03:020 311436 sta ttdd4 # set ptr to current divisor
03:021 270000 ttdd1: ldm POINTER # check for end of table
03:022 200000 or 0 # marked with 0
03:023 030000 sz
03:024 221432 jump ttdd2 # jump if more decades,
03:025 000000
03:025 000000 # Remainder is less than 10; output directly.
03:025 000000
03:025 271407 ldm ttddr # set return from routine
03:026 321410 sto ttddr2
03:027 270025 ldm ttarg # get remainder
03:030 320024 sto ttchar
03:031 221444 jump ttdd5 # go output
03:032 000000
03:032 000000 # Determine quotient/digit by repeated subtraction of
03:032 000000 # the decade divisor.
03:032 000000
03:032 270037 ttdd2: ldm minus1 # seed to enter loop
03:033 000000
03:033 160001 ttdd3: add 1
03:034 320024 sto ttchar # next try
03:035 270025 ldm ttarg # the remainder,
03:036 240000 ttdd4: addm POINTER # subtract decade,
03:037 050000 sc
03:040 221444 jump ttdd5 # until underflow,
03:041 320025 sto ttarg # repeat
03:042 270024 ldm ttchar
03:043 221433 jump ttdd3 # until it does.
03:044 000000
03:044 000000 # Underflow -- TTCHAR is number of decades.
03:044 000000 # Output the value in TTARG as a decimal character,
03:044 000000 # but suppressing leading zeroes as indicated. This returns
03:044 000000 # according to previously-set ttddr2.
03:044 000000
03:044 270024 ttdd5: ldm ttchar # decimal value,
03:045 200000 or 0 # (test it)
03:046 271406 ldm ttzchr # output left-fill char
03:047 040000 snz
03:050 221460 jump ttdd6a # if leading zero
03:051 210066 ld '0 # non-zero value,
03:052 321406 sto ttzchr # clear zero-suppress
03:053 270024 ldm ttchar
03:054 210041 ld digtbl # ptr to decimal characters,
03:055 240024 addm ttchar # index it,
03:056 311457 sta ttdd6
03:057 270000 ttdd6: ldm POINTER # fetch the character,
03:060 320024 ttdd6a: sto ttchar
03:061 271410 ldm ttddr2 # where we return to...
03:062 220001 jump ttyo # output character
03:063 000000
03:063 271421 ttdd7: ldm ttdd1 # ... here during loop.
03:064 160001 add 1 # advance divisor table ptr
03:065 221417 jump ttdd0 # loop.
03:066 000000
03:066 000000
04:066 000004 track 4
04:000 000000 sector 0
04:000 000000
04:000 000000
04:000 000000 # Output ttarg as an octal number.
04:000 312023 ttyoox: sta ttoor
04:001 270040 ldm minus6 # oct digits in word,
04:002 320026 sto ttopt
04:003 270025 ldm ttarg # get passed value,
04:004 070000 ttoo1: rlc # shift MSB into Cy,
04:005 070000 rlc # rotate MS octal digit
04:006 320025 sto ttarg # because carry gets lost
04:007 070000 rlc # to LS bits
04:010 070000 rlc
04:011 170007 and 7
04:012 160041 add digtbl # ptr into digit table,
04:013 312014 sta ttoo2
04:014 270000 ttoo2: ldm POINTER # load digit
04:015 320024 sto ttchar # setup for call ttyo
04:016 212020 ld ttoo3
04:017 220001 jump ttyo # print digit,
04:020 270026 ttoo3: ldm ttopt
04:021 160001 add 1
04:022 040000 snz # exit after 6 digits
04:023 220000 ttoor: jump RETURN
04:024 320026 sto ttopt
04:025 270025 ldm ttarg
04:026 070000 rlc
04:027 222004 jump ttoo1
04:030 000000
04:030 000000
04:030 000000
04:030 000000 # ----------------------------------------------------------------
04:030 000000 # END of library, start of test code.
04:030 000000
04:030 000000
12:030 000012 track 10
12:000 000000 sector 0
12:000 000000
12:000 000000 t1: text / TIMES /
12:001 062004 4, 16, 6
12:002 050134 28, 1, 5
12:003 000004 4, 0
12:003 000000 t2: text / IS /
12:004 050604 4, 6, 5
12:005 000004 4, 0
12:005 000000 t3: text 4, 8, 2
12:006 021004 4, 8, 2
12:007 000000 0
12:007 000000 t4: text /, OCTAL /
12:010 300454 44, 4, 24
12:011 032016 14, 16, 3
12:012 000422 18, 4, 0
12:012 000000 t5: text / OVERFLOW!/, 4, 8
12:013 363004 4, 24, 30
12:014 151201 1, 10, 13
12:015 233022 18, 24, 19
12:016 100455 45, 4, 8
12:017 000000 0
12:017 000021 n: 17
12:020 000003 m: 3
12:021 777766 i: -10
12:022 000000
12:022 000000 tx1: text /OK, SO HOW DOES THIS GO? IT IS PROBABLY/, 2, 8, /STILL VERY, VERY SLOW./, 2, 8
12:023 541730 24, 15, 44
12:024 300504 4, 5, 24
12:025 302404 4, 20, 24
12:026 110423 19, 4, 9
12:027 050130 24, 1, 5
12:030 242004 4, 16, 20
12:031 040506 6, 5, 4
12:032 713032 26, 24, 57
12:033 200604 4, 6, 16
12:034 050604 4, 6, 5
12:035 122604 4, 22, 10
12:036 033130 24, 25, 3
12:037 252231 25, 18, 21
12:040 051002 2, 8, 5
12:041 220620 16, 6, 18
12:042 360422 18, 4, 30
12:043 251201 1, 10, 21
12:044 360454 44, 4, 30
12:045 251201 1, 10, 21
12:046 220504 4, 5, 18
12:047 742330 24, 19, 60
12:050 001002 2, 8, 0
12:050 000000
13:050 000013 track 11
13:000 000000 sector 0
13:000 000000
13:000 000000 # test code
13:000 000000
13:000 275017 test: ldm n
13:001 320032 sto mcand # multiply this
13:002 320025 sto ttarg
13:003 170000 and 0
13:004 320030 sto errno
13:005 320027 sto zschar # suppress leading 0's
13:006 305410 lda C+2
13:007 221411 jump ttyodx # print m'cand
13:010 000000
13:010 215000 test2: ld t1
13:011 320024 sto ttchar
13:012 305414 lda C+2
13:013 221000 jump ttyosx # print " times "
13:014 000000
13:014 275020 ldm m
13:015 320031 sto mper # by this
13:016 320025 sto ttarg
13:017 305421 lda C+2
13:020 221411 jump ttyodx # print m'per
13:021 000000
13:021 215003 ld t2
13:022 320024 sto ttchar
13:023 305425 lda C+2 # "equals"
13:024 221000 jump ttyosx
13:025 000000
13:025 305427 lda C+2
13:026 220400 jump multUDx # multiply
13:027 000000
13:027 270030 ldm errno # check for o'flow
13:030 200000 or 0
13:031 040000 snz
13:032 225437 jump mzzz1
13:033 000000
13:033 215012 ld t5 # OVERFLOW ERROR!
13:034 320024 sto ttchar
13:035 305462 lda done
13:036 221000 jump ttyosx
13:037 000000
13:037 270035 mzzz1: ldm MQ
13:040 320025 sto ttarg
13:041 305443 lda C+2
13:042 221411 jump ttyodx # print m'per
13:043 000000
13:043 000000
13:043 215007 ld t4
13:044 320024 sto ttchar # print "octal"
13:045 305447 lda C+2
13:046 221000 jump ttyosx
13:047 000000
13:047 270035 ldm MQ
13:050 320025 sto ttarg
13:051 305453 lda C+2
13:052 222000 jump ttyoox # print octal
13:053 000000
13:053 215005 ld t3
13:054 320024 sto ttchar # print CR, LF
13:055 305457 lda C+2
13:056 221000 jump ttyosx
13:057 000000
13:057 275017 ldm n
13:060 160021 add 17
13:061 060000 snc
13:062 010001 done: halt 1
13:063 325017 sto n
13:064 225410 jump test2
13:065 000000
13:065 000000
13:065 000000
13:065 000013 track 11
13:000 000000 sector 0
13:000 000000
13:000 000000
13:000 215022 tex: ld tx1
13:001 320024 sto ttchar
13:002 215404 ld tex2
13:003 221000 jump ttyosx
13:004 010000 tex2: halt 0
13:005 000000
13:005 000000
13:005 000000 # ---------------------------------------------------------------
13:005 000000
SYMBOLS
MSLR=000464 308=000464 TTOPT=000026 22=000026 TTDD0=001417
783=001417 TTDD1=001421 785=001421 TEX=005400 2816=005400
TTDD2=001432 794=001432 TTDD3=001433 795=001433 TTDD4=001436
798=001436 TTDD5=001444 804=001444 MCANDH=000033 27=000033
TTDD6=001457 815=001457 TTDD7=001463 819=001463 TTS0=001002
514=001002 TTS1=001003 515=001003 MQ=000035 29=000035
MDL1=000405 261=000405 MDL2=000422 274=000422 TTW0=001021
529=001021 TTW1=001024 532=001024 TTW2=001030 536=001030
TTW3=001036 542=001036 START=000000 0=000000 POINTER=000000
0=000000 TTDDR2=001410 776=001410 M10R=000072 58=000072
TTDDR=001407 775=001407 MTEST=000034 28=000034 M10X=000061
49=000061 MZZZ1=005437 2847=005437 TTWJ2=001023 531=001023
TTDDK1=001400 768=001400 TTYOD=000005 5=000005 TTYOOX=002000
1024=002000 MDLR=000434 284=000434 MULTUDX=000400 256=000400
RETURN=000000 0=000000 TTWR=001027 535=001027 MINUS1=000037
31=000037 TTYOO=000006 6=000006 TTYOSX=001000 512=001000
DIGTBL=000041 33=000041 TTOO1=002004 1028=002004 TTOO2=002014
1036=002014 TTYODX=001411 777=001411 MINUS6=000040 32=000040
TTOO3=002020 1040=002020 TTYOS=000004 4=000004 VAR=000000
0=000000 TTYOW=000003 3=000003 TTWV1=001047 551=001047
TTYOWX=001015 525=001015 TTCHAR=000024 20=000024 TTYSR=001010
520=001010 DONE=005462 2866=005462 I=005021 2577=005021
TTARG=000025 21=000025 ERRNO=000030 24=000030 M=005020
2576=005020 N=005017 2575=005017 MQH=000036 30=000036
MCAND=000032 26=000032 T1=005000 2560=005000 TTOOR=002023
1043=002023 TTZCHR=001406 774=001406 T2=005003 2563=005003
MSL1=000442 290=000442 T3=005005 2565=005005 MULTUD=000010
8=000010 MSL2=000454 300=000454 T4=005007 2567=005007
T5=005012 2570=005012 ZSCHAR=000027 23=000027 TEST=005400
2816=005400 TX1=005022 2578=005022 MPER=000031 25=000031
TEX2=005404 2820=005404 MULTUS=000007 7=000007 TTYI=000002
2=000002 TTDD6A=001460 816=001460 MULTUX=000436 286=000436
TEST2=005410 2824=005410 TTYO=000001 1=000001 M10=000011
9=000011
# 0 errors, 634 words, 166 symbols
Appendix A
ORDER CODES
Appendix B
TELETYPE CHARACTER CODE
Appendix C
POWERS OF TWO
power (n) (n)
of two 2 decimal 2 octal
0 0 0
1 1 1
2 3 3
3 7 7
4 15 17
5 31 37
6 63 77
7 127 177
8 255 377
9 511 777
10 1023 1777
11 2047 3777
12 4095 7777
13 8191 17777
14 16383 37777
15 32767 77777
16 65535 177777
17 131071 377777
18 262143 777777
Appendix D
Initial orders
Universal Machine Operators Manual Copyright Tom Jennings 1999-2002 Page 44