Programming the LGP-30

A program for the LGP-30 is a list of instructions and numbers, each placed at an address on the drum that you choose. The IDE uses a small assembly notation for this. Writing a correct program is the easy part. Choosing the addresses well is the skill.

Addresses

An address names a track and a sector, each from 00 to 63. The IDE writes them as four decimal digits, track first: 1005 is track 10, sector 5. The real machine used its own hexadecimal, with the letters f, g, j, k, q and w standing for 10 to 15 (see LGP-30 Hex). The IDE uses plain decimal instead.

Syntax

One instruction or directive per line. A semicolon starts a comment.

start 0000         ; where execution begins
0000 b 0008        ; <address> <instruction letter> <operand address>
0008 dw 7          ; <address> dw <signed decimal number>

A first program

This is Example 1 from the IDE. It adds three numbers and stores the total.

start 0000
0000 b 0008  ; acc = 7
0001 a 0009  ; acc = acc + 12
0002 a 0010  ; acc = acc + 23
0003 h 0011  ; store the total in 0011
0004 z 0000  ; stop

0008 dw 7
0009 dw 12
0010 dw 23
0011 dw 0    ; result: 42

b brings a word from memory into the accumulator. a adds a word to it. h stores the accumulator and keeps it. z stops the machine. The numbers live in sectors 8 to 11 of track 0.

Instructions

LetterNameWhat it does
z Stop Halts computation.
b Bring acc = mem[addr]
y Store address Replaces mem[addr]'s address-field bits with the accumulator's.
r Return address Stores (this instruction's address)+2 into mem[addr]'s address field — call/return idiom.
i Input Shifts one 4-bit code per step into the accumulator, until 8 characters or a stop code.
d Divide acc = acc / mem[addr], rounded. Overflows outside a magnitude of 1.
n N Multiply acc = low 31 bits of acc * mem[addr] (magnitudes). Left-shifting idiom.
m M Multiply acc = top 30 bits of acc * mem[addr] (magnitudes) + XOR sign. Fractional idiom.
p Print addr's track field (6 bits) is the literal output code — not a memory address.
e Extract acc = acc & mem[addr] (bitwise AND mask).
u Unconditional transfer counter = addr.
t Test Branches to addr if the accumulator is negative.
h Hold and Store mem[addr] = acc; acc unaffected.
c Clear and Store mem[addr] = acc, then acc = 0.
a Add acc = acc + mem[addr] (signed). Overflows outside [-2^30, 2^30-1].
s Subtract acc = acc - mem[addr] (signed). Overflows outside [-2^30, 2^30-1].

Timing

Every time the machine fetches an instruction or reads or writes an operand, it waits for that sector to come round under the head. Look at Example 1 again. The instruction at sector 0 reads its operand from sector 8. By the time that is done, sector 1, where the next instruction lives, has already gone by. The machine waits most of a revolution to fetch it, and the same happens at every step.

The program is correct, but it is slow. Arranging instructions and data so that each one arrives just as it is needed can make the same program several times faster. The debugger shows this as it happens: the drum tape marks how many sectors each step swept past, and the memory view highlights what was read and written.

The Magnetic Drum page has the background. The quickest way to learn is to open an example in the IDE, run it in the debugger, and then try to make it faster.