Beruflich Dokumente
Kultur Dokumente
Daniel Fremont
May 8, 2009
Abstract
The goal of this project was to design and build a simple computer
made of relays. The computer was designed to have as few relays as
possible, while remaining Turing-complete1 and reasonably usable. A
simulator was also implemented, in order to test the computer design
before construction began. At this point the computer has been entirely
built, and testing is in progress. The computer should be completely
operational sometime next week.
1 Introduction
1.1 Motivation
The idea for this project came from a brief mention in Make Magazine of the
relay computer built by Harry Porter. His computer, although rudimentary
compared to transistor-based machines, is quite complex — it has over four
hundred relays.[1] This was a sizable deterrent, as the time necessary to assemble
such a collosus is immense. However, upon further reflection it seemed possible
to build a computer with much the same power using far fewer relays. This has
proved to be the case.
Once past the problem of not having sufficient time to wire up four hundred
relays, the project became very attractive. It involves considerable abstract
thought, on levels ranging from Boolean logic for one relay to architecture design
for the whole computer. It provides a chance to build what is one of the most
important inventions yet invented, albeit a very simple version. But even in
its simplicity, it provides a huge opportunity to learn about the functioning of
computers at bottom, to learn about what is actually going on inside. And,
of course, it is a wonderful feeling to hear something you built clicking away
calculating the Fibonacci numbers.
1 Turing-complete machines are of the same computational “strength” as one devised by
one of the founders of computer science, Alan Turing. In more than 70 years no one has been
able to invent a more powerful computer, in the sense that Turing’s machine can calculate any
function that any computer today can. The relay computer, like real computers, is Turing-
complete, meaning that it can perform any calculation a real computer can (technically no
actual computer is Turing-complete, since that requires an infinite amount of memory —
however this is not a problem in practice).
1
1.2 Relevance
Although it might seem that building a computer out of outmoded, slow, noisy
electric parts is worthless, it actually involves a couple concepts still very im-
portant today. First of all, the relay is almost an ideal switch, even more so
than the transistor. This (practically) removes considerations of current, volt-
age, etc. and leaves behind just the switches which run the computer. This
allows complete attention to be paid to the logical design of the computer. On
this level, the relay computer and the transistor computer are very similar, so
that in building the former one learns a huge amount about the latter.
The second reason this project will be valuable is its stress on efficiency.
Designing minimal machines which still fulfill stringent requirements (in this
case Turing-completeness) is difficult, and being forced to strip away all unnec-
essary components yields a greater understanding of what the essentials are.
This project requires careful consideration of not just how to do something, but
of how to do it best. That knowledge is very likely to be applicable far beyond
relay computers.
1.3 History
The first general-purpose digital electric computer was designed by Konrad Zuse
in the late 1930s and completed in 1941.[2, 3, 4] Beyond this (rather impressive)
distinction the computer — the Z3 — was also the first to utilize the binary
system, be capable of performing floating point arithmetic, and to be Turing-
complete.[5] It was also made of relays — 2400 of them.[3]
Zuse was attempting to design a computer to aid in engineering calculations.
One of his fundamental ideas — using binary — led him to consider relays, which
can be either on or off. His first computer (the Z1) was built using mechanical,
not electric, relays, but was the first general-purpose digital computer. The
Z3 was essentially of the same design but converted to use electromagnetic
relays. A friend of Zuse’s actually suggested they try vacuum tubes instead,
but their designs were met with criticism because of vacuum tubes’ notorious
unreliability.[3] Indeed, even at peak efficiency ENIAC, the first general-purpose
electronic computer, required a tube to be replaced on average every two days.[6]
Despite this unreliability, vacuum tube computers came to dominate through
their blindingly-fast speeds.
Still, relay computers remained in use through the mid 1950s, even after the
invention of the transistor in 1947.[7] However, the transistor would prove to be
the end of the relay computers. With their ability to operate without warming
up, on very little power, and in a very small volume, transistors had completely
replaced relays and vacuum tubes by the early 1960s.
Relays are still in use today, but in a different way. Having been supplanted
as a logic component by the transistor, they still possess one major advantage:
they can handle very large amounts of current. Therefore they are widely used
as heavy-duty electric switches, doing everything from turning on the heating
element in a dryer to routing current in the power grid. Relays no longer have
2
the status they once had, but they are still a very useful electric component.
2 Design
In the discussion that follows, all pins can be either “high,” connected to positive
voltage, or “low,” left floating. Note that this is different from the usual meaning
of “low”: connected to ground.
All circuits used in the computer were designed by the author, with the
exception of the Zuse adder circuit (see section 2.4).
Register S Register A
Main
Memory ALU
Program Counter Register B
Figure 1: Block diagram of the relay computer. Arrows indicate major data
paths (not control signals and the like).
2.2 Registers
Registers, buffers used to store persistent data, are absolutely essential in any
computer. They are used to store, for example, the arguments to and the
results of operators, intermediate results of address calculations, and the current
execution state of the computer.
The basic component of all the registers is the latch circuit, depicted in
Figure 2. Figure 3 shows the latch in operation. When the latch pin is held
high, a pulse on the input/output pin will cause the relay to switch and remain
3
switched. The input/output pin will remain high even if the external circuit
stops driving it. Thus the latch acts like a 1-bit memory cell which can be
cleared by bringing the latch pin low.
I/O
Figure 2: 1-bit latch circuit. I/O is the input/output pin, and L is the latch pin.
0 1
1 1
Figure 3: Operation of the latch circuit. In the right diagram, the data pin has
gone high, causing the relay to activate. The high latch pin continues to power
the coil, keeping the data pin high regardless of external circuitry.
This is actually the second latch design intended for use in the computer.
The first is illustrated in Figure 4. This latch is supposed to work due to the
inductive nature of the relay: as it switches it cuts off its own power, but the
coil remains on long enough for contact to be made with the lower throw and
power resupplied. If it worked, this latch would have the advantage that after
activating, it isolates the input. Unfortunately it does not work, because the
coil does not remain on long enough. Instead the relay switches back and forth
as fast as possible, a damaging condition known as “fluttering”. Fortunately
this was discovered during preliminary testing before the main construction of
the computer, and all circuits which depended on the input isolation could be
modified to use the latch in Figure 2.
The computer has a number of registers with differing functions. They are
briefly summarized in the following sections.
4
O I
Figure 4: Original latch design, with input isolation. This design is susceptible
to fluttering.
2.2.2 Register C
Register C stores the results of ALU operations. It cannot be written to in any
other manner. The contents of Register C may be written into main memory
at a specified address. They may also be copied into Registers X and Y.
2.2.5 Register O
Register O is an internal register used to store the current opcode. It may not
be read or written to in any way.
5
2.2.6 Program Counter
The Program Counter (PC) is a 16-bit register used to store the current address
in the program. It cannot be written to directly, although its contents may be
changed by a successful branch command. It cannot be read. The PC has an
embedded increment unit and an auxiliary 16-bit storage register (Register S)
which are used internally and are not available to the program. One of the
latches used in the PC is shown in Figure 5.
Co +V
Co Ci
S Ci
I/O L
Figure 5: 1-bit latch circuit with embedded increment unit. I/O and L are the
same as in Figure 2. Ci and Co are the carry in and out lines, connected
sequentially as in the ALU (see Section 2.4). S is the sum. If the carry in line
for the first relay in the register is held high, the S lines will output one plus the
address in the register.
6
In computers, addition is done by connecting a number of components called
full adders in parallel. A full adder takes two 1-bit inputs and a carry in bit,
and produces the 1-bit sum and a carry out signal. For example, if one input
was high and the carry in was high, the full adder would produce a sum of zero
but emit a carry out signal. If the carry out of each adder is connected to the
carry in of the next (except the first, which is kept low), a complete addition
unit able to add multi-bit numbers is formed.
Implementing a full adder efficiently does not have an obvious solution. At
first glance, it appears to take in three inputs, therefore requiring three relays to
deal with all possibilities. However, the carry in bit is not a proper input, since
it is generated by the previous adder and is not independent of the numbers to
be added. A very clever circuit that takes advantage of this is Konrad Zuse’s
full adder, depicted in Figure 6.[1] This adder manages to use only two relays,
by transmitting not just the carry signal but also its negation (symbolized in
standard Boolean logic notation by a horizontal bar over the pin name). Us-
ing one Zuse adder for each of the bits of the inputs, a full addition can be
accomplished with sixteen relays.
Co
Co
Ci
+V
Ci
Figure 6: Zuse full adder circuit. A and B are the bits to be added, Ci and Co
are the carry in and out bits, and S is the sum.
The ALU must also calculate a number of logical operations. While AND,
OR, and NOT (of one input) can be easily implemented with one relay, it
7
takes two for XOR (exclusive or, i.e. one or the other but not both) and XNOR
(negated exclusive or). Combined with the addition unit, this would require four
relays per bit of data, for a total of thirty-two. Recall that Zuse’s adder works
with only two relays by transmitting both the carry bit and its negation. Since
more relays are needed anyway for logical operations, this kind of trick might
no longer be necessary. Therefore the author searched for a combined addition-
logic unit that shared relays. The result is shown in Figure 7. This circuit
requires only three relays, but calculates all the logical operations (including
NOT for both inputs) as well as addition.
+V
+V
OR
+V
+V NOTA
A
S
Co AND
Ci
+V NOTB
XOR
XNOR
B
Figure 7: 1-bit combined logic and addition unit. A and B are the bits to be
operated upon, Ci and Co are the carry in and out bits, S is the sum, and
the remaining pins are labeled with the logical operation corresponding to their
output.
This circuit would seem to yield a total of 24 relays for the ALU. However,
there is another cost we have not yet considered. Although 24 relays are suf-
ficient to produce all the outputs desired, there must also be a way to select
a particular one. The outputs cannot all be directly connected to a register,
since they all give differing signals. Therefore for each output there must be
two relays which will only allow the output through if they are turned on (we
need two because each relay has four poles and so can control four bits of data).
We can select which output we want by turning on only its two relays, causing
8
its value to be transferred into a register. The total relay count for the ALU is
thus not 24 but 38!
Fortunately, there is a way not only to get around the buffering problem,
but also decrease the number of relays needed for the actual calculations at the
same time! Observe the truth tables given in Tables 1 and 2. Notice anything?
The other logical operations are contained within addition’s truth table. For
example, if we hold Ci high, then the value of S is the same as A XNOR B (in
the table, the magenta column {1,0,0,1} ). We can find any other operation’s
values by looking at S or Co for different values of Ci (N.B. NOT is not in the
table — however, it can be easily calculated by forcing Ci high and adding zero).
This is illustrated in Table 3, which is simply a compressed version of Table 2.
Rather than have specialized circuitry for the logical operations, we can now
simply reuse the Zuse adders already present. Four relays can be used to disable
the normal carry chaining, where a carry from one adder is propagated to the
next (like when adding on paper we carry over to the next digit). One more can
be used to select the desired value of Ci . Two more relays are needed to select
between S and Co , and note further that now we have only one consolidated
output. Therefore we completely avoid the buffering problem, requiring only
two relays for the single output. All together, the ALU can perform addition
and all logical operations using 29 relays (including the four for both NOT
operations).
It can be shown that the NOT operation along with either AND or OR is
sufficient to generate all the other logical operations. However, the ALU design
is so efficient that removing the capability to directly compute the three others
(XOR, XNOR, and either OR or AND) would only allow a savings of a single
relay. Therefore this particular optimization has not been taken, in order to
gain the benefits of additional built-in operations at very low cost.
9
A B AND OR XOR XNOR
1 1 1 1 0 1
1 0 0 1 1 0
0 1 0 1 1 0
0 0 0 0 0 1
Table 1: Truth table for the binary logical operations. Compare colored sections
with Figure 2.
Ci A B S Co
1 1 1 1 1
1 1 0 0 1
1 0 1 0 1
1 0 0 1 0
0 1 1 0 1
0 1 0 1 0
0 0 1 1 0
0 0 0 0 0
Table 2: Truth table for the sum and carry out bit. Note the presence of the
logical operations in the colored sections.
Ci S Co
1 XNOR OR
0 XOR AND
Table 3: Compressed truth table for the sum and carry out bit.
10
1 2 3
L1out
+V
S
CLK CLK CLK L2out
CLK
L1in
R
Figure 8: State controller circuit. State 1 is on by default, and the state incre-
ments on every edge of CLK. S, L1, and L2 are signal and latch control pins
and should be connected to the next relays in the same way shown for relays 1,
2, and 3. Note also that each relay alternates being connected to CLK or CLK
inverted. R is the reset pin.
the previous relay. Note further that all the relays to the left are on at this point,
and the first relay (the leftmost one in the diagram) has this pin connected to
power. This emits a signal which propagates through all the activated relays.
Eventually it reaches a relay which is off, and is directed to that relay’s state
output. Also, when the previous relay turned on, it connected one of the latch
pins (in the diagram pin L2out) to either the clock or the clock inverted. Since
the relays alternate between the two, whichever one L2out connects to for a
given relay will be initially low. Therefore the only thing that happens on the
first clock cycle is that the state output is driven high.
When the clock switches again, L2out will go high, turning on the middle
latch. This will disconnect its state output and propagate the signal on to
drive the next state. Notice that the signal from L2out is routed through the
relay after the middle one. This is because after the middle latch turns on, it
will continue to drive the L2out of the previous relay high. Since that pin is
connected to the clock (or in this case the clock inverted), this will force the
clock to stay in one position. In the Figure 8 design, however, the signal will be
cut off when the rightmost relay turns on, thereby allowing the clock to continue
to switch.
Generally, each relay in the state controller passes through three modes. In
the first, its state output is on. In the second, it turns the next state output on.
And in the third, it turns the next relay on. These three modes “move” up the
chain of relays, activating each state in succession.
The sequence of 12 states used by the computer is shown in Figure 9. Most
instructions complete after state 9, and follow the first return arrow in the
diagram back to state 1 (the return occurs after state 10 for technical reasons,
although state 10’s actions are disabled in this case). Some instructions require
11
a second increment of the program counter, and use the second return arrow
(see Section A.1).
Execute Secondary
Load Opcode Increment PC Instruction PC Increment
{
{
{
{
1 2 3 4 5 6 7 8 9 10 11 12
Figure 9: The sequence of states used in the computer. Note that a new cycle
may be started after either state 10 or state 12.
Finally, some operations use the state of the latches themselves in addition
to the state outputs. Since the latches turn on once and remain on for the rest
of the 12-state cycle, they can be used to drive processes which need to be on
for more than one state. Specifically, the state controller provides signals which
turn on at states 7 and 8 and remain on through state 9.
12
SPC
1 S CLEAR
+V
+V
+V
2
PC+S
+V
3
PC CLEAR
Figure 10: Program counter increment logic. The numbered inputs on the left
are states from the state generator (actually states 4, 5, and 6). Note that all
three states disable the S-to-PC buffer — it is re-enabled automatically during
state 7.
000
001
010
011
100
101
+V 110
111
Figure 11: The type demultiplexer. The three input bits at the bottom select a
particular wire on the right to be held high.
13
State Generator
Buffer
Load Logic
Buffer
Store Logic
Buffer
Move Logic
Buffer
ALU Logic
Buffer
Branch Logic
Buffer
LSH Logic
Type
Demultiplexer
Opcode Register
Figure 12: Block diagram of the instruction processing system. The first three
bits of the opcode are decoded by the type demultiplexer and turn on one of
the six buffers. This buffer then allows the states from the state generator to
pass through to the corresponding logic circuit and execute the instruction. The
remaining five bits of the opcode are used by the logic circuits to determine which
specific operation is desired.
14
Details of the instruction set are given in Appendix A.
2.8 Construction
The vast majority of the relays in the computer are Aromat model DS4E-M-
DC5V. These relays operate at 5V, are capable of carrying up to 3A of current,
and are in 4PDT configuration (four-pole, double-throw). They are mounted on
three 4” by 17” sheets of perfboard and are connected with 30 gauge wire-wrap
wire for the most part (some high-current connections use heavier wire). 6 fans
are arranged around the boards for cooling.
3 Conclusion
The computer is nearly complete. All circuits have been wired (except the
memory, which has been left disconnected during testing for safety), and testing
is ongoing. A number of important components have already been tested and are
working perfectly. Unfortunately a problem has arisen which requires rewiring
of a number of circuits. Workarounds have been devised for all instances of the
problem, and testing should be able to resume shortly. The computer should
be fully operational sometime next week.
Although this project is not quite over, I feel that it has been very much
a success. The computer is painfully close to working, and I am very excited
to see it run on its own soon. The circuits I designed appear to actually work,
and nothing has melted so far! In a little while, I will have a board with 200
little boxes that makes a huge racket and has a bunch of blinking lights on it.
If nothing else, I can use it as a cool paperweight.
A Instruction Set
Following are brief descriptions of the operations in the instruction set, along
with their opcodes.
15
These operations load a byte from main memory into a register. In the case
of the LD* commands, the next byte occurring in the program is loaded into the
register. The LD* commands are the only operations which require a secondary
PC increment. The LDI* commands (load i ndexed) load the byte located at
the address currently stored in the index register.
The mode bits specify which registers to load data into, and whether or not
to use indexed addressing. Their settings for the basic operations are depicted
in Table 4.
LA LB LX LY IA
LDA 1 0 0 0 0
LDB 0 1 0 0 0
LDX 0 0 1 0 0
LDY 0 0 0 1 0
LDIA 1 0 0 0 1
LDIB 0 1 0 0 1
Data can be loaded into multiple registers at once by setting the correspond-
ing mode bits for each register. For example, the value stored at the current
location in memory could be loaded into registers A, B, and Y using the opcode
00011010. Note, however, that registers X and Y must not be loaded using
indexed addressing, as this will cause a hardware failure.
16
These operations perform calculations with the ALU. ADD performs an 8-bit
addition. AND, OR, NOTA, NOTB, XOR, and XNOR perform the correspond-
ing logical operations. ATC and BTC move the contents of the specified register
into Register C unchanged.
All ALU operations initially clear the CCR. After a result has been calcu-
lated, the appropriate flags will be set — Z if the result is zero, N if the result
is negative (has its most significant bit set), and C if an overflow carry has
occurred.
The mode bits ENA and ENB enable inputs into the ALU from registers A
and B respectively. SC, sequential carry, specifies whether the carry signals from
each bit adder should be fed into the next, as in addition. CL, carry low, specifies
that the carry signals should be low if sequential carrying is disabled. Finally,
OS, output select, specifies if the carry signals should be output instead of the
sum. The mode bits for the basic operations are depicted in Table 5.
ENA ENB SC CL OS
ADD 1 1 1 * 0
AND 1 1 0 1 1
OR 1 1 0 0 1
XOR 1 1 0 1 0
XNOR 1 1 0 0 0
NOTA 1 0 0 0 0
NOTB 0 1 0 0 0
ATC 1 0 * 1 0
BTC 0 1 * 1 0
Table 5: Mode bits for the basic ALU operations. An asterisk means the state
of the mode bit is irrelevant.
Other operations are possible with different combinations of mode bits. For
example, the opcode 01100010 would fill Register C with zeroes, and the opcode
01100000 would fill it with ones.
17
or carry flags of the CCR, respectively, are set. Combinations of the mode
bits are not permitted — this will cause corruption of the CCR register. The
mode bits for the branch operations are depicted in Table 6, and the branch
instruction logic is shown in Figure 13.
JU JZ JN JC
GOTO 1 0 0 0
BRAZ 0 1 0 0
BRAN 0 0 1 0
BRAC 0 0 0 1
+V
PC CLEAR
1
+V
S CLEAR
2
IRPC
JU
JZ JN JC
Figure 13: Branch instruction processing logic. The relays connected to the PC
and S clear wires are to isolate this circuit from the PC increment circuit, which
also drives those wires.
This operation performs a circular left shift on Register A, storing the result
in Register C. It clears the CCR, however it does not set the CCR Z flag even if
18
the result is zero. This is not a problem since the shift can only produce a zero
from a zero, which could be checked for before the operation.
Due to its radically-different hardware implementation, the LSH operation is
not an ALU operation. It does not use any mode bits.
B A Sample Operation
In order to understand more clearly what the computer actually does, following
is a walkthrough of one complete operation. As mentioned in Section 2.5, the
computer cycles through a series of twelve states. Let us assume that the last
state has just completed and a new cycle is about to begin.
States 1 through 3 load the next opcode of the program from memory. First
state 1 is activated, which clears Register O so that the new opcode may be
stored in it. Then state 2 connects the program counter, containing the current
program address, to the address inputs of the main memory chip. Finally, state
3 loads the output of the memory chip (the new opcode) into Register O.
States 4 through 6 advance the program counter so that the next cycle will
read the program instruction following the current one. State 4 clears Register S
so that the incremented value of the program counter may be stored in it. State
5 then connects the program counter’s embedded increment unit to Register S.
Now that the new value has been stored, state 6 clears the program counter so
the new value may be copied back in. This copying is actually done at the same
time as state 7.
States 7 through 9 execute the current instruction. The specific actions
which are taken depend on the instruction, but for this example let us assume
that Register O contains the opcode 10001000. The first three bits of this
opcode, 100, are decoded by the instruction demultiplexer as representing a
branch operation, and select states 7 through 9 into the branch logic circuit.
This circuit determines that the remainder of the opcode (01000) specifies the
operation JZ. This means that a jump will occur if the value stored in Register
C is zero. Let us assume that this is the case. Then, state 7 first clears both
the program counter and Register S. Finally state 8 transfers the contents of
the index register into the program counter. This means that on the next cycle
execution of the program will not proceed to the following instruction, but will
jump to the newly loaded address. Note that the branch operations do not use
state 9, but other operations do.
States 10 through 12 are optional, and advance the program counter again
in certain circumstances. This is necessary if the operation read an argument
directly from the program and not just from the current opcode. In this case,
the branch operation did not do this, and so these states are skipped (due to
implementation details, state 10 is actually executed, however it is blocked from
beginning another increment).
Now the state generator is reset back to state 1, and another cycle begins.
All operations follow this basic sequence, the only variation being in states 7
through 9 and a possible second increment of the program counter.
19
References
[1] H. Porter, Harry Porter’s relay computer (November 2007), http://web.
cecs.pdx.edu/~harry/Relay/.
[2] Timeline of computer history (2006), http://www.computerhistory.org/
timeline/?category=cmptr.
[3] K. Zuse, Computer design - past, present, future, online reproduction
of lecture (October 1987), http://ei.cs.vt.edu/~history/Zuse.html,
http://ei.cs.vt.edu/~history/Zuse.2.html.
[4] History of computing hardware (May 2009), http://en.wikipedia.org/
wiki/History_of_computing_hardware.
[9] Utron Technology Inc., 32K X 8 Bit Low Power CMOS SRAM
(September 2000), http://pdf1.alldatasheet.com/datasheet-pdf/
view/77316/ETC/UT62256PC-70LL.html.
[10] Panasonic, Highly Sensitive 1500 V FCC Surge Withstanding
Miniature Relay, http://sigma.octopart.com/2347/datasheet/
Panasonic-DS4E-S-DC5V.pdf.
20