Stage-by-Stage Datapath
In a single-cycle CPU, every instruction—fetch, decode, execute, memory, and write-back—completes in exactly one clock tick. Below we’ll walk through the high-level datapath, then zoom into each stage to see how data and control signals flow.
flowchart TB
PC["PC"]
IM["Instruction Memory<br/>(32-bit instruction)"]
CU["Control Unit<br/>(decodes opcode)"]
RF["Register File"]
IMGen["Immediate Generator"]
ALU["ALU"]
BC["Branch Comparator"]
Adder4["+4 Adder"]
BranchMux{"PC Mux<br/>(select PC+imm or PC+4)"}
DM["Data Memory"]
WB["Writeback Mux<br/>(select ALU result or memory data)"]
%% PC and instruction memory
PC -- "PC address" --> IM
BranchMux -- "next PC" --> PC
%% Instruction memory outputs
IM -- "opcode<br/>(instr[6:0])" --> CU
IM -- "funct3, funct7<br/>(instr[14:12], instr[31:25])" --> CU
IM -- "rs1 idx<br/>rs2 idx<br/>rd idx" --> RF
IM -- "imm bits" --> IMGen
%% control signals
CU -- "ALUOp<br/>funct3<br/>funct7" --> ALU
CU -- "BranchSel" --> BC
CU -- "MemRead<br/>MemWrite<br/>MemtoReg<br/>RegWrite" --> WB
%% register file I/O
RF -- "rs1 data<br/>rs2 data" --> ALU
RF -- "rs1 data<br/>rs2 data" --> BC
WB -- "result<br/>RegWrite<br/>rd idx" --> RF
%% immediate
IMGen -- "imm" --> ALU
%% ALU outputs
ALU -- "ALU result (addr/data)<br/>calc result" --> DM
ALU -- "ALU result" --> WB
%% data memory I/O
RF -- "rs2 data (store data)" --> DM
DM -- "read data" --> WB
%% branch & PC update
PC -- "PC" --> Adder4
Adder4 -- "PC+4" --> BranchMux
BC -- "branchTaken" --> BranchMux
Stages
1. Instruction Fetch (IF)
The IF stage uses the program counter (PC) to read a 32-bit instruction from memory. Simultaneously, a +4 adder computes the address of the next sequential instruction.
---
config:
layout: elk
theme: default
look: classic
---
flowchart LR
subgraph IF [Instruction Fetch]
PC["PC"]
IM["Instruction Memory<br>(32-bit instruction)"]
Adder4["+4 Adder"]
BranchMux{"PC Mux<br>(select PC+imm or PC+4)"}
%% Internal fetch interactions
PC -- "PC" --> IM
PC -- "PC" --> Adder4
Adder4 -- "PC+4" --> BranchMux
BranchMux -- "Next PC" --> PC
end
%% Cross-stage signals
IM_out(["Instruction (output)"])
IM -- "Instruction" --> IM_out
style IF fill:#E0F7FA,stroke:#006064,stroke-width:2px
2. Instruction Decode (ID)
In ID, the Control Unit decodes opcode bits to generate control signals, the Register File (RF) reads source registers, and the Immediate Generator extracts any immediate operand.
---
config:
layout: elk
theme: default
look: classic
---
flowchart LR
subgraph ID [Instruction Decode]
CU["Control Unit<br>(decodes opcode)"]
RF["Register File"]
IMGen["Immediate Generator"]
end
%% Cross-stage signals
IM_input(["Instruction (input)"])
EX_output(["Control Signals (output)"])
RD_output(["Register Data (output)"])
IMM_output(["Immediate (output)"])
IM_input -- "Instruction" --> CU
IM_input -- "Instruction" --> RF
IM_input -- "Instruction" --> IMGen
CU -- "Control Signals" --> EX_output
RF -- "Register Data" --> RD_output
IMGen -- "Immediate" --> IMM_output
style ID fill:#E8F5E9,stroke:#2E7D32,stroke-width:2px
3. Execute (EX)
During EX, the ALU performs arithmetic/logical operations using register data and immediates, while the Branch Comparator determines if a branch should be taken.
---
config:
layout: elk
theme: default
look: classic
---
flowchart LR
subgraph EX [Execute]
ALU["ALU"]
BC["Branch Comparator"]
end
%% Cross-stage signals
CTRL_input(["Control Signals (input)"])
RD_input(["Register Data (input)"])
IMM_input(["Immediate (input)"])
MEM_output(["Memory Access<br>(output)"])
WB_input(["Write Back<br>(output)"])
CTRL_input -- "Control Signals" --> ALU
CTRL_input -- "Control Signals" --> BC
RD_input -- "Read Data" --> ALU
RD_input -- "Read Data" --> BC
IMM_input -- "Immediate" --> ALU
ALU -- "ALU Result" --> MEM_output
ALU -- "ALU Result" --> WB_input
BC -- "Branch Taken?" --> MEM_output
style EX fill:#FFF3E0,stroke:#EF6C00,stroke-width:2px
4. Memory Access (MEM)
On loads and stores, the Data Memory stage reads or writes data using the address computed by the ALU.
---
config:
layout: elk
theme: default
look: classic
---
flowchart LR
subgraph MEM [Memory Access]
DM["Data Memory"]
end
%% Cross-stage signals
ALU_out(["ALU Result (input)"])
WB_out(["Memory Access<br>(input)"])
ALU_out -- "ALU Result" --> DM
DM -- "Memory Data" --> WB_out
style MEM fill:#F3E5F5,stroke:#6A1B9A,stroke-width:2px
5. Write-Back (WB)
Finally, the Write-back Mux selects between the ALU result and memory data, writing the chosen value back into the Register File.
---
config:
layout: elk
theme: default
look: classic
---
flowchart LR
subgraph WB [Write Back]
WB_mux["Writeback Mux<br>(select ALU result or memory data)"]
RF["Register File"]
%% Internal writeback interaction
WB_mux -- "Write Data" --> RF
end
%% Cross-stage signals
ALU_sig(["ALU Result (input)"])
DM_sig(["Memory Data (input)"])
ALU_sig -- "ALU Result" --> WB_mux
DM_sig -- "Memory Data" --> WB_mux
style WB fill:#FFEBEE,stroke:#C62828,stroke-width:2px