History of the Leo III Software Preservation Project
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
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.
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
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:
But the printing was very indistinct in
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
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
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.
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
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
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,
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.
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
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
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:
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
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.
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
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
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.
We also have a set of 3 demonstrations of the software, each of which is described in the readme.htm file in both of:
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:
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.
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:
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.
- leo3.c The emulator for Leo III
- mtdiag.c A diagnostic prinbtout of a Leo III mag tape
- modernise.c A program to post-process output from 08000
- getbin.c A program to extract binary program from a 08000 output tape
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):
- Raw material is the line printer output saved by Colin Tully.
This is the output listing produced by the Intercode Translator translating itself.
- This was photographed, and then copy-typed using spreadsheets to produce
- This can be processed using a specially written translator
(it.c) to produce a listing that is also a binary program:
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
- The binary program generated by the Intercode Translator is on the output
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
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.
- 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
move MT-A2.leo MT-A1.leo
leo3 -d demo.htm NullAmend.txt
- 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
- 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
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
PROGRAMME UNLOADED: ADDRESS = 11616 after 22861490 instructions
F:\dh\leo>getbin -b5000 -b8192 -b160 MT-A6.leo t.bin
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
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
PROGRAMME UNLOADED: ADDRESS = 11616 after 22861490 instructions
Appendix B: Techniques and Technicalities
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
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).
|Leo III||typescript|| |
> |g||right arrow|
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
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:
So then it just remained to populate the individual elements of the case statement,
leading eventually to leo3.c.
- Open the Leo III page in Acrobat Reader.
- Select the text of the table listing the instruction set.
- Paste it into a plain text file.
- Write a small generator program to read this file and generate a giant case statement
- Write a skeletal framework into which the case statement can sit
- Modify the generator program to merge the two together.
- Test it with a very crude input file.
To see how KDF9 lineprinter listings have been turned into working software, please look
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
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.
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
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 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
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.