How Does an ALU Combine Arithmetic and Logic Operations?
An arithmetic logic unit (ALU) is the core digital circuit inside a processor that performs both mathematical calculations and bitwise logical operations on binary numbers. Rather than building completely separate, isolated hardware for every individual instruction, an ALU combines shared logic gates, adders, and multiplexers so that a single circuit can switch between addition, subtraction, AND, OR, XOR, and other functions based on control signals.
The Role of Control Signals and Multiplexers
At the heart of an ALU's versatility is the multiplexer, often abbreviated as MUX. A multiplexer acts like a programmable railway switch: it takes multiple data inputs and uses a set of control bits—called the opcode or function select lines—to route only one of those inputs to the output.
In a typical design, the ALU receives two \(n\)-bit operands, \(A\) and \(B\), along with a control signal. Both the arithmetic unit and the logic unit may process \(A\) and \(B\) simultaneously, or specific sub-circuits may be enabled. The multiplexer at the output stage then selects which result is actually passed forward to the processor's registers or bus.
How Bitwise Logic Operations Work
Bitwise logic operations are the simplest part of the ALU because each bit position is completely independent of its neighbors. There is no carry or borrow between bits.
For an \(n\)-bit ALU, the logic stage consists of \(n\) identical 1-bit logic slices running in parallel. Each slice contains basic gates:
- AND (\(A_i \land B_i\)): Outputs \(1\) only if both input bits are \(1\).
- OR (\(A_i \lor B_i\)): Outputs \(1\) if at least one input bit is \(1\).
- XOR (\(A_i \oplus B_i\)): Outputs \(1\) if the input bits are different.
- NOT (\(\overline{A_i}\)): Inverts the input bit.
A small multiplexer inside each 1-bit slice uses the ALU's control bits to choose which gate's output represents the final logic result for that bit position.
How Arithmetic Operations Share Hardware
Unlike bitwise logic, arithmetic operations such as addition and subtraction require communication between adjacent bit positions through a carry bit. The foundational building block here is the full adder.
A full adder takes three 1-bit inputs—\(A_i\), \(B_i\), and a carry-in (\(C_{in}\))—and produces a sum bit (\(S_i\)) and a carry-out bit (\(C_{out}\)):
\[S_i = A_i \oplus B_i \oplus C_{in}\]
\[C_{out} = (A_i \land B_i) \lor (C_{in} \land (A_i \oplus B_i))\]
By chaining \(n\) full adders together, where the \(C_{out}\) of one stage feeds into the \(C_{in}\) of the next, the ALU forms a ripple-carry adder (or a faster carry-lookahead adder in modern CPUs).
Unifying Addition and Subtraction
An ALU does not need a separate subtractor circuit. Instead, it uses two's complement arithmetic to perform subtraction with the exact same adder hardware. To compute \(A - B\), the ALU inverts every bit of \(B\) and adds \(1\):
\[A - B = A + \overline{B} + 1\]
This is achieved by placing an XOR gate in front of each \(B_i\) input and connecting the other input
of the XOR gate to a Subtract control line:
- When
Subtractis \(0\), \(B_i \oplus 0 = B_i\), and \(C_{in}\) to the first adder is \(0\), performing \(A + B\). - When
Subtractis \(1\), \(B_i \oplus 1 = \overline{B_i}\), and \(C_{in}\) to the first adder is \(1\), performing \(A + \overline{B} + 1\).
Bringing Arithmetic and Logic Together
In a classic 1-bit ALU slice, the arithmetic and logic paths are combined into a single modular unit. The inputs \(A_i\) and \(B_i\) enter the slice, where they are fed into the logic gates (AND, OR, XOR) and the full adder simultaneously.
A 2-to-1 or 4-to-1 multiplexer at the end of the slice takes the outputs from the logic gates and the sum output (\(S_i\)) from the full adder. Depending on the control signals from the CPU's control unit, the multiplexer outputs either the chosen bitwise logic result or the arithmetic sum.
Status Flags
Beyond the \(n\)-bit result, the combined ALU also generates status flags that inform the processor about the outcome of the operation:
- Zero (Z): Set to \(1\) if all bits of the output are \(0\).
- Carry (C): Set to \(1\) if an arithmetic operation produces a carry-out from the most significant bit.
- Overflow (V): Set to \(1\) if a signed arithmetic result exceeds the range \([-2^{n-1}, 2^{n-1} - 1]\).
- Negative (N): Mirrors the most significant bit of the result in signed two's complement representation.
By stacking \(n\) of these 1-bit slices together and linking their carry lines, a classical computer creates a unified \(n\)-bit ALU capable of executing both arithmetic and bitwise logic efficiently on shared silicon.