15.3 Logic Unit: Bitwise AND, OR, XOR, NOT
Explain the role of the logic unit inside the ALU, describe what each bitwise operation is used for in real code, and explain how a function-select signal chooses among them.
The logic unit is the half of the ALU responsible for bitwise operations — AND, OR, XOR, and NOT — applied independently to every bit position of the operands, rather than the carry-propagating arithmetic performed by the adder/subtractor covered in Section 15.2. Because each output bit depends only on the corresponding input bit(s) at the same position, with no carry chain linking positions together, the logic unit is simpler and faster than the arithmetic unit, and it underlies an enormous range of everyday low-level programming idioms: bit masking, flag manipulation, and bit toggling all reduce directly to these four operations.
The Four Bitwise Operations
AND performs a bitwise logical AND between corresponding bits of the two operands — each output bit is 1 only if both corresponding input bits are 1. OR performs a bitwise logical OR — each output bit is 1 if either (or both) corresponding input bit is 1. XOR performs a bitwise exclusive-OR — each output bit is 1 if the corresponding input bits differ (exactly one is 1). NOT performs a bitwise complement on a single operand — every bit is inverted, 0 becomes 1 and 1 becomes 0.
Unlike the adder, none of these four operations involves any inter-bit carry propagation: bit position 3 of the AND result depends only on bit position 3 of each operand, completely independent of what happens at bit position 2 or bit position 4. This makes the logic unit's hardware simply N parallel single-bit gates (one AND gate, one OR gate, one XOR gate, and one NOT gate per bit position, for an N-bit-wide ALU), each combinational and delay-independent of the others — considerably simpler and faster than the arithmetic unit's carry chain.
• AND: output bit = 1 only if both input bits are 1 — used for masking (clearing) bits. • OR: output bit = 1 if either input bit is 1 — used for setting bits. • XOR: output bit = 1 if input bits differ — used for toggling bits and detecting differences. • NOT: inverts every bit of a single operand — used for forming complements (and feeding subtraction, per Section 15.2).
Function Selection and Everyday Uses
Just like the ALU's overall operation select, the logic unit uses a function-select signal (typically a 2-bit code for four operations) driving a multiplexer that picks which of the four parallel bitwise results reaches the logic unit's output. In many real ALU designs, this logic-unit multiplexer is itself one of the inputs to the ALU's top-level output multiplexer (alongside the arithmetic unit's result), with the overall ALUOp control signal deciding whether an arithmetic result or a logic result becomes the final ALU output.
Each bitwise operation maps to a specific, extremely common programming pattern. AND with a mask of 1s in specific positions and 0s elsewhere clears (zeroes out) every bit outside the mask while leaving masked bits unchanged — this is how software reads a specific field out of a packed status/control register. OR with a mask sets specific bits to 1 without disturbing others — used to enable specific flag bits. XOR with a mask toggles specific bits (flips each one to its opposite) — used for things like toggling an LED's on/off state or, doubled, for a classic value-swap-without-a-temporary-variable trick. NOT produces a bitwise complement, most commonly seen as a building block inside two's-complement negation (Section 15.2) or for inverting an entire mask before using it with AND.
• Function-select signal (e.g. 2 bits) chooses which of AND/OR/XOR/NOT reaches the logic unit output. • AND + mask → clear specific bits, read a specific field. • OR + mask → set specific bits. • XOR + mask → toggle specific bits. • NOT → bitwise complement, used standalone or as part of two's-complement negation.
Practical and Real-World Applications
Bitwise operations are ubiquitous in embedded systems and systems programming: reading and writing individual bits of a microcontroller's hardware status/control registers, packing multiple small flags into one word of memory, implementing simple encryption/checksum algorithms (XOR is a favorite there), and computing parity or masks for network protocols all rest directly on the logic unit's four operations. At the CPU level, the logic unit's output also frequently feeds directly into the ALU's Zero flag logic — testing whether an AND of a value against a mask produced all-zero bits is a standard, fast way to test whether specific flag bits are clear.
Bitwise operation truth behavior
Every operation is applied bit-by-bit in parallel across the full operand width — there is no carry chain linking bit positions.
AND(a,b) = 1 only if a=1 AND b=1
OR(a,b) = 1 if a=1 OR b=1 (or both)
XOR(a,b) = 1 if a and b differ
NOT(a) = the inverted value of a
FuncSelect (2 bits) → chooses AND / OR / XOR / NOT for the whole N-bit operand pairCode Examples
ANDing the register with a mask that has 1s only in the three least-significant positions forces every other bit to 0, while passing through the masked bits unchanged — this isolates just the field of interest (here, value 110 = 6) from the rest of the packed register. Expected result: 0000_0110
AND with a mask clears every bit outside the mask, passing through masked bits unchanged.
XORing a value with a mask that has a 1 exactly where a bit should flip inverts only that bit position and leaves every other bit unchanged, since XOR with 0 is identity and XOR with 1 is inversion. This is the standard way to flip an individual flag or GPIO output bit without disturbing the rest of the register. Expected result: 0000_1000
XOR with a single-bit mask flips exactly that bit, leaving all others unchanged.
Status register = 1011_0110
Mask (read bits 2-0) = 0000_0111
Result = Status AND Mask
= 1011_0110
& 0000_0111
= 0000_0110Value = 0000_1010
Toggle mask (bit 1) = 0000_0010
Result = Value XOR Toggle mask
= 0000_1010
^ 0000_0010
= 0000_1000Important Rules
AND, OR, XOR, NOT are all bit-independent — no carry chain links adjacent bit positions.
AND + mask clears (zeroes) unmasked bits and reads/passes masked bits unchanged.
OR + mask sets masked bits to 1 without disturbing other bits.
XOR + mask toggles masked bits; NOT inverts every bit of a single operand.
A function-select signal chooses which bitwise operation's result reaches the logic unit's output.
Where the logic unit shows up
Embedded firmware reading and writing hardware status/control registers, packed bitfields in network protocol headers, simple checksum and XOR-based encoding schemes, and every high-level language's &, |, ^, and ~ operators all compile down directly to this same ALU logic unit.
Using OR when the intent is to clear specific bits (e.g., trying value | mask to zero out bits described by mask).
Use AND with the complement of the mask (value & ~mask) to clear specific bits — OR can only ever set bits to 1, never force them to 0.
OR's truth behavior is output=1 if either input bit is 1, so ORing with a mask can only turn bits on, never off; clearing specific bits requires ANDing with a mask that has 0s exactly where you want bits cleared (often built by NOTing a 'set' mask).
Which bitwise operation is used to clear (force to 0) specific bits of a value while leaving other bits unchanged? A. OR with a mask B. AND with a mask (0s where bits should clear) C. XOR with a mask D. NOT the entire value
B. AND with a mask (0s where bits should clear) — AND only outputs 1 where both operand bits are 1, so ANDing with a mask that has 0s exactly where bits should be cleared forces those positions to 0 regardless of the original value, while positions with a 1 in the mask pass through the original bit unchanged.
Why is the logic unit's hardware generally faster than the arithmetic unit's adder/subtractor for the same bit width? A. The logic unit uses a completely different number system B. AND, OR, XOR, and NOT are computed independently at each bit position with no carry propagation between bits, unlike an adder's carry chain C. The logic unit only operates on 1-bit operands D. Logic operations always run at a slower clock speed intentionally
B. AND, OR, XOR, and NOT are computed independently at each bit position with no carry propagation between bits, unlike an adder's carry chain — Because each output bit of AND/OR/XOR/NOT depends only on the input bit(s) at that same position, every bit position can be computed simultaneously with no dependency on neighboring bits — unlike an adder, where a carry must ripple (or be computed via look-ahead logic) from lower to higher bit positions, adding propagation delay.
Given Value = 1100_1010, write the mask and operation needed to (a) set bits 0 and 1 to 1 without disturbing other bits, and (b) clear bit 5 without disturbing other bits.
(a) OR with mask 0000_0011: Value | 0000_0011 = 1100_1011 — bits 0 and 1 are now set, everything else unchanged. (b) AND with mask 1101_1111 (all 1s except bit 5): Value & 1101_1111 = 1100_1010 & 1101_1111 = 1100_1010 (bit 5 was already 0 here, but the AND correctly forces bit 5 to 0 regardless of its prior value while leaving all other bits untouched).
Use OR with a mask that has 1s exactly where you want to set bits; use AND with a mask that has 0 exactly where you want to clear a bit and 1s everywhere else.