Single Instruction Microprocessor

Amazing SIM Lockdown Project!

Page last updated 22 August 2021

The above contraption is a computer.

A home-made computer, made mostly with very basic components.

It is rather special in that it is one of the simplest possible machines that could in theory do any calculation that a more complicated computer, such as the one in your PC or smartphone, could do.

I say in theory because its memory is much smaller than that in those computers, which limits the complexity of the calculations it can perform. However it could have been designed with more memory, although this would have required additional components. The size of its memory is 8 times that of the Sinclair ZX80 home computer launched in 1980 and is enough to allow it to run modest but non-trivial programs.

Modern computers operate on at least eight bits of data (a byte) at a time, but some early computers operated on just one bit at a time. It clearly requires less circuitry to operate on one bit than on eight bits, so if one is intending to design a computer having fewest components then operating on one bit at a time is going to help.

The processors of modern computers can have a repertoire of a hundred or so different instructions such as various forms of arithmetical and logical operations, as well as things like copy, compare, jump, and often very complicated instructions also. However, a large instruction repertoire is not essential. The Manchester Small Scale Experimental Machine (nicknamed the Baby, shown below), built in the late 1940’s, the first computer to have its instructions stored in an electronic memory, had a repertoire of just 7 instructions, one of which was HALT. In fact it is possible for a computer to have an instruction repertoire of 1, which is clearly going to make a machine simpler.

The single instruction

My machine therefore has a single instruction which operates on just one bit. There are many possible single instruction machines (or SIMs), but the instruction that this SIM performs is this:

Invert the bit at address A; if the bit is now a 1 take the next instruction from address B; if the bit is now a 0 take the next instruction from address C.

The instruction consists entirely of addresses, nothing else, and may be written

A, B, C

When it is desired to show that an instruction resides at address N in memory we can write it thus:

N: A, B, C

This notation is a form of what is known as assembler language, the programming language closest to the actual code that a machine understands and obeys. To convert assembler language into the data that will actually be put into the machine’s memory a program called an assembler is needed. It takes instructions of the form

A, B, C

and converts them into data in the form of 1’s and 0’s, for example

00000100 10000011 00000000 00001010

which are the four bytes actually put in the machine’s memory to make it perform the instruction specified in the assembler language.

It is obvious that this machine can test a bit. The following program does that (words in brackets are comments):

0: A, 1, 1 (invert the bit at A and always go to the instruction at 1)

1: A, 2, 3 (invert the bit again to restore it to its original value and go to different places depending on its value)

2: (come here if the bit is 0)

3: (come here if the bit is 1)

It is also possible to set a bit to 1 whatever its original value:

0: D, 4, 0 (invert the bit at D; if it is now 0 repeat this instruction; if it is now 1 go to the instruction at 4:)

4: (come here when the bit has been set)

And similarly it can reset a bit to 0:

0: D, 0, 5 (invert the bit at D; if it is now 1 repeat this instruction; if it is now 0 go to the instruction at 5:)

5: (come here when the bit has been reset)

So, under program control, this SIM can test a bit and it can set a bit to a desired value, which is all that a computing machine needs to be able to do. Before a program runs the memory contains a certain pattern of bits; the objective of the program is to transform the memory contents into another pattern of bits, which can be done by the three functions described above, no other functions being essential to do this. Of course having additional kinds of instruction can vastly increase the speed at which the transformation can take place, which is why real life computers have bigger instruction repertoires ‒ circuitry is very cheap and speed of computation is very important, so one uses more circuitry to get the performance needed. Operating on more than one bit at a time will also improve the performance very significantly, and again extra circuitry has to be used to get this.


What was built

The SIM that I wanted to build is a machine similar in architecture to nearly all modern computers in that it consists of 1) a memory which contains the programs and the data that is to be manipulated.

2) a means for putting data and the instructions comprising a program into the memory, and means for extracting and/or displaying the results; and

3) a processor which executes the program and actually does the manipulation of the data. Computer scientists have invented many theoretical kinds of simple computing machine, such as the Turing machine (a particular one of which was the first machine proved (by Turing) to be capable of completely general-purpose computation), but these machines would not be as simple to realise as the one I have made.

So why did I build this machine? Well, for a start, engineers like making things. I had designed this SIM many years ago and the Covid lockdown provided me with the time to make it. I am a STEM ambassador and intend to demonstrate it to schoolchildren to show them the basics of computation, both in theory and in practical realisation ‒ my machine has several of the fundamental sub-units that all computers have. The construction of such a machine could possibly be a 6th-form project.

When designing a computing machine the first thing to decide is what technology to use. If I had been a mechanical engineer I would have been tempted to build a mechanical machine, perhaps out of Meccano. Mechanical things with visible moving parts are more interesting to watch than electronic circuits by a long way − many more people flock to see a steam locomotive than a diesel one! I chose to use relays; being electro-mechanical they have moving parts, and hence one can see and hear things happening. They are also robust electrically and physically, not as easily damaged by mistreatment as electronic components. They can operate at voltages which are not dangerous (unlike valves, which were another candidate). There is a small amount of low-voltage electronic circuitry in my machine, however.

The economical provision of a memory which can reliably store many bits and be written and read at electronic speeds was one of the big problems for early computers; the Manchester Baby was built to test the feasibility and reliability of a new memory technology. (This it did successfully and the first commercially-available computer, the Manchester Mark 1, was based on it, with a larger memory size and an instruction repertoire increased to 30.) With the need to store thousands of bits there is really no practical alternative to using electronic memory, even more so in a home-made computer.

The other main bit of electronic circuitry is the clock pulse generator. This provides a series of pulses which define at a basic level when things are going to happen. It runs continuously, even when the SIM is stopped, so that it may be started in an orderly fashion. Having relays operating and releasing continuously when nothing else is happening would shorten their life unnecessarily, which is why this unit is implemented electronically.

With their associated LEDs the relays take about 100mA each to operate. This is way above what simple integrated circuits, especially the memory, can provide. The relay driver card has the transistors needed to drive relays from the memory data bus. This card also has 8 LEDs which show the state of the memory data bus.

The chosen relays operate from 12 volts, a convenient voltage which is readily available from mains power supplies or even a car battery. The electronic circuitry requires 5 volts, so a 5V regulator card generates this voltage from the 12V supplying the relays.

The final bit of electronic circuitry is the means to load data and programs into the memory from an external source, and to read the contents of the memory so as to get the results of a computation. This will be done from/to a laptop via an Arduino card. It is also possible to write to and read from the memory via the control panel.

Relays can perform all the functions needed to implement a computer, and indeed conventional computers have been built using them. They can perform logical operations, such as inversion and ANDing and ORing signals together. A relay can store one bit of information, for example the value 1 when the relay is operated, and the value 0 when it is released. Groups of relays can form a register, which holds a number of bits which have a common meaning. The next photo shows the various registers and other sections of the SIM, powered on this time.


Thanks to Mike Wenman for annotation graphics above.

A short, fun video can be played here: best with sound on! Video (Videos currently provided via YouTube)

Or for a more detailed walk through the functional areas with commentary from the inventor click here

The machine’s registers and other units


The 8-bit memory data register holds data read from the memory. The interface to the memory is 8 bits wide; 8 bits are read from it and 8 bits are written to it at a time. The memory data register also holds the data that is going to be written back to the memory after it has been processed.

The 8-bit instruction address register holds the memory address of the instruction that is being or about to be executed. An instruction is 4 bytes long; the sequencer generates two additional low-order bits to make the 10-bit address of each byte of the instruction being fetched from memory.

Two 8-bit operand address registers together hold the 16-bit memory address of the data that is being operated on by the instruction. Actually 13 of these bits indicate which byte is going to be operated on, and the remaining 3 bits indicate which bit in the byte is going to be operated on (i.e. inverted).

The sequencer unit operates rather like the camshaft in a car engine. In a car engine the camshaft controls which valves, inlet or exhaust for each cylinder, are opened and closed as the engine runs. In this SIM the sequencer indicates which register is going to be loaded with data and when the memory is going to be read or written. It endlessly runs through the same unvarying sequence of actions, just like a camshaft. It also controls the starting and stopping of the machine.

Nearly all processors have a register often known as the program counter. It holds the address of the instruction being or about to be executed, as does the instruction address register in the SIM. But it does more; it is a register which can count, i.e. its contents can be incremented. It is incremented during an instruction in order to generate the address of the next instruction. It can also be re-loaded when the program wants the processor to jump to a different part of the program. A register which can count requires more circuitry than one which does not; therefore circuitry is saved by having the instruction address register in the SIM not able to count. Instead, the address of the next instruction is always obtained from the instruction being executed. Another reason for not having a program counter in the SIM is that it would be rather perverse to have a function in the hardware (i.e. increment a word of many bits) which is not available for the programmer to use.

The SIM is not quite as simple as possible, for various debug aids have been incorporated. The relays have LEDs associated with them which show when a relay is operated. (The flashing of these LEDs when the SIM is running give it the popular appearance of a computer.) It is possible to step through the execution of a program one instruction at a time, and examine or alter the contents of the memory after each instruction. It is possible to make the machine stop when the instruction at a specified address is about to be executed. To aid explanation of how the SIM works it is possible to control the speed at which it operates, slowing it down considerably from its phenomenal maximum speed of a little over 3 instructions per second.


Performance


The relays take about 10 milliseconds to operate and 24mS to release. The clock pulses must therefore be at least 24mS long. There are 12 clock pulses in one instruction, so the time to execute one instruction cannot be shorter than 288mS. This means that the maximum possible instruction rate is a stupendous 3.4 instructions per second.

The Manchester Baby computer could perform 700 instructions per second, so it could do 700 32-bit subtractions per second (the only arithmetical instructions in its repertoire were subtract and negate; using these, all other arithmetical operations can be performed by programming). My SIM will execute between 64 and 96 instructions when subtracting two 32-bit numbers, an average of 80 instructions, which is 0.0425 subtractions per second. The Baby was therefore nearly 16,500 times more powerful than my SIM.

The SIM consumes on average 36 watts when operating. The Baby, with its 550 valves, consumed 3,500 watts. Per watt the Baby was a bit more than 165 times as powerful as my SIM.

The processor on the Arduino card used for the host interface executes 16 million instructions per second. It is an 8-bit machine so it can add two 8-bit numbers in 62.5 nanoseconds. My SIM adds two 8-bit numbers in 5.76 seconds (see appendix 1 for a program to do this). The Arduino processor is therefore about 92,000,000 times more powerful than my SIM. Enough SIMs like mine to provide the same computing power as the Arduino processor would consume about 3.3 gigawatts, which is more than the full power output of the Sizewell C nuclear power station (3.2 gigawatts), so it would not be able to power this monstrous collection of machines. One Arduino processor consumes a paltry 15 milliwatts.

But these comparisons, though dramatic, are not really fair. My SIM was designed for simplicity, not speed. Simplicity is its raison d’être. Its processor has a mere 57 active components (the relays); the Arduino processor has an estimated 1,000,000 active components (transistors). To get high computing performance you need a fast technology, complex circuitry, and a good helping of cleverness in the design.

Appendix 1


To show that this machine really can perform useful calculations, here is an assembler language program to add the 8-bit number at A to the 8-bit number at B. The notation A.0 means bit 0 of the byte at location A. Bit 0 is the low-order bit of a byte. The first instruction executed is at location 00.

(Because we have to test the value of each of the bits of A (except bit 0) in two places, and to test a bit requires two instructions, it saves 7 instructions if we first invert all the bits of A so that the subsequent tests only need one instruction each)

00: A.0, 01, 01

01: A.1, 02, 02

02: A.2, 03, 03

03: A.3, 04, 04

04: A.4, 05, 05

05: A.5, 06, 06

06: A.6, 07, 07

07: A.7, 08, 08


(Now we do the addition proper, starting with bit 0)

08: A.0, 09, 10 (test A.0; if it is a 0 move on to bit 1; if it is a 1 we must invert B.0)

09: B.0, 10, 11 (invert B.0; if it is now 0 we have carry into the bit 1 addition)

(Process bit 1)

10: A.1, 12, 13 (test A.1 when there is no carry from bit 0; if it is a 0 move on to bit 2 with no carry; if it is a 1 invert B.1)

11: A.1, 14, 12 (test A.1 when there is carry from bit 0; if it is a 0 invert B.1; if it is a 1 move on to bit 2 with carry)

12: B.1, 13, 14 (invert B.1; if it is now 0 we have carry into the bit 2 addition)


(Process bit 2)

13: A.2, 15, 16 (test A.2 when there is no carry from bit 1)

14: A.2, 17, 15 (test A.2 when there is carry from bit 1)

15: B.2, 16, 17 (invert B.2; if it is now 0 we have carry into the bit 3 addition)


(I’m sure you see the pattern which can be repeated for any number of bits. Let’s skip to the last two bits.)

(Process bit 6)

25: A.6, 27, 28 (test A.6 when there is no carry from bit 5)

26: A.6, 29, 27 (test A.6 when there is carry from bit 5)

27: B.6, 28, 29 (invert B.6; if it is now 0 we have carry into the bit 7 addition)


(Process bit 7)

28: A.7, 30, 31 (test A.7 when there is no carry from bit 6; if it is 0 the addition is complete, with no

overflow; if it is 1 invert B.7)

29: A.7, 32, 30 (test A.7 when there is carry from bit 6; if it is 0 invert B.7; if it is 1 the addition is

complete, with overflow)

30: B.7, 31, 32 (invert B.7; if it is now 0 we have overflow, if 1 the addition ends with no overflow)


31: (come here when the addition completed without overflow)

32: (come here when the addition completed with overflow)


The end.

David Haigh