Saturday, June 18, 2022

A G-15 Four-Word Memory Clear Program

A little over a year ago, while researching the Bendix G-15 computer system, I came across a blog, "The Way It Was: Tales from a life in computing," by Jim Horning. The earlier posts in that blog discuss his early programming experiences, starting in 1959, with a G-15 in the Data Processing Lab at Pacific Union College in Angwin, California. Jim went on to spend significant portions of his career at Xerox PARC and the DEC Systems Research Center.

I enjoyed Jim's stories of his adventures with the G-15, but one post in particular caught my attention, "My shortest Program," from 31 August 2006. In it he describes a program for the G-15, only four words long, that would completely clear the machine's drum-based main memory, its software-accessible registers, the arithmetic overflow flag, and a sign flip-flop used in double-precision arithmetic. That's a lot to accomplish in just four 29-bit words, especially since one of those words was executed only once, at the beginning of the program.

Jim did not provide the code for the program, and in the original post described it only in very general terms. His memory was stimulated by a reader's comment to that post, resulting in Jim appending a rather long comment of his own. In that comment he described in some detail the types of commands the program used, the general scheme by which they worked, and gave many clues for how the program used quirks in the G-15 architecture to achieve its ends. I suspect that in 2006 he was working entirely from an almost 50-year old memory and perhaps was unable to recreate the actual code of the program.

Having recently written a software emulator for the G-15 and taken it to the point where it is working fairly well, I thought it would be interesting to try to reconstruct that four-word program and get it to work. It would be a nice test of the emulator, and something of a programming challenge for me. So I started out by reading his post and long comment multiple times, making notes, and trying to write down what the commands must have looked like.

Overview

You can read Jim's post and long comment at the link above for details, but the general scheme of the program, once initialized, was a loop consisting of five commands:

  1. CLEAR—clear one "line" (track) on the drum using the value (initially) in AR, the accumulator register, which was cleared to zero during initialization by the command that got executed only once.
  2. SWAP—exchange that CLEAR command in memory with the zero in AR.
  3. NOOP—execute the zero word just swapped, which was effectively a no-op (short for "no operation"), i.e., it made no change to the internal state of the computer except to specify the location of the next command to be executed.
  4. INCREMENT—increase the value of a field in the original CLEAR command (now swapped into AR) such that it addressed a different line on the drum, and when executed would clear that line.
  5. SWAP—again exchange AR with the NOOP command in memory, leaving the zero value in AR and the incremented CLEAR command in memory ready to be executed again. Then specify the CLEAR command as the next one to be executed and repeat the process from step 1.

That's a five-word command sequence that fits in three words of memory! How is that possible? As Jim pointed out, one of the commands gets held in the AR register, alternating between CLEAR and NOOP on each cycle through the loop, so that's actually four words of storage. The fifth command is SWAP. It gets executed twice, but in both cases it's the same word in the same location of memory.

How that loop works requires some explanation. Understanding that explanation in turn requires some background on the G-15 and how its commands worked, so I'll start there. One of Jim's clues was that the program modified itself during initialization, so the form in which the program was loaded into the system was different than the form in which it did most of its work.

I'll describe that second form first, since it is easier to understand. After that, I'll describe the initial form the program had when it was loaded, then how it started executing and transformed itself into the second form that actually cleared system.

The Bendix G-15

The G-15 was a mid-1950s, binary, vacuum tube, drum memory computer. As Jim hinted in his blog, there were two models, the original G-15A and the 1957 G-15D. There were some minor differences between the two that need not concern us here. My emulator is for the D model.

Drum Memory

The drum memory was organized as 29-bit words arranged in "lines", or tracks. There were 20 108-word ("long") lines numbered 0-19, four 4-word ("short" or "fast") lines numbered 20-23, three 2-word lines that functioned as double-precision registers numbered 24, 25, 26, and known as MQ (Multiplier-Quotient), ID (Multiplicand-Denominator), and PN (Product-Numerator), respectively. There was a single 1-word line numbered 28, AR, the single-precision accumulator. Line numbers 27 and 29-31 did not directly reference storage lines on the drum, but instead specified special functions the processor could perform. Note that the arithmetic registers were storage lines on the drum, not sets of flip-flops inside the processor.

All of the storage lines were implemented as recirculating delay lines, meaning that all of them were read and completely rewritten during each cycle through the line. The long lines cycled every 108 words (about once every 29 milliseconds). The fast lines cycled every four words (about once every millisecond), and AR cycled every word (once every 0.269 milliseconds). The amount of time it took for one word to pass its read or write head on the drum was termed a "word-time," also 0.269 milliseconds.

The basic operation the G-15 performed when executing commands was termed "transfer." Usually this involved copying one or more words from a location on one of the drum lines (termed the "source") to the corresponding location on another line (termed the "destination"). In some cases it was meaningful to specify the same line as both source and destination. When transferring between lines of different sizes, the locations were interpreted modulo the line size, e.g., location 2 on a 4-word line was also location 6, 10, 14, 18,... 102, and 106. 

By default, the transfer simply copied the bits from source to destination without change. A command could specify that certain transformations on a word were to take place during transfer, however. We will see one example of that in the memory-clear program. When a line was not being written by a software command, its bits were simply copied from its read head to its write head, hence recirculating them. The "delay" in the line was the time it took a bit on the surface of the drum to rotate from its write head back around to its read head.

Command Words

A command word in the G-15 executed a specific operation and consisted of eight fields having the following arrangement:

G-15 Command Word Layout

Briefly, the fields in this word, from right to left, had these purposes:

S/D (Single/Double) Bit

This is the sign bit in the word. In a command word it usually specified whether the processor operated in single (0) or double (1) precision mode. It was always zero in the memory-clear program, so need not concern us further here.

D (Destination) Field

The destination line for the transfer operation. This five-bit field could have values from 0 to 31, corresponding to the line numbers described above for the drum. Destination 31 specified that a special function was to be performed. The S field in this case, sometimes in conjunction with the CH field, specified the function. You will see below that the INCREMENT command of the memory-clear program was a Destination 31 command.

S (Source) Field

The source line for the transfer operation. Like D, this five-bit field could have values from 0 to 31. Sources 27 and 29-31 were not storage lines. Instead they supplied a value generated from Boolean operations on other storage lines.

CH (Characteristic) Field

This 2-bit field usually specified a transformation that was applied to a word as it transferred from source to destination. In commands that did not involve line-to-line data transfer, this field sometimes specified optional or variant behavior of the command. In the memory-clear program, this field was always zero—meaning no transformation, the bits were just copied—except for the SWAP command, where it was 2. The meaning of that code will be explained in the next section.

N (Next Command Word-Time) Field

As with many drum or delay-line memory systems of its era, each G-15 command specified the location of the next command to be executed. In most systems with other types of memories, commands were taken from sequential locations unless some command specifically altered the sequence. In the G-15, commands were executed from a single drum line at a time, each command's N field specifying the location of the next command on that line to be executed. Execution continued from that line until a command switched it to a different line. The memory-clear program was loaded into and ran entirely from the 4-word line 23.

BP (Breakpoint) Bit

This bit, if 1, caused the processor to halt if the COMPUTE switch was in the BP position. It was also always zero in the memory-clear program, and thus can be ignored in this discussion.

T (Timing) Field

This field controlled the timing of the transfer phase of the command. The way that field was interpreted depended on the state of the I/D bit described next.

I/D (Immediate/Deferred) Bit

This bit specified whether the command was to be run in Immediate (0) or Deferred (1) mode. All commands in the memory-clear program were Immediate, so we need not be concerned with Deferred mode. In Immediate mode, transfer began with the word-time (location) immediately following that of the command itself, although often on different source and destination lines. Transfer continued up to, but not including, the word-time specified in the T field. You will see below that the use of the T field in the INCREMENT command of the memory-clear program was an exception to this.

For more detailed information on G-15 commands, you may wish to look at a prior post in this blog, which gives fuller descriptions. For the whole story, the best reference is the G-15 Programmers Reference Manual. If you are feeling particularly brave, circuit-level details of command execution can be found in the G-15 Theory of Operation Manual.

Precession

A very important concept in the G-15 is precession, which is a form of data shifting. The processor did precession in units of bits and whole words; the input/output subsystem did precession in units of one bit, three bits, and four bits. All of these were accomplished by interrupting the normal transfer path from the read head for the source drum line and routing that stream of bits through a shift register of length n bits before routing the bits to the write head for the destination line. The effect of this was to delay writing to the destination line by n bits. The end result was:

  • The original n bits of the register became the low-order n bits of the first word written to the destination line.
  • The original contents of the destination line were shifted to the left (towards higher addresses) by n bits.
  • The original high-order n bits in the last word from the source line were left in the register.

This was a powerful, if somewhat unusual, feature of the system and was used extensively in many programs. The SWAP command in the memory-clear program made use of whole-word precession, primarily to exchange the CLEAR and NOOP commands through the AR register, but also as part of the transformation the program underwent from its loaded to its executing form.

The Second Program Form

As previously mentioned, the memory-clear program changed during its initialization from the form in which it was initially loaded to the form in which it cleared the system. This section describes that second form the program took and how it worked. The following table shows the program's command words immediately following their initialization:

L Hex T N CH S D Description
0 060235z 6 2 0 26 31 INCREMENT AR by 3
1 02693vw 2 105 0 29 28 Set AR to 0 (not used here)
2 0403uz7 4 3 2 23 23 SWAP location 3 with AR
3 0402380* 4 2 0 28* 0* CLEAR a line to zero
0000000 0 0 0 0 0 NOOP (copy line 0 to itself)

L is the location of the command in line 23 on the drum. The Hex column shows the hexadecimal value of the command word with the low-order sign bit stripped off, since it is always zero, leaving the 7 hex digits of the remaining 28 bits. Note the use of the G-15 convention for hexadecimal digits: u=10(a), v=11(b), w=12(c), x=13(d), y=14(e), and z=15(f).

The initialization phase of the program loads zero into the AR register, transforms the code into this second form, and then sets location 3 to be the next command executed. The table entry for location 3 shows two commands, CLEAR and NOOP, because these commands are swapped with the AR register on each cycle through the program's loop. When the CLEAR command is in location 3, the NOOP command (a word of zeroes) is in AR, and vice versa.

Execution of this phase begins at location 3 with the CLEAR command, shown here in its initial state. That command copies zeroes from AR (line 28) to long line 0. This command is modified by the INCREMENT command, however, changing the value of the CLEAR command's D field to address a sequence of lines on the drum. Hence the asterisks and underscores in those table cells, indicating that these values change as the program runs.

The command in location 1 is not executed during this phase of the program and was used only once to initialize AR to zero. Note that this command has a strange N value of 105. How can you have a next-command location of 105 for a 4-word line? It turns out you can, and that value is critically important to the initialization process, as will be explained in the next section.

We are now ready to trace through the execution of this phase of the program, starting with the CLEAR command in word 3. The AR register is zero.

CLEAR—This command transfers the value of AR to a line on the drum, initially line 0. Because it executes in Immediate mode, transfer begins with the word-time (location) after that of the command itself. Since the command is at word-time 3, transfer begins at 4. The transfer phase for an Immediate command continues up to but not including the value in the T field, 4, so transfer ends at word-time 3. Thus this one command will copy the zero in AR to locations 4, 5, 6,... 106, 107, 0, 1, 2, and 3, clearing the entire 108-word line.

The N field of the command specifies that the next command will be taken from word-time 2, the SWAP command.

SWAP—This command has source 23 and destination 23, which is the line from which the program's commands are being executed. This seems like it will not accomplish anything useful other than to specify the next command location, but this command has a CH (characteristic) field of 2.

CH=2 specifies a type of transformation termed Transfer Via AR (TVA). This is a form of whole-word precession. During each word-time of the transfer phase, the value of the word from the source line is copied to AR, while simultaneously copying the value originally in AR to the corresponding location on the destination line.

Since this is an Immediate command at word-time 2 with a T field of 4, the transfer phase will start with word-time 3 and end with word-time 3. That means that a single word will be precessed from the source through AR to the destination. Also, in this case the source and destination lines are the same, so the effect is simply to swap the contents of AR with the word at location 3, leaving the CLEAR command in AR and the word of zeroes (the NOOP command) in location 3.

The N field of the command specifies that the next command will be taken from word-time 3, now the NOOP command.

NOOP—This command, being a word of zero, simply copies data from line 0 to line 0. Since the location of the command is 3 and the T field is 0, transfer state will extend from word-times 4 through 107, but that is not important, because nothing gets changed. The only effect of this command comes from its N field, which specifies the next command will be taken from word-time 0, the INCREMENT command. Another (passive) purpose of this command is to preserve the value of zero while the CLEAR command is in the AR register being incremented.

INCREMENT—As Jim pointed out in his long comment, this is actually a G-15 shift command. It shifts the MQ register (line 24) left while simultaneously shifting the ID register (line 25) right. Since these are 2-word registers, each shift requires two word-times. This command executes in Immediate mode, but the T field in this case is interpreted as an absolute count, not the ending word-time. Since each shift requires two word-times, the T value must be twice the number of shifts desired.

The shifting behavior of the command is not relevant to its purpose in this program, however, and those registers are eventually going to be cleared anyway. Instead, the command is used for a side effect—if the CH field of the command is 0, the AR register is incremented by one for each shift performed.

At this point, the AR register holds the CLEAR command. The T field has the value 6, which means that three shifts will be performed. Thus, the real purpose of this command is to increment the D field of the CLEAR command by 3. Jim explains the rationale for incrementing by 3 in his long comment, but suffice it to say that this results in a sequence of values for the D field of 0, 3, 9,... 24, 27, 30, 1, 4, 7,... 25, 28, 31, 2, 5, 8,... 23, 26, 29, 0. Overflows from field D into field S of the CLEAR command occur when incrementing from 30 to 1 (yielding S=29) and from 31 to 2 (yielding S=30). The reason why the CLEAR command continued to work properly after its S field no longer referenced AR is explained below.

The N field of the INCREMENT command specifies that the next command will be taken from word-time 2, which is again the SWAP command.

SWAP—This is exactly the same SWAP command as the one above and works in exactly the same way, swapping AR with the word in location 3. The difference this time, however, is that the incremented CLEAR command is in AR and the zero for the NOOP command is in location 3. These are exchanged so that once again the zero is in AR and the CLEAR command is in location 3.

The N field of this command is still 3, so the next command to be executed will be the now-incremented CLEAR command. This completes the program's cycle for one destination line. That cycle now starts over again at the CLEAR command.

There are a several additional details necessary to complete the picture of how this phase of the program worked, most of which Jim mentioned in his long comment.

  • How does the program terminate? It doesn't. Once line 23 gets cleared, the program no longer exists, or rather, its words have all been overwritten with zeroes, which are NOOP commands. No matter in which word-time the CLEAR for line 23 ends, the NOOP will copy line 0 to line 0 and take the next command from location 0, which is also a NOOP. Thus, the program finishes by endlessly executing NOOP commands, copying line 0 to line 0 until the operator halts the system.
  • The CLEAR command always executes with AR being zero, so once the CLEAR for line 23 finishes, AR remains zero, as do all of the other registers.
  • Note from the discussion of the INCREMENT command above that the sequence of incremented D field values for the CLEAR command does not end with 23—destinations 26 and 29 come after that. Thus, once line 23 is cleared and the system starts continuously executing NOOPs, those last two destinations do not get cleared. That does not matter, though, because:
    • As Jim pointed out, line 26 is the PN register, which the system automatically clears when a value is copied to line 25, the ID register. This happens before line 23 is cleared.
    • Destination 29 is not actually a storage line on the drum. Instead it is a destination used to add a value to AR. Thus, not copying (nor adding) anything to it is not a problem.
  • When a value from an even word-time is copied into line 25 (ID), the sign of that value is copied automatically into the IP flip-flop, which holds the sign for multiplication and division commands. Thus, when line 25 is cleared to zero, IP also gets reset.
  • Destination 27 is also not a storage line on the drum. It is the TEST destination. If during the transfer phase it receives any 1-bits, then the next command is taken from the location one after that specified in the N field of the test command. The CLEAR command only transfers zero bits, however, so this "skip on non-zero" action never takes place.
  • Similarly, destination 31 is not a storage line on the drum. It indicates that the operation specified by the S field in the command will be performed. Destination 31 will be addressed during the time that the S field in the CLEAR command has the value 29. The combination D=31, S=29 tests and resets the arithmetic overflow flip-flop. As with the TEST destination above, if the overflow flip-flop was set, the next command is taken from the location one after that specified in the N field of the command. The CLEAR command that triggers this test has an N field of 2, so if the overflow flip-flop was not set, execution continues to that location in the normal manner. If overflow was set, however, the next command will be taken from location 3, which is once again the CLEAR command for destination 27. This time, though, the overflow flip-flop is guaranteed to be reset, since the test done by the prior CLEAR would have reset it, and execution will still continue to location 2 in the normal manner.

How was I able to reconstruct this form of the program? Jim's description in his long comment of the individual commands and the sequence in which they operated gave me a general idea of what the commands needed to be. What wasn't so clear were the locations in which they needed to be stored and values of the T and N fields in each command. I was able to piece the rest of it together by reading between the lines a bit and taking into consideration some constraints imposed by the G-15 architecture.

  1. As Jim pointed out, the INCREMENT command had to be in location 0, because the NOOP command specified it as the next command, and the N field of the NOOP command was 0.
  2. The command that cleared AR to zero was executed only once during initialization, so its location was unimportant during this phase of the program, and it could be placed anywhere.
  3. The most tantalizing clue was this statement of Jim's:
    "The final bit of cleverness was the third use of SWAP. When used in the loop, it executed for a single word time, thereby exchanging AR and a single word of line 23. But it was a block command, and its first execution was at a different word time than all the others. It precessed line 23 to place INCREMENT in word 0."
    That suggested to me that the initial precession rotated all four words of line 23 by one word. The command that cleared AR probably had to be in location 0 initially, so that it would be first to be executed after the program loaded. Precession moves words to higher locations; thus after precession that command would be in location 1.
  4. That left only two undetermined locations, 2 and 3, which had to be used for the SWAP and CLEAR/NOOP commands. Since SWAP was an Immediate command, the CLEAR/NOOP command it operated on during its transfer phase had to start at the word-time immediately after its own. Therefore SWAP had to be at location 2 and CLEAR/NOOP at location 3.

Once those locations were determined, the values for the N fields were obvious (well, except for that weird N=105 in the command that cleared AR—that came later), and the values for the T fields were straightforward to calculate from the command locations.

Sad to say, this phase of the program was the easy part to figure out. Understanding how the program had to be structured for loading and how it got transformed into this second form was much more difficult and took a lot longer. That is the goal of the next section.

The Initial Program Form

Programs were typically loaded into the G-15 from paper tape, something that could be initiated from the typewriter by engaging the ENABLE switch on the base of the typewriter and pressing the "p" key. Jim pointed out that you could also enter programs directly from the typewriter keyboard using a different sequence of control commands that are discussed in the final section of this post. Typewriter entry was practical only for very small programs like this one, though. There was no way to backspace or make corrections—one mistake and you had to start all over.

An input operation read data from paper tape or the typewriter and precessed it into line 19 in blocks of up to 108 words. Line 19, however, with a cycle time of 29 milliseconds, was too slow to precess digits directly from the paper tape reader, which at 250 characters/second read tape frames every 4 milliseconds. To get around this, 4-word line 23, which cycled about once per millisecond, was used as an intermediate high-speed buffer. Once line 23 accumulated four words, an operation termed "reload" would cause the hardware to copy the contents of line 23 to another 4-word line, MZ, which was not visible to software. From there MZ had plenty of time to precess its data into the beginning of line 19 while line 23 continued to fill up with digits from the reader. Reload was triggered by a control frame on the tape or the "/" key on the typewriter, although a later enhancement to the G-15 to handle alphanumeric data allowed reload to happen automatically.

Input from the typewriter was slow enough that direct entry into line 19 would have been feasible, but typewriter input still went through the same Tinker-to-Evers-to-Chance process that input from paper tape did. Since the memory-clear program was only four words long, there was no need for a reload to move it into line 19, as those four words could be executed directly from line 23.

With that preface on how a program gets loaded into the G-15, my problem at this point was to figure out how to arrange the words of code for the memory-clear program so that it would start executing properly.

Since programs started executing at word 0 after loading and the command that cleared AR to zero was executed only once, it made sense to assume that one-time command should be loaded into word 0. That command transferred source 29 (the Input Register, IR) to destination 28 (the AR register). The IR was a means to read a word of bits from external equipment, but unless it was enabled and the external equipment was actually present, it supplied zeroes, thus clearing AR.

The next issue was to understand how the initial execution of the SWAP command could precess the words in line 23 so that the INCREMENT command would end up in word 0 on the line, where from the discussion in the prior section we know it had to be. The only thing that made sense was to have the SWAP command rotate the entire line by one word. This is tricky, because in doing that rotate, all of the words would change location, including that for the SWAP command itself. It also meant that the next command originally addressed by the N field of the SWAP wouldn't be there any more after the swap—a different command would be in that location.

How a SWAP command executed from one location could rotate all four words of the line and the exact same command executed from a different location after the rotation would exchange only one word on the line with AR was the most difficult part of the initialization phase to figure out. The fact that the SWAP command moved, though, was also a clue. Executing the command from a different location would change the effect of the T field in that command, namely, the number of word-times the command's transfer phase would last.

Recall that a command executing in Immediate mode starts its transfer phase in the word-time immediately after that command's word-time on the drum. Transfer continues up to, but not including the location specified by the T field. Thus far, I have been using the terms "word-time" and "location" as if they are interchangeable, but they are not. It is tempting to think of the values in the T and N fields of a command as locations (addresses) of words on a drum line, but they are not that either. Those values actually represent counts.

The G-15 did not keep track of addresses on the drum. Instead it loaded the T and N values into a register, which then counted its way to the correct position on the drum. In reality, it loaded the complement of the difference between the T or N value and the drum's current position into the register and counted up until the 7-bit register overflowed. The counts were held and incremented as fields in a 1-word line on the drum, CM, the Command register, that was not visible to software. Exactly how this worked is complicated and is described in the G-15 Theory of Operation manual, section C-17 (starting on page 40, or PDF page 46).

After struggling over a number of days with how the initial SWAP command could be made to do different things from different locations, I finally realized that the answer had to be in the potential difference between a command's drum location and its word-time. For the long 108-word lines there normally is no difference, but for a 4-word line, word-times are still accounted for on a 108-word basis, even though a word's physical location is its word-time modulo 4. What I needed to do was arrange for the SWAP command to start at a word-time that was congruent modulo 4 with its drum location but that allowed the command's transfer phase to run longer.

For that, I first had to determine how many word-times of the SWAP command's TVA transformation were necessary to rotate all four words of line 23 by one word. TVA uses AR for its precession, and AR at that point has the zero value that will be needed by the CLEAR commands later, so this execution of SWAP had to work in a way that also preserved the zero for later use.

The answer turned out to be six word-times. To see this, first look at the sequence of commands as I now knew they had to be loaded into line 23. Un-rotating the commands as presented in the prior section, that sequence is:

0: SET-ZERO (set AR to zero)
1: SWAP
2: CLEAR
3: INCREMENT

Precessing these words through six TVA transformations yields the following sequence of exchanges:

Step Drum
Word
Before After
AR Line 23 AR Line 23
1 2 0 CLEAR CLEAR 0
2 3 CLEAR INCREMENT INCREMENT CLEAR
3 0 INCREMENT SET-ZERO SET-ZERO INCREMENT
4 1 SET-ZERO SWAP SWAP SET-ZERO
5 2 SWAP 0 0 SWAP
6 3 0 CLEAR CLEAR 0

The SWAP is executed from location 1 (but not word-time 1—that important detail will be discussed next), so it starts operating on the word immediately after that at location 2. After the command finishes, line 23 has been rotated by one word and now has the following arrangement:

0: INCREMENT
1: SET-ZERO
2: SWAP
3: NOOP (the 0 originally in AR)

The only remaining piece of the puzzle was to arrange for the initial execution of the SWAP command to run for six word-times instead of one. The solution to that involves the difference between drum locations and word-times, and is the reason for that weird N value of 105 in the one-time command that sets the AR register to zero.

N=105 modulo 4 is 1, so that will specify the SWAP command, initially at location 1, as the next command. The SWAP command will then start its transfer phase in the word-time after that, 106, and will continue up to but not including the word-time specified by its T field, 4. Thus, the transfer phase for the initial SWAP command executes during word-times 106, 107, 0, 1, 2, and 3—for a total of 6 word times.

After this point, the SWAP is in location 2 and is specified as the next command by the INCREMENT and CLEAR commands, which both have N=2, so in those instances there is no difference between location and word-time, and thus the SWAP executes only during word-time 3.

The way in which this precession worked is pretty slick, but it left me with two curiosities. First the CLEAR command was not at word 3 in line 23 anymore where I thought it needed to be—it was now in AR and word 3 now had a 0, the NOOP command. Second, and even more curious, the N field of the SWAP command has a value of 3, and therefore:

  • The next command to be executed after the initial SWAP will be the NOOP.
  • The only effect of the NOOP will be to move on to the command specified by its N field, which is 0, specifying the INCREMENT command.
  • The INCREMENT command will add 3 to the contents of AR (the CLEAR command), then move to its next command, the SWAP, now at location 2.
  • The SWAP, now in its new location, will execute for a single word time and exchange the NOOP and CLEAR commands, leaving the value 0 in AR and the CLEAR command in location 3.
  • SWAP still designates its next command to be location 3, now the CLEAR, which starts the second phase of the program as described in the prior section.

Thus, this sequence of commands has rearranged the words of line 23 into precisely the form needed to clear the system, just as described in the prior section.

The only problem now is that the CLEAR command has already been incremented, so if it had originally been loaded ready to clear line 0, it now has a D field of 3, meaning line 3 would be the first to be cleared and the program would never get to line 0. This was disappointing—the program had transformed itself exactly as needed except for that initial INCREMENT messing up the CLEAR command's starting line number.

I couldn't see any way to bypass the INCREMENT step, and worried over the problem for more than an hour before finally realizing (and smacking myself upside the head for being so dense) that the obvious solution was to load the CLEAR command so that incrementing it would properly address line 0 at the start of the clearing phase. Instead of loading the command with S=28 and D=0, it needed to be loaded with S=27 and D=29. Adding 3 to the word would increase D to 32, which in its five-bit field would be zero, and the resulting overflow into S would increase that field to 28. VoilĂ !

Therefore, the initial form of the program as loaded is this:

L Hex T N CH S D Description
0 02693vw 2 105 0 29 28 Set AR to 0
1 0403uz7 4 3 2 23 23 SWAP (rotate line 23 by 1 word)
2 040237x* 4 2 0 27* 29* CLEAR (before initial INCREMENT)
3 060235z 6 2 0 26 31 INCREMENT AR by 3

The asterisks indicate fields that are modified by the initial INCREMENT command during the initialization process.

In Summary

The form of the program that Jim would have typed on the G-15 typewriter at Pacific Union likely would have been this:

060235z02011vy8100yvxw04x2778s

The "s" at the end is a Stop control code that terminated typewriter input. The hexadecimal string above is in a compact form where the 116 bits of the four 29-bit words are packed into 4-bit hex digits without regard to word boundaries. The underscores indicate digits that contain bits from adjacent words.

There is a less-compact and more-easily understood form that could also be used:

060235zT 040237xT 0403uz7T 02693vwT s

where the "T"s represent pressing the Tab key on the typewriter and "s" again represents the Stop code. The spaces are optional and will be ignored by the G-15 hardware. Note that the words must be entered in the reverse of the order that they will be stored in memory—an artifact of the precession mechanism used by the G-15 input/output subsystem.

Jim would have have preceded either of these forms by engaging the ENABLE switch on the base of the typewriter and typing "sc7fq". The ENABLE switch caused the G-15 hardware to recognize certain typewriter keys as control commands. These keys caused the following to occur:

  • "s" canceled any input/output operation that was currently in progress. This was not needed if no I/O was active.
  • "c7" set the system's Command Line register to 7, which would cause the processor to execute commands from line 23.
  • "f" set the location (word-time) of the next command to be executed as 0. When the system was started, it would thus take its first command from word 0 of line 23.
  • "q" enabled the typewriter for data input.

See the G-15 Operating Manual for more information on the ENABLE switch, its keyboard commands, and data entry from the typewriter.

I can't be certain that the code I have presented here is exactly what Jim would have remembered using. It's possible there may be variations on what I have managed to reconstruct that would also work, although my code does match his description, and more importantly, it works just as Jim described. In my retro-g15 emulator, which attempts to run at the same speed as a real G-15, the program takes about six seconds to complete.

You can download a paper-tape image of the program code, in a form that will work in my emulator, from the project's GitHub software repository. There is also a text file containing a trace of the program's execution as it initializes itself and proceeds to clear the system.

This program is a good example—perhaps even an extreme one—of the cleverness and trickery in which programmers were willing to engage during the 1950s and early 1960s in order to obtain maximum performance in minimum storage space from early computer systems. It illustrates a couple of important G-15 programming techniques, including precession and the gaming of word-times to control what a command did.

I was quite pleased with myself for being able to reconstruct this program from Jim's description and my still-growing knowledge of G-15 architecture and programming techniques. Multiple head-pounding episodes of frustration aside, it was a lot of fun, and very gratifying to accomplish.

I had hoped to contact Jim after getting the program to work and telling him about my efforts and my interest in the G-15. Alas, I learned from a mutual friend that Jim had passed away in 2011, and I regret that I was never able to know him. His blog is still available, though, and I recommend it to anyone who is interested in knowing what it was like ca. 1960 to use a slow and difficult system from computing's early days.


Sunday, June 5, 2022

Introducing the retro-g15 Emulator

In the prior post, I described the origins and architecture of the Bendix G-15, a mid-1950s, binary, vacuum tube, drum memory computer system. In this post I will describe the retro-g15 software emulator I have written for that system. As with my earlier retro-b5500, retro-205, and retro-220 emulators, retro-g15 is written in JavaScript and runs in a standard web browser.

At time I am writing this, the emulator is at version 1.00. We don't yet have much software for the system, but it successfully runs a diagnostic program we do have, and appears to run the ubiquitous PPR (Program Preparation Routine) utility program correctly. The emulator presently implements only a basic G-15 system, supporting just paper tape and typewriter input/output. Support for magnetic tape, punched cards, and alphanumeric devices is feasible, but we don't yet have any software that requires those devices. Until we do, it is not worth trying to implement them.

For those who would like to jump ahead and start using the emulator, the source code and resource files for it are maintained as an open-source project at https://github.com/pkimpel/retro-g15/. You can run the emulator from a hosting site I have set up, or you can clone or download the files from the project's Git repository and set them up on your own web server. See the section Using the Emulator, below, for details on how to do this. Additional set-up and operating instructions can be found in the project wiki.

Choosing to Emulate the G-15

I studied Chemical Engineering at the University of Delaware from 1966 to 1970. During that time the campus Computer Center was located on the third floor of DuPont Hall. Outside the doors to that room and a short distance down the hall from it was a stairwell that went down to the ground floor. DuPont Hall is a three-story building, but for some reason the stairwell went up another half floor, where there was a large landing at the top.

On that landing, for the entire time I was on campus, there sat a Bendix G-15 in its turquoise livery, disconnected, forlorn, and all alone. I suspect that this may have been the University's first digital computer. By 1966, the G-15 was out of production, no longer supported, and seriously obsolete. My guess is that it had been decommissioned and moved up to the landing a couple of years before I arrived, to make room for the University's Scientific Data Systems 9300 computer, and then forgotten about. When I visited campus some years after graduation, I climbed back up to that landing, but the G-15 by that time was gone. I have no idea what happened to it.

I was intrigued by that abandoned system and wondered how it worked and how it had been used. That has remained sort of an idle curiosity since. I have a faint memory that someone (I don't remember who, probably one of my instructors) told me a G-15 had been used by Professors Jack Gerster and Robert Pigford to do pioneering work in modeling multi-tray distillation towers, a subject that would have been important to the large chemical industry in the Delaware River valley. If so, it would be interesting to know more about that, even though my days of understanding the chemistry, physics, and math of such a thing are long past.

As I approached retirement and had some success in building software emulators for old computer systems, I realized that this was now an itch that I could scratch. The bitsavers.org web site has a good collection of scanned G-15 manuals, and for the past couple of years I have been looking at those periodically. In late 2021 I started working on the design and development of the emulator in earnest.

Using the Emulator

As mentioned above, the emulator runs in a standard web browser, with Firefox and Chrome being the two I have used the most. You will also need a reasonably powerful workstation. Emulation of the G-15 instructions requires almost nothing, but update of the panels and I/O device windows can be graphics-intensive, and requires a fair amount of horsepower. My eight-year old Dell PC with a 3GHz quad-core Pentium i3 processor handles the emulator without difficulty.

The emulator must be served to your browser from a web server over HTTP. You will not be able to download the emulator files to your workstation and run them directly from your local file system. That is a limitation with the way that browsers work, not with the emulator. Of course, there's no reason you can't run a web server on your workstation and serve the emulator files from there. Regardless, once the emulator is loaded into your workstation, it runs entirely locally, and needs no further access to the web server.

Setting Up the Emulator

The easiest way to get started with the emulator is to run it from the hosting site where I have set up the emulator files. Feel free to use it:

If you would prefer to run the emulator from another web server, download the files from the Git repository on the project site. You can download a zip file of the latest version of the emulator source code and related resources by clicking the Download ZIP button on the repository's home page:

Alternatively, you can clone the project from the repository using the following Git command:

git clone https://github.com/pkimpel/retro-g15 retro-g15

Although the GitHub project site uses a Git source code repository, GitHub also allows you to access the repository using Subversion clients. A read-only checkout of the emulator files can be performed using a Subversion command similar to this:

 svn checkout https://github.com/pkimpel/retro-g15/trunk retro-g15

You will need at least the emulator/, webUI/, and webUI/resources/ directories from the repository. The emulator/ and webUI/ directories must be rooted in the same virtual directory on your web server. You may also wish to download/check out the software/ directory, as it contains some utility scripts, but that directory is not required to run the emulator.

The emulator may open a number of sub-windows when it initializes. Most browsers will consider these windows to be "pop-ups," so if you are using a pop-up blocker, you may need to disable it before starting the emulator. Most pop-up blockers will allow you to disable blocking for specific web sites, however, which will allow you to run the emulator without having to forgo protection from pop-ups for all sites. Modern browsers enable a pop-up blocker by default, and many browser toolbar plug-ins implement additional ones. All of them may need to be disabled for the emulator site.

More information on system requirements, setting up the emulator, and using a local web server is available on the Getting Started wiki page.

The Emulator Home Page

When you first load the emulator, it initializes with a default configuration, which is adequate to get started using it. Once it loads into your browser, it's ready to run. The hosting-site URL above references the emulator's home page, which looks like this:

retro-g15 emulator Home Page
retro-g15 Emulator Home Page

The picture on the page is the late Harry Huskey, the G-15 designer, apparently at the typewriter of his personal G-15 system. To start the emulator, just click the Start the Emulator button on the page. That will open the Control Panel for the emulator, which will overlay the Home Page in the same browser tab.

The Emulator Control Panel

The Control Panel for the emulator is a somewhat simplified version of the G-15 front panel and looks like this:

retro-g15 Control Panel and Typewriter

The top portion of the panel has the controls for the in-built paper tape punch and reader. The middle portion reproduces the lamps from the front the physical G-15 cabinet.The portion below that shows a few buttons and lamps that on a real G-15 were used to power the machine up and down; in the emulator those serve to initialize and terminate the emulator and are discussed in more detail below.

The meters and knobs on a real G-15 front panel are not shown -- they were used for monitoring power levels and maintenance functions, and are not relevant to the implementation or operation of the emulator.

Below the Control Panel is a gray box with a number of radio-button controls. These represent three toggle switches that were located on the base of the system's typewriter.

  • The ENABLE switch controlled the ability to enter certain hardware control commands from the typewriter keyboard.
  • The PAPER TAPE switch in its PUNCH position caused all characters sent to the typewriter to be output as well to the paper tape punch; in its REWIND position, it caused the paper tape reader to rewind its tape.
  • The COMPUTE switch controlled the G-15 processor. In its center (off) position, the processor was halted. Moving the switch to its GO position started the processor executing commands. Moving the switch to its BP (breakpoint) position worked like GO, but in addition, if the processor executed a command word with a particular bit set, the processor would halt. This feature was typically used for debugging.

The white area below the switches represents the "paper" of the typewriter. Its size is responsive to the size of the browser window, and will scroll once the typed output fills up the visible area. Your workstation keyboard functions as the typewriter keyboard and is active whenever the browser window has the input focus. Whether pressing a key on the keyboard has any effect on the system other than echoing that character to the paper depends on the setting of the ENABLE switch and whether a "Type In" command is currently being executed.

To power up a real G-15, you turned on the master A/C switch (labeled START) on the front panel. After the tubes in the power supplies warmed up, you would then press and hold the RESET button until the red DC lamp lit, then release the RESET button. At that point, the G-15 hardware performed an automatic sequence of functions that included:

  1. Read the first block of data from the paper tape reader to line (track) 19 on the drum.
  2. Copy that data from line 19 to a separate line on the drum known as the Number Track. This track provided a set of timing and logic signals to the hardware logic. The hardware logic also wrote to portions of this track during its operation, so that line on the drum had to function as a recirculating delay line like all of the others on the drum. All data was lost from these recirculating delay lines when the system was powered off, which is why the Number Track had to be reloaded each time the system was powered up.
  3. Set the Command Line register to 7, which would cause the processor to execute instructions from the four-word ("fast") line 23.
  4. Set the location of the next word to be executed from that line to zero.
  5. Read the next block of data from the paper tape reader to line 19. This block was typically a loader routine for some program that followed it on the tape. The way that paper tape was read on the G-15 required that line 23 be used as a high-speed buffer, allowing four words at a time to be read from the tape, then precessed (shifted) from line 23 to the beginning of line 19. The words had to be on the tape in reverse order, and the reading worked in such a manner that a copy of the four words stored at the beginning of line 19 were also left in line 23. Thus you actually bootstrapped a program from line 23, which usually transferred control to the actual loader routine located somewhere in line 19.
  6. Terminate the initialization process by turning on the green READY lamp and leaving the system in a halted state.

Initializing the emulator works in a very similar way. Clicking the Start the Emulator button on the Home Page is equivalent to turning on the master A/C switch. Once the Control Panel appears, you click the RESET button (although holding it down is not necessary). After a short delay the DC lamp lights and the system attempts to read two blocks from paper tape and perform the other actions described above.

The emulator does not actually use the data on the Number Track for its operations, but a program can execute a command that will copy the Number Track to line 18 on the drum, from which the program could read and make use of that data. Except for that detail, the emulator will still function properly if there is no tape in the reader when the RESET button is clicked, or if the first block does not actually contain Number Track data.

As a convenience, the emulator preloads the paper tape reader's buffer with a tape image for PPR (the Program Preparation Routine), a very common utility program for the G-15. This image has the Number Track data and the PPR loader as its first two blocks. Thus, by default you can simply start the emulator, click the RESET button, wait for the green READY light to come on, then move the COMPUTE switch to GO to run PPR. If you want to initialize the system with a different tape image, just unload the PPR image from the reader and load the other image before clicking RESET.

As another convenience, the ESC key on the keyboard can substitute for the ENABLE switch. It is a little awkward in the emulator to have to turn on the ENABLE switch, press a typewriter key for one of the hardware control commands, and then turn the switch off. Instead, you can use the ESC key like a shift key. If you press and hold the ESC key, the ENABLE switch will move to its ON position. Once you release the ESC key, the switch will revert to its off position.

For more information on the layout and functioning of the Control Panel, including the paper tape and typewriter devices, see the "Using the Control Panel" wiki page. For information on the hardware control commands, use of the ENABLE switch, and the PPR program, see the G-15 Operating Manual.

The G-15 was not a particularly easy system to use, and a great deal of responsibility fell on the person running the system to know how to perform the necessary functions and to do them properly. Aside from a few conveniences in its interface, the retro-g15 emulator works the same way -- by design. This is a time trip to 1950s computing and you are going to suffer, so plan to do some reading before trying to use the emulator.

The Diagnostic Panel

To aid in debugging the emulator, I implemented a more detailed panel that shows all of the registers, the current command word separated into its several fields, the current drum and command locations, and several significant flip-flops in the system. The panel displays all four of the 4-word (fast) lines and the MZ line that was used as an I/O buffer but was not visible to software. You can select a single 108-word (long) line for display as well.

At the bottom of the panel are three buttons that can be used to start, stop, and single-step the processor.

retro-g15 Diagnostic Panel

To open this panel, double-click the G-15 logo on the Control Panel. You can open and close the Diagnostic Panel at will while the emulator is running. "Powering off" the emulator automatically closes the Diagnostic Panel window if it is open. The panel updates itself at a rate of about 20Hz. The display of the drum lines updates a couple of times a second.

Even if you don't use it for diagnostic purposes, this panel can be interesting to watch while the system is running.

Software

We do not yet have much software for the G-15 in terms of standalone programs. There is more available and I am working to acquire it, but that is probably going to take some time. In the interim, thanks to David Green in Western Australia and Paul Pierce in Portland, Oregon, we have these three interesting items.

PPR (Program Preparation Routine)

PPR, as mentioned earlier, was a utility program that was used by most G-15 sites and developers. It was operated from the system's typewriter and provided features for:

  • Entering object code words as a series of decimal fields and assembling those fields into binary command words.
  • Reading existing object code from paper tapes and editing the code in memory.
  • Merging library routines from other paper tapes into memory.
  • Punching new tape from the edited code.
  • Typing the contents of tape blocks in hexadecimal.
  • Computing and typing out checksums of tape block contents.
  • Disassembling code from tape blocks in a format similar to that used for entering command words.
  • Debugging programs with breakpoints and tracing.
  • Creating the loader routines for a program.
  • Relocating code for library routines so they could be moved to different lines on the memory drum.

A bootable paper tape image of the program can be downloaded from the G15-software code repository. As described above, the retro-g15 emulator preloads this tape image into its paper tape reader during initialization. This tape image was obtained from David Green.

Instructions for running PPR can be found in the G-15 Operating Manual. A listing of the object code for the program, in the form of G-15 coding sheets, is available on bitsavers.org.

BXTST

The standard G-15 diagnostic program that was provided by Bendix.

A bootable paper tape image of the program can be downloaded from the G15-software code repository. Instructions for running the program and discussions of the various error codes can be found in "PART III - APPENDIX" of the G-15 Theory of Operations manual, starting on PDF page 193.

This is a bootable paper tape image and includes the Number Track and test loader as the first two blocks on the tape. This tape image is from Paul Pierce's web site. A slightly different version of the program from David Green, G15TAPE, is also available in that repository.

TQ

This is a short, one-block program that plays a numeric version of the game "Twenty Questions." The idea is that the player chooses a number between zero and 1048575 (220 - 1) and the program will discover that number.

A bootable tape image of the program and instructions for it can be downloaded from the G15-software code repository. This tape image was obtained from Paul Pierce.

In the next post to this blog, I will describe another interesting, but very short, program that I have recently recovered.


A G-15 Four-Word Memory Clear Program

A little over a year ago, while researching the Bendix G-15 computer system, I came across a blog, " The Way It Was: Tales from a life ...