Skip to main content

Common Circuit Components

Just as a complicated piece of software is never written from scratch entirely from the most basic program statements, a complicated hardware design is not approached purely at the gate level. Where a programmer will break the task into a hierarchy of objects and functions, relying on familiar idioms and existing code from program libraries to avoid reinventing the wheel, a hardware designer will use a hierarchy of functional blocks, relying on familiar patterns and existing libraries of subcircuits.

Adders

We have already seen one of these common componentsone of the sample circuits seen earlier is known as the half adder. Here it is again:

Circuit diagram for s=(a OR b) AND NOT (a AND b) and c=a AND b

If aa and bb represent one-bit binary numbers, then ss is their one-bit sum and cc is the carry into the next bit. For example, when aa and bb are both 1, ss is 0 and cc is 1; in binary, this says 1+1=101+1=10. We may represent this block in a circuit diagram with an appropriately named box:

Symbol for a half adder

It is called a half adder because, when you are adding multiple columns of bits, it only does half the work: it adds the two bits for a column, but it doesn't add in the carry from the next smaller column. A full adder takes three inputs: aa and bb, plus the incoming carry, cinc_\textit{\scriptsize in}. The outputs are ss, the sum that stays in the column, plus the outgoing carry to the next column, coutc_\textit{\scriptsize out}. We may build a full adder out of two half adders by first adding aa to bb, then adding cinc_\textit{\scriptsize in}; since the highest total in a full adder is three (11), we will never have a carry out of more than one of the half adders, so the resulting coutc_\textit{\scriptsize out} is just the OR of the two half adder carries. Here is the circuit with its block symbol and its truth table:

Circuit diagram for a full adder

abcincouts0000000101010010111010001101101101011111\begin{array}{ccl|rc} a & b & c_\textit{\scriptsize in} & c_\textit{\scriptsize out} & s\\ \hline 0 & 0 & 0 & 0 & 0\\ 0 & 0 & 1 & 0 & 1\\ 0 & 1 & 0 & 0 & 1\\ 0 & 1 & 1 & 1 & 0\\ 1 & 0 & 0 & 0 & 1\\ 1 & 0 & 1 & 1 & 0\\ 1 & 1 & 0 & 1 & 0\\ 1 & 1 & 1 & 1 & 1 \end{array}

Given a full adder, we may construct multiple-bit adders by cascading them, with the carry from each column feeding into the next. Here, for example, is a four-bit adder; the inputs are a3a2a1a0a_3a_2a_1a_0 and b3b2b1b0b_3b_2b_1b_0, plus an incoming carry cinc_\textit{\scriptsize in} to column 0 (the one's column), and the outputs are s3s2s1s0s_3s_2s_1s_0, plus a carry from column 3 (the eight's column), coutc_\textit{\scriptsize out}:

Circuit diagram for a four-bit adder

One of the exercises below explores whether this is a good design. Here is a collection of CircuitVerse circuits where you can explore these adders:

Enabling Input

A common pattern in logic circuits is to use the AND gate to "enable" (or disable) some signal. For example, in the half adder, the sum output, ss, is true when one of the inputs is true (a+ba+b), except it is disabled when there is a carry (both are true, aba\land b). For another example, suppose we have a circuit which is supposed to compute one of two functions, either ff or gg, depending on a "select" input; the circuit might look like this:

Circuit diagram selecting the output of one of two subcircuits

When select is 0, the output is computed by ff; when it is 1, the output is computed by gg.

The idea of selecting from two signals may be generalized to using a kk-bit input to select from one of up to 2k2^k signals; the result is known as a multiplexer (often abbreviated MUX). For example, with two select lines, s1s0s_1s_0, you can choose one of four inputs: a00a_{00}, a01a_{01}, a10a_{10}, or a11a_{11}. Each input is enabled by an appropriate combination of the select lines and their complements, then all four possibilities (of which at most one may be true) are combined with OR. Here is the circuit and its common symbol:

Circuit diagram and symbol for a multiplexer

Note the similarity of the multiplexer circuit to the layers of the sum-of-products circuit from the Circuit Simplification section. If we view the input lines aija_{ij} as the enabling inputs, then a multiplexer gives a direct way of implementing a truth table: hard-wire the input lines to 0 or 1 according to the corresponding entries in the truth table, then use the select lines to choose the desired row to send to the output. For example, if a01a_{01} and a10a_{10} are both tied to 1, while a00a_{00} and a11a_{11} are 0, then the output of the multiplexer will be the exclusive-OR of s1s_1 and s0s_0.

The opposite of a multiplexer is a demultiplexer (DEMUX). It takes one input signal plus kk select lines, and delivers the input signal to one of 2k2^k output lines. A special case is known as a (kk-bit) decoder: if the input signal is fixed at 1, then the decoder will send a 1 to exactly one of its output lines. Alternately, a demultiplexer can be viewed as a decoder with an "enable" input, where the selected output line will be 1 only if the enabling input signal is 1. Here is the common symbol for a four-line demultiplexer:

Circuit symbol for a demultiplexer

The implementation of this circuit is left as an exercise.

CPU Fragment

As an application of adders, multiplexers, and demultiplexers, here is a fragment of a simple CPU design:

The four 8-bit inputs on the left represent the incoming values from four machine registers, and the four 8-bit outputs on the right represent the new value to be stored in one of the registers (the other three outputs show all zeros and should be ignored). The 9-bit input at the top represents a machine instruction, which specifies two input registers (the first two pairs of bits) and an output register (the last pair of bits), along with an operation code (a 3-bit control signal). The operation code is used to select which operation is performed by the ALU (arithmetic and logic unit) device, which in this implementation has seven different operations it can perform. For example, when the opcode is 000, it computes the bitwise-AND of its inputs, while when the opcode is 010 it adds the inputs. The ALU itself is a combination of an 8-bit adder and some other circuits performing various logical operations, with some additional enabling circuitry to choose which subcircuit will have its output selected to be the result of the ALU.

Divide-and-Conquer Design

See Sections 13.57 of Aho & Ullman.

Exercises

  1. Compute the total gate delays for a half adder, a full adder, and a four-bit cascaded adder as described in this section. The total delay is the maximum number of gate delays between any input signal changing and all output signals stabilizing to reflect the changed input.

    Answer

    For the half adder, it takes only one gate delay for the Carry output to stabilize, but three gate delays for the Sum output. Therefore, when two half adders are connected into a full adder, it will take six gate delays for the outputs to fully stabilize (although the Carry is correct after only five delays).

    In the cascaded adder, each successive unit adds two gate delays to incorporate the Carry coming in and stabilize on the Carry going out; an additional gate delay is required before the Sum is finished and stable. Therefore, the total delay for the four-bit adder is 5+2+2+3=125+2+2+3=12 gate delays, with the longest path going from a0a_0 and b0b_0 to s3s_3.

  2. Draw the circuit diagram for an implementation of a four-line demultiplexer.

    Answer
  3. A parity bit generator is a circuit that takes some number of lines of input and produces one output which is 0 if an even number of the inputs are 1, and 1 if an odd number of the inputs are 1. If the input bits are transmitted along with the generated parity bit, then a recipient can check whether any single bit was mis-transmitted by ensuring that the total number of 1 bits received is even. A two-input parity bit generator is just the exclusive-OR circuit, whose common symbol is:

Circuit symbol for exclusive OR

Give an implementation of a two-input parity bit generator using only NAND gates, and then show how to use XOR gates to build an eight-input parity bit generator.

Answer

The XOR operation is computed by pq=(¬pq)(p¬q)p\oplus q=(\lnot p\land q)\lor(p\land\lnot q). Using the NAND operator (\uparrow) and De Morgan's laws, this is equivalent to (¬pq)(p¬q)(\lnot p\uparrow q)\uparrow(p\uparrow\lnot q):

If we split the inputs to a 2k2k-input parity bit generator into two groups (each of size kk, although the following argument doesn't depend on the groups having the same size), then the total number of 1 bits will be the sum of the 1 bits in each group. The only way for the sum of two numbers to be odd is if one is odd and the other is even. This means that if we can compute the parity bit for each group, then the overall parity bit is just the XOR of those two parity bits Therefore, we may construct an eight-input parity bit generator by cascading XOR gates as follows:

  1. The opposite of a decoder is an encoder: given 2k2^k input lines, the output will be a kk-bit binary number representing which input is 1. In case more than one input line is 1, the output will give the highest such line number; this is known as a "priority encoder." For example, when k=3k=3, if lines a1a_1, a4a_4, and a5a_5 are all 1, while the rest are 0, then the output will be 101 (5 in binary). If no input line is 1, then the output will be 000. There is one additional output line, gg (the "group" signal) that will only be 1 if at least one of the inputs is 1; this allows us to tell the difference between no input and only line a0a_0 being 1.

Give a truth table for a four-input (k=2k=2) priority encoder, then draw a circuit diagram that implements it.

Answer
a3a_3a2a_2a1a_1a0a_0e1e0e_1e_0gg
0000000
0001001
0010011
0011011
0100101
0101101
0110101
0111101
1000111
1001111
1010111
1011111
1100111
1101111
1110111
1111111

Here is a circuit (drawn with the CircuitVerse combinational analysis tool):

  1. Show how to construct a 2k2k-input parity bit generator given a block that implements a kk-input parity bit generator.

    Answer

    See the answer to question 3 above.

  2. Show how to construct a 2k2k-input priority encoder given a block that implements a kk-input priority encoder.

    Answer

    If we apply a kk-input priority encoder to the first kk inputs to get a group signal g0g^0 and an encoded output ek10e10e00e^0_{k-1}\ldots e^0_1e^0_0, and another to the remaining kk inputs to get a group signal g1g^1 and encoded output ek11e11e01e^1_{k-1}\ldots e^1_1e^1_0, then the combined group signal is just g=g1g0g=g^1\lor g^0. If g1g^1 is true, then there must be a 1 in the second half of the inputs, and the binary number for the highest 1 line will be 1ek11e11e011e^1_{k-1}\ldots e^1_1e^1_0. However, if g1g^1 is false, then if there is a 1 it must be in the first half, and the binary number for the highest 1 line will be 0ek10e10e000e^0_{k-1}\ldots e^0_1e^0_0. Therefore the overall encoded output is given by ek=g1e_k=g^1 and ei=(g1ei1)(¬g1ei0)e_i=(g^1\land e^1_i)\lor(\lnot g^1\land e^0_i), for 0i<k0\le i<k.