Section7.1Combinational Logic Circuits¶ permalink
Combinational logic circuits have no memory. The output at any given time depends completely upon the circuit configuration and the input(s).
Subsection7.1.1Adder Circuits¶ permalink
One of the most fundamental operations performed in the CPU is to add two bits. We begin with two definitions. (The reason for the names will become clear later in this section.)
 Half Adder

A combinational logic device that has two 1bit inputs, \(x_{i}\) and \(y_{i}\text{,}\) and two outputs that are related as shown by the truth table:
\(x_{i}\) \(y_{i}\) \(Carry_{i+1}\) \(Sum_{i}\) \(\binary{0}\) \(\binary{0}\) \(\binary{0}\) \(\binary{0}\) \(\binary{0}\) \(\binary{1}\) \(\binary{0}\) \(\binary{1}\) \(\binary{1}\) \(\binary{0}\) \(\binary{0}\) \(\binary{1}\) \(\binary{1}\) \(\binary{1}\) \(\binary{1}\) \(\binary{0}\) where \(x_{i}\) is the \(i^{th}\) bit of the multiple bit value, \(x\text{;}\) \(y_{i}\) is the \(i^{th}\) bit of the multiple bit value, \(y\text{;}\) \(Sum_{i}\) is the \(i^{th}\) bit of the multiple bit value, \(Sum\text{;}\) \(Carry_{i+1}\) is the carry from adding the nextlower significant bits, \(x_{i}\text{,}\) \(y_{i}\text{.}\)
 Full Adder

A combinational logic device that has three 1bit inputs, \(Carry_{i}\text{,}\) \(x_{i}\text{,}\) and \(y_{i}\) and two outputs that are related as shown by the truth table:
\(Carry_{i}\) \(x_{i}\) \(y_{i}\) \(Carry_{i+1}\) \(Sum_{i}\) \(\binary{0}\) \(\binary{0}\) \(\binary{0}\) \(\binary{0}\) \(\binary{0}\) \(\binary{0}\) \(\binary{0}\) \(\binary{1}\) \(\binary{0}\) \(\binary{1}\) \(\binary{0}\) \(\binary{1}\) \(\binary{0}\) \(\binary{0}\) \(\binary{1}\) \(\binary{0}\) \(\binary{1}\) \(\binary{1}\) \(\binary{1}\) \(\binary{0}\) \(\binary{1}\) \(\binary{0}\) \(\binary{0}\) \(\binary{0}\) \(\binary{0}\) \(\binary{1}\) \(\binary{0}\) \(\binary{1}\) \(\binary{1}\) \(\binary{0}\) \(\binary{1}\) \(\binary{1}\) \(\binary{0}\) \(\binary{1}\) \(\binary{0}\) \(\binary{1}\) \(\binary{1}\) \(\binary{1}\) \(\binary{1}\) \(\binary{1}\) where \(x_{i}\) is the \(i^{th}\) bit of the multiple bit value, \(x\text{;}\) \(y_{i}\) is the \(i^{th}\) bit of the multiple bit value, \(y\text{;}\) \(Sum_{i}\) is the \(i^{th}\) bit of the multiple bit value, \(Sum\text{;}\) \(Carry_{i+1}\) is the carry from adding the nextlower significant bits, \(x_{i}\text{,}\) \(y_{i}\text{,}\) and \(Carry_{i}\text{.}\)
First, let us look at the Karnaugh map for the sum:
There are no obvious groupings. We can write the function as a sum of product terms from the Karnaugh map. \begin{align} Sum_i(Carry_i,x_i,y_i) &= Carry_i' \cdot x_i' \cdot y_i + Carry_i' \cdot x_i \cdot y_i'\notag\\ &\quad +\ Carry_i \cdot x_i' \cdot y_i' + Carry_i \cdot x_i \cdot y_i\label{eqsum}\tag{7.1.1} \end{align} We can readily see three groupings on the Karnaugh map for carry:
These groupings yield a threeterm function that defines when \(Carry_{i+1} = 1\text{:}\) \begin{gather} Carry_{i+1} = x_i \cdot y_i + Carry_i \cdot y_i + Carry_i \cdot x_i \label{eqcarry}\tag{7.1.2} \end{gather} Equation (7.1.1) together with Equation (7.1.2) lead directly to the circuit for a full adder in Figure 7.1.1.
For a different approach, we look at the definition of half adder. The sum is simply the XOR of the two inputs, and the carry is the AND of the two inputs. This leads to the circuit in Figure 7.1.2.
Instead of using Karnaugh maps, we will perform some algebraic manipulations on Equation (7.1.1). Using the distribution rule, we can rearrange: \begin{align} Sum_i(Carry_i,x_i,y_i) &= Carry_i' \cdot (x_i' \cdot y_i + x \cdot y_i') + Carry_i \cdot (x_i' \cdot y_i' + x_i \cdot y_i)\notag\\ &= Carry_i' \cdot (x_i \oplus y_i ) + Carry_i \cdot (x_i' \cdot y_i' + x_i \cdot y_i)\label{eqmaybexor}\tag{7.1.3} \end{align} Let us manipulate the last product term in Equation (7.1.3). \begin{align*} x_i' \cdot y_i' + x_i \cdot y_i &= x_i \cdot x_i' + x_i \cdot y_i + x_i' \cdot y_i' + y_i \cdot y_i'\\ &= x_i \cdot (x_i' + y_i) + y_i' \cdot (x_i' + y_i)\\ &= (x_i + y_i') \cdot (x_i' + y_i)'\\ &= (x_i \oplus y_i)' \end{align*} Thus, \begin{align} Sum_i(Carry_i,x_i,y_i)&= Carry_i' \cdot (x_i \oplus y_i ) + Carry_i \cdot (x_i \oplus y_i)'\notag\\ &= Carry_i \oplus (x_i \oplus y_i)\label{mrow141}\tag{7.1.4} \end{align}
Similarly, if we ignore the two overlapping groupings on the Karnaugh map that gave us Equation (7.1.2), we get:
to give the equation: \begin{align} Carry_{i+1}&= x_i \cdot y_i + Carry_i \cdot x_i' \cdot y_i + Carry_i \cdot x_i \cdot y_i'\notag\\ &= x_i \cdot y_i + Carry_i \cdot (x_i' \cdot y_i + x_i \cdot y_i')\notag\\ &= x_i \cdot y_i + Carry_i \cdot (x_i \oplus y_i)\label{eqfullcarry}\tag{7.1.5} \end{align} Notice that the first product term in Equation (7.1.5), \(x_i \cdot y_i\text{,}\) is generated by the \(Carry\) portion of a halfadder, and that the exclusive or portion, \(x_i \oplus y_i\text{,}\) of the second product term is generated by the \(Sum\) portion. A logic gate implementation of a full adder is shown in Figure 7.1.3.
You can see that it is implemented using two half adders and an OR gate. And now you understand the terminology “half adder” and “full adder.”
We cannot say which of the two adder circuits, Figure 7.1.1 or Figure 7.1.3, is better from just looking at the logic circuits. Good engineering design depends on many factors, such as how each logic gate is implemented, the cost of the logic gates and their availability, etc. The two designs are given here to show that different approaches can lead to different, but functionally equivalent, designs.
Subsection7.1.2RippleCarry Addition/Subtraction Circuits¶ permalink
An $n$bit adder can be implemented with \(n\) full adders. Figure 7.1.4 shows a 4bit adder.
Addition begins with the full adder on the right receiving the two lowestorder bits, \(x_0\) and \(y_0\text{.}\) Since this is the lowestorder bit there is no carry and \(c_0 = 0\text{.}\) The bit sum is \(s_0\text{,}\) and the carry from this addition, \(c_1\text{,}\) is connected to the carry input of the next full adder to the left, where it is added to \(x_1\) and \(y_1\text{.}\)
So the \(^{th}\) full adder adds the two $i^{th}$ bits of the operands, plus the carry (which is either \(\binary{0}\) or \(\binary{1}\)) from the \((i1)^{th}\) full adder. Thus, each full adder handles one bit (often referred to as a “slice”) of the total width of the values being added, and the carry “ripples” from the lowestorder place to the highestorder.
The final carry from the highestorder full adder, \(c_4\) in the 4bit adder of Figure 7.1.4, is stored in the CF bit of the Flags register (see Section 8.2). And the exclusive or of the final carry and penultimate carry, \(c_4 \oplus c_3\) in the 4bit adder of Figure 7.1.4, is stored in the OF bit.
Recall that in the 2's complement code for storing integers a number is negated by taking its 2's complement. So we can subtract \(y\) from \(x\) by doing: \begin{align} x  y&= x + (\textrm{2's complement of}\ y)\notag\\ &= x + [(y\textrm{'s bits flipped}) + 1]\label{mrow146}\tag{7.1.6} \end{align} Thus, subtraction can be performed with our adder in Figure 7.1.4 if we complement each \(y_i\) and set the initial carry in to \(\binary{1}\) instead of \(\binary{0}\text{.}\) Each \(y_i\) can be complemented by XORing it with \(\binary{1}\text{.}\) This leads to the 4bit circuit in Figure 7.1.5 that will add two 4bit numbers when \(func = 0\) and subtract them when \(func = 1\text{.}\)
There is, of course, a time delay as the sum is computed from right to left. The computation time can be significantly reduced through more complex circuit designs that precompute the carry.
Subsection7.1.3Decoders¶ permalink
Each instruction must be decoded by the CPU before the instruction can be carried out. In the ARM architecture the instruction for adding the 32 bits in one source register to the 32 bits in another source register and leaving the 32bit result in a destination register is \begin{equation*} \binary{111100001000} xxxx dddd \binary{00000000} yyyy \end{equation*}
where “\(xxxx\)” specifies one source register, “\(yyyy\)” the other source register, and “\(dddd\)” specifies the destination register. The Control Unit must select the correct three registers based on these three 4bit patterns in the instruction. It uses a decoder circuit to perform this selection.
 Decoder
A device with \(n\) binary inputs and \(2^n\) binary outputs. Each bit pattern at the input causes exactly one of the \(2^n\) outpurs to equal \(\binary{1}\text{.}\)
So a decoder can be thought of as a device for converting an nbit input to one of \(2^n\) outputs. In some applications not all the \(2^n\) outputs are used. For example, Table 7.1.6 is a truth table that shows how a decoder can be used to convert a BCD value to its corresponding decimal numeral display.
\(x_{3}\)  \(x_{2}\)  \(x_{1}\)  \(x_{0}\)  ‘9’  ‘8’  ‘7’  ‘6’  ‘5’  ‘4’  ‘3’  ‘2’  ‘1’  ‘0’ 
\(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\) 
\(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\) 
\(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\) 
\(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\) 
\(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\) 
\(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\) 
\(\binary{0}\)  \(\binary{1}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\) 
\(\binary{0}\)  \(\binary{1}\)  \(\binary{1}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\) 
\(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\) 
\(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\) 
A \(\binary{1}\) in a “display” column means that is the numeral that is selected by the corresponding 4bit input value. There are six other possible outputs corresponding to the input values \(1010\)–\(1111\text{.}\) But these input values are illegal in BCD, so these outputs are simply ignored.
It is common for decoders to have an additional input that is used to enable the output. The truth table in Table 7.1.7 shows a decoder with a 3bit input, an enable line, and an 8bit (\(2^3\)) output.
\(enable\)  \(x_{2}\)  \(x_{1}\)  \(x_{0}\)  \(y_{7}\)  \(y_{6}\)  \(y_{5}\)  \(y_{4}\)  \(y_{3}\)  \(y_{2}\)  \(y_{1}\)  \(y_{0}\) 
\(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\) 
\(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\) 
\(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\) 
\(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\) 
\(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\) 
\(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\) 
\(\binary{0}\)  \(\binary{1}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\) 
\(\binary{0}\)  \(\binary{1}\)  \(\binary{1}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\) 
\(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\) 
\(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\) 
\(\binary{1}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\) 
\(\binary{1}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\) 
\(\binary{1}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\) 
\(\binary{1}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\) 
\(\binary{1}\)  \(\binary{1}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\) 
\(\binary{1}\)  \(\binary{1}\)  \(\binary{1}\)  \(\binary{1}\)  \(\binary{1}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\)  \(\binary{0}\) 
The output is 0 whenever \(enable = 0\text{.}\) When \(enable = 1\text{,}\) the \(i^{th}\) output bit is 1 if and only if the binary value of the input is equal to \(i\text{.}\) For example, when \(enable = 1\) and \(x = 011_2\text{,}\) \(y = 00001000_2\text{.}\) That is, \begin{align} y_3 &= x_2' \cdot x_1 \cdot x_0\notag\\ &= m_3\label{mrow148}\tag{7.1.7} \end{align} This clearly generalizes such that we can give the following description of a decoder:
For \(n\) input bits (excluding an \(enable\) bit) there are \(2^n\) output bits.
The \(i^{th}\) output bit is equal to the \(i^{th}\) minterm for the \(n\) input bits.
The \(3 \times 8\) decoder specified in Table 7.1.7 can be implemented with 4input AND gates as shown in Figure 7.1.8.
Decoders are more versatile than it might seem at first glance. Each possible input can be seen as a minterm. Since each output is \(\binary{1}\) only when a particular minterm evaluates to \(\binary{1}\text{,}\) a decoder can be viewed as a “minterm generator.” We know that any logical expression can be represented as the OR of minterms, so it follows that we can implement any logical expression by ORing the output(s) of a decoder.
For example, let us rewrite Equation (7.1.1) for the Sum expression of a full adder using minterm notation (see Section 5.3.2): \begin{gather} Sum_i(Carry_i,x_i,y_i) = m_1 + m_2 + m_4 + m_7\label{mrow149}\tag{7.1.8} \end{gather} and for the Carry expression: \begin{gather} Carry_{i+1}(Carry_i,x_i,y_i) = m_3 + m_5 + m_6 + m_7\label{mrow150}\tag{7.1.9} \end{gather} where the subscripts on \(x\text{,}\) \(y\text{,}\) and \(Carry\) refer to the bit slice, and the subscripts on \(m\) are part of the minterm notation. We can implement a full adder with a \(3 \times 8\) decoder and two 4input OR gates, as shown in Figure 7.1.9.
Subsection7.1.4Multiplexers¶ permalink
There are many places in the CPU where one of several signals must be selected to pass onward. For example, as you will see in Chapter 11, values to be added in the CPU may come from a CPU register, come from memory, or actually be stored as part of the instruction itself. The device that allows this selection is essentially a switch.
 Mutliplexer (MUX)
A device that selects one of multiple inputs to be passed on as the output based on one or more selection lines. Up to \(2^n\) inputs can be selected by \(n\) selection lines.
A 4way multiplexer requires 2 selection lines and could be implemented as shown in Figure 7.1.10.
The output is given by: \begin{gather} Output = s_0' \cdot s_1' \cdot w + s_0' \cdot s_1 \cdot x + s_0 \cdot s_1' \cdot y + s_0 \cdot s_1 \cdot z\label{mrow151}\tag{7.1.10} \end{gather} The symbol used for a multiplexer is shown in Figure 7.1.11.(a).
\(s_{1}\)  \(s_{0}\)  \(Output\) 
\(\binary{0}\)  \(\binary{0}\)  \(w\) 
\(\binary{0}\)  \(\binary{1}\)  \(x\) 
\(\binary{1}\)  \(\binary{0}\)  \(y\) 
\(\binary{1}\)  \(\binary{1}\)  \(z\) 