History of the Leo III Software Preservation Project

David Holdsworth

1. Starting Point

2. Strategy

3. Manuals — understanding Leo III

4. Emulation — First Steps

5. Digitisation — First Steps

6. Intercode Translator — First Steps

7. Copy-Typing — Methodology Emerges

8. Intercode Translator — Second Steps

9. Coming together

10. Modernisation of Access

11. Deeper into Intercode

12. Beginning to Understand Intercode

13. Magnetic Tape

14. Progress

15. First Bootstrap — Intercode Translator
   
16. A Genuine User Programme

17. An Intercode Facility for the 21st Century

18. First Steps — Master Routine

19. Copy-Typing Methodology

20. Further Steps — Master Routine

21. Alarming messages

22. First Steps into the Master Routine

23. Operator Interface

24. Object Programmes

25. Boot Tape

26. Demonstration Facilities

27. Imperfections

28. On-line Resources

Appendix A Translator Bootstrap

Appendix B: Techniques and Technicalities

This is an attempt to record the steps along the way, before memories become too unreliable.

I undertook this project in order to get a better appreciation of the issues that would face historians (archæologists) of the future faced with remnants of software from a long dead machine. I had the (unfair) advantage of living veterans, without which the project would have been much more difficult.

This document attempts to recreate the chronological sequence of emerging knowledge of Leo software and the on-going computational effort. It begins by looking at the starting point, and the strategic decisions taken at the outset. The developments pretty much adhered to the strategy, despite my surprise discoveries along the way. At the end, all three software components work and inter-work correctly, and their source text can be browsed as HTML with cross reference links and links to the images of the original material, as can the manuals.

After the main body of the document which describes steps along the way, there are two appendices. Appendix A spells out how to make the whole thing work starting from the raw material, and can be followed on your own machine in order to relive the creation of the working Intercode Translator. Appendix B gives expanded detail on various technical points concerniong the Leo III, many of which are far from obvious to computer people in the 21st century.

1. Starting Point

Our original material was a box of lineprinter listings of systems software, and original manuals for the system, which had been collected by the late Colin Tully. Here is a list of all the photographs of listings and diagrams. Via a separate source, we received a fairly mysterious box of paper tapes which are described here.

From the several listings which survived we elected to work on the Intercode Translator (08000), the Master Routine (09001) and the generator programme for customising the master routine (08004). All of these are written in Intercode. No binary code for these items has survived.

I was surprised to discover that almost everthing is described in numbers, the names of programmes, the instruction codes, the subroutines, the addresses in memory, and more besides. The logical names of I/O files do consist of a single letter and a single digit. There are a few reserved words in Intercode.

2. Strategy

The aim of the project was and is to create an environment within which this software can be preserved indefinitely, in such a way that it can be appreciated by future generations, both by the casual observer and also the serious student of computer history. The documentation and source text was to be (and is) available on-line in text form and as scanned images. The on-line source material was to include links to assist following execution paths in source code, and cross-references in documentation. The use of HTML was to be deliberately conservative in order to avoid sensitivity to browser versions.

Ultimately, everything should run under an emulator which executes the Leo III machine code, but in order to get to that stage we need to be able to translate Intercode into machine code, which needs the Intercode Translator 08000, for which we did not have a binary program. We then need to be able to run code that contains calls to facilities in the Master Routine before we are in a position to generate our own Master Routine. The Intercode Translator has the capability to list the binary program at the end of its listing, but this part had been torn off our surviving listing. The decision was to develop in parallel an emulator for computer code, a translator for the minimum Intercode capability to translate 08000, and the digitised source code of 08000. The source code was “digitised” by copy-typing of the original listings, which proceeded alongside the development of the code which is all written in a subset of C. To see the rationale for programming in a subset of C, please look here.

The parallel implementation of the emulator (leo3.c), the copy-typing and the interim translator (called it.c) for generating a binary program from 08000 enabled the emerging the C code to be tested against known valid Leo III Intercode.

3. Manuals — understanding Leo III

As a vital early step, we made on-line manuals available. They can be seen here, on a server which may not be up 24/7. There remains some work to be done on editing, but what is there is very usable. We have preserved the original wording although some terms used differ from today's usage, e.g. a word of store is often referred to as a compartment.

The decision was to try to reproduce the style of the originals using very simple HTML exploiting the <PRE> tag so that the material would be immune from sensitivity to browser versions. We have used this technique and it works well in almost every instance. The browsers in smartphones and smart TVs seem to lack a monospaced font. Even then the manuals read quite well, except for some of the tables.

There are five volumes of manuals:
        Vol I − Computer Facilities which describes the Leo III at the machine code level (called computer code in Leo speak).
        Vol II − CLEO which describes the Leo III high-level language, whose software seems sadly not to have survived.
        Vol III − Intercode which describes Intercode in which all of our software is written.
        Vol IV − Standard Programmes which describes various items of Leo III software, especially the Master Routine.
        Vol V − Other Standard Programmes which describes various other items of Leo III software.

We have concentrated on volumes I, III and IV. It is with regret that volume II remains untouched awaiting the discovery of a CLEO compiler.

4. Emulation — First Steps

At the heart of an emulator is a giant switch statement with individual instructions as its elements. The Leo III instruction is 21 bits long, 5 function bits, a single discriminant bit which selects between short word and long word addressing, 2 modifier bits and 13 address bits. For many instructions the 3 bits that form the discriminant and the modifier are actually used as part of the function code (often callec action in Leo-speak), so it was decided that the switch should operate on the 8 bits of function, discriminant and modifier. I started with the order code summary in the Leo III page in the Our Computer Heritage website. This was converted to plain text by a simple copy and paste, and then fed through a purpose-build generator program to generate the switch statement in which every instruction was flagged as Illegal: not implemented, but the discriminant and modifier bits were handled in appropriate places. The text from the OCH web page survived as comment, and is still conspicuously visible in the emulator (leo3.c) today.

As an early step to understanding the workings of Leo III, I began by implementing the famous mixed-radix arithmetic of Leo III, and feeding it with examples from the Computer Manual. Throughout the emulation implementation, only those instructions that we have actually encountered in real Leo III programmes have been implemented. It all looked quite good until we tried to translate PROCR 126 (see below).

5. Digitisation — First Steps

The manuals are loose-leaf, and we have two copies, so we decided to trust one of them to a sheet-feed scanner in the Leeds University computer centre. The paper size did not correspond with any of the scanner's pre-conceived ideas so we had to weight down the A3 sensor and get scans with a lot of white on the right hand side. Nonetheless, the Omnipage OCR software made quite a good fist of recognising the characters, but very much lost the layout. However, for the most part the layout follows a regular pattern and it was easy to write a little program to recover it.

The Intercode listings were clearly not amenable to OCR, having been produced on barrel printers which were past the first flush of youth. This image is the start of the Intercode Translator, and this is the start of the Master Routine. These are among the worst examples. Here is typical page from the Intercode Translator (08000), and here is typical page from the Master Routine (09001), which is not a top copy. The decision was to copy-type in duplicate with a team of volunteers drawn from Leo veterans in the Leo Society. This technique had already worked very well with KDF9 listings.

The plan is to capture enough of the listing to reproduce the binary programme that went alongside it. Not all the columns are needed for this.
In order to generate the binary programme we need columns Serial Number, Action, Reference, Item, Discriminant, Modifier and Literal. However, we obviously also need to store the comment. At this stage I was unaware that there were two sorts of comment: comment and notes, nor was I aware of their critical role in defining configurations of the Master Routine.

After one or two experiments we decided to type the chosen columns into a spread sheet, and then save the result as a comma-seperated data file for further processing. The Leo III character set does not have lower-case letters, so we used lower-case letters for those Leo III characters that do not exist in ASCII, e.g. 't' for the Leo III ten character where the two digits are squashed into a single character space (see Appendix B).

As an illustration of the difficulty of reading the listings we detected a typo in which line 67469 should be:
        67469 6,1,1,1,9;
               and not
        67469 0,1,1,1,9;
But the printing was very indistinct in this page.

6. Intercode Translator — First Steps

Intercode is a machine-level language for a fictitious machine with a somewhat richer instruction set than Leo III. Programme 08000 is the Intercode Translator which takes in Intercode and generates machine code (called computer code in Leo-speak). It also produces a printer listing of the source code. During this process the line serial numbers are likely to be changed by the Translator as a result of the amendments. These serial numbers even get changed on an initial translation. At this point I (DH) was unaware that the listing produced by 08000 was not the same as the input, and had set things up to copy-type just the parts of the listings that corresponded with the source code. In retrospect, this turned out well, probably better than if we had tried to type proper 08000 input from the print-outs.

The first step is to produce the interim translator which can make a binary version of 08000 which we can then execute with our emulator. We can then use this to translate the source code of 08000 to produce a genuine binary programme. An appendix to Volume III of the manual gives computer code expansions for the different Intercode actions. I decided to do a two-pass translation and to generate absolute binary which we could load directly into the emulator. The input format to the emulator had by this stage crystallised to be just one short word per line with the components separated by / as in the Leo manuals, and initial experiments just produced a single file with the binary code at the left and the source code to the right of that, so you could see what had been generated against the Intercode that was input. In the event, this format survived and evolved into HTML with cross references which can be seen here. You need to scroll down quite a way to get the full flavour.

Like the emulator, this interim translator embodies a giant switch statement, one case for each of the 150 or so Intercode actions. It was implemented using a small generator program to read the list of Intercode actions and generate the C source code. To begin with every action was treated as an error.

7. Copy-Typing — Methodology Emerges

We established a modus operandi in which there was an on-line booking system in which a volunteer would choose a page to copy, and choose whether to do the primary copy or the secondary copy. We decided to omit the comments from the secondary copy. In order to eliminate the vagaries of individual typing styles, I wrote a program to make a canonical form of a copy-typed CSV file, and then used an old utility windiff to compare the versions. Where differences occurred I consulted the photograph, and occasionally asked John Daines to consult the paper copy. Quite quickly the Intercode source code started to emerge, and it became possible to feed it in to the interim translator.

8. Intercode Translator — Second Steps

The initial version of the interim translator flagged every action as invalid. One by one the code to generate the necessary expansion was inserted in the list of Intercode actions and the generator rerun, then a rerun of the newly generated interim translator. An array indexed on serial number kept track of memory locations in the first pass, and then the second pass could refer to correct locations. The code is divided into chapters which are in turn divided into procedures (called PROCR) and sections each of which can be either a list of constant values (key word CONST), or a TABLE. There are also sections which are working storage, which is not initialised at load time, and values in CONST sections do get used as variables. Each line has a serial number which has 5 digits. The first 3 are the PROCR or section number, and the last 2 increment as if a machine address. They are consecutive in a PROCR as if they are seen as a machine address, and they all slide up one after a new instruction is added. The memory of the machine can treat 2 consecutive short words as a long word, and tables generate one long word per line, and the serial numbers go up in twos.

9. Coming together

At this stage the source text is growing, and from time to time it gains a previously unseen Intercode action, whereupon the interim translator is enhanced to cope with the new arrival. Any unimplemented Intercode action results in a HALT instruction in the output. Fortunately execution of 08000 starts very near the beginning of the source code, so we could start trying out our emulator on genuine code very early in the project. It has a wonderfully encouraging effect on the team to see the 50-year old code executed again. It seems that the date is always 2 digits so there would be Y2K problem as one crossed over into the 21st century, but now that we are safely there the year just appears as 15. We've not yet got any software that deals with money, but that would be LSD, and the tenpence and elevenpence characters turn up elsewhere from time to time.

All was going very well until the copy-typing included PROCR 126. In PROCR 102 (line 10230).is a reference to item 15 PROCR 126, i.e. line 12615 which up until this point had flagged an error because the procedure was unknown. However, it turned out the there is no line 12615. It only goes up to 12610, so it still flagged an error. Several mutually uncomprehending e-mail exchanges with the volunteer veterans eventually got me to understand that for jump instructions the item number is indeed the line serial number as I had assumed, but for a fetch or store instruction, the item is the relative location from the start of the procedure with 2 added on because there are two heading lines. The mystery instruction was picking up an instruction out of the expansion of an Intercode instruction, 13 short words on from the start of PROCR 126. So long as each Intercode source line generates only one computer code instruction these two interpretations of the item are identical. In the output from the interim translator I marked situation where this was not the case. The listing includes a letter 's' where the serial number has been used and a letter 'a' where the absolute address offset has been used.

In previous emulation activity in resurrecting old software, I had met the situation where you encounter an undocumented feature of the machine. The Leo III Intercode Translator proved to be no exception. The manual’s description of decimal arithmetic only covers the case where all the digits in the operands are less than 10. However, we met many cases of subtract to test equality where some of the digits exceeded 9. There was even a case of testing the sign of the result. In such cases our emulator originally flagged an error, but it now just delivers the result of a binary subtraction. None of the veterans was able to say what actually happened on the real machine, until much later when it was pointed out that the description in the manual is actually about non-binary arithmetic, not just decimal, and from it one can deduce that a carry is generated if any digit is bigger than the radix. However, there is not a single example of this situation, so in a sense it is undocumented. Our emulation only works if the carry is no more than one binary digit. Hence the problems.

10. Modernisation of Access

We also have ambitions to make the appreciation of usage of Leo III accessible to a 21st century audience. We have packaged our emulator as a web facility for submitting an Intercode program, and for running the resulting binary program, all using the genuine Leo III software, currently available here.

The listings produced by 08000 were on fanfold printer paper and probably perused by kneeling on the floor upon which the listing was spread out. Our modernise.c progam takes the listing file, and turns all the references into hot links to the relevant routine, this making it much easier to follow executions paths that was ever the case in real life. It also inserts links to the original scanned images, and adds the description of the Intercode action field for the benefit of those of us who cannot remember that action 76 means jump.

The documentation has been similarly modernised with hot links in its contents pages.

11. Deeper into Intercode

Appendix A of Volume III of the manual lists the computer code expansions of all of the Intercode actions, and drops hints that transit areas might be different, and indeed they are. The actions are in groups so that group 2 contains all the actions from 20 to 29, etc. Group 4 contains actions 40 to 49 which are concerned with input and output. Here the manual contains phrases like “control information to B” and “type of operation in Q6”, without specifying what the values are that need to go into B and Q6. Section 5 of the manual does describe exactly what the actions should do, but not the nature of the interface between the computer code programme and the Master Routine. The solution was to devise our own interface, and to implement that in the interim translator and the emulator, exploiting the fact that the Master Routine would only ever be entered at a few very specific addresses.

12. Beginning to Understand Intercode

At this stage I was beginning to understand something of the structure of Intercode programmes. Each chapter has a procedure 0 which contains pointers to all the chapters so that it is possible to address data anywhere in the programme. All the op-codes (called actions in Leo-speak) are numeric, as is all the addressing. Now that we had some implementation of I/O there was the question as to what the paper tape input should look like. The manual instructs programmers how to fill in their coding sheets, but does not tell the data prep staff how to encode this on the paper tape. Volunteers report that there was a standard procedure, but it must have been documented elsewhere. The serial numbers on input are different from those in our listings. This blank coding sheet has preprinted serial numbers starting at 0, whereas the code starts at 2 in the listing. I suspected that Leo veterans had tried to tell me this, but my natural incredulity at such an arrangement prevented me from understanding their messages. A modified version of our interim translator was quickly cobbled together to output the paper tape instead of the binary programme.

As well as changing the serial number at the start of each line, some of the item numbers needed changing. We were now at the stage where we were starting to read paper tape (or file images thereof) which was the source code of the real Intercode Translator, even though the copy-typing of the code was nowhere near complete. Seeing things start to work was a great boost to morale.

13. Magnetic Tape

We first encountered attempts to write data to mag tape as soon as we started executing the code generated by our interim translator. Our implementation at this stage just wrote out the data from the store (an array of integers) as is, with a header word to give the size of the block. This enables the implementation of reading the data back into store so long as you do not try back skips, which turned out to be quite common. An enhancement to the header word added in the size of the previous block, thus enabling implementation of back skip. The niceties of tape labels, serial numbers and end of file sentinels were to come later. We still do not emulate multi-reel operation. Our magnetic tapes can be very long, − also the paper tapes. The source code of 08000 would be almost a mile if punched with no run outs.

This format of tape makes emulation very easy (well fairly) but is architecture dependent.

14. Progress

Our efforts were still concentrated on bootstrapping the Intercode Translator (08000). We now had people copy-typing 08000, and simultaneous development of two C programs: the interim translator (called it.c) and the emulator (called leo3.c). Each program had many places which flagged not implemented, indicating some feature of Intercode or computer code that we had never met.

As the copy-typing proceeded I had an (unfullfilled) ambition to get others to do the comparison of duplicates. This would surely involve removing dependence the the obsolete windiff, which only runs on my Win 98 desktop system. I produced a Java program to do comparisons in a very simple way and started to run it on the laptop in front of the TV where I could use the SmartTV facility to show the printer listing on the big screen.

Eventually the copy-typing of 08000 was complete and the binary programme generated by our interim translator was now a viable computer code version of the real 08000. When fed with Hello World! (a popular minimal test program that merely output the text “Hello World!”) it produced a plausible listing and an output magnetic tape with the binary programme on it. On a real Leo III this magnetic tape would be loaded into memory by the Master Routine prior to execution. In the absence of a Master Routine, it was decided to write a loader program (getbin.c) to read the image of the magnetic tape and generate a binary program in the format required by leo3.c. We had a manual page documenting the format of the tape, though progress was somewhat slowed by a couple of errors in the diagram. However, it was not long before our Leo III operator’s typewriter greeted the world in the time-honoured fashion, minus the customary exclamation mark as the character is not in the Leo III character set.

15. First Bootstrap — Intercode Translator

Although the successful execution of Hello World! translated by the real Intercode Translator was a great morale booster, the next goal was the execution of 08000 as translated by our demo.htm that was generated by our interim translator (see Appendix A). Our interim translator reads our CSV files, whereas the real Intercode Translator reads a paper tape of a somewhat different format. This necessitated yet another program (mkpt.c) to generate a file to represent the paper tape. Also we needed to enhance our loader program getbin.c to handle multiple chapters and overlaying. In addition, the Intercode I/O actions were translated by our interim translator into very non-Leo entries to the non-existent Master Routine that were then emulated by our emulator. The binary programme that we had now generated had in it the proper calls to the Master Routine using the undocumented parameters. This meant that we needed to reverse engineer the interface (API). This process is described in Appendix B.

I have forgotten the detail, but there is something in 08000 which is sensitive to its own serial number. A translation from paper tape (or cards) always produces a serial number of zero, so we had to run a null amendment to set it to 801, its proper value. A separate web page provides instructions for running this bootstrap on one’s own machine, and a fuller account in is Appendix A.

16. A Genuine User Programme

Within the mysterious box of paper tapes mentioned earlier was just one Intercode programme called bindec (official number 08006), which produced a table of decimal to binary conversion, and which also translated and ran, except that the output was a statement of the obvious, until we realised that user programmes must start with a decimal radix. Until I discovered the numeric nature of Intercode, I had assumed this tape to be data for a programme that we did not have, rather than source code.

17. An Intercode Facility for the 21st Century

In the 1960s Leo III programme developers wrote their code by hand on coding sheets and then submitted them to the data preparation staff for punching onto paper tape or cards. This was then passed to the operators who actually run the programme on the machine, and then sent the printer output back the the programmer. In an attempt to emulate this on a much shortened timescale, and omitting the hand-written coding sheet, we have implemented a facility for running Intercode programmes via a web page. It is somewhat rudimentary and runs on a Raspberry Pi. As a further confidence builder one volunteer who had written lots of Interocde in the past (KK) ran various tests that he had written which led to some fixes in the emulator.

18. First Steps — Master Routine

The next ambition is to run the Master Routine. We have two printouts of the Master Routine. One is a decent quality top copy. Althought the first page looks like this, later pages such as this one are much more encouraging. The downside was the discovery that a few pages were missing. The other copy is complete, but is not a top copy, and rather faint. This is the first page, but it does improve somewhat, as can be seen here. A further difficulty arose when we thought to use the good copy for most of the copy-tying and use the blue stuff in the middle. Unfortunately, they are slightly different versions, and the Intercode amendment process shuffles the line numbers and routine numbers in such a way this was not feasible, and the Master Routine was heroically copy-typed from the blue copy.

We now had a proper Intercode Translator, the real programme 08000 with which to process the source code of the Master Routine. This is the generic Master Routine which contains all possible facilities, and is too big to fit in a real Leo III computer. We were pleased to see that the error reports from our translation matched those on the surviving printout.

19. Copy-Typing Methodology

Our copy-typists are all volunteers, and I was always keen that they should volunteer in to type a page, and not be told what to do. The booking arrangement worked well throughout. By this time a customised comparison program had been developed and it now took only a very few minutes per page so long as there were not any big errors.

Throughout the copy-typing process the source text would gradually grow, and was frequently put through the Intercode Translator as a confidence builder.

20. Further Steps — Master Routine

A real Leo III Master Routine is produced from the generic Master Routine by the generator programme, known by its friends as 08004. The translation of the generic Master Routine by the Intercode Translator (08000) produces a magnetic tape which is then used as input to 08004.

We possess only one listing of of the generator programme, which was subjected to the same copy-typing ritual as the other two listings. As usual we ran the emerging source text through the Translator, and because the programme starts at the beginning it was possible to start execution before the copy-typing was complete. Before long we hit a snag. This generator programme was written to process a master routine called 09002, whereas we have 09001. Clearly we had a version compatibility problem. We altered the constant 9002 in 08004 to be 9001, crossed our fingers and carried on.

So we know we have slightly incompatible version of software, and in general we cannot be sure that we have compatible verssion of documentation either.

21. Alarming messages

The Leo III operator’s console has a typewriter upon which a log of the machine's activities is printed. Messages requiring a response from the operator are called alarms and appear as a star and a number on the typewriter. There are examples in this Leo III console log which shows the operators’ typewriter output from later on in the story when we had succeeded in generating our own master tape. An ALARM *77 occurs very early on and looks like this:
         14323 T/W: 26 * 77 09001 00401

At this stage, we have not seen the genuine format of the output, so when the Leo III programme obeys the system call to indicate ALARM *07, our emulator just says: something like:
         ALARM *07 for operator
         and waits for the user to type in the appropriate reply number.

Not all of these messages are actually alarming, e.g. ALARM *06 indicates successful translation of an Intercode programme. However our running of 08004 produced a wholly unexpected ALARM *13. This looked rather unlucky, but it did appear in a manual, and there was a reply 4 to say carry on regardless, which just led to another ALARM *13. Suspecting a loop, I just gave up at this point, Ray Smith repeated the exercise, and sent an e-mail saying: “put in a second reply 4 and stand well back”. The file emulating the printer suddenly contained lots of output, and correct output at that.

22. First Steps into the Master Routine

After 08004 announced that it had achieved the generation of a new Master Routine, by an ALARM *06 the manual said that we could choose option 3 to generate a bootable mag tape. This led to a comprehensive crash where it was clear that the store did not contain what the programmer had expected. Choice of option 1 was no better. We eventually discovered a dirty trick whereby the information describing the memory allocation of chapters was modified to change the location of the last overlay. This necessitated some insanitary programming in getbin.c to match this address, after which we were soon obeying action 19, which is a master mode peripheral operation. Time to extend our emulation of magnetic tape, printer and paper tape reader. (These are the only peripherals that our Leo III currently supports.)

Quite soon we were at the stage where a new message appeared:
         ISSUE 0 GO EVEN FASTER MASTER ROUTINE 09001 00401
We had not expected 08004 to end by converting itself into the new Master Routine so at first we thought that this was some mistake, but when we used our crude interface to inject an operator command to print out the priority queue (list of running programmes), we got output to confirm that the list was empty. All sorts of things worked. We could dump store contents to tape, print information about peripherals.

23. Operator Interface

Until this point an object programme's calls to the Master Routine had all been handled by code in our emulator. The emulator has been running single shot runs of object programmes, with magnetic tapes defined by their file-names and operator input (replies to ALARMs) just keyed in on the keyboard. A 1960s master routine interacts with a team of operators who input commands, and obey instructions to load and unload mag tapes and to deal with paper tapes and printer output. I was amazed at this stage to discover that the Leo III did not have a QWERTY keyboard for input of operator commands. The operator has a set of 12 2-position switches upon which the reply number is keyed in binary as 3 groups of four digit numbers. The operating instructions give the values that should be set on these keys. As a crude emulation of this, some of the instructions to read the indicator register result in a query on the command window. This is still the case (Oct 2015), and could do with improvement.

24. Object Programmes

It begins to look as though we are close to having an emulated Leo III running proper software. The Leo word ALLOCATE is used to describe loading and entering a programme. Just add a few facilities to leo3.c to emulate the operators loading mag tapes and paper tapes, and input the magic three numbers to emulate the 3 × 4 operator key switches, and off we go. It read the correct mag tape which had been written by 08000 running as a single shot programme under the emulator, before crashing obeying code that was obvious rubbish. After much searching down blind alleys and writing special purpose analysis code we uncovered the mechanism by which much of the programme loading function is on the programme tape rather than having it clog up valuable memory by being built in to the main part of the Master Routine. Loading this code from the tape in such a way as to link to code and variable in the master routine involved 3 or 4 pages of densely packed constants in the 08000 source code. The typographical error in line 67469 mentioned earlier completely screwed up this relocation and linkage process leading to computational mayhem whenever we tried to load a programme.

It took a long time to diagnose, and one keystroke to fix it, but it was most beneficial. It works.

25. Boot Tape

Option 3 at the end of 08004 writes a tape that can be loaded into a bare machine, using the mag tape start button that reads the first block into store starting at word 0 and then jumps to word 0 — what we would call a boot tape today. This tape seems to be written just after entry to the new Master Routine. After some diligent reading of the manual, Ray Smith was able to generate the configuration data. We were able to discover which tapes to put on which mag tape route and we had a start tape.

So now we need to emulate the mag tape start key, and there is also a paper tape start key where the read is from the paper tape reader. I was initially incredulous that this process could work as described. The reading of data puts 6-bit characters into octets, with 5 octets in each long word. A long word is composed of 2 short words, each 21 bits, 5 quartets and a sign bit. Each computer code instruction occupies one short word. This reading process leaves 6 bits in each short word set to zero, including the sign bit that is part of the function code. Amazingly Leo programmers wrote code using less than half the order code which took the code from the tape (where one long word encodes one instruction) and were able to read the master routine into memory. We decided to implement the mag tape start key by writing a tiny computer code programme directly in the plain text format of the leo3.c input which just did the read and then jumped to word 0.

So now we have generated a Master Routine on tape and can load it into our emulator just as on a real Leo machine, and it can then run programmes and produce typewriter output that evokes nostalgic reaction from ex-operators.

26. Demonstration Facilities

We made an on-line facility for running an Intercode programme using the emulator to run just 08000, the Intercode Translator, and then to run the resulting binary programme using our getbin utility.
        /LEOIT/N/leo/emuLeo/runleoIT.htm

We also have a set of 3 demonstrations of the software, each of which is described in the readme.htm file in both of:
        http://sw-pres.computerconservationsociety.org/leo/LeoIIIdemo.zip
        http://sw-pres.computerconservationsociety.org/leo/LeoIIIdemo2.zip

Each of these demonstrations runs all 3 of the preserved Intercode Programmes culminating in the generation of a master boot tape. Two of the demonstrations use only our emulator and genuine Leo III software all of it running under the Master Routine.

It was always clear that the emulator’s running of the Master Routine did not really capture the experience of the Leo III operators. Some new ideas in 2019 led to another demo:
        http://sw-pres.computerconservationsociety.org/leo/LeoIIIdemo3.zip
The readme.htm file from this ZIP file is available on-line. In addition to the emulator are two Java programs, one which emulates the Leo III operators’ panel, and one which emulates the line-printer (including all Leo special characters). The demonstration runs all three programs on the same Windows computer. It is quite easy to copy the commands from the Windows go.bat file to run on UNIX-like systems (including Mac), but you need to compile the emulator with gcc. In addition there is a facility for specifying that the operators’ panel is on a different computer.. Similarly the printer can also be on a different computer.

This configuration was demonstrated at the Leo Society Reunion in April 2019 with the emulation and the printer running on a Raspberry-Pi while the operators’ panel was on an Intel ubuntu laptop. This involved no modification to any of the three programs.

27. Imperfections

We still have an unexplained crash in the Master Routine when we try to run the programme trials system (PTS). The crash occurs at the point where the newly translated Intercode programme is being prepared for execution by setting up the parameters that point to actual devices and chapter addresses. This is very much in the close integration between the Intercode Translator and the Master Routine, which seems to indicate that the problem could well be due to the fudging of versions when we discovered that 08004 wanted to process 09002, not 09001 which is what we have.

Only LeoIIIdemo3 offers a fairly realistic operator interface. On a real Leo III the indicator neons were closely coupled to the CPU. Because of the latency in passing the information from the emulator to the console program, we have not monitored the more rapidly changing neons.

28. On-line Resources

In addition to the demonstration facilities listed above, we have Leo III Manuals, and source text:
 080000900108004Generated
Master
Post-processed listing from the Translator here here here here
Raw output listing from the Translator here here here here
Paper tape input as would be keyed originally here here here N/A
Within the post-processed listings are links to the photographs or the original listings from which the copy typists worked.

There is source code of useful software: Windows binary programs for these can be found here. Alternative versions are here, but read the caveat at the head of the page.

The output from our interim translator shows how Intercode is expanded into machine code.

Appendix A Translator Bootstrap

The current state of play can be accessed via the link in the status section above, but our first major milestone was the creation of an executable Intercode Translator which successfully translates itself. We now have considerable experience of using this on the master routine and its generator program and it has proven very reliable.

Here is the story of the steps in this generation process (which is part of the example accessed from the status section above):
  1. Raw material is the line printer output saved by Colin Tully. This is the output listing produced by the Intercode Translator translating itself.
  2. This was photographed, and then copy-typed using spreadsheets to produce 08000.csv.
  3. This can be processed using a specially written translator (it.c) to produce a listing that is also a binary program: demo.htm.
    This can be run with the emulator (leo3.c) to translate Intercode programs in paper tape initial translation format, such as hello.txt:
                  leo3 -d demo.htm hello.txt
  4. The binary program generated by the Intercode Translator is on the output tape MT-A2.leo. This is in a form ready for the Master Routine’s loading process. We have yet to implement the Master Routine, but the program getbin.c extracts the program from this output tape and generates a binary program in a form suitable for our emulator (leo3.c). E.G. after translating hello.txt as above, it can be executed using the sequence:
                  getbin MT-A2.leo t.bin
                  leo3 -d t.bin
    The getbin program involves reading a tape for which we have only partial documentation, in effect reverse engineering the loading process of the Master Routine that we have yet to implement. Consequently, it produces quite a lot of diagnostic commentary on the contents of the tape.
    The -d switch used with leo3.c sends its diagnostics to a file log.txt. If you omit this switch there is some extra output on your screen. Details of the diagnostic facilities are in a comment at the head of leo3.c.
  5. The Intercode Translator can be translated using the demo.htm version of itself. The original raw material (08000.csv) is first converted to paper tape initial translation format (08000.txt) using a program mkpt.c, before running demo.htm with the emulator:
                  leo3 -d demo.htm 08000.txt
    The Intercode Translator works slightly differently in translating itself, and as a result the binary program ends up on tape MT-A6.leo. Although the binary program is also on MT-A2.leo it seems to be in a slightly different format. The suspicion is that this is something to do with the overlay mechanism. A binary version of the self-translated Translator can be generated by
                  getbin -b5000 -b8192 -b160 MT-A6.leo t.bin
    The -b5000 -b8192 -b160 switches define the location in memory of chapters 1, 2 and 3 respectively. Chapter 3 is the extra chapter generated by the translator. Chapters 4 onwards are overlaid over chapter 2. Chapter 4 in the binary program corresponds to chapter 3 in the source code.
  6. The Intercode Translator is aware of its own issue number and its behaviour depends on this number, which is always zero for an initial translation from paper tape. So we have to rename the output file as the input file and do a null amendment to enable us to set the issue number to 8 using file NullAmend.txt:
                  move MT-A2.leo MT-A1.leo
                  leo3 -d demo.htm NullAmend.txt
  7. The result of this translation is a properly functioning issue 8 Intercode Translator (probably) written on MT-A6.leo. We can extract a binary program suitable for our emulator from this by
                  getbin -b5000 -b8192 -b160 MT-A6.leo 08000.bin
  8. We can substitute 08000.bin for demo.htm in the commands above, and even have it regenerate itself, see below:
    F:\dh\leo>leo3 -d 08000.bin 08000.txt
     8257 LOG: 08000 PROG OUT  08000      0   +PTS
    11450 LOG:   08000 MAKES PASS3 COPY ON  8000
    ALARM *06 for operator
    1
    PROGRAMME UNLOADED: ADDRESS = 11616 after 31505788 instructions
    **********************************
    
    F:\dh\leo>move MT-A2.leo MT-A1.leo
    F:\DH\LEO\MT-A2.leo => F:\DH\LEO\MT-A1.leo [ok]
    
    F:\dh\leo>leo3 -d 08000.bin NullAmend.txt
     8940 LOG: 08000  AMEND  08000     0
     8257 LOG: 08000 PROG OUT  08000    801
    11450 LOG:   08000 MAKES PASS3 COPY ON  8000
    ALARM *06 for operator
    1
    PROGRAMME UNLOADED: ADDRESS = 11616 after 22861490 instructions
    **********************************
    
    F:\dh\leo>getbin -b5000 -b8192 -b160 MT-A6.leo t.bin
    File: MT-A6.leo
        3 PASS3 marker for program 08000 found
       73 ALLOC block found
       Total chaps = 11 (init 3)  files(R) = 5  Transit Areas = 5
       Enter at address 41 in chapter 2
      112 File details block (5 routes)
       File D1 type 14 -- chap 6 annex at 598 length 394
        Annex 0 is in chapter 6 - reallocated to 3
       File B1 type 15 -- chap 4 annex at 6810 length 58
       File A1 type 7 -- chap 4 annex at 6868 length 154
       File A2 type 8 -- chap 4 annex at 7022 length 154
       File A6 type 7 -- chap 4 annex at 7176 length 154
    Transit area 0 is in chapter 6 - reallocated to 3
    
    Loading
      235 CHAPTer 1 start at 5000 (progid = 08000)
      242 CHAPTer 2 start at 8192 (progid = 08000)
      454 CHAPTer 3 start at 160 (progid = 08000)
    Extra chapter 3 located at 361 (param = 3840)
      456 CHAPTer 4 start at 8192 (progid = 08000)
    Overlaying chapter 2 by 4
      893 CHAPTer 5 start at 8192 (progid = 08000)
    Overlaying chapter 4 by 5
     1329 CHAPTer 6 start at 8192 (progid = 08000)
    Overlaying chapter 5 by 6
     1687 CHAPTer 7 start at 8192 (progid = 08000)
    Overlaying chapter 6 by 7
     1942 CHAPTer 8 start at 8192 (progid = 08000)
    Overlaying chapter 7 by 8
     2356 CHAPTer 9 start at 8192 (progid = 08000)
    Overlaying chapter 8 by 9
     2538 CHAPTer 10 start at 8192 (progid = 08000)
    Overlaying chapter 9 by 10
     2544 CHAPTer 11 start at 8192 (progid = 08000)
    Overlaying chapter 10 by 11
    Overlaying last chapter 11
    
    F:\dh\leo>leo3 -d t.bin NullAmend.txt
     8940 LOG: 08000  AMEND  08000     0
     8257 LOG: 08000 PROG OUT  08000    801
    11450 LOG:   08000 MAKES PASS3 COPY ON  8000
    ALARM *06 for operator
    1
    PROGRAMME UNLOADED: ADDRESS = 11616 after 22861490 instructions
    **********************************
    

Appendix B: Techniques and Technicalities

Parallel Implementation

The parellel implementation of the emulator (leo3.c), the copy-typing and the interim translator (called it.c) for generating abinary program from 08000 enabled the emerging the C code to be tested against known valid Leo III Intercode. To see the rationale for programming in a aubset of C, please look here.

Copy-typing

Leo IIItypescript 
£ppound sign
Юttenpence
eelevenpence
>gright arrow
Leo III had its own character code, including some fancy characters that do not appear on modern keyboards. For the purpose of input and for the emulation we have restricted ourselves to those characters that are represented in a single byte in UTF-8, so that everything works whether using 8-bit characters or 16-bit. All letters in Leo III code are in upper case, so the fancy characters were represented by lower case letters in the typescript, and also in the raw printer output, which we then post-processed into HTML using Unicode near equivalents (see table).

Each line in the Intercode listing represents an Intercode instruction, which may result in more than one computer code instruction. The layout is in columns, with a serial number in the left-hand column. Although the listing should be read line-by-line, it seems easier to copy-type in columns, using the spreadsheet capabilities to generate the serial numbers, and to copy down the often repeated zeros. The spreadsheet is then saved as comma-separated data and this is what is read by the interim intercode translator (it.c), which only needs to work on those parts of the language that are used in those parts of the real Intercode Translator that are needed for translating itself.

Each page of listing was photographed, and the photos were put on a webserver. The pages were copy-typed by volunteer Leo III veterans, each one in duplicate by different people. We had an on-line booking system for people to volunteer to claim a page for either typing the primary copy (comments included) or the secondary copy (no comments). The two copies were then brought together and compared to produce a comparison file that shows which lines did not compare, and picked out where the mis-match happened within the line. At the foot of the page is a link to the original photograph in a separate tab, giving rapid comparison. It has to be admitted that this comparison system developed over several months.

When attemtion switched to the Master Routine it was revealed that the configuration program (08004) used information that was stored in the comment area to guide the configuration process, so we then had to move to a regime in which both copies has the comments in.

Interim Intercode Translator

The interim intercode translator (it.c) uses 2 passes, and takes as input the CSV file from the copy-typing. The first pass allocates addresses for all the instructions and constants, and the second one generates the code. The translator is generated from a file that defines the Intercode instructions, which is then merged with a wrapper to produce the translator. When our interim translator processed the copy-typed listing of the real Intercode Translator, this was the result. On the left-hand side is the machine code which is read into store by the emulator, so this file plays the role of both binary program and listing. As a by product the generator program also makes an HTML file for use as a cross reference into the documentation.

Initial Leo III emulation

Our original emulation was made from the Leo III page in Our Computer Heritage.

This was done by:
  1. Open the Leo III page in Acrobat Reader.
  2. Select the text of the table listing the instruction set.
  3. Paste it into a plain text file.
  4. Write a small generator program to read this file and generate a giant case statement
  5. Write a skeletal framework into which the case statement can sit
  6. Modify the generator program to merge the two together.
  7. Test it with a very crude input file.
So then it just remained to populate the individual elements of the case statement, leading eventually to leo3.c.

To see how KDF9 lineprinter listings have been turned into working software, please look here.

Peripheral Transfers

On Leo III all use of periphersl by a user programme is by a call to the master routine. All these calls to the Master Routine enter the Master at address 160. As mentioned earlier, we did not initially know the API (application program interface) for this system call, but the manual did document what the Intercode operation did. The intercode actions are numbered 40 to 49, and our interim translator translate action 40 as a system call to word 40, and so on. The emulator treats a system call to one of these low addresses specially, and emulates the action as specified in the Intercode manual. Once the Intercode Translator translated itself it now generated the proper API for the system calls for the peripheral instructions. Until we have a working Master Routine, we need to make our emulator process the API that a proper Master Routine provides, and also produce a way of loading the binary program into our emulator (see the next section). We reverse engineered the API by running the code and every time that the emulator encountered a new type of I/O operation it was flagged as unimplemented. We then had to go back to the source code and find out just which system call this was in order to incorporate it into our emulation. This survives in the 3 modes of execution of leo3.c which are documented in the source code. We did not replace the original implementation so the emulator will work both with code produced by our interim translator and with code produced by the proper 08000.

When we started to execute the Master Routine we encountered for the time the real hardware instructions for driving the peripherals, all of which come under computer code action 19. So not only did we have to emulate the transfer of data, but also the autonomous nature of peripheral transfers. We have done this rather crudely, and the emulated time delay for a transfer is much shorter than a real Leo III. With realistic delays any use of the diagnostic facilities produces enormous amounts of output.

Running the translated programs

When we run the Intercode Translator under our emulator, the translated binary program ends up on an emulated magnetic tape. It is not absolute binary, but relocatable as Leo III did not have address translation. This relocation process is part of the Master Routine but we needed a way of running output from the Intercode Translator (08000) before we could produce a Master Routine. A program (getbin.c) was written to read the emulated tape and generate a memory image for loading into our emulator (leo3.c).

Once a few test programs had been run, including the ubiquitous Hello World!, attention switched to 08000 itself. It was at this point that I discovered that the input to 08000 differed non-trivially from the listing that 08000 produced, and yet another program (mkpt.c) was need to make a paper tape for input to our newly generated 08000. Of course this was an emulated paper tape. A real one would have been about a mile long.

At last we have a mag tape which holds the binary version of 08000. This can be run with the aid of getbin.c and leo3.c. This is spelt out in more detail in Appendix A above.

We can now take Intercode source text and execute it on our emulator, so long as it does not contain instructions that we have not met yet. A vital part of the strategy is only to implement those instructions for which we have known examples from historic code.

Master Routine

The copy-typing of the generic master (09001) and the generator program (08004) produced CSV files, which are easily converted to emulated paper tapes using mkpt.c. The translation of 09001 produced a listing that compared most convincingly with the photos, and also a magnetic tape on its file A2, which is then used as input file A1 by 08004. At this point we hit a snag. When we ran 08004 it read the tape and complained that it could not find 09002. Clearly we have an incompatibility here. We patched the binary 08004 program to accept 09001 instead, and after another couple of patches it processed the tape, and transformed itself into a Master Routine executing in our emulator, which soon complained that various master mode instructions were not implemented.

Implementation of the missing instructions soon led to the generation of a master boot tape suitable for use with mag tape start (Leo-speak for intial bootstrap from mag tape). The simplest way to implement the mag tape start is to write a program (MT-start.bin) in the simple loader format of our leo3.c emulator.
          Mag tape start programme
          When it asks for indicator type m00 MT-start.leo
          where MT-start.leo is the tape that you wish to load
          Note: Thre are no second chances.
                You must get it right first time, with just the one space
L999 initial bootstrap loaded at word 999
19/1/2 24    unload paper tape to set done19 flag
25/1/2 7     read indicators to allow tape to be mounted
19/0/1 0     read initial block on tape
26/1/0 0     test route
0/0/0 0      halt not available
24/1/0 1002  loop until transfer finished
0/0/0 0      doubtful block
0/0/0 0      warning of end
25/1/2 0     A := 0
2/0/0 258    store[129] will become 0 rather than 0x80
24/1/0 0     enter bootstrap
E999  entering at address 999
There was some little understood problem which was solved by altering one word in the bootstrap code on the tape (see above), and we can load our Master Routine and it runs programs, including 08000 with then produces binary programs that we can also run.

A facility for generating a Leo III Master Routine on your own machine is here.

Acknowledgements

This 21st century exploration of Leo III has been been possible because of the dedicated efforts of several Leo III veterans, and the goodwill of the Leo Society. John Daines, Ray Smith, Geoff Cooper and Ken Kemp have stuck with the enterprise and continue to do so. Valuable work continues in improving our on-line documentation. Chuck Knowles, Tony Jackson and Dave Jones also made invaluable contributions to the laborious and painstaking process of copy-typing the surviving line-printer listings. Helpful nuggets of information have been provided from time by other members of the Leo Society.