Part IIISingle-Cycle, Multi-Cycle, and Pipelined CPUs

The Control Unit

August 3, 2026·27 min read·intermediate

The single-cycle datapath of Chapter 25 sits inert without a control unit. The wires are in place, the functional units are wired together, but every multiplexer select, every memory enable, and every register…

The single-cycle datapath of Chapter 25 sits inert without a control unit. The wires are in place, the functional units are wired together, but every multiplexer select, every memory enable, and every register write needs a signal that says “on” or “off” at the right moment. The control unit is the block that decides what each instruction means and translates that meaning into the bit pattern of control signals that the datapath needs.

This chapter builds the control unit two ways. The first is hardwired, the dominant style in RISC processors and in every RV32I implementation. A purely combinational decoder reads the instruction’s opcode and function fields and emits the control signal vector for that instruction. The second is microcoded, the dominant style in early CISC processors and still present in modern x86. A small ROM holds a program (the microcode) that sequences each architectural instruction through one or more cycles of control signal vectors. Both styles are still in use, in different roles, in 2026. The chapter develops the truth table for the single-cycle RV32I control unit, traces the historical origin of microcode to Wilkes in 1951 [1], and explains why RISC-V uses hardwired control while modern x86 retains microcode for the most complex instructions.

01.What the Control Unit Must Decide

The complete single-cycle datapath of [fig:complete-datapath] contains roughly ten control signals. For each instruction class, the control unit must produce the correct value of each signal.

The signal inventory

Table 1. The control signals of the single-cycle RV32I datapath.

SignalWidthPurpose
RegWrite1 bitEnables the register file’s write port.
MemRead1 bitEnables a read from data memory.
MemWrite1 bitEnables a write to data memory.
ALUSrc1 bitSelects ALU source B (0 = rs2, 1 = imm).
ALUOp4 bitsSelects ALU operation.
WBSel2 bitsWriteback source (00 = ALU, 01 = MEM, 10 = PC+4).
Branch1 bitThe instruction is a conditional branch.
Jump1 bitThe instruction is an unconditional jump.
ImmSel3 bitsImmediate format (I, S, B, U, J).

The total is on the order of 15 bits of control signal per cycle. The control unit’s task is to compute these 15 bits from the 32-bit instruction word in each cycle.

The relevant instruction fields

Three fields of the instruction word carry all the information the control unit needs.

  • opcode (bits [6:0]). 7 bits. Identifies the top-level instruction class (OP, OP-IMM, LOAD, STORE, BRANCH, JAL, JALR, LUI, AUIPC, SYSTEM, MISC-MEM, etc.).

  • funct3 (bits [14:12]). 3 bits. Distinguishes instructions within an opcode class. For OP, funct3 chooses among ADD/SUB, SLL, SLT, SLTU, XOR, SRL/SRA, OR, AND. For LOAD, it picks LB, LH, LW, LBU, LHU.

  • funct7 (bits [31:25]). 7 bits. Used in OP-class instructions to distinguish ADD from SUB, SRL from SRA, and so on. The same bit positions also separate SRAI from SRLI in the OP-IMM shift instructions. Within the base ISA only funct7[5] varies, and the other bits are zero.

Out of the 32 bits in the instruction word, only 17 (opcode + funct3 + funct7) carry control-relevant information. The other 15 are immediate or register-specifier bits that flow into the datapath without passing through the control unit.

02.The Hardwired Control Unit

The hardwired approach implements the control unit as a single combinational block that maps opcode, funct3, and funct7 to the control signal vector.

The truth table

Walk through the instruction classes from Chapter 25 and tabulate the control signal values for each.

Table 2. Control signal values for nine RV32I instructions. X means don’t care.

InstrRegWrMemRdMemWrALUSrcALUOpWBSelBranchJumpImmSel
ADD1000ADDALU00X
SUB1000SUBALU00X
AND1000ANDALU00X
OR1000ORALU00X
ADDI1001ADDALU00I
LW1101ADDMEM00I
SW0011ADDX00S
BEQ0000SUBX10B
JAL100XXPC+401J

Read the table as a description of nine combinational functions of (opcode, funct3, funct7), one function per control signal.

From truth table to gates

Each output column of the truth table defines a boolean function of the input columns. Take MemRead as the simplest example. MemRead = 1 only when the instruction is a load. All loads have opcode 0000011. So MemRead = (opcode == 0000011), which is the AND of opcode[6:0] == 0000011, requiring seven literal comparisons.

For ALUOp, the function is more involved. The ALU operation depends on the opcode (different classes have different defaults) and on funct3 and funct7 (different OP instructions ask for different operations). A small two-level decode tree typically computes ALUOp:

  1. Stage 1 maps the opcode to a coarse ALU class. OP-IMM and LOAD and STORE all want ADD by default. OP wants “look at funct3 and funct7”. BRANCH wants SUB (so the zero flag tells the comparison result). JAL wants “don’t care”.

  2. Stage 2 reads funct3 and funct7 (when applicable) to choose among the ten possible ALU operations for OP-class instructions.

This two-stage approach is sometimes called the “main control” plus “ALU control” decomposition. The main control unit reads the opcode and emits a 2-bit ALUOp_class signal. A separate ALU control unit reads that signal plus funct3 and funct7 and emits the final 4-bit ALUOp.

Physical realization: PLA, ROM, or random logic

Three common implementations of the combinational decoder exist.

Random logic. The synthesizer maps each column of the truth table to an optimized network of AND, OR, NOT, XOR, and multiplexer cells from the standard cell library. The result is small but not very regular. Most modern RISC processors use this style because the EDA tools handle it well.

Programmable Logic Array (PLA). A PLA implements arbitrary sum-of-products logic as a regular two-level array. Inputs feed an AND plane that produces one product term per needed row. The product terms feed an OR plane that produces one sum per output. PLAs are regular, predictable in area and delay, and easy to lay out by hand. The 1980s ARM1, the MIPS R2000, and many academic CPUs used PLAs for control.

ROM lookup. The truth table is stored directly in a small ROM, indexed by the input bits. For a control unit with 17 input bits and 15 output bits, the ROM would have 217=131,0722^{17} = 131{,}072 entries of 15 bits each, which is \approx 250 KB. That is far too large for the use, so a pure ROM is impractical for the single-cycle RV32I control. Sparse ROM compression brings the size down by a factor of 100, but at the cost of an additional decoder stage.

03.The Microcoded Control Unit

The microcoded approach replaces the combinational decoder with a small CPU inside the CPU. A read-only memory (the microcode ROM) holds a program written in a special low-level language. Each entry of the ROM is a microinstruction that specifies the control signal values for one cycle. The microengine sequences the microinstructions, fetching one per cycle and applying its control signals to the datapath.

Wilkes’ 1951 motivation

Maurice Wilkes at Cambridge invented microprogramming in 1951 [1]. The motivation was simple. By 1951 the EDSAC computer had been in operation for two years. Wilkes observed that the random control logic that interpreted each machine instruction was difficult to debug, difficult to modify, and prone to errors. A small change in the instruction set required physically rewiring the control unit.

Wilkes proposed a different organization. Each machine instruction would be implemented as a short program (a microcode sequence) running on a simpler underlying engine. The microprogram would live in a fast, read-only memory. Changing the instruction set or fixing a bug in instruction execution would amount to changing the contents of that memory rather than rewiring the machine. Wilkes called the technique “micro-programming”, the stored routines “micro-programs”, and the individual steps “micro-operations”.

The idea took two decades to become mainstream. The IBM System/360 family, announced in 1964, was the first commercially successful microcoded architecture. The same architectural ISA was implemented across six models that differed in cost, performance, and physical size, all sharing one microcode source controlled by IBM. Customers could upgrade from a slow Model 30 to a fast Model 75 and run the same programs. The microcode made that compatibility cheap to engineer.

The structure of a microcoded control unit

A microcoded controller has four parts:

  1. The microcode ROM. A small (a few hundred to a few thousand words) read-only memory whose contents are the control signal vectors plus next-microinstruction-address fields.

  2. The micro-program counter (microPC). A small register that holds the address of the current microinstruction.

  3. The microsequencer. The combinational logic that selects the next microPC value. Choices include incrementing by one (sequential), branching to a constant address, or jumping based on a field of the machine instruction.

  4. The microinstruction format. The bit layout of each ROM word. Horizontal microcode has one bit per control signal (wide, high-throughput, more storage). Vertical microcode encodes the control signals more compactly (narrow, smaller storage, slower because of extra decoding).

Microcode for a single-cycle interpreter

For a single-cycle CPU, the microprogram is trivial. Each machine instruction takes exactly one microinstruction (and one cycle). The microcode ROM is indexed by the opcode (or by opcode + funct3 for OP-class instructions). The ROM’s contents are exactly the rows of the table below.

In this form the microcode ROM is functionally identical to a hardwired truth-table decoder. The only difference is physical: the microcode is stored in a memory array rather than synthesized into random logic. The choice between the two is engineering preference.

Microcode for a multi-cycle interpreter

The microcoded style becomes interesting in multi-cycle CPUs and in CISC architectures. The next chapter (Chapter 27) builds a multi-cycle RV32I datapath in which each instruction takes three to five cycles. The microcode for that machine has multiple microinstructions per machine instruction. Each microinstruction asserts a different control signal vector to advance the datapath through fetch, decode, execute, memory, and writeback phases.

For a CISC like the original Intel 8086, the disparity is more dramatic. A single machine instruction such as REP MOVS (repeated memory-to-memory move) might expand into dozens of microinstructions that loop over the source and destination addresses, decrementing the count, until the count reaches zero. The microcode is the program. The hardware just executes it.

04.Microcode in Modern x86

The microcoded style was largely abandoned by the RISC processors of the 1980s and 1990s. ARM, MIPS, SPARC, and the early DEC Alpha were all built with hardwired control. The reason was speed. Microcoded control adds at least one cycle of latency (the microcode fetch) and limits the maximum clock frequency. For RISC instruction sets simple enough that each instruction can be decoded in a single combinational pass, microcode is dead weight.

But microcode is not extinct. Modern x86 processors from Intel and AMD use a hybrid scheme that mixes hardwired decoders with microcode for the most complex instructions. The architectural picture is described in the Intel Software Developer’s Manual [2] and the AMD Architecture Programmer’s Manual [3].

The micro-op architecture

Every modern x86 implementation since the Pentium Pro (1995) internally executes a stream of fixed-format micro-ops rather than the variable-length x86 architectural instructions directly. The CPU’s front end decodes incoming x86 instructions and emits a sequence of micro-ops. Simple instructions like ADD reg, reg decode to a single micro-op. Complex instructions like REP MOVS or CPUID decode to many micro-ops.

The decoding is performed in two paths:

  • Simple decoders. Three or four parallel hardwired decoders, each capable of converting a simple x86 instruction (one that decodes to a single micro-op) into the corresponding micro-op in one cycle. These decoders are hardwired in the classical RISC sense.

  • Microcode sequencer (MS-ROM). A microcode ROM that holds the micro-op sequences for the complex x86 instructions. When a complex instruction is seen, the simple decoders stall and the microcode sequencer feeds the micro-op stream for that instruction. After the sequence finishes, the simple decoders resume.

The split is not arbitrary. Roughly 95% of all x86 instructions executed in typical programs are simple instructions that go through the hardwired path. The complex 5% pays a microcode latency penalty but uses only a small amount of ROM area.

Why x86 keeps microcode

Three reasons. First, the x86 ISA has accumulated several thousand instruction encodings over forty-eight years (since 1978). Some are extremely rare, used only by specific operating system code paths or by legacy applications. Implementing each of them with random hardwired logic would cost area for negligible benefit. Microcode amortizes the cost across one ROM.

Second, microcode is field-updatable. Intel and AMD ship microcode updates as binary patches that the BIOS loads at boot. These patches can fix bugs in instruction execution, as when Intel disabled the defective Transactional Synchronization Extensions on Haswell parts through a microcode update in 2014, or close speculative-execution side-channel vulnerabilities like the Spectre family. The reach of the mechanism has limits. The infamous Pentium FDIV bug of 1994 sat in a lookup table inside the hardware divider, where a microcode patch could not reach it, so Intel had to replace the affected parts and correct the array in later steppings. Hardwired control cannot be patched after fabrication.

Third, certain new instructions are introduced as microcoded implementations in their first generation, then promoted to hardwired in later silicon. The microcode acts as a low-cost prototype that proves the instruction’s value before committing silicon area to a fast path.

The cost of microcode in x86

The MS-ROM in modern x86 is typically 20–50 KB of ROM. At the roughly 0.03 square micrometers per bit of a dense 7 nm array, 50 KB of storage is about 0.012 square millimeters of cells, so even after decoder and sense-amplifier overhead the structure occupies a few hundredths of a square millimeter of die area on that process. The latency cost is one to two cycles to access the ROM, plus several cycles for each micro-op in the sequence. For simple instructions the cost is zero (they bypass the ROM entirely). For complex instructions the latency is hidden by out-of-order execution machinery covered in Part V.

05.Why RISC-V Uses Hardwired Control

RISC-V is designed for hardwired decode. The four reasons are direct consequences of the ISA design decisions covered in Chapter 15.

Fixed-width instructions

Every RV32I instruction is exactly 32 bits, aligned on 4-byte boundaries. The fetch logic always reads 4 bytes. The opcode is always in bits [6:0]. The decoder always knows where to look. There is no need for a multi-pass length decoder of the kind required by x86’s 1-to-15-byte variable instruction length.

Few formats, regular fields

Six instruction formats (R, I, S, B, U, J) cover all of base RV32I. The register fields are always in the same bit positions across formats. The decoder has only six combinational paths to maintain, with regular routing of immediate bits.

No string or memory-to-memory operations

RV32I has no instructions that loop internally over a memory buffer. LW loads one word. There is no REP MOVS equivalent. Every architectural instruction completes in one micro-op-equivalent operation. There is nothing to microcode.

No condition codes

RV32I has no global flag register that one instruction sets and another reads. BEQ x1, x2, target explicitly names the two registers to compare. The decoder does not need to track implicit flag dependencies.

The aggregate result is a control unit that synthesizes to a few hundred gates and decodes a complete RV32I instruction in well under a nanosecond. Microcode would add storage area and one cycle of latency for no functional benefit. The RISC-V base ISA is essentially the asymptote of “how simple can the control unit be” that the RISC movement was pursuing in the 1980s.

06.Building the RV32I Hardwired Control

Putting the pieces together, the RV32I single-cycle control unit has the following structure.

The two-stage hardwired control unit. The main control reads the opcode and emits the bulk of the control signals plus a 2-bit ALUOp class that tells the ALU control how to interpret funct3 and funct7. The ALU control then emits the final 4-bit ALUOp.
Figure 1. The two-stage hardwired control unit. The main control reads the opcode and emits the bulk of the control signals plus a 2-bit ALUOp class that tells the ALU control how to interpret funct3 and funct7. The ALU control then emits the final 4-bit ALUOp.

The split into “main control” and “ALU control” is a classical textbook organization due to Patterson [4]. It localizes the opcode-only decisions (everything except the ALU operation within OP-class) in one block and the OP-class refinement in another. The two blocks are both combinational and run in parallel within a single cycle.

Main control as a sum-of-products

For each opcode, list which signals are asserted and which are deasserted. The main control’s truth table has one row per opcode value, so the nine instructions of the running example need only six rows. ADD, SUB, AND, and OR share the opcode 0110011, so their four rows in the table below collapse into a single main-control row and differ only in the ALU operation that the ALU control stage supplies. The other five rows are ADDI, LW, SW, BEQ, and JAL, with the don’t-care entries left undefined.

In SystemVerilog, the main control is a case statement on the opcode that assigns the control signal vector for each case. The synthesizer flattens the case statement into a PLA-like structure. The control signal latency is one to two gate delays.

ALU control as a small lookup

The ALU control’s input is the 2-bit ALUOp class plus funct3 (and, for OP-class only, funct7[5]). The output is the 4-bit ALUOp. The truth table:

Table 3. ALU control mapping. ALUOp class is from main control. funct7[5] distinguishes ADD/SUB and SRL/SRA. Other entries are don’t care.

ALUOp classfunct3funct7[5]ALUOp
00 (LW/SW/ADDI)XXADD
01 (BEQ)XXSUB
10 (OP)0000ADD
10 (OP)0001SUB
10 (OP)001XSLL
10 (OP)010XSLT
10 (OP)011XSLTU
10 (OP)100XXOR
10 (OP)1010SRL
10 (OP)1011SRA
10 (OP)110XOR
10 (OP)111XAND

The table is small enough to encode by hand in a few lines of SystemVerilog. The synthesized logic is a handful of gates.

SystemVerilog skeleton

Hardwired main control skeleton for RV32I

Code
module rv32i_main_control (
input logic [6:0] opcode,
output logic reg_write,
output logic mem_read,
output logic mem_write,
output logic alu_src,
output logic [1:0] wb_sel,
output logic branch,
output logic jump,
output logic [1:0] alu_op_class,
output logic [2:0] imm_sel
);
always_comb begin
// default deassertions
reg_write = 1'b0;
mem_read = 1'b0;
mem_write = 1'b0;
alu_src = 1'b0;
wb_sel = 2'b00;
branch = 1'b0;
jump = 1'b0;
alu_op_class = 2'b00;
imm_sel = 3'b000;
unique case (opcode)
7'b0110011: begin // OP (R-type)
reg_write = 1'b1;
alu_op_class = 2'b10;
end
7'b0010011: begin // OP-IMM (I-type)
reg_write = 1'b1;
alu_src = 1'b1;
imm_sel = 3'b000; // I
end
7'b0000011: begin // LOAD
reg_write = 1'b1;
mem_read = 1'b1;
alu_src = 1'b1;
wb_sel = 2'b01; // MEM
imm_sel = 3'b000; // I
end
7'b0100011: begin // STORE
mem_write = 1'b1;
alu_src = 1'b1;
imm_sel = 3'b001; // S
end
7'b1100011: begin // BRANCH
branch = 1'b1;
alu_op_class = 2'b01;
imm_sel = 3'b010; // B
end
7'b1101111: begin // JAL
reg_write = 1'b1;
jump = 1'b1;
wb_sel = 2'b10; // PC+4
imm_sel = 3'b011; // J
end
default: ; // illegal: all deasserted
endcase
end
endmodule

The synthesizer converts this into combinational logic in a few dozen lookup-table cells (LUT-4 or LUT-6 in an FPGA). The total area is negligible compared with the register file, ALU, and memory ports.

07.Microcode in Other Modern Processors

x86 is not alone in retaining microcode. Other modern processors use microcode for specific roles.

ARM A64

ARM A64 cores have largely hardwired decoders. ARM’s publicly released technical reference manuals (e.g. [5]) describe instruction execution in terms of architectural semantics without exposing a microcode layer. However, ARM does keep a microcode-like sequencer for certain complex sequences. Load-pair and store-pair instructions on older cores sometimes expand into two micro-ops. The SVC (supervisor call) and HVC (hypervisor call) exception entry sequences traverse small internal sequencers. The bulk of integer and floating-point execution is hardwired.

POWER and other large RISCs

IBM POWER processors use hardwired decode for the vast majority of instructions but retain microcode (or its equivalent) for exception entry, decimal arithmetic, and a few legacy instructions inherited from the original POWER1. The same pattern applies to SPARC and to the older DEC Alpha.

Embedded microcontrollers

Tiny microcontrollers (ARM Cortex-M0, RISC-V PicoRV32) often use multi-cycle execution rather than pipelining, with microcoded or quasi-microcoded sequencers that walk each instruction through fetch, decode, execute, and writeback. The next chapter (Chapter 27) develops this organization in detail.

08.When Microcode Wins, When Hardwired Wins

The choice between microcoded and hardwired control is governed by four factors.

Instruction set complexity

Simple ISAs (RV32I, ARM A64 base) favor hardwired control. The combinational decode logic is small and fast. The microcode ROM would add storage area for no benefit. Complex ISAs (x86, mainframe System/z, legacy CISC) favor microcoded or hybrid control. The ROM amortizes the cost of implementing thousands of rare instruction encodings.

Clock frequency target

At very high clock frequencies (5 GHz and above), microcode adds a cycle of front-end latency that can hurt branch misprediction recovery time. Hardwired decoders integrate more directly into the pipeline’s front-end stages.

Field-update requirement

If the processor needs to support post-fabrication bug fixes, microcode is the only option. Hardwired control cannot be patched. This is one of the strongest reasons modern x86 retains microcode for complex instructions.

Verification burden

Hardwired control with a few hundred gates can be exhaustively verified by formal methods. Microcode with hundreds of routines requires architectural test programs and is harder to verify formally. For safety-critical or certifiable designs (automotive, aerospace, medical), hardwired control is preferred for this reason.

The historical trajectory is clear. The 1950s through 1980s were the era of microcode (System/360, VAX, Motorola 68000). The 1980s RISC movement (MIPS, SPARC, ARM, Alpha) was the era of hardwired control. The 1990s saw the convergence in x86 toward hybrid control with hardwired simple paths and microcoded complex paths. RISC-V in 2010 returned to pure hardwired control with a clean slate. The pendulum may swing back if some future ISA accumulates complexity, but RISC-V is currently the asymptote of simplicity.

09.Worked Examples

10.Exercises

References

  1. [1]Wilkes, Maurice V. (1951). “The Best Way to Design an Automatic Calculating Machine.” In Report of the Manchester University Computer Inaugural Conference, pp. 16--18.
  2. [2](2024). “Intel.”
  3. [3](2024). “AMD64.”
  4. [4]Patterson, David A. and Hennessy, John L. (2020). “Computer Organization and Design RISC-V Edition: The Hardware Software Interface.” Morgan Kaufmann.
  5. [5](2024). “ARM.”
Book mode
computer-architecturesingle-cycle-multi-cycle-and-pipelined-cpus
Was this helpful?