• ### Winding Down

I posted a video of WDC-1 in "action" today calculating a couple of digits of the Fibonacci Sequence.

It's been a lot of fun but, time to move on.  I appreciate the all follows, likes, and views. Thank you!

• ### Running a Program on WDC-1

With everything together I wanted to do something interesting on my Working Digital Computer Version 1 so I wrote the following program to calculate the first few numbers in the Fibonacci sequence (which we know starts with 0, 1 and that each subsequent element is the sum of the previous two numbers in the sequence (so 0, 1, 1, 2, 3, 5, 8, 13...)).

        ; Calculate the first few Fibonacci numbers.
; Assumes that the first two numbers 0 and 1 are in the
;  INPUT Encoder A and Encoder B addresses.
;
1000 1000    RIN    A        ; Read the first seed
0110 0000    TRA             ; Transfer A to X
1000 0100    RIN    B        ; Read the second seed
0001 1100    STO    C1       ; Save the last number
0100 1101    ADD    4        ; A + X  Result in A
1110 0011    RUT    1s       ; Result < 10 show in OUTPUT
0001 0010    STO    C2       ; Remember result
1000 1100    RIN    C1       ; Get last number
0110 0000    TRA             ; Transfer A to X
1000 0010    RIN    C2       ; Get current result back
1010 0001    SHL    1        ; Is the current result >= 8?
1001 0001    COJ    1        ; Result >= 8
1000 0010    RIN    C2       ; Get current result back
0001 1100    STO    C1       ; New last number
0101 1101    JMP    4        ; Go back to add
1000 0010    RIN    C2       ; Get current result back
0100 0000    ADD             ; A + X  Result in A
1110 1111    RUT    BCD      ; Convert binary to BCD put result in OUTPUT
0000 0111    NOP    ANS      ; Final result

The hardest part was keeping the program length down to 20 instructions, the current limit for my "low density" drum memory.  I'll have to get going on the "high density" drum if I want to do more. I've "run" the program a few times and it seems to operate as expected.  I guess my current thinking is to make a video of WDC-1 in action.

• ### Finishing Touches

With all of the major components complete it's time to put it all together.  I attached a 3-wire power cable with a 3.5 mm stereo plugs to each of the peripheral modules.

For the Input and Output panels the extra power wire would allow me to selectively power the Encoder A, Encoder B, 10^1, and 10^0 elements independently should I choose.

After that there was nothing left to do but plug it all together and power it on.

• ### Control Panel Done

Just finished wiring and testing the Control Panel. The wiring got a bit hairy but it works well.

I used a 10 lead ribbon cable to connect the Drum Instruction Memory to the panel itself. Two leads were for power and the other 8 were for the op code and address control bits (4 for each). The drum base has lights marked Even and Odd hooked up to the two timing switches. These will alternate between instructions to give a visual indication that you have move to the next instruction correctly. You could also have both on to indicate the first line of the program and both off for the last line (say).

Lots of wire but the two 4 to 16 decoders basically just map the each op code and address to a single indicator light on the panel. There are 31 LEDs in total.  I guess you could say this is WDC-1's instruction decoder.

The Control Panel is also where the power comes in and gets distributed to the other components of the machine. I'm using 3.5 mm stereo jacks and plugs so that the various pieces of the machine can be easily disconnected for close examination.

As I was setting up the power I also decided to make another small change from the book.  The power "Junction Box" in the book was set up to power the components only when they were being used for part of an instruction. So for the command:

RIN Address A

for instance only the ALU and the Input Panel's Encoder A part of the machine would be enabled.  This might provide a little extra clarity when executing instructions, but prevents a demonstrator from just showing what each part of the machine does in the absence of the proper commands. So I have decided to keep all of the modules powered all the time. I have not closed the door on the book's method, I can easily rewire for it, but for now I'm going with always on.

• ### 2BCD, Or Not 2BCD, That Is the Question

When I first started looking at the book "How to Build a Working Digital Computer" I noticed with interest that the Input Panel converted decimal numbers to Binary Coded Decimal (BCD) and the Output Panel in turn converted BCD results back to decimal numbers.  In between the ALU is pure binary. This was new for me as all of my other projects were pretty much binary only. Cool. The encoders and decoders for these panels were pretty straight forward as they only had to deal with single digit decimal numbers and their BCD equivalents.

What I didn't give a lot of thought to was this, "How does a binary result that is greater than 9 get converted into the two BCD inputs that the Output Panel is expecting?". Well the answer is simple, run a program.  Here is the "Readout Program" from the book.

Wait there's more...

So if I'm demonstrating WDC-1 and want to show something basic like adding 8 + 7 I would run a program something like this (assumes the two addends are in Address A and B):

RIN Address A  ; Read first addend into A
TRA            ; Transfer A to X
ADD            ; Add A and X. Result in A

With the result now in the accumulator at this point I say "Please bear with me as I perform 43 more complex and potentially error prone instructions so I can show you the answer.".

This felt like a gap to me so I started looking into binary to BCD conversion. How hard could it be? Well it turns out that while BIN2BCD conversion is not really that hard, it's not easy to do with a simple circuit.  It requires computation, hence the 43 instruction "Readout Program". So I think I understand why the authors relegated their solution to the very back of the book.

I learned that there are a few ways to perform binary to BCD conversion. You can create a circuit to do this. Here is a design I found on Stack Exchange with thanks to jonk that employs the Double Dabble (love the name) algorithm:

This first schematic accepts a binary value and leaves it unchanged if the value is $$≤ 4$$. Otherwise, it adds $$3$$ to the binary input.

The second schematic uses the above circuit (named PLUS3 below), repeatedly:

Like I said, binary to BCD is not an easy get with logic circuits. I can't imagine how this could have been done with "household" items.

Another clever way to do a binary to BCD conversion is to use a binary up/down  counter (SN74LS191 say) and a BCD counter (SN74LS192 say). The binary number is in parallel jammed into the up/down counter. Then the counter is clocked to count down to zero. The same clock is used to clock the BCD counter up from zero. When the binary counter reaches zero, the BCD counter will contain the binary number in BCD format.

A third option is to use a microprocessor.  Now at this point I had already decided that I really needed (wanted) a BIN2BCD component to get me past the awkward 8 + 7 show the result issue. I was tempted by option number 2, the counters solution, which was more in line with my use of 7400 series ICs in other modules, but I literally had an Arduino Nano sitting on the desk in front of me. So microprocessor it is. Here is my BIN2BCD module:

The first thing you'll notice is that I chose different colors for this component. I wanted to make it clear that this module, with it's definitely not from the 60s microprocessor, was somehow "outside" of the Working Digital Computer book implementation.  At a minimum the different color should initiate a discussion as to why.

I wrote a "brute force" but hopefully easy to understand sketch for the Arduino:

#include <avr/pgmspace.h>

/**
* Debug. Uncomment the following line for debugging.
*/
// #define DEBUG 1

// Only recalculate if different.
int oldDecimal = -1;

void setup() {

// Initialize serial debugging.
#ifdef DEBUG
Serial.begin(115000);
Serial.println("Setup Binary to BCD.");
#endif

// Setup A0-A5,11,12 to output the BCD. A0-A3 represent
//  the tens value and the rest the ones value.
pinMode(A0, OUTPUT);
pinMode(A1, OUTPUT);
pinMode(A2, OUTPUT);
pinMode(A3, OUTPUT);
pinMode(A4, OUTPUT);
pinMode(A5, OUTPUT);
pinMode(11, OUTPUT);
pinMode(12, OUTPUT);

// Clear the BCD display.
clearBCD();

// Set D3-D10 to input the Binary were D3 = 1 and
//  D10 = 128.
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
pinMode(6, INPUT_PULLUP);
pinMode(7, INPUT_PULLUP);
pinMode(8, INPUT_PULLUP);
pinMode(9, INPUT_PULLUP);
pinMode(10, INPUT_PULLUP);

// Clear the inputs.
digitalWrite(3, HIGH);
digitalWrite(4, HIGH);
digitalWrite(5, HIGH);
digitalWrite(6, HIGH);
digitalWrite(7, HIGH);
digitalWrite(8, HIGH);
digitalWrite(9, HIGH);
digitalWrite(10, HIGH);
}

void loop() {
// Calculate the BCD values the delay a second.
calculateBCD();
delay(1000);
}

/**
* Nothing fancy here. Convert the binary inputs to a decimal
* number. If the number is greater than 99 emit a zero as an
* invalid indicator. Otherwise emit the tens and ones as BCD
* values.
*/
void calculateBCD() {

// Find the decimal number.
int decimal = 0;
decimal += 1;
}
decimal += 2;
}
decimal += 4;
}
decimal += 8;
}
decimal += 16;
}
decimal += 32;
}
decimal += 64;
}
decimal += 128;
}

#ifdef DEBUG
Serial.print("Decimal = ");
Serial.println(decimal);
#endif

// Only change if inputs have changed.
if (decimal != oldDecimal) {
oldDecimal = decimal;

//  Check for value out of bounds.
if (decimal > 99) {
decimal = 0;
}

// Clear the old values.
clearBCD();

// Then output the new BCD values.
int tens = decimal / 10;
int ones = decimal % 10;

#ifdef DEBUG
Serial.print("Tens = ");
Serial.println(tens);
Serial.print("Ones = ");
Serial.println(ones);
#endif

if ((tens & 1) > 0) {
digitalWrite(A4, HIGH);
}
if ((tens & 2) > 0) {
digitalWrite(A5, HIGH);
}
if ((tens & 4) > 0) {
digitalWrite(11, HIGH);
}
if ((tens & 8) > 0) {
digitalWrite(12, HIGH);
}

if ((ones & 1) > 0) {
digitalWrite(A0, HIGH);
}
if ((ones & 2) > 0) {
digitalWrite(A1, HIGH);
}
if ((ones & 4) > 0) {
digitalWrite(A2, HIGH);
}
if ((ones & 8) > 0) {
digitalWrite(A3, HIGH);
}
}
}

/**
* Turn off all the BCD lights.
*/
void clearBCD() {
digitalWrite(A0, LOW);
digitalWrite(A1, LOW);
digitalWrite(A2, LOW);
digitalWrite(A3, LOW);
digitalWrite(A4, LOW);
digitalWrite(A5, LOW);
digitalWrite(11, LOW);
digitalWrite(12, LOW);
}


That's it. I think I now appreciate why the authors did not tackle this as part of their build. For me though, 2BCD is the answer.

## From the Book

The unit "that unifies all of the computer elements" built so far is the Control Panel.  It consists of two major parts, a display panel

to tell the operator (you) what program instructions to perform, and a drum memory

device to hold those instructions. The drum memory was by far the most complex of all the components described in the book. It was constructed from a tin can wrapped in paper with holes (much like their decimal to binary encoder), a frame, and many, many paper clips. Here is the construction diagram:

Despite the complexity of the drum memory, the Control Panel implementation in the book is very simple. The Working Digital Computer supports 10 different instructions and the 16 addresses that those instructions can act upon. Here they are:

There is a paperclip "contact" for each individual command and address, plus two contacts for "timing", and another to act as the common ground for all  the other contacts. That makes 29 in total. Each command and address contact is connected to an appropriately labeled light on the display panel.  The timing contacts drive two lights beside the rotating drum that alternate being on indicating even and odd instruction lines.  Like I say pretty simple.

## My Implementation

My first thought was that the 29 paperclip contacts seemed pretty extreme.  I have a great deal of respect for gort59 for getting this to work in his wonderfully authentic Working Digital Computer build (as seen in the video in the Details section). I understand that  he used the small springs from ball point pens which may have helped. Still kudos gort59!

I had also at this point decided to take advantage of my beefed up ALU and add 6 more op codes bringing the total up to 35. Thats a lot of switches leading to a lot of potential points of failure. Given that the total number of commands and addresses  were both 16 or less, and that I already had a 4 to 16 decoder designed and working for the Output Panel, I decided to implement a 10 bit encoded instruction instead.  This is what I came up with:

Each instruction would have 4 bits for the op code, 4 bits for the address, and I would keep the 2 timing bits as is.

The advantage of having a single bit for each command and address is that an instruction can have more than one "address" bit for each op code. For example the STO command would have an Address C bit to enable the Core Panel (essentially power the panel - this feels more like a control bit to me than an address) and a Core bit to indicate which word to store the value of the accumulator in.  With encoded addresses this is not possible, so some small tweaks to the implementation were required. For the above example I eliminated the Address C address altogether and will enable the Core Panel if any of the Core 1 to Core 5 addresses are used. Here are the other small changes:

• Display ACC removed. Like the Address C bit this would be added to any command that required the accumulator to enable the ALU. Since this is most commands I will simply leave the accumulator "on" all the time.
• JMP changed. The JUP op code used in the book just seemed very wrong to me.
• ENJ command added.  The COJ and JMP instructions used the 1-4 addresses as a way to label the target instruction for the jump. They can still be used this way for instructions that do not take an address (like ADD for instance), but for instructions with an address (like STO for instance) an ENJ instruction with the target 1-4 can be added just prior.
• ORA command added.  Boolean Or the A and X registers. Store result in A.
• XOR command added.  Boolean Exclusive Or the A and X registers. Store result in A.
• AND command added.  Boolean And the A and X registers. Store result in A.
• INV command added.  Boolean Invert A register. Store result in A.
• NOP command added.  No Operation. Do Nothing.
• BCD address added. I'll cover this off in a future log.

With the more compact instruction size I built my drum memory unit:

I guess the design should come as no surprise.  It uses the same pegs and switches as the Input Panel and ALU encoders.  The right 2 "rings" have alternating pegs to trigger the even/odd instruction lights. One command line is visible, a STO Core 2 instruction.

The one disadvantage of this design is that the peg size doesn't allow for very many instructions lines on this 80 mm diameter cylinder, only 20. The one from the book has 50 program instructions. I have another design in mind for a "high density" drum memory using magnets and reed switches (so predictable).

Finally here is the Control Panel with two 4 to 16 decoders ready to be wired and connected to the instruction memory drum.

The new BCD command has not been added yet either.

• ### WDC-1 Presentation

With some of the components finished, I started thinking about what the final project would look like. My initial thought was to build a slanted console and arrange the panels on top much like the CT-650 pictured in the Description above or a Minivac 601.  But when I started thinking about Max Maxfield and Joe Farr's talk about implementing their computer as a: "...a series of glass-fronted wooden cabinets" plus the very nature of the Working Digital Computer as a teaching tool I changed my mind.  Instead I designed some simple stands to hold the panels upright at a small angle:

The components will be wired together with quick connects so they can be easily detached and examined.  It's my convertible with the top down look.

BTW here is a sneak peek at my Control Panel implementation with a clue to where I will be going with it.

• ### WDC-1 ALU Panel Done

I got the ALU wired up and ready to go...

There were a few issues to be resolved that were discovered when "integration testing" the whole unit.

1. The first was easy. XOR was not working as expected. It turned out I had messed up the Encoder Pegs for XOR. Rearranged pegs. Done.
2. On a more serious note both ADD and SUB, the two operations that I actually need for a Working Digital Computer were not working either.  Checked the Encoder Pegs but no joy I had installed them correctly. Turned out there were two distinct issues.
1. For ADD, when creating the 4-Bit ALU PCB I had crossed the Q and Co pins. Needed a little surgery to fix.
2. The operation of SUB as defined isn't quite right. A + NOT B is not the whole story, there needs to be a +1 in there to get the two's complement. Fortunately I noticed that the GS2 control line was not being used by any of the operations I had defined. So I was able to tie that input on the PCB to ground and use the GS2 switch on the encoder to control the Ci input on the PCB. So now the SUB operation (only) has a Peg in the GS2 position which makes the Carry In bit high introducing the required +1.

All operations are now working as expected.