JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

The ALU: The Datapath's Calculator

Every add, subtract, compare, and bit-twiddle a processor performs flows through one block of logic at the heart of the datapath. Meet the arithmetic logic unit — what it computes, the status flags it whispers back, and why it is a calculator with no memory of its own.

Where the ALU sits, and what it is for

From the logic rung you can already build adders out of full adders, and from the ISA rung you know an instruction like 'add x5, x6, x7' is a contract: take the values in two registers, combine them, write the result back. The block that actually does the combining is the arithmetic logic unit, or ALU. Think of it as the datapath's pocket calculator — a single slab of combinational logic that takes two number inputs, plus a few control wires telling it which operation to perform, and produces one result. It is where 'compute something' physically happens.

Crucially the ALU is combinational, not sequential: it has no clock, no latches, no memory of what it did a nanosecond ago. Put two numbers and an operation code on its inputs, wait for the signals to settle through the gates, and the answer appears on the output. Change the inputs and the output follows immediately. That is exactly what we mean by a calculator with no memory of its own — it never remembers the last sum, it just keeps recomputing whatever is on its wires right now. Anything that must be remembered (the operands, the result) lives outside the ALU, in the register file that feeds it.

What an ALU actually computes

The 'arithmetic' half does what the name says: binary addition and binary subtraction, the bread and butter of every program — incrementing a loop counter, computing a memory address, taking a difference. The 'logic' half does bit-by-bit boolean work: AND, OR, XOR, and NOT applied to each bit position independently, the tools you use to mask, set, clear, or test individual bits. A typical ALU also performs comparisons (is a less than b?) and often shifts (slide all the bits left or right), though on many designs a separate shifter handles the latter.

All of these share a structure: compute every candidate result in parallel, then let a control code pick which one reaches the output. Picture a row of small circuits — an adder, an AND gate array, an OR gate array, a comparator — all chewing on the same two inputs at once, and a multiplexer at the end choosing one to pass through. The operation-select wires are the steering wheel; the data wires are the road. The ALU does not decide what to compute, it is told.

         a[n-1..0]   b[n-1..0]
              |          |
      +-------v----------v-------+
      |  add  and  or  xor  cmp  |   <- all compute in parallel
      +----+----+----+----+----+-+
           |    |    |    |    |
           +----+--MUX--+-+----+        <- ALUop selects one
                    |
                 result        flags: Z N C V

  ALUop=0010 -> result = a + b   (add)
  ALUop=0110 -> result = a - b   (subtract / compare)
  ALUop=0000 -> result = a & b   (and)
Sketch of an ALU: many operations run in parallel; the ALUop control wires steer one result out, and a few flag bits fall out as a by-product.

The flags: status the ALU whispers back

Alongside the numeric result, the ALU emits a handful of one-bit condition flags that describe the result without being part of it. The four classic ones are Zero (Z, set when every result bit is 0), Negative (N, a copy of the result's sign bit), Carry (C, set when an unsigned add overflowed the top or a subtract borrowed), and Overflow (V, set when a signed result no longer fits). These are computed almost for free as a side effect of the operation — the Zero flag, for instance, is just a big NOR over all the result bits.

Why bother? Because the flags are how arithmetic talks to control flow. When you write 'if a equals b', the machine subtracts a minus b and checks the Zero flag; 'if a less than b' reads the Negative and Overflow flags together. A branch instruction does not re-examine the numbers — it just consults the flags the previous ALU operation left behind. So the ALU is not only a calculator, it is the eyes of every decision the program makes.

How the ALU is told what to do

The operation-select wires do not appear by magic; they are produced by a small piece of logic called ALU control. When an instruction is decoded, the main control unit looks at the opcode and works out the broad intent — is this an arithmetic instruction, a load, a branch? It then hands the ALU control a compact hint, and the ALU control, sometimes also peeking at extra function bits in the instruction, produces the exact operation code the ALU needs. A load instruction, for instance, needs the ALU to add a base register to an offset to form an address, so the control logic quietly selects 'add' even though the programmer wrote a memory access, not a sum.

  1. The two source operands arrive on the ALU's data inputs, read out of the register file during the same clock cycle.
  2. ALU control places the operation code on the select wires — say, the pattern meaning 'subtract'.
  3. Signals ripple through the gates; after the worst-case delay (the critical path) the result and the flags settle to their final values.
  4. The datapath captures the result — into a register, or onward to memory — and may stash the flags for the next branch to read.

Notice the timing implication. Because the ALU is combinational, its slowest path — typically the adder's carry rippling all the way from the lowest bit to the highest — often sets a floor on how short a clock cycle can be. That is why so much engineering effort goes into making addition fast, the subject of the carry-lookahead adder later in this rung. A faster ALU can mean a faster clock, which loops right back to the iron law of performance you met earlier: shaving cycle time is one of only three levers on run time.

Honest limits, and what comes next

Be careful not to over-promise what one ALU does. A basic integer ALU handles add, subtract, the bitwise logicals, and comparisons in a single pass, but the harder arithmetic is deliberately not in it. Multiplication and division take many steps or much more hardware and usually live in separate units (the topic of a later guide), and floating-point — with its exponents and rounding — needs a whole floating-point unit of its own. The plain ALU is the fast, common case; the rare, expensive operations are handled elsewhere so the common path stays lean.

Keep one more honest line straight: the ALU is hardware that computes, but it does not interpret meaning. It will happily add two bit patterns whether you meant them as unsigned counts, signed numbers, or addresses — the bits go in, the bits come out, and the same adder serves all three readings. Meaning lives in the convention the program and ISA agree on, exactly as you learned with bit patterns earlier. The ALU is gloriously, deliberately dumb: it adds, it does not understand.

With this map in hand, the rest of the rung zooms into the pieces. The next guide opens up addition and subtraction and the carry-versus-overflow puzzle; the one after trades gates for speed with fast adders; then multiplication and division, where you will see why division is the slow child of arithmetic; and finally floating point, where the honest surprises (0.1 plus 0.2 is not exactly 0.3) come home to roost. The ALU you have just met is the stage on which all of that plays out.