(by Tom Sawyer)
WRITE - A Slow Output Method
WRITE was the "Achilles heel" of the ALGOL compiler for
the Burroughs 205. While the compiler produced reasonably efficient code, and results from any scientific calculation became available quickly, getting them out onto printed paper was a lengthy process. I had forgotten just how maddeningly slow the output process was until I began testing the recovered WRITE program. The blinking lights in the B-register as a line of print was formed brought back memories of waiting for each line to show up on our IBM 407. Five to ten seconds between lines was typical, but longer lines could easily take 30 seconds.
How It Works
Let's review what WRITE does. The format of a WRITE statement is:
WRITE(;;OUT1,FORM1);
This references a list of variables intended to be printed, such as:
OUTPUT OUT1(I,J,K,X,Y,Z);
and a format description such as:
FORMAT FORM1(*THE ANSWERS ARE*,3I8,3X8.5,W0);
Together, these three statements will deliver a single line containing "THE ANSWERS ARE" text, three integers and three decimal-embedded floating-point numbers each in an 8 character field, preceded by a single line slew on the printer.
One might expect that the FORMAT statement would be used to generate a CARDATRON format band taking advantage of the ability of a Burroughs 205 to move full words over to a CARDATRON cabinet and let that system insert spaces and decimal points, suppress leading zeroes and so on. (See Paul Kimpel's CARDATRON posts here.)
Instead, each line of print is formed in an output buffer and all of the editing is done on the 205. When complete, all 120 characters are sent as a long alphanumeric string to the CARDATRON. To describe this as slow is an understatement. The WRITE process yields a net speed of about 3 to 4 characters per second. Since the Flexowriter could deliver 10 characters per second and the CARDATRON up to 300 characters per second from machine language or assembly language code, the wait for output was agonizing.
The WRITE subroutine is completely driven by the FORMAT statement which is simply stored in-line in the program and is interpreted at run time by the WRITE subroutine. Each time that WRITE completes the interpretation of a numeric field in the FORMAT, a connection is made to the OUTPUT statement and the next variable is retrieved to place in the line at the current position.
Reconstructing WRITE From the Author's Notes
The biggest job I faced in restoring Don Knuth's Algebraic Compiler for the Burroughs 205 was reconstructing this WRITE subroutine. Anticipating a difficult job, I put it off until I had finished the first three arithmetic subroutines, SQRT, SIN and COS.
Fortunately by that time, I had the guidance of Knuth's original coding sheets! By the time I began to work on WRITE, Paul Kimpel had received the package from professor Knuth (described in my Sine post) that included early coding for the compiler and several subroutines.
There were two full pages devoted to WRITE.
I studied the code carefully before beginning to transcribe it into a source deck for Paul Kimpel's copy of the EASY assembler - making a few notes along the way.
Some Clever Code
Most of the code is straightforward, but it is interesting to look at a bit of it to gain insight into the programming style of this early era. Let's take a closer look at the upper left block of code on the sheet above.
The purpose of this snippet is to take a single alphanumeric character contained in the left two digits of the A-register and place it into the current position of an 80 position buffer that contains the line of print being generated. Simple enough in any machine that can address individual characters - but not so simple on our Datatron!
This block of code is written as a subroutine and entered with the B-register holding the return address.
The first thing to notice is that the code module consists of exactly twenty words. Coding a module to fit within a single one of the Burrough's 205 20 word high-speed memory loops was key to optimizing a program.
ZOUT is the variable containing a pointer to the current position in the buffer where the character in the A-register is to be placed. ZOUT is conveniently stored in main memory within this code block so that it is immediately available to us in high-speed memory.
The essential function of the code is to store that character in the right place and some calculations must be done. That requires use of the A-register so the routine must save the current contents (our character to be inserted) someplace and instruction 2 of this block stores the A-reg over the top of instruction 1. Using the 7000-loop itself for temporary storage is a mark of experience. (No harm was done to the content of any location in main memory by this trick.)
The final steps of the code block appear to be three standard Burroughs 205 instructions:
15 0000
72 BUFFR+5016
72 0000
15 is a Normalize (shift left to eliminate leading zeroes) and 72 is a Set B-register.
But, these are not what they appear to be. When this code is executed with ZOUT holding a value of 12, for instance, These three words will have been transformed into:
14 9976
74 0013+BUFFR
02 0013+BUFFR
which will be executed as SHIFT LEFT 16 positions, ADD, and STORE instructions placing the character in the appropriate position of the third word from the left edge of the line being developed at address BUFFR. One need not be a Burroughs 205 expert to appreciate the elegance of this code snippet. Once again, no harm came to any instructions in main memory. Modifying instructions on the fly would not be frowned upon for almost another decade.
The snippet also shows the early stage at which this sheet was prepared since it referenced a 16 word (80 character) buffer and would later actually require 24 words; it also contains a small error as the second SR (shift right) instruction should read SR 10, not SR 8.
Eventually, I found and fixed all of the "small errors" and had a beautifully functioning WRITE routine.
Dealing With the WRITE Speed.
To deal with the slow speed of WRITE, the only alternatives are to use the existing interface to code a simplified output routine, for instance printing a word at a time on the Flexowriter. Knuth discusses this approach with the director of the University of Virginia's computer center in his correspondence, noting that Purdue had already done so.
Another approach would be to skip direct printing and generate output to magnetic tape using the MTWRITE subroutine. Printing can then be accomplished with a separate customized assembler program that processes the output tape.
No comments:
Post a Comment