Please note, this is archived content and is no longer being updated. Please update your bookmarks and links to point to this permanent URL: http://curation.cs.manchester.ac.uk/digital60/www.digital60.org/birth/manchestercomputers/mark1/program.html.

The writing and preparation of programs on the Manchester Mark 1 and the early years of the Ferranti Mark 1 was heavily based on working in a numerical system to the base 32. In the end, to do any serious programming, you had to learn the following table of correspondence between the 32 digits of the number base, their numerical equivalent, and their equivalent in binary notation. Both the binary form and the base-32 form of numbers were written with the least significant digit to the left. (This was for the convenience of the engineers!)

0 | 00000 | / | 8 | 00010 | ½ | 16 | 00001 | T | 24 | 00011 | O |

1 | 10000 | E | 9 | 10010 | D | 17 | 10001 | Z | 25 | 10011 | B |

2 | 01000 | @ | 10 | 01010 | R | 18 | 01001 | L | 26 | 01011 | G |

3 | 11000 | A | 11 | 11010 | J | 19 | 11001 | W | 27 | 11011 | " |

4 | 00100 | : | 12 | 00110 | N | 20 | 00101 | H | 28 | 00111 | M |

5 | 10100 | S | 13 | 10110 | F | 21 | 10101 | Y | 29 | 10111 | X |

6 | 01100 | I | 14 | 01110 | C | 22 | 01101 | P | 30 | 01111 | V |

7 | 11100 | U | 15 | 11110 | K | 23 | 11101 | Q | 31 | 11111 | £ |

So the 40-digit number :

10001 11011 10100 01001 10001 11001 01010 10110

could be written more concisely as: Z"SLZWRF.

Similarly a 20-bit instruction could be written as four characters and a CRT store address as two.

These symbols are essentially the teleprinter code for letter shift. As
5-hole tape only provided 32 different values, and around 50 are necessary to
provide for letters (upper case only), digits 0 - 9, and a reasonable selection
of other symbols, there were two code sets, "letter shift" and "figure shift",
with two special codes (the same in each set) to indicate that subsequent
codes were to be interpreted as belonging to the letter shift set or figure
shift until the next special code was met. The 6 non-letter codes in letter
shift, 00000, 01000, 00100, 00010, 11011, 11111 had special (non-character)
effects in true teleprinter code, i.e.

No effect (blank tape), Line feed, Space, Carriage Return, Figure Shift,
Letter Shift.

These were given special characters so that they could be written down
on paper, respectively /, @, :, ½, ", £.
It was unfortunate that the teleprinter codes for letters bore no obvious
relation to their alphabetic order.

Converting between large decimal numbers or fractions and their equivalent base-32 codes was in general unpleasant. However the endemic use of base-32 representation did at least mean that you could "read" the information on the display tube relatively easily, particularly in relation to instructions, as a 20-bit line on a display tube was laid out in four groups of 5 bits, each of which corresponded directly with a base-32 character. Similarly 5-hole tape could be "read" directly.

The situation however was not as bad as it seems; certainly instruction and
address codes were not that bad to handle. And there were always library
routines available to input and output numbers from *inside a running
program* using the full standard figure and letter shift character range of
the teleprinter.

The CRT store comprised 8 tubes, 0 - 7, each holding a page of information. A page was laid out as 64
20-bit
lines, in two columns of 32 rows. So if you consider some random store address
e.g. 242, this is 01001 11100 in (reverse) binary and **LU** or [18][7] in base-32. So this is line 18 of half-page 7, i.e. of the
right column of CRT 3.
Now in general store addresses are arbitrary values, where you want to refer to
a particular instruction, constant or scalar variable. So **LU** is as
convenient a name as 242, provided it can be constructed easily. This is clearly
the case in relation to coding sheets (see below). It is
more awkward where you are laying out store for e.g. vectors, or where you are
wanting to construct the difference between two addresses.

Consider an instruction e.g. add the number in store location **IR** (and
the next line) to the accumulator. In binary this is :

01100 01010 00001 01110

and in base-32 **IRTC**, or [6][10][16][14].

The coding of instructions was: bits 0-8 the CRT
address, bits 10-12 the B-line address and bits 14-19 the function code. E.g. :

01100 01010 00001 01110

So where there was no instruction
modification (so the B-line was 0, which by convention always held value 0), the
first two characters of the instruction gave a straightforward store address,
e.g. **IR**, the 6th line of half-page 10, i.e. the left column of CRT 5;
and the last two characters were the function code, e.g. **TC**, which was
the code for adding the value of a standard integer in the given store line
(and its successor) to the accumulator. Given that only the top bit of character
3 was used, all instruction codes would start with **/** [0] or **T** [16]. The only inconvenience was for those instructions involving B-line
modification; here the appropriate B-line, e.g. 2, would have to be "added" to
the **/** or **T**, e.g. giving **IRLC** for :

01100 01010 01001 01110

The saving grace in using the system was the standard
preprinted **coding sheet**. This gave a
template representing a page of store, on which you could write out your two
columns of instructions, with the base-32 code down the
middle (giving the address within a column) and the half-page
address of the column at the top (at positions Lpa and Rpa). Comments could be
written by the appropriate side of each instruction. E.g. :

Lpa | | | | | / | | | | | Rpa | ||

| | | | E | | | | | ||||

| | | | @ | | | | | ||||

| | | | A | | | | | ||||

| | | | : | | | | | ||||

| | | | S | | | | | ||||

| | | | I | | | | | ||||

: | ||||||||

: | ||||||||

| | | | V | | | | | ||||

| | | | £ | | | | |

Clearly with instructions and constants (and possibly local scalar variables) laid out on a coding sheet, it was trivial to fill in address references in instructions.

*A full description of the above notation, the order code, and the different
representations of the 40-bit number can be found in Chapter 1 of the Turing-Brooker
Programming Manual.*

For any medium to large sized program, there were two alternative "schemes" to
use, Scheme A and the later Scheme B. These were a set of conventions in terms
of store usage, routine calling and input routines for setting up a program
before running it. Given the large and fast
backing store (up to 512 pages) and the small CRT store (8 pages), the standard
convention was to hold all routines of the program on the magnetic drum
backing store, and bring them down systematically each time they were called
into CRT pages 0 and 1. Page 2, **PERM** remained permanent throughout the
program run (except for the odd working line) and held the powers of two and
the Routine Changing Sequence for the Scheme being used. *(In fact the
standard Ferranti Mark 1 Display Tube photograph, shows the PERM
for Scheme A!)* Then pages 3 to 7 were used for data (or possibly more
instructions), with some minor conventions operating.

There were standard conventions for passing parameters and returning results from routines/functions. Routine calling was organised by "cues", 40-bit words coded up with inter alia the page on drum store it occupied, the page in CRT store it was to run in, and the address within the page of the entry point. An alternative facility allowed a cue to instead give an entry in a directory held on drum where the drum page would be given. This provided flexibility for programs to use different drum pages for subroutines between different runs.

**Scheme A** was devised by Alan Turing with
the assistance of Cecily Popplewell for the arrival
of the Ferranti Mark 1, building on their experience of the Manchester Mark 1.
It used one routine per page on backing store, and routines were called into CRT
page 0 or 1 as appropriate. Data conventions were that Page 3 held working
scalar variables and constants, and Page 4 any constant tables.

The later alternative **Scheme B**, devised by Tony
Brooker, used two pages on a single track on the drum for each
routine, which was called down into CRT pages 0 and 1 each time the routine was
called. Whereas for Scheme 1 you could operate with one higher-level routine in
one page calling a set of subroutines in the other, for Scheme B you needed to
call down the calling routine on return (therefore you would not in general keep
your local scalars in the routine's code space).

Unfortunately (you missed your chance Turing!) there was no attempt to provide a simple assembly language based on the full figure and letter shift teleprinter code. This would have allowed simple helpful mnemonics for instructions, decimal representation of numbers, and labelling of instructions, constants and variables. Instead the input was very much based on base-32 representation, putting strings of base-32 instructions or constants into base-32 positions in store.

There was however a sophisticated input routine provided for each Scheme, using special warning characters for special effects, that made the whole operation of setting up a program and running it much easier. As well as allowing for input of the program and constants, it dealt with the organisation of setting up the routines on the drum, and many other more detailed aspects of running both development and production programs.

In Scheme A Input, the best you could do for inputting decimal constants was
(after special warning characters) to type them out using the
corresponding digits of the base-32 system. So number
e.g. 319326 would be typed in input as [3][1][9][3][2][6], i.e. **AEDA@I**.
However in Scheme B there was a facility available that could input a string of
numbers in familiar figure shift characters into a given area of store.

There were no hardware integer division or floating point operations on the Ferranti Mark 1, but there were library routines to carry them out. Floating point operations were done on consecutive 40-bit words, holding the fraction in one and the exponent in the other (a bit extravagant!). There was also a library of standard functions, although surprisingly the amount of library code that was held permanently on the magnetic drum was small, so you would have to input non-basic library routines from paper tape onto the drum before you input your program.

Obviously if you used all these conventions and especially floating point numbers, the program would run relatively slowly, though with the average drum transfer time of around 30 instructions, extensive use of the drum store was not that disastrous. If you wanted to you could pack code more tightly and use the higher pages.

When R.A. (Tony) Brooker joined the Computing Machine Laboratory from Cambridge in 1951, to replace Alan Turing in charge of the software side, much of the mechanism for running programs was already in place. Rather than improve matters by producing an assembly language, he provided the alternative Scheme B and then moved on within a couple of years to produce a (relatively!) high level language. This was a simple Autocode, predating Fortran, which for the first time enabled people to write programs with a close relationship with how they thought about the algorithms they were wanting to code (remembering that the applications were mostly mathematical and scientific).

He also simplified matters by treating the store as a large one-level store, being prepared to hold variables on the drum, but doing some optimisation behind the scenes to reduce unnecessary transfers (e.g. when processing vectors). And he provided floating point variables as default.

You were provided with a range of floating point variables "v1" to say "v5000" and 18 short integral indices "n1" to "n18", and you could access a variable by having its serial number in an index (e.g. n3) by vn3. So to find the scalar product of two 80-element vectors starting at v201 and v301, leaving the answer in v99 (and using v98 as workspace) :

n1 | = | 201 | |

n2 | = | 301 | |

v99 | = | 0 | |

7 | v98 | = | vn1 x vn2 |

v99 | = | v99+v98 | |

n1 | = | n1+1 | |

n2 | = | n2+1 | |

j7 | , | 280 >= n1 |

It can well be imagined the relief this brought to the programming community, especially those new to the computer! However obviously the use of interpretive routines for all the "v" arithmetic, and storing each "v" on the drum meant that a program ran an order of magnitude more slowly.