About Zusie

I amuse myself by constructing a computer almost entirely out of relays. Relays were used to construct computers well before vacuum tubes, transistors or integrated circuits were feasible for the task. The main inspiration is the machines by Konrad Zuse of the late 30s and early 40s.

Why relays? In addition to constituting an important historical link between the mechanical and electronic computers, relays are especially fun to work with since they

- are big and slow, with huge propagation delays and a tendency to oscillate if you hook them up wrong.
- are noisy, especially when lots of relays switch at the same time.
- consume lots of power to do even the simplest of calculations.
- subscribe to Lenz' law, i.e. generate lots of EMF and flyback current that make for all sorts of interesting interference in places you couldn't even guess.

Quick feature list:

- 8-bit data bus and 16-bit address bus
- 3 x 8-bit accumulator registers, 2 x 12-bit registers (for index, addresses and jumps)
- 64k solid state memory, holding heap, stack and program
- 12-bit program counter and 12-bit stack pointer
- ALU capable of not, and, or, xor, add, increment, decrement, shift, and indirectly, subtraction
- Writable microprogram stored in solid-state device for sequencing
- Assembler and Microassembler running in DOS and communicating with Zusie over parallel port.

To build a relay computer, you clearly need a lot of relays. I had the good fortune of locating about 100 discarded telephone exchange circuit boards with about 15 four-and six pole relays on each board. I bought them at scrap prices and desoldered them with a hot-air gun and wound up with some 1500 excellent-quality relays.

Here is a block diagram of Zusie's architecture (click for larger version). It is a fairly regular CISC, microcoded architecture.

Here are some terminology used below and in Zusie assembly code:

- A
*literal*is a constant numeric value between 0 and 255. Can be written in decimal form, in hexadecimal form preceded by h (`h80`) or binary preceded by b (`b10000000`). - A
*label*is a jump or call destination. In Zusie Assembly, it's written on a line preceded with a colon (such as`:label`). It evaluates to the address of the next instruction after the label. The label takes up no program space of its own and is only an assembly helper construct. - Some instructions like jumps takes an address (or label) as argument. They usually come in
two versions, long and short. Shorts are prefixed or suffixed by an
`s`. Shorts only alter the lower byte of the program counter, and so can only jump to addresses within the same 256-byte code segment. Always use shorts if you can (i.e. when not writing absolutely huge programs), since they are faster and have only one address byte as payload, contrasted with two bytes for long instructions. These varieties are referred to as*distance*below.

Here is a comprehensive list of Zusie instructions and mnemonics:

**Load Literal**Load numeric constant into register.

`LDL->r v`where r may be A,B or C, and v is a literal**Load Condition Code from Register**Populates the condition code register according to register r.

`LDC<-r`where r may be A, B or C.**Subroutine Calls and Returns**CALLd instructions saves the value of the program counter and proceeds execution at a label. A RETd instruction restores the program counter to the instruction after the last CALLd. d can be either s for a short jump or empty for a long jump. Call and return distance must match.

`CALL label`and`RET`

`CALLS label`and`RETS`**Stack Push**Pushes the value of a register onto the stack.

`PUSHr`where r may be A, B or C.**Stack Pop**Pops the top value off the stack and into a register

`POP->r`where r may be A, B or C.**Increment/Decrement 16-bit register**Atomically replaces the content of r with content+1 or content-1, or increments/decrements into another register.

`INCr`where r may be J or XY.

`DECr`where r may be J or XY.

`INCr->s`where r,s may be J or XY, and r not equal to s.

`DECr->s`where r,s may be J or XY, and r not equal to s.**Read Memory**Reads a memory byte from the address stored in r into register s

`RDr->s`where r may be J or XY and s may be A, B or C; or, r is J and s is X or Y**Write Memory**Write a byte from register s into memory (and, alternatively any mapped device such as the flipdot display) at the address stored in r.

`WRr<-s`where r may be J or XY and s may be A, B or C; or, r is J and s is X or Y**Long Branch**Continues program execution at a new label or address, possibly conditionally.

`BR l`Branch unconditionally to l

`BRZ l`Branch to l if condition code Z (zero) is set

`BRNZ l`Branch to l if condition code Z (zero) is not set

`BRC l`Branch to l if condition code C (carry) is set

`BRNC l`Branch to l if condition code C (carry) is not set

`BRS l`Branch to l if condition code S (sign) is set

`BRNS l`Branch to l if condition code S (sign) is not set**Short Branch**Continues program execution at a new label or address, possibly conditionally.

`SBR l`Branch unconditionally to l

`SBRZ l`Branch to l if condition code Z (zero) is set

`SBRNZ l`Branch to l if condition code Z (zero) is not set

`SBRC l`Branch to l if condition code C (carry) is set

`SBRNC l`Branch to l if condition code C (carry) is not set

`SBRS l`Branch to l if condition code S (sign) is set

`SBRNS l`Branch to l if condition code S (sign) is not set**8-Bit Moves**Copies the value in r to register s.

`MOVr->s`, where r,s=A,B,C,X,Y and r not equal to s**16-Bit Moves**Copies the value in r to register s.

`MOVr->s`, where r,s=XY,J,S,P and r not equal to s. Observe necessary precautions for fiddling with S (the stack pointer) or P (program counter) ;-)**Unary ALU operations**Performs ALU operation on the value in register r, storing it in s. r and s may not be the same. If the "->s" construct is omitted, it does not store the value in a register, but only loads the condition code register according to the result. If s is MXY or MJ, the result is stored in memory at address given by XY or J respectively.

`NOTr, NOTr->s`, where r=A,B,C, s=A,B,C,MJ,MXY. Performs logical NOT.

`INCr, INCr->s`, where r=A,B,C, s=A,B,C,MJ,MXY. Increments r.

`DECr, DECr->s`, where r=A,B,C, s=A,B,C,MJ,MXY. Decrements r.

`SRr, SRr->s`, where r=A,B,C. Rotates the bits in r one step to the right.**Binary heterogeneous ALU operations**Performs ALU operation on the value in register r and the value in register s, storing it in t. No two of r, s and t may not be the same. If the "->t" construct is omitted, it does not store the value in a register, but only loads the condition code register according to the result. If t is MXY or MJ, the result is stored in memory at address given by XY or J respectively.

`ANDrs, ANDrs->t`, where r,s=A,B,C, t=A,B,C,MJ,MXY. Performs logical AND.

`ORrs, ORrs->t`, where r,s=A,B,C, t=A,B,C,MJ,MXY. Performs logical OR.

`XORrs, XORrs->t`, where r,s=A,B,C, t=A,B,C,MJ,MXY. Performs logical XOR.**ALU addition operations**Performs an addition operation on the value in register r and the value in register s, storing it in t. r and s MAY be the same register, but neither r or s may be the same as t. If the "->t" construct is omitted, it does not store the value in a register, but only loads the condition code register according to the result. If t is MXY or MJ, the result is stored in memory at address given by XY or J respectively. Note that operations like`ADDAA`tt> is effectively the same as 2*A, and also A shifted to the left.

`ADDrs, ADDrs->t`, where r,s=A,B,C, t=A,B,C,MJ,MXY.

*Fredrik Andersson - nablaman[at]nablaman.com*

Back to Zuse home | Back to my home page