Back to Blog

The Control Unit: Generating Every Control Signal from the Opcode

August 18, 202625 min read
Computer Architecture CPU Design Digital Logic Learning

Lesson 2, Part 2 built the datapath — the ALU, the register file, instruction and data memory, all wired together with muxes selecting between candidate values. But every mux in that datapath has a select line, and every memory and register has an enable line, and none of those wires know what to do on their own. This is Lesson 2, Part 3: we derive exactly what drives every mux and every enable line in that datapath, for all 7 instructions, starting from nothing but the opcode.

1. What the Control Unit Actually Is

Strip away the mystique: the control unit is a small block of pure combinational logic. It has one primary input — the 6-bit opcode field sitting in bits [31:26] of the currently fetched instruction — and it produces a fixed bundle of output signals every single cycle, with no memory of its own and no state carried from one instruction to the next.

Instruction bits [31:26] Control Unit (opcode) (pure combinational RegDst logic) ALUSrc MemToReg RegWrite MemRead MemWrite Branch ALUOp[1:0]

That "no memory of its own" detail is worth sitting with, because it is the entire reason a single-cycle CPU can execute one instruction per clock cycle at all. If the control unit had internal state — if it needed to remember something about the previous instruction to decide the current one — you would need extra cycles just to let that state settle, or you would need to worry about race conditions between control decisions and datapath timing. Instead, the control unit behaves exactly like the ALU from Part 2 of Lesson 1: feed it inputs, and after one gate-delay's worth of propagation, the outputs are correct and stable for that instruction, full stop. Change the opcode on the next cycle, and the outputs change accordingly — there's no "previous cycle" baked into the circuit.

This is also why the diagram above is legitimately the entire control unit for the main decode step. It is not a metaphor for "there's some complicated logic somewhere that figures out what to do." It is a literal one-input, eight-output combinational block, and by the end of this post you will be able to write out its truth table on one page and derive at least one of its outputs as an explicit boolean equation.

One clarification before we go further: the control unit reads the opcode, not the funct field, to make its top-level decision. For R-type instructions specifically, that top-level decision is deliberately incomplete — it says "this is some ALU-register-register operation," and punts the which ALU operation question one level down. We'll get to exactly why that punt is necessary, and how it's resolved, in Section 6.

2. The Eight Signals, and What Each One Actually Drives

Before building the truth table, it's worth being precise about what each of the eight named signals physically controls in the datapath from Part 2. Vague signal names are how people end up memorizing a table instead of understanding it — so here is exactly which wire each signal is, and what happens on either side of it.

  • RegDst — selects the destination register address fed into the register file's write-address port. It's a 2-to-1 mux select: 0 picks the rt field (bits [20:16]), 1 picks the rd field (bits [15:11]). R-type instructions name their destination in rd; I-type instructions (when they write a register at all) name it in rt. There is no third option because our instruction formats only ever put a destination register in one of those two places.
  • ALUSrc — selects the ALU's second input operand. 0 picks the second register-file read port (ReadData2, i.e. the value in rt). 1 picks the sign-extended 16-bit immediate. This is the mux that decides "is this an ALU op between two registers, or between a register and a constant?"
  • MemToReg — selects what value actually lands on the register file's write-data port. 0 picks the ALU's result; 1 picks the value just read out of data memory. This mux exists purely because two different instruction classes produce a register's new value in two structurally different places in the datapath — the ALU output and the data-memory output — and only one of them can drive the write-data bus on a given cycle.
  • RegWrite — the register file's write-enable line, directly. When 0, whatever is sitting on the write-data and write-address ports is irrelevant; nothing in the register file changes at the clock edge. When 1, the addressed register captures the write-data value on the next rising edge — exactly the write-enable discipline from Lesson 1, Part 3.
  • MemRead — data memory's read-enable line. Gates whether the memory actually drives valid data out onto its read-data output this cycle. Only ever needed for LW.
  • MemWrite — data memory's write-enable line, the memory-side analog of RegWrite. Gates whether Mem[address] ← WriteData actually commits at the clock edge. Only ever needed for SW.
  • Branch — asserted for instructions whose next PC might not be PC + 4. It doesn't select the next PC by itself; it's ANDed with the ALU's Zero output (asserted when the ALU computes rs − rt = 0) to produce the actual select line for the PC-source mux described in Part 2 and in Lesson 1, Part 5's discussion of PC control. Branch = 1 and Zero = 1 together mean "take the branch"; Branch = 1 and Zero = 0 means "this was a branch instruction, but the condition failed, fall through to PC + 4."
  • ALUOp — a deliberately coarse, 2-bit signal that does not by itself select the ALU's operation. It selects a mode for a second, smaller decoder — the ALU control unit — which combines it with the instruction's funct field to produce the real ALU operation select. Section 5 through 7 are entirely about why this indirection exists and exactly how it works.

Every one of these eight signals is either a mux select line or a write/read enable line — nothing more exotic than that. The entire job of "understanding what the control unit does" reduces to: for each of our 7 instructions, which muxes need to point which way, and which enables need to fire?

3. Deriving the Table, Instruction by Instruction

Rather than presenting the finished truth table and asking you to trust it, let's derive each row by asking, instruction by instruction, "what does this instruction actually need the datapath to do?" Recall the instruction formats and semantics from the shared spec this series has been using:

R-type (ADD, SUB, AND, OR):
  opcode(6)=000000 | rs(5) | rt(5) | rd(5) | shamt(5, unused) | funct(6)
  semantics: rd ← rs OP rt
 
I-type LW:   opcode=100011 | rs(5) | rt(5) | immediate(16)
  semantics: rt ← Mem[rs + signext(immediate)]
 
I-type SW:   opcode=101011 | rs(5) | rt(5) | immediate(16)
  semantics: Mem[rs + signext(immediate)] ← rt
 
I-type BEQ:  opcode=000100 | rs(5) | rt(5) | immediate(16)
  semantics: if (rs == rt) PC ← PC + 4 + (signext(immediate) << 2)
             else           PC ← PC + 4

3.1 R-type (ADD, SUB, AND, OR)

  • RegDst = 1. The destination is named in the rd field, not rt — the mux must select rd.
  • ALUSrc = 0. Both ALU operands are register values: rs and rt. There's no immediate involved anywhere in an R-type instruction's execution.
  • MemToReg = 0. The value to write back into rd is the ALU's result (rs OP rt) — it never touches memory, so the write-back mux must select the ALU output.
  • RegWrite = 1. Every R-type instruction in our set writes a result back to a register. This has to be asserted or the entire instruction is a no-op.
  • MemRead = 0. R-type instructions never touch data memory.
  • MemWrite = 0. Same reason — no memory access at all.
  • Branch = 0. R-type instructions never redirect control flow; the next PC is always PC + 4.
  • ALUOp = 10. This is the "defer to funct" signal — R-type is exactly the case where the opcode alone cannot tell the ALU control unit which of ADD/SUB/AND/OR to perform, because all four share the identical opcode 000000. More on this in Section 6.

3.2 LW

  • RegDst = 0 (technically don't-care, see the note below, but the canonical choice is 0). LW's destination register is named in rt, not rd — I-type instructions don't even have an rd field at that bit position; those bits are part of the immediate. The mux must select rt.
  • ALUSrc = 1. The ALU's second operand is the sign-extended 16-bit immediate — the effective address is computed as rs + signext(immediate), and that immediate has to come from the instruction word, not a second register.
  • MemToReg = 1. The value written back into rt comes from data memory, not the ALU — the ALU here computed an address, not the datum itself. This is the signal named explicitly in the task: LW sets MemToReg = 1 because the register write-back data comes from memory, not the ALU.
  • RegWrite = 1. LW writes a loaded value into rt.
  • MemRead = 1. LW is, definitionally, a memory read — this line has to fire so the memory actually drives its output data bus this cycle.
  • MemWrite = 0. LW never writes memory.
  • Branch = 0. LW never affects control flow.
  • ALUOp = 00. The ALU's job here is a plain add (rs + signext(immediate)) to compute the effective address. No ambiguity, no funct field involved — LW doesn't even carry a meaningful funct field, since that bit range is occupied by the immediate.

3.3 SW

  • RegDst = X (don't-care). SW writes no register at all, so which register the destination-mux happens to select is irrelevant — nothing downstream reads that mux's output this cycle, because RegWrite = 0 blocks the register file from acting on it. We'll come back to why "don't-care" is a meaningful, useful value and not a cop-out.
  • ALUSrc = 1. Just like LW, SW needs the ALU to compute an effective address, rs + signext(immediate), so the second ALU operand must be the immediate.
  • MemToReg = X (don't-care). No register write happens, so the write-back mux's selection is never consumed.
  • RegWrite = 0. SW does not modify the register file. rt here is a source — its value is what gets stored to memory — not a destination.
  • MemRead = 0. SW doesn't read memory to produce a result; it only writes.
  • MemWrite = 1. This is the entire point of the instruction: Mem[rs + signext(immediate)] ← rt. Without this line asserted, the store simply doesn't happen.
  • Branch = 0. SW never touches the PC.
  • ALUOp = 00. Exactly like LW, the ALU's only job is computing the effective address by addition. SW and LW share this address-calculation subproblem completely, which is precisely why they share the same ALUOp encoding.

3.4 BEQ

  • RegDst = X (don't-care). BEQ writes no register, so again this mux's output is never consumed downstream.
  • ALUSrc = 0. This is the detail that differs from LW/SW and trips people up: BEQ's ALU input is the second register (rt), not the immediate. The 16-bit immediate in a BEQ instruction is a branch offset, added to PC + 4 by a separate adder in the PC-update path (see Lesson 1, Part 5) — it never goes anywhere near the main ALU. The main ALU's only job for BEQ is comparing two register values.
  • MemToReg = X (don't-care). No register write, so irrelevant.
  • RegWrite = 0. BEQ modifies control flow, not register state.
  • MemRead = 0. No memory access.
  • MemWrite = 0. No memory access.
  • Branch = 1. This is the signal that tells the PC-source mux "this instruction might not fall through to PC + 4 — check the ALU's Zero output before deciding."
  • ALUOp = 01. The ALU must compute rs − rt so that its Zero flag reflects equality (rs − rt = 0 exactly when rs = rt). Subtraction, not addition, is the operation — hence a distinct ALUOp encoding from LW/SW's 00.

3.5 A Note on "Don't-Care"

Several cells above are marked X. This is not the control unit shrugging — it's a specific, useful piece of information for anyone building or minimizing this circuit: the value on this signal has zero effect on the machine's behavior for this instruction, because the thing it controls is gated off by another signal anyway. Concretely, RegDst for SW is irrelevant because RegWrite = 0 means nothing consumes the register file's write-address port that cycle regardless of what address is sitting on it. When you actually implement this table as logic (or feed it to a synthesis tool as a truth table for minimization, exactly as GeeksforGeeks and most digital-design courses describe deriving hardwired control from Boolean truth tables), those don't-care cells are exactly what lets the minimizer produce a smaller circuit than if every cell were pinned to a concrete 0 or 1 — the synthesis tool is free to pick whichever value makes the resulting gate-level expression simplest.

4. The Complete Main Control Table

Putting Section 3 together, here is the full main-control truth table for all 7 instructions. Because ADD, SUB, AND, and OR share an identical opcode (000000), they collapse into a single row here — the main control unit genuinely cannot and does not distinguish them. That's the entire subject of Sections 6 and 7.

InstructionopcodeRegDstALUSrcMemToRegRegWriteMemReadMemWriteBranchALUOp
ADD / SUB / AND / OR (R-type)000000100100010
LW100011011110000
SW101011X1X001000
BEQ000100X0X000101

This is, column for column, the same table shape used in Patterson and Hennessy's Computer Organization and Design for the classic MIPS single-cycle datapath (there it also includes J for unconditional jump, which our 7-instruction subset omits). Every entry in it was derived, not memorized, in Section 3 — and that derivability is the actual point: this table isn't a fact to look up, it's the direct, mechanical consequence of what each instruction's semantics require from the datapath's muxes and enable lines.

A quick cross-check worth doing: scan down the RegWrite column. It's 1 exactly for R-type and LW — the only two instructions in our set that put a new value into a register — and 0 for SW and BEQ, which don't. Scan the MemRead/MemWrite columns and you'll find exactly one 1 total across all four rows in each, precisely matching that only LW reads memory and only SW writes it. The table isn't just internally consistent by luck; each column is a direct restatement of one architectural fact about which instructions do what.

5. The Control Unit Is Just a Lookup Table — Here's the Boolean Equation

Section 1 claimed the control unit is "a small combinational circuit that's just a lookup table." Let's make that literal by deriving one output signal as an actual boolean equation from the table above, using the three concrete opcodes involved: R-type = 000000, LW = 100011, SW = 101011, BEQ = 000100.

Look at the RegWrite column. It's 1 for exactly two rows — R-type and LW — and 0 for the other two. In other words:

RegWrite = 1  when (instruction is R-type)  OR  (instruction is LW)
RegWrite = 0  otherwise

Written the way the task frames it, in prose/inline-code form rather than any circuit-diagram notation:

RegWrite = R-type OR LW

Expanding "R-type" and "LW" into their actual opcode-bit conditions (writing the opcode as bits op5 op4 op3 op2 op1 op0, MSB first):

R-type  ⇔  opcode == 000000
        ⇔  NOT(op5) AND NOT(op4) AND NOT(op3) AND NOT(op2) AND NOT(op1) AND NOT(op0)
 
LW      ⇔  opcode == 100011
        ⇔  op5 AND NOT(op4) AND NOT(op3) AND op2 AND op1 AND op0
 
RegWrite = (NOT op5 AND NOT op4 AND NOT op3 AND NOT op2 AND NOT op1 AND NOT op0)
           OR
           (op5 AND NOT op4 AND NOT op3 AND op2 AND op1 AND op0)

That expression is a completely ordinary sum-of-products boolean function of six input bits — nothing about it is special-cased or "smart." A gate-level implementation is just two 6-input AND gates (one per product term, with inverters on the appropriate opcode bits) feeding a single OR gate. Every one of the other seven signals (RegDst, ALUSrc, MemToReg, MemRead, MemWrite, Branch, and the two ALUOp bits) is derivable the exact same way, directly from its own column in the Section 4 table — each is just a different sum-of-products expression over the same six opcode input bits. In an actual synthesized implementation, all eight of these boolean functions would typically be collapsed together into a single PLA (programmable logic array) or ROM lookup, sharing the AND-gate "product terms" across outputs wherever they overlap — but the underlying logic is exactly this: six input bits in, eight (mostly independent) boolean functions out, computed combinationally, one gate-delay deep, every single cycle.

This is worth internalizing precisely because "control unit" sounds like it should be the most software-like, most mysterious part of a CPU — surely there's some kind of program running to figure out what to do? There isn't. It's a truth table, minimized into gates, exactly like the ALU's operation-select logic from Lesson 1, Part 2.

6. Why One Level of Decoding Isn't Enough

Here is the problem the main control table in Section 4 deliberately leaves unsolved: ADD, SUB, AND, and OR all share the identical opcode 000000. If the main control unit's job were to directly select the ALU's operation from the opcode alone, it would be stuck on any R-type instruction — the opcode contains no information about which of the four operations to perform.

ADD: opcode = 000000, funct = 100000 SUB: opcode = 000000, funct = 100010 identical opcode, AND: opcode = 000000, funct = 100100 different funct OR: opcode = 000000, funct = 100101

This is exactly what the funct field exists for, and it's a deliberate encoding choice, not an accident: MIPS reserves the entire opcode 000000 as "this is an arithmetic/logical register-register operation, look at the funct field to find out which one." That's a genuinely different kind of instruction-format design than, say, giving ADD and SUB their own distinct top-level opcodes the way LW/SW/BEQ each have their own — and it exists because the R-type format has 6 unused bits (funct) sitting right there after shamt, so the ISA designers used them as a second-level operation selector instead of "spending" scarce opcode space on every individual ALU variant.

The practical consequence: the main control unit, looking only at the opcode, physically cannot produce a correct ALU-operation-select signal for R-type instructions. It doesn't have the information. Its only honest options are either (a) also read the funct field directly and fold it into an enormous single-level truth table with the full 12-bit {opcode, funct} as input, or (b) emit a coarse "defer" signal and let a second, smaller piece of logic — one that does look at funct — finish the job. Real MIPS single-cycle designs, following Patterson & Hennessy, take approach (b): that coarse signal is exactly ALUOp, and the second piece of logic is the ALU control unit.

Option (a) isn't wrong, to be clear — it would work. But it's wasteful: LW, SW, and BEQ never look at funct at all (their bits in that position are part of the immediate field, not a real funct field), so building one giant table keyed on {opcode, funct} means most of that table's rows are redundant duplicates differing only in funct bits nothing downstream actually reads. Splitting the decision into "coarse opcode-level mode" (main control) plus "fine funct-level operation, only when relevant" (ALU control) keeps each piece of logic small, and — just as importantly for a real chip — keeps the wiring for the funct field entirely local to the one small block of logic that needs it, instead of routing it all the way through the main control unit for instructions that never use it.

7. The Two-Level ALU Control Scheme

7.1 ALUOp: A Deliberately Coarse Signal

ALUOp is 2 bits — only 4 possible values — and it does not attempt to name an ALU operation directly. Instead it names a mode:

ALUOp = 00  →  "this instruction needs the ALU to add"          (LW, SW — address calc)
ALUOp = 01  →  "this instruction needs the ALU to subtract"     (BEQ — equality test)
ALUOp = 10  →  "look at the funct field to find out"            (R-type)

(The fourth encoding, 11, is unused in our 7-instruction subset — in the full MIPS ISA it's typically reserved for other instruction classes, such as SLT-family comparisons, that this series' pedagogical subset deliberately excludes.)

Notice that ALUOp is literally one of the eight columns already derived in Section 3 and tabulated in Section 4 — it's produced by the main control unit, from the opcode, exactly like every other signal in this post. What's new here is what consumes it.

7.2 The ALU Control Unit: A Second, Smaller Decoder

The ALU control unit is a separate combinational block, downstream of the main control unit, with two inputs — ALUOp[1:0] and the instruction's funct[5:0] field — and one output: the actual ALU operation-select signal that drives the ALU built in Lesson 1, Part 2 (we'll use a 4-bit select code here, matching the style of ALU-control-line encodings used in Patterson & Hennessy's presentation).

ALUOp[1:0] ALU Control Unit ALU operation select (4 bits) funct[5:0] (combinational logic) feeds the ALU's op-select input from Lesson 1, Part 2

Its truth table is small precisely because it only has real work to do when ALUOp = 10:

ALUOpfunct (when relevant)funct meaningALU operationALU control code
00XXXXXX (don't-care — LW/SW never inspect funct)add0010
01XXXXXX (don't-care — BEQ never inspects funct)subtract0110
10100000ADDadd0010
10100010SUBsubtract0110
10100100ANDAND0000
10100101OROR0001

Reading this table by row: when ALUOp = 00, the ALU control unit ignores funct entirely and always outputs the "add" code — this is exactly LW/SW's address calculation. When ALUOp = 01, it always outputs "subtract" — BEQ's comparison. It's only when ALUOp = 10 — meaning "the main control unit has told me this is an R-type instruction" — that the ALU control unit actually looks at funct, and now funct's six bits do real, discriminating work: 100000 selects add, 100010 selects subtract, 100100 selects AND, 100101 selects OR. Each of those funct values maps to a distinct output code, which is exactly the distinguishing power that the opcode alone was missing in Section 6.

Structurally, this ALU control unit is every bit as much "just a lookup table" as the main control unit from Section 5 — it's a boolean function of 8 input bits (2 ALUOp bits + 6 funct bits) producing a 4-bit output, fully derivable as sum-of-products the same way RegWrite was derived above. It's simply a smaller table than "opcode + funct → everything," because it only ever has to answer one narrow question: which ALU operation, given that the main control unit has already settled every other signal.

7.3 Why Two Small Decoders Beat One Big One

Stepping back, the two-level scheme is a direct application of a familiar systems-design instinct: decompose a decision into an outer, coarse-grained decision and an inner, fine-grained one, and only pay the cost of the fine-grained decision on the paths that actually need it.

  • The main control unit stays a clean function of the 6-bit opcode alone, producing all eight signals from Section 4 — including the 2-bit hint ALUOp for the one case (R-type) where opcode isn't the whole story.
  • The ALU control unit stays a small, local function of ALUOp and funct, and it is the only piece of logic in the whole control path that ever has to route or interpret the funct field. LW, SW, and BEQ's instruction words don't even contain a meaningful funct field in the ISA sense (those bit positions hold immediate bits), and correspondingly, nothing about their control-signal generation depends on decoding it.
  • Each piece is independently small enough to write out completely by hand — as this post just did, twice — which is a real engineering virtue in itself: smaller truth tables are easier to verify exhaustively, easier to lay out as compact PLAs, and easier to extend later (adding a new R-type ALU operation, say XOR, only touches the ALU control table, never the main control table).

7.4 Sanity Check Against the Running Example

The shared running example program for this lesson starts R1=10, R2=20, R4=100, Mem[100]=0 and executes:

0: ADD  R3, R1, R2
4: BEQ  R6, R2, 1     # taken

For instruction 0 (ADD R3, R1, R2): opcode 000000 → main control asserts RegDst=1, ALUSrc=0, MemToReg=0, RegWrite=1, MemRead=0, MemWrite=0, Branch=0, ALUOp=10. ALUOp=10 hands off to the ALU control unit, which reads funct=100000 and outputs the "add" code 0010. The ALU computes 10 + 20 = 30, and because RegDst=1, that result lands in rd = R3 at the next clock edge — matching the semantics exactly.

For instruction 4 (BEQ R6, R2, 1): opcode 000100 → main control asserts ALUSrc=0, RegWrite=0, MemRead=0, MemWrite=0, Branch=1, ALUOp=01. ALUOp=01 bypasses funct entirely (BEQ's low bits are immediate, not funct) and the ALU control unit outputs "subtract," 0110. The ALU computes R6 − R2; whatever R6 holds by this point in the trace, if it equals R2 = 20 the ALU's Zero output fires, Branch AND Zero = 1, and the PC-source mux (Section 2's Branch bullet) selects the branch target instead of PC + 4 — which is exactly why this branch is annotated # taken in the program. The full cycle-by-cycle version of this trace, register values and all, is the entire subject of Part 4.

Key takeaway: ALUOp is not the ALU's operation — it's a 2-bit hint from the main control unit telling a second, small decoder whether to output "add," output "subtract," or go read the funct field. This two-level split exists because R-type instructions share one opcode across four different operations, and the opcode alone cannot resolve that ambiguity; funct exists specifically to resolve it, and only the ALU control unit needs to care.

8. Aside: Hardwired vs. Microcoded Control

Everything in this post describes hardwired control: every signal is a fixed boolean function of the opcode (and, one level down, funct), implemented directly as gates — AND/OR/NOT logic or a PLA, with no memory or sequencing involved. This is the natural fit for a single-cycle RISC-style design like ours: every instruction is the same width, formats are simple and few, and every instruction's control signals are needed in exactly one cycle. Hardwired control is fast — it's pure propagation delay through a handful of gate levels, nothing more — but it's comparatively rigid: extending the instruction set means literally re-deriving and re-wiring truth tables, which is exactly the derivation exercise Sections 3–7 just walked through by hand.

The historical alternative is microcoded (microprogrammed) control, where instead of gates implementing a truth table, control signals for a given instruction are stored as one or more "microinstructions" in a small internal ROM, and the control unit becomes a tiny sequencer that steps through a micro-program to execute each machine instruction — sometimes several microinstructions long for one CISC instruction. This trades raw speed (fetching microinstructions from a control store costs real cycles that pure gate logic doesn't) for flexibility: adding or fixing an instruction's behavior can mean rewriting microcode rather than re-laying-out a circuit, which historically mattered enormously for CISC ISAs like x86, whose instruction set grew incrementally over decades and includes wildly irregular, variable-length, multi-step instructions that a purely hardwired scheme would struggle to decode cleanly. Modern x86 implementations are, notably, a hybrid: common, simple instructions get decoded and executed via fast hardwired-style paths, while rare, complex instructions fall back to microcode ROM — the same fast/flexible tradeoff this section describes, just applied selectively rather than uniformly across the whole ISA.

Our 7-instruction MIPS-style subset needs none of that complexity: fixed-width instructions, a handful of formats, one control decision per instruction, every signal resolvable in the same single cycle. That's precisely the design space where hardwired control is not just adequate but strictly better — faster and simpler — which is exactly why the classic Patterson & Hennessy single-cycle MIPS design, and this post's derivation of it, use it throughout.

Further Reading

Every signal derived in this post — every mux select, every read/write enable, both levels of ALU decoding — has so far only been discussed in the abstract, instruction by instruction. Lesson 2, Part 4, "Cycle-by-Cycle Trace: Running a Real Program on Our CPU," is where that changes: we run the full seven-instruction example program from this lesson through the complete datapath, cycle by cycle, and watch these exact signals fire, register values update, and the branch at instruction 4 actually redirect the PC.