I also had the assumption that my build would serve as inspiration and a source of ideas for what could be done to extend Ben’s computer or build a more complex version.

While I’m still not sure anyone wants to build a clone of the Bentuim Pro I am realising that there’s a demand for a complete description along with schematics. So I’m now going to go ‘back to the beginning’, starting with the ALU which I’ve been writing about recently, to describe the entire system in detail and with full schematics which will include a Github repo for both the schematics along with anything else which may be of interest/use to the reader.

A side note as far as schematics is that I’ve never drawn one before. I played with Fritzing a few months ago and hated it (part of the reason I was planning not to give schematics) but I’ve been using KiCad recently which is an absolute joy and makes me realise I’ve chosen the wrong career in life. Since I’m a newbie I’m sure I’m making some glaring schoolboy errors for which I apologise and I’d appreciate any helpful comments, especially on style etc. which I’m not appreciating.

When I gave my introduction to the ALU recently I feel as though I glossed over the general principles on how it functions. I hope this block diagram explains things a bit better.

The ALU uses two internal, registers, W and Z, for storing operands. These registers can read from the bus but not write to it. These registers are then passed, via a pair of internal busses, to each of the functional units. The functional units being the adder for addition and subtraction, the logic units for AND, OR, XOR operations and the shift/rotate unit for, left and right shift and rotate operations.

These functional units ‘calculate’ their respective output. Each operation within the functional units has a bus transceiver for output to the system bus. Thus each functional unit is always active and the control logic determines which unit’s output is needed for the current operation and enables that units bus transceiver to write that output to the bus.

There is also a 4-bit flags register and associated circuitry (not shown in the block diagram) to evaluate the flag values to be written to the flags register and also circuitry to feed the carry flag as input to the other units as needed.

The W and Z registers, as stated above, are purely internal to the ALU and invisible to the programmer, although the control logic can use the W register as a temporary register, which will be needed for CALL to subroutine operations.

In reference to Ben’s original design my W register is equivalent to his A register and my Z register is equivalent to his B register.

The design of these registers is identical to Ben’s with each using a pair or 74LS173 4-bit latches. The Z register however, can be independently cleared (the z_clear control signal) which is needed for the INCrement and DECrement operations as well as for the temporary storage ability. (The temporary storage feature will simply add 0 to the value stored in W).

The W and Z registers each output onto one-way, permanently on busses which pass to the other functional units (adder, logic, shift/rotate). (The shift/rotate units only operate on the W register).

The adder circuit is, again, identical to Ben’s design using a pair of 74LS283 4-bit adders and a pair of 74LS86 2-input XOR ICs to invert the Z register when doing a subtraction.

The ALU can actually perform add and subtract with and without carry as well as increment (add one) and decrement (subtract one) operations but this is all done by manipulating the carry in and Z register with no changes needed directly to the adder. This is discussed in my post about adding extra operations to Ben’s ALU.

Looking at the circuit diagram you will also see XOR gates inverting the raw_carry_in input and the carry_out output if the operation is a subtraction. The function of these is detailed in my blog posts about adding extra operations to Ben’s ALU and the flags register respectively.

The carry_out and carry_in outputs are both fed out to the carry selection circuit in the flags unit as possible values to write to the carry flag. Bit 7 of the result from the adders is fed, as the adder_bit_7 signal, to the negative flag in the flags register to signify that the result of a two’s complement operation was negative. For an unsigned operation this value is meaningless. These lines are explained in more detail in my post about the flags register.

The functioning of the logic units is pretty simple. Each bit of the W and Z busses is fed into an array of logic gates and the outputs fed to their respective bus transceiver for output to the system bus.

The only thing of note here is the xor_bit_7 output which is fed back to the flags unit to be used in calculating the overflow flag. Again this is explained in my post on the flags register.

The shift and rotate circuit is a *little* more interesting.

All operations happen against the W register. Again there’s a bus transceiver for output of each of the left and right operations. The appropriate lines from the W bus are fed directly to the inputs of each transceiver but shifted one bit to the right or left. All that’s left to do is shift the correct value into the remaining bit.

This is done with a 74LS153 4-bit selector/multiplexer. This chip allows the selection of one of four possible inputs (I0 to I3) depending on a two-bit selector input (S0 and S1). The chip contains two ‘units’ and I’m using one unit for each direction. The selectors (S0, S1) apply to both units at the same time.

For a right shift/rotate operation the four possible input values are (with the equivalent z80 opcodes) :

- carry flag (rotate through carry): RR/RRA
- W bit 0 (rotate with carry): RRC/RRCA
- 0 (shift logical): SRL
- W bit 7 (shift arithmetic – see below): SRA

For a left shift/rotate operation the four possible input values are:

- carry flag (rotate through carry): RL/RLA
- W bit 7 (rotate branch carry): RLC/RRLA
- 0 (shift arithmetic): SLA
- 1 (shift logical. Not really needed, but we have the input so may as well use it <g>. On the z80 this is an undocumented instruction usually referred to as SLL): SLL

The diagram below shows each of the operations visually:

The shift right arithmetic operation preserves the value of bit 7. Why might this be useful? Think about two’s complement binary. Bit 7 is the sign bit so if we preserve it then we preserve the sign of the value and the operation as a whole gives us a two’s complement divide by two which works with both positive and negative numbers. Neat. This can be extended across multiple bytes by using the rotate right through carry (RR/RRA) operation on the less significant byte(s).

The ‘spare’ bit from both left and write operations – the bit which ‘falls out’ the other end – get fed back to the carry flag. You won’t see these output from the schematic though as they are fed to the flag circuitry directly from the W register which keeps the wiring shorter. And bit 7 of the W register is also used as part of the overflow flag calculation. You can see these two bits paring off the W bus on the ALU overview schematic (see next section). For discussion of the carry out circuitry see my post on the flags register.

The 74LS153, as described, uses two bits to select the desired operation. In the Bentium Pro I have a very limited number of control lines available so I’m reusing the use_carry and carry_set signals from the carry select circuit. Since we won’t be using both the shifter and the adder at the same time this won’t cause any problems. The choice if which line is used for which input is purely arbitrary.

Talking of the ALU overview schematic and the carry select circuit you can see this circuitry towards the bottom-left of the schematic below. This circuit is described in my post on expanding the adder but, for the schematic, the XOR with the subtract signal has been moved to within the adder unit, where it makes both logical sense – being paired with the invert carry out on subtraction – and simplifies the overview schematic.

And finally, and for completeness, here are the schematics for the flags section of the ALU.

UPDATE: I’ve corrected the carry select circuit in the overview schematic

]]>As a reminder, the Bentium Pro has four flags:

- Carry. This can contain the carry/borrow from the adder and also the bit moved ‘out’ by a shift/rotate operation. It will be cleared by a logic AND, OR, or XOR operation and can also be explicitly set, cleared or inverted.
- Overflow. The overflow operation indicates that the result of a two’s complement arithmetic operation was too large a positive number or too large a negative number to be represented in a single byte.
- Not-zero. Whether the result was zero or not. This takes input from the bus so can be used for anything output by the ALU as well as anything placed on the bus from elsewhere in the computer (e.g. an I/O operation).
- Negative (sign). This is set if the result of a two’s complement operation was negative.

Figure 1 above shows the circuit diagram for the register. The flags are stored in a 74LS173 4-bit latch (the same as used for the registers in Ben’s original Bentium and also in the Bentium Pro).

Data is latched into the register by the /flags_latch control signal. Note that all four flags will always be stored but a /flags_latch signal. If an operation doesn’t generate a meaningful value for one or more flags then those flags will not contain valid information.

This is a quick an easy one. The negative flag indicates if the result of the last addition (or subtraction) was negative. It only contains a meaningful value if the operation was a two’s complement operation and only the programmer knows if her operation involved two’s complement numbers.

A two’s complement number is negative if the most significant bit (bit 7) is set, so this flag simply takes bit 7 as output by the adder.

For operations other than addition/subtraction this value will be meaningless.

I actually intended to have a zero flag rather than a not-zero flag but the value output from the basic circuitry is not-zero and I didn’t have any board space left to invert it. Since this is purely a semantic issue which can easily be compensated for by the assembly language code I’ve decided to leave it this way.

Not-Zero is evaluated simply by testing whether all eight output bits are zero and all we have to do to evaluate that is OR all eight bits together. The only part available for this would be a 74LS version of the 74HC4078 8-input OR/NOR gate but even the 74HC version is listed as obsolete. We could use seven two input OR gates but this would require two 74LS32 ICs, as shown below.

I didn’t want to have to use that much board space so decided to use diode logic instead. If you’ve never encountered diode logic before I would strongly recommend reading my article about it.

The diagram above shows my actual circuit. This uses a 74LS245 bus transceiver to act as a buffer between the main bus and the diodes. I use this to ensure that the diodes are getting good, solid input signals and also to isolate the diodes from the bus so they don’t cause any unwanted side-effects. This may well be unnecessary but I didn’t want to have to deal with debugging obscure problems later. The ‘245 is permanently enabled.

The diode OR gate works such that, if all the outputs from the ‘245 are low then the resistor pulls the not_zero_flag_out signal low. If one or more of outputs from the ‘245 are high then the not_zero_flag_out signal will become high.

The resistor value is, admittedly, the result of trial and error. I initially used a 10k resistor but the output was unreliable. Moving down to 3.3k has given a faultless output, so far.

As you may remember from Ben Eater’s video on negative numbers in binary than a single byte in two’s complement format can hold a number between -128 and 127. An overflow happens when the result is a number which is too large a positive number or too small a negative number to fit into the output (in our case an 8-bit byte).

This happens when we add two numbers and the total is more than 127 or when we subtract two number and the result is less than -128. (The latter properly termed an underflow).

Lets look at all the possible operations and the largest result we could get from each and see which could cause an overflow or underflow.

- positive + positive: 127 + 127 = 254 Overflow
- positive + negative: 0 + -128 = -128
- negative + positive: -1 + 127 = 126
- negative + negative: -128 + -128 = -256 Underflow
- positive – positive: 0 – 127 = 0 + -127 = -127
- positive – negative: 127 – -128 = 127 + 128 = 255 Overflow
- negative – positive: -128 – 127 = -128 + -127 = -255 Underflow
- negative – negative: -128 – -128 = -128 + 128 = 0

In the above list I have also rewritten the subtractions as additions which shows there is only one operation which could cause an overflow: adding a positive number to a positive number; and only one condition which could cause an underflow, subtracting a negative number from a negative number.

In two’s complement a positive number will always have a 0 if the most significant bit (MSB) (values 0 .. 127). An overflow happens when the result causes a carry into the most significant bit (values 128..255). I.e. when both inputs are positive but the result is negative. When the MSB of both inputs is zero and the MSB of the result is 1.

Negative numbers always have a 1 as the MSB. An underflow happens when there is a carry into the MSB. Since the MSB of both inputs is 1 this results in a carry out of the MSB and the MSB of the result is 0. For example:

-128 + -1 = -129 10000000 + 11111111 = 1.01111111 -128 + -128 = -256 10000000 + 10000000 = 1.00000000

(I recommend having a play with a two’s complement decimal to binary converter to help visualise this).

Thus we get an underflow when both inputs are negative but the result is positive. When the MSB of both inputs is 1 and the MSB of the output is 0.

If we name the MSB of input W as w7 and the same for input Z as z7 and for the result as r7 then we get an overflow when (w7 == z7) AND (w7 != r7).

How do we test a boolean for equality (or inequality)? Look at the truth table for an exclusive OR:

a b q 0 0 0 0 1 1 1 0 1 1 1 0

and you can see that if both inputs are the same we get a zero out, if both inputs are different we get a one. We can rewrite our overflow formula above as NOT (w7 XOR z7) AND (w7 XOR r7) giving the following circuit:

On the Bentium Pro I had no space for an inverter but I did have a spare XOR gate so I used that to do the inversion by XORing against a fixed high input. I also had no spare space for an AND gate so I used a diode logic AND gate giving the final circuit below:

In practice the ALU is already calculating W XOR Z as part of the logic circuitry so I can use bit 7 of the output from this as the w7 XOR z7 value and save a XOR gate (which I don’t have room for anyway!). I’ve termed this xor_bit_7. My final circuit diagram for the flags module is:

The final flag is the carry flag. As mentioned above this can take a value from one of four different sources depending on the operation:

- Carry out from the adder.
- Left shift/rotate.
- Right shift/rotate.
- An explicit value for logic operations, set carry, clear carry and complement carry.

Before I get to the circuitry for selecting a source for the carry flag I want to talk about where the flag values come from.

This is, fairly obviously, the carry out from the 74LS161 calculating the most significant nybble of the sum. However when I initially wired this up I found that, for a subtraction, the value was the inverse of what I was expecting.

Googling for the reason why gave me two possible explanations:

- The carry is actually a borrow for a subtraction so needs to be inverted.
- I’m inverting the Z register and the carry flag on input to the adders and therefore need to invert the carry flag again on the way out.

(These explanations are not necessarily exclusive: they may both be correct). I’m ashamed to say that I can’t give a proper reason why, but the end result of this is that I need to invert the carry out if I’m doing a subtraction and this can be done, as it is for the carry in by XORing the carry out with the subtract control signal.

These two options are simple to explain. When the value is shifted/rotated right the value in the old least significant bit is the carry out. When the value is shifted/rotated left the old most significant bit is the carry out.

The shift/rotate circuit only works on the W register and the potential carry out bits aren’t actually modified in any way by the shift/rotate circuit so, to keep the wiring shorter, values are fed directly from the W register. If you look at the register circuit board you can see the two brown wires leading up from bits 7 and 0 to the carry out selector.

The final option for the carry output is an explicit on/off/inverted value. If you’ve read my article about Adding ADC, SBC, INC & DEC Operations To Ben Eater’s ALU you’ll know that this circuit has the ability to feed an explicit zero (for DEC and ADD), one (for INC) and inverted carry flag (for SBC).

So all I need to do is feed this output back as a potential input to the carry flag.

The only thing left to do is to select a suitable source for the carry flag.

The ALU as a whole evaluates every possible output and has a 74LS245 bus transceiver for each possible output. The control logic sends an enable signal for the appropriate value to be output to the bus. I.e. for an addition or subtraction the ‘245 for the adder will be enabled. For an AND the ‘245 for the AND will be enabled, and so on for OR, XOR, left shift/rotate and right shift/rotate.

We can reuse those signals to select our carry out source. In programming terms we need a case statement:

on adder_read: use adder_carry_out on left_read: use left_carry out on right_read: use right_carry_out etc...

We might think of the using something like the 74LS153 Data selector/multiplexer which selects one of four possible inputs as the output (as used in the shift/rotate circuit) but this chip uses a two bit binary input to select a source and we have four separate selection signals.

How about using AND gates? Have a look at the truth table for an AND gate with the inputs renamed:

Select Signal Output 0 0 0 0 1 0 1 0 0 1 1 1

If select is 0 the output will always be 0. If select is 1 the output is the same as the signal input.

Extending this to multiple sources with a separate AND gate for each source then, as long as we’re only sending one select signal at a time, every AND gate will be outputting a 0 except the selected gate which will only be outputting a 1 if it’s signal input is one:

OutputA OutputB OutputC OutputD Output 0 0 0 0 0 (Nothing select or selected signal is 0). 0 0 0 1 1 0 0 1 0 1 0 1 0 0 1 1 0 0 0 1

It should be easy to see that our final output is the result of ORing the outputs of the four AND gates.

But the ‘245 uses an inverted enable signal so these signals are also inverted. Thus we need to select a value based on whichever signal is low. This is just as easy to do but harder to understand. In inverted logic an AND gate becomes and OR gate, and an OR gate becomes an AND gate.

We need to OR each signal with each potential value. The OR gate outputs will normally be high (because the select/enables, when off are high). When a select/enable becomes low the OR gate outputs the signal (the potential carry value).

So the final output will be high unless the selected signal is low: an AND gate.

So the circuit needs four OR gates, one for each signal, plus an AND gate to combine the four outputs. But given my lack of space and thrill of playing with diode logic I’ve used a diode AND gate to do this, and here’s the circuit:

In the passages above I glossed over the selector for the fourth carry output value. Remember this is the explicit on/off/invert value.

I also want my AND/OR/XOR operations to clear the carry flag. They’re already affecting the not-zero flag and, because the flags register writes all four flags at the same time then <i>something</i> will be going into the carry flag and we may as well make this something which could be useful to the programmer.

I chose to select by fourth carry value when any of the AND, OR or XOR ‘245 bus transceivers is enabled and added a little hack to use one of those signals for the explicit carry on/off/invert operations. This means that when to do a carry on/off/invert one of the logic outputs will also be writing to the bus but we just need to make sure that nothing else is using the bus at the same time.

Again those enable signals are inverted. To get an inverted select signal when any of them is active needs and AND gate. Again I didn’t have any board space for an AND gate and used one built with diodes.

On the physical boards you can see these diodes next to each of the ‘245s in the logic section on the left hand side of the bottom three boards.

And that epic post wraps up the flags section of the ALU. Next time I’ll move back to the beginning to describe the ALU registers, adder and logic circuits, all of which are either almost identical to Ben Eater’s originals or refreshingly simple to explain.

]]>So, why would I want to build logic circuits with diodes instead of ‘proper’ logic ICs? My answer to that is simply one of space. Building processors and computers on breadboards requires a lot of gates which means a lot of chips. And using a lot of chips takes up a lot of space. Sometimes I need just a single gate but when doing this with chips I have to add a whole chip. Sometimes adding an extra chip would mean a module expanding onto an extra breadboard.

And, I’m not going to lie, doing something in a different and unusual way is always fun.

Let’s take a look at how diode logic works starting with the easiest to understand – a diode OR gate.

Consider how we use a standard OR gate. A and B are outputs from some arbitrary TTL ICs. Z is an input to an arbitrary TTL IC. If A or B (or both) is high then the output at Z will be high.

We might naively assume that the OR gate itself is unnecessary. If A is high then surely Z will be high? Except, of course, that if B is low then the current from A will ‘sink’ into B as our logic chip dies in a puff of smoke.

But what if there a way to stop the current flowing back into B? We can easily do that with a diode. Now when A is high the only place it can flow to is into Z.

And to fix the identical issue with current from B flowing back into A we’ll also add a diode to A’s output. So now, when A is high current flows into Z. When B is high current flows into Z. When they’e both high current flows into Z.

But what happens when neither is high? We might innocently assume that when both A and B are low (i.e. at zero volts) then Z will also be at zero volts. In reality Z is actually floating and, as with any floating input, we can’t determine what the input value is.

Why is this? Well, we tend to think of TTL outputs as being … outputs. In reality when they are high they output, but when they are low they’re actually inputs connected to ground. Any stray voltages ‘hanging around’ their outputs will, like a black hole, get sucked in resulting in the zero volt ‘low’ output.

But the diodes here prevent any current flowing into the outputs and Z floats.

In the 74LS logic that I’m usually using for breadboarding inputs normally float high. Although that’s not guaranteed and we’d be foolish to depend on it.

What we need to do here is use a resistor to tie the output low. Now when A or B is high current flows though one or other diode and Z becomes high. When both A and B are low the resistor pulls Z low.

And we have our final working circuit. The only question left is what value of resistor to use. And at this point I have to admit that I’m not an electrical engineer and Google is not helping me to find a formula.

But since 10k is a good general purpose value for a a tie up/tie down resistor for 5V TTL then that’s where I’ve started and in most cases it works fine. This value didn’t work reliably for my 8-input OR gate in the ALU of my Bentium Pro computer and I dropped down to a 3.3k instead. So, for a hobbyist use, I’d say start at 10k and tweak if it doesn’t work reliably.

And, since I mentioned an 8-input OR gate here’s a circuit diagram for one. You can extend to as many inputs as you want by extending the circuit.

Talking about pull up/pull down resistors gives us a good starting point to talk about diode AND gates.

This circuit shows a circuit using a pull-up resistor. The resistor ensures that the circuit ‘defaults’ to 5V if the output from A is floating. Of course it never will be and it’s utterly pointless in this circuit…

…but when we add a diode it almost starts to find a purpose. Now when A is high current can’t flow through the diode. Input Z would be floating, except that the resistor keeps it high. When A is low the current from Z flows through the diode and Z goes low.

And with a second output we can turn this into an actual, useful circuit. If A is high current can’t flow through it’s diode to Z. If B is high current can’t flow through it’s diode to Z. In both cases Z floats and is pulled high by the resistor.

But if A is low then current can sink from Z through it’s diode and Z get’s pulled low. If B is low then current can sink through it’s diode and Z gets pulled low. In other words, if either A or B (or both) is low then Z is low. The only time when Z is high is when both A and B are high. Drawing that up as a truth table gives us:

A B Z Comments low high low Current flows into A and pulls Z low. high low low Current flows into B and pulls Z low. low low low Current flows into both A and B and pulls Z low. high high high Current can't flow from either A or B to Z. Z is pulled high by the resistor.

The rest of this article has probably given away what was going to happen, but look carefully and you’ll see this is the truth table for an AND gate!

Our diode AND gate is again taking advantage of the fact that a logic low is an input sucking in current. Look at Figure 9 again. Z ‘defaults’ to 5V because of the pull-up resistor but if A goes low it ‘sucks’ current through the diode to take Z low. Similarly with B going low. If both A and B are high then the diodes mean current can’t flow out of them to Z and Z stays pulled up.

As with the OR gate we can extend this to any number of outputs. This may actually help you to understand things. If ALL the outputs are high, then nothing flows through the diodes (in either direction) and Z is pulled high by the resistor. If ANY of the outputs goes low then current flows through the corresponding diode and Z goes low. I.e. Z will only be high when A and B and C and D and E and F and G and H are high.

As with TTL logic you can combine diode logic into more advanced circuits. This gives us Z = A and (B or C).

And here we have Z = (A and B) or C or D.

I’ll leave you to examine how these work in detail!

The limit to how far you can take such combinations is the voltage drop over the diodes which, over a few gates, will cause the voltages to fall outside the levels needed to accurately trigger the TTL inputs. There’s probably also a limit to how much you can actually understand such circuits.

For me, when breadboarding computers, I’ll probably stick to single gates largely due to the voltage drops that happen on breadboards already and which could affect the reliability of any circuits.

While all this is fun there is a major limitation to diode logic: you can’t use it to invert signals. And without inverters you can’t create NAND, NOR or exclusive OR gates which depend on them.

If you want to see some diode logic in action then the ALU of my Bentium Pro breadboard computer makes a fair bit of use of them for evaluating the flags.

]]>You could do this by expanding to a 16-bit design, but even with this you’d still be limited to the 16-bit size of the bus, registers and ALU. What if you wanted to be able to add and subtract arbitrarily large numbers? For that you need the ability to store numbers across multiple bytes/words, and you need an ALU which can handle those multi-byte numbers.

As you may remember from Ben’s computer if the result of a sum is too large for a single byte then you get a ‘carry’ out. To be able to do multi-byte arithmetic the ALU needs some way to feed that carry into the next calculation.

To be able to do this the ALU needs to have add with carry (ADC) and subtract with carry (SBC) operations^{1}. I also wanted my ALU to have increment (INC) and decrement (DEC) operations. As the names imply those operations either add one or subtract one from the operand and enable faster processing of, for example, loop counters^{2}.

First, lets have a reminder of how Ben’s ALU works. He has two registers, A and B^{3}, which feed into a pair of 74LS283 4-bit adders. An ADD operation is very simple: feed the two registers in and read the output.

A SUBtraction takes a little more work. We need to do a bitwise invert of the operand to be subtracted (the B register) and then add 1 (watch Ben’s video on two’s complement arithmetic). In other words the operation A – B becomes A + ~B + 1 (where ~ means a bitwise inversion).

Ben’s design does this with a pair of 74LS86 XOR gate ICs to do the inversion when the subtract control signal is high. He also uses the subtract control signal as the carry in to the adder ICs.

Now lets look at how we can extend that design to add our extra functionality.

First up is add with carry (ADC). We can think of this operation as A + B + c (where c is the carry flag).

To do this we simply need to use the current value of the carry flag as the carry in to the adder ICs. So we need a way to select whether the carry in comes from the carry flag or the subtract control signal.

Lets do this by adding an extra control signal which I’ll call ‘use_carry’.

Subtract with carry means that if the carry flag is set then we subtract one from the result of the calculation. In other words we’re calculating A – B – c. Rewriting this as an addition we get A + ~B + 1 – c.

Given that we’re already using the carry in for the + 1 section of that equation, how do we perform the – c? Do we have to add lots of extra circuitry or do an additional operation?

Actually no. Look at the 1 – c part of that equation and remember that c is either a 1 or a zero and you’ll see that all we’re doing is inverting c. If c is 1 then 1 – 1 = 0 and if c is 0 then 1 – 0 = 1.

It’s interesting to refer back to the ADD and SUB without carry operations. For ADD we set carry in to 0, for SUB we set carry in to 1. And we’re using the subtract signal for this. But you can also think of this as always passing in a zero but inverting it for a subtraction.

And this inverting if it’s a subtraction is exactly what we’re doing for our ADC/SBC with carry operations.

So, the next thing we need to add to our circuit is something to invert the carry in if we are doing a subtraction.

The use_carry control signal which we introduced above to select between the carry flag and the subtract signal now needs to select between the carry flag or an explicit zero, and whichever value is selected will then be inverted by the subtract signal to become the actual carry in.

The next operation I want to look at is the increment operation. This simply adds one to the A register.

We could implement this by setting the B register to one and performing an addition but how do we get a one into the B register?

Instead we can ‘hack’ this one. Clearing a register is easy so what if we clear the B register to zero and then use the carry in as the + 1? We’re basically doing an ADC but with the carry in set explicitly to one rather than coming from the carry flag.

Well, that was easy. All we need is to add a control signal to clear the B register and another control signal to send an explicit 1 to the carry in. We can do this with an additional control signal, which I’ll call ‘carry_set’. Our use_carry control signal will now be selecting between the carry flag and the carry_set control signal.

We just need to make sure our control logic sends the correct values for these three signals:

Operations use_carry carry_set ADD/SUB 0 0 ADC/SBC 1 (irrelevant) INC 1 1

And, finally, we get to our DEC operation. Can we do this the same way as our INC operation?

In mathematical terms we’re doing A – 0 – 1. Converted to an addition this becomes A + ~0 + 1 – 1. Simplifying that we get A + ~0 + 0. So we just need to set our carry in to zero. But remember that our carry in gets inverted if we’re doing a subtraction so we actually need to send a one as the carry so it will be inverted to the needed zero.

And, what are we doing for our INC operation above? Why, we’re sending a 1 as carry using the carry_set control signal.

So, in answer to the question, yes, we can do the DEC operation in exactly the same way we do the INC operation.

So we now need:

- A use_carry control signal.
- A carry_set control signal.
- Circuitry to select the carry in based on the above two control signals.
- A way to invert the carry in if we’re doing a subtraction.
- A clear_b control signal to clear the B register if we’re doing an INC or DEC operation.
- To pass in the correct control signals:

`Operation use_carry carry_set clear_b`^{4}
ADD/SUB 0 0 False
ADC/SBC 1 (irrelevant) False
INC/DEC 1 1 True

We can now start designing some silicon. The most complicated part of that is the circuitry to select which carry signal to use as input so let’s begin with that. We have two possible inputs, the carry flag or the carry_set input signal and we’re using the use_carry signal to select one or the other.

Let’s look at the truth table for an AND gate but we’ll call one of the inputs select and the other data.

select data out 0 0 0 0 1 0 1 0 0 1 1 1

Notice that if the select input is zero then we always get a zero out but if the select signal is one then the output is the same as the data input.

Using this fact gives us the circuit below. The inverter on the use_carry signal means that one or other of the AND gates will have a 1 as input as the select signal. Whichever AND gate has the 1 as the select signal will be outputting the data signal, and the other AND gate will be outputting zero. We then combine the outputs from the AND gates with an OR gate.

However, this circuit would mean using three ICs and I’d like to keep the chip count down if possible. Since any circuit can be built with NAND gates lets using them instead to get the circuit below.

Here I’ve used a NAND gate in place of the inverter and also swapped the AND gates to NAND gates. Now the selected NAND gate will be outputting it’s signal inverted while the unselected gate outputs a 1. If both the NAND gates are outputting a 1 then the final output needs to be a zero. If either is outputting zero (meaning the selected input is one) then the output needs to be zero and this is exactly the function performed by a NAND gate.

Rather conveniently this circuit uses four NAND gates which means that all I needs is a single 74LS00 IC.

The next step is to invert the output from the above circuitry if the subtract control signal is high. This simply needs a XOR gate. Pulling this all together gives us the complete circuitry for the carry in:

The photo above shows the adder circuitry on the Bentium Pro. The topmost breadboard is the flags in input processing, the middle board is the adder ICs, the bottom row is the registers. The highlighted area shows (from left to right): red LED showing carry flag state (illuminated); Orange LED for use_carry (not illuminated); Orange LED for carry_set (illuminated); 74LS00 quad NAND gate IC; 74LS86 quad XOR gate IC. The brown wire from here runs down to the carry input of the 74LS283 adder IC and the associated orange indicator LED (not illuminated). The other brown wire here is the carry output from the first adder IC.

The only other change we need is the ability to clear the B register on command. We’re using 74LS173 ICs for our registers which have an active high clear input (pin 13) and this input is independent of the clock signal, so all we need is an extra signal from the control logic wired directly to pin 13.

And after running through a tonne of explanation and detail it’s rather pleasing to see that we can get all this extra functionality from just five logic gates, two ICs and three control signals. It’s always nice when the universe is being kind.

UPDATE: I’ve corrected the three circuit diagrams above. In my originals the labels for the carry_flag and use_carry_flag inputs where switched. My apologies.

]]>As soon as I’d finished it I knew I wanted to make some upgrades. And when I looked at what upgrades I wanted I realised that my next project would be pretty much a completely new build.

I find the phrase ‘Ben Eater’s 8-bit breadboard computer’ rather long-winded so I’ve taken to referring to his machine as the ‘Bentium’. (Ben-tium/Pentium? Get it?) and I’m calling my upgraded version the ‘Bentium Pro’.

I have so far built the program counter, memory, registers, ALU and control logic, and I’m using Ben’s original clock module as is.

This is my first post about the project and I’m going to start off by giving an overview of the ALU. I may have got a little bit carried away with features as this little box of tricks can now perform twenty different operations…

- Add
- Subtract
- Add with carry
- Subtract with carry
- Increment (add 1)
- Decrement (subtract 1)
- And
- Or
- Exclusive or
- Rotate left
- Rotate left through carry
- Shift left
- Shift left with 1 input (to bit 0)
- Rotate right
- Rotate right through carry
- Shift right
- Shift right logical (preserve sign bit)
- Zero carry flag
- Set carry flag
- Complement carry flag

…not including the fact that it can act as a temporary register.

It also has a flags register containing four flags:

- Carry
- Overflow (for twos complement arithmetic)
- Non-zero (I wanted a zero flag but didn’t have space to invert it!)
- Sign (again for twos complement arithmetic.

And in addition to all the TTL chippery involved I’ve been playing with diode logic which helps save some board space but, if I’m honest, it just gives me some cool new tricks to play with.

Lets have a quick run through of what you’re seeing in the photos. I’ll run through from the top-most breadboard to the bottom-most looking at each chip from left to right.

But firstly it will be helpful to discuss the colour schemes for wires and LEDs. For the LEDs:

- Red = data.
- Yellow = outputting to the bus.
- Green = reading (usually from the bus) into (usually) a latch or register.
- Orange = other control signals and internal state.

And for the wires (for the module itself, the Arduino board uses a slightly different colour scheme! And the Dupont jumper wires are mostly there for the tester and using whatever I had that was long enough)

- Blue = data bus.
- Green = data internal to the module.
- Purple = control signal (positive logic), as opposed to…
- Pink = inverted logic control signal.
- Brown = other stuff internal to the module.
- Red & Black = if you need these explaining you clicked on the wrong thing but congratulations for making it this far.
- Rainbow ribbon cable = data bus.

In case your getting worried, no, my ALU does not use an Arduino. This is just attached temporarily for testing. And, trust me, this thing takes a fair bit of testing. My current test quite runs through over 3,000 tests across all the different operations. And I don’t fancy doing that by moving Dupont wires around!

But, since you’re going to ask anyway, in addition to the Arduino Nano there’s a 74LS245 bus transceiver for writing to and reading from the bus and a pair of 74HC595 shift registers for sending input and control signals.

for sending input and control signals.

Pin A0 is used for sending the clock signal and pins A1 to A4 are used to read the flags register.

On the left we have a 74LS245 (I’m using 74LS logic throughout so I’ll shorten stuff from now on…) which is buffering the bus to a set of diodes which are calculating the non-zero flag.

Next is a ’32 OR gate which selects one of four sources to use to set the carry flag value. The possible sources are left shift/rotate, right shift/rotate, adder, and the carry input being sent to the adder (which allows it to do the zero/set/complement carry functions). An OR gate is used because the control signals are inverted (pink wires) meaning it is equivalent to an AND gate. This then uses a diode logic AND gate which is equivalent to a positive logic OR gate. Not complicated at all then!

Then we have the ‘173 flags register itself.

Beyond the indicator LED’s is a ’00 NAND gate which selects a carry signal to input to (mainly) the adder. The possible inputs here are: use the carry flag; input a zero; input a one. This (along with the subtract signal) is what makes all those different maths operations possible.

The final chip is a ’86 XOR gate. The top half is calculating the overflow flag (with the help of a diode AND gate using the resistor and a pair of diodes mostly hidden under wiring). The bottom half inverts the carry both into and out of the adders when we’re doing a subtract operation. The output of the input side also feeds back as a possible input to the carry flag for those zero/set/complement carry operations.

This is works exactly the same as Ben’s original. A ‘245 transceiver for bus output, a pair of ‘283 4-bit adders and a pair of ’86 XOR gates to invert the second input when doing a subtraction.

The LED on the far right displays the subtract control signal and the orange one to it’s left indicates the carry input to the adders.

I realise you’re probably getting bored by now so I’ll speed through this board. A pair of registers (called W and Z) equivalent to Ben’s A and B registers except that these are exclusively for use as inputs to the ALU. Each register using a pair of ‘173s.

Note that these are input only but the W register can also be used as a temporary register when needed by the control logic (it’s not available for direct use by the programmer). This will be needed by the CALL subroutine opcode. (Did I mention the Bentium Pro will have a stack and the ability to use subroutines?).

The Z register has it’s own clear signal (hence the orange LED). This is needed for the increment and decrement operations. These work by zeroing the Z register and manipulating the carry input to get the +1 or -1.

(I genuinely intended to speed though this but there was more to talk about than I realised. Sorry).

The three leftmost chips on each board are doing, from top to bottom, AND, OR and XOR operations. There’s a ‘245 transceiver for output and a pair of ’08, ’32 and ’86s for each of the operations.

Notice on the left of each board is another diode attached to the enable inputs of the ‘245 transceivers. This is yet more diode logic. Another AND gate (which is actually an inverted logic OR gate) to select a carry output.

This means each of these operations will clear the carry flag (with the correct carry and subtract input signals). I’ll also be using one of these operations to do the zero/set/complement carry opcodes which saves a control signal and saves me having to have a fifth selector for the carry flag output.

Boards 5 and 6 here are left and right shift/rotate respectively. This is very simple with the data wires being directly connected to a ‘245 transceiver but one pin to the left or right of where they began.

The spare pin at the end is fed in from board 4. The chip here is a ‘153 twin 4 to 1 multiplexer. This allows the ALU to select one of four possible inputs for each of those spare shift/rotate input pins.

The control signals for this, by the way, are shared with those for the carry selection inputs because my control logic is running very short of control lines!

If you made it through that lot I congratulate you. I’ve tried to keep this fairly shortish which means I’ve had to gloss over a fair bit of how everything works. I’m planning some follow-up posts with more detail but if there’s anything you’re especially interested in then I’d love to hear your feedback.

You can also comment if you’d rather I moved on to the rest of the computer design (so far), or if you want to see me plug the ALU into the control logic to see if it does, actually work.

Or, to be honest, since this blog is brand new, any kind of feedback to let me know this is of interest to anybody would be great. Until next time…

]]>I set off in search of an alternative. At first I looked for some kind of driver chip which could directly convert a 4-bit binary input into the needed outputs for a 7-segment display. These are available in decimal but a little searching showed there may be some ICs around which can do it but they’re all obscure, no longer manufactured and difficult to track down.

So that idea was a no go. But was there any type of display which could take a 4-bit input and display a hex output? After much searching and a fair few dead ends I managed to track down the Broadcom/Avago HDSP-0762 and it’s sisters. Still in production and widely available they run off a standard 5-volt TTL signal, take a 4-bit binary TTL input and have a couple of other features to boot. The only downside being a hefty price tag. But lets take a look at these displays and how they work.

As you can see in the photo they are pleasingly different to the 7-segment LED displays we’re all used to, using an array of pixels to display each digit, with the result that the numbers and letters they display are a little more refined than we’re used to. The shapes of the numbers are a little more rounded and all of the letters are clearly uppercase with none of the ugly compromises you get from a 7-segment display.

The HDSP-0762 is the standard red hexadecimal version. There are also versions to display decimal and +/-1 indications, as well as high-intensity red, yellow and green.

Let’s look at the data sheet to see how to connect these up. The decimal and +/-1 versions behave slightly differently. For the hexadecimal version pins 7 and 6 are the 5 volt and ground connections respectively. Pins 1, 2, 3 and 8 are binary inputs. Input 1 (pin 8) is for the least significant bit, followed pins Input 2 (pin 1), 3 (pin 2) and 4 (pin 3). I’ll discuss pins 4 and 5 in a moment.

In my example circuit I’m using two of the displays, and you can see they nestle nicely next to each other. Both sets of binary inputs are connected to a DIP switch which either connects them to ground or leaves them floating. Obviously for a working circuit you’d want to drive them at 5V or use pull up resistors but I’m using the fact the inputs float high to save some wiring.

On the left hand display pins 4 and 5 are hard wired to ground. On the right hand display I’m using jumpers so you can see the behaviour of these pins.

You can’t see it in a photo but as I change the inputs the display updates to reflect the changes. These really are the prefect displays for showing binary numbers!

Moving back to pins 4 and 5, pin 4 is called the ‘blanking control’ If it is low the display is illuminated, if high the display is off. (On the decimal versions of the display this pin controls the display of the decimal point).

Pin 5 is the ‘Latch enable’. The chip actually contains a memory, or latch, to store the input. Whilst the pin is connected low it stores the current input value into the latch, and updates the latch if the input value changes. When the pin is high the latch retains the stored value remains unchanged if the binary inputs change. This feature means we could, for instance, create an output to show the value on a bus by directly connecting a couple of these to the bus and simply pulsing the ‘latch enable’ input when we wanted to see the current bus value. Very simple.

One other thing to note is that the ‘latch enable’ and ‘blanking control’ operate entirely separately. If the blanking control is on and the latch enable is off you can change the input values but the display remembers the last latched value. With the display off (blanking control on) you can still update the value in the latch and only have it displayed when the blanking control returns to off. And even if the input value has changed the display remembers the value from when the ‘latch enable’ signal was active and displays this when the display is re-enabled rather than the current value on the input pins.

I mentioned earlier that these displays are expensive. The HDSP-0762 model I’m using here costs over $30 for a single digit at the large electronics websites. I’ve seen prices on ebay which are more than double than, however I have tracked down an ebay seller (see below) selling two of then for about $30, and this is the seller from which I bought mine.

If purchasing bear in mind that there are a number of similar models so take care that you get the correct one.

Some of the following are affiliate links, meaning I earn a small percentage of anything you buy via the link. This helps to pay for running the blog. These links are marked “(Aff)”.

**HDSP-0762 Hexadecimal display**

Ebay (Aff) the seller I mention above selling two for about $30 and whom I bought mine from. – Ebay (Aff) Other sellers. – Amazon (Aff) – Mouser