Hazards
Overview
In a pipelined processor, maximum throughput is achieved when a new instruction is fetched on every single clock cycle. However, conditions called hazards arise that prevent the next instruction in the instruction stream from executing in its designated clock cycle. If left unhandled, hazards cause the pipeline to execute stale data or incorrect instructions, leading to critical state corruption.
The Risk-V architecture features a centralized hardware Hazard Controller that dynamically monitors instructions across all pipeline stages, resolves dependencies, and maintains strict program correctness through two primary recovery mechanisms:
- Pipeline Stalls (Interlocks): Freezing early pipeline stages while allowing later stages to advance, creating an execution gap.
- Pipeline Flushes (Bubbles): Synchronously clearing speculative instructions out of boundary registers and replacing them with non-operational (
NOP) tokens.
Hazard Categorization
The Risk-V 5-stage pipeline detects and mitigates two main classes of architectural hazards: Data Hazards and Control Hazards.
1. Data Hazards
Data hazards occur when an instruction depends on the result of a previous instruction that is still moving through the pipeline and has not yet committed its final value to the Register File.
- RAW (Read-After-Write) Hazards: This is the primary data hazard present in the Risk-V pipeline. It happens when an instruction in the Decode (ID) stage needs to read a register (
rs1orrs2) that a preceding instruction in the Execute (EX), Memory (MEM), or Writeback (WB) stage is scheduled to write back to (rd). - ALU Dependency: Resolved transparently with zero-latency overhead via the Forwarding Unit, which routes calculated results straight from the
EX_MEMorMEM_WBregisters back to the ALU inputs. - Load-Use Dependency: Occurs when an instruction immediately following a load instruction (
lw,lh,lb) requires the loaded data. Because data memory reads finish late in the MEM stage, the operand cannot be bypassed back to the ALU in time for the execution edge. This requires a structural 1-cycle pipeline stall.
Cycle 1 Cycle 2 Cycle 3 Cycle 4 Cycle 5 Cycle 6
lw x5, 0(x10) [IF] --------> [ID] --------> [EX] --------> [MEM] -------> [WB]
| (Data ready late)
v (Cannot bridge backward)
add x6, x5, x7 [IF] --------> [ID] (STALL) -> [EX] -------> [MEM] -------> [WB]
2. Control Hazards
Control hazards occur when the pipeline fetches subsequent instructions based on a speculative Program Counter path before a branch or jump instruction has completed its target address evaluation.
- Branch Misprediction / Jump Redirection: The Risk-V pipeline utilizes a baseline Static Predict-Not-Taken approach, speculatively fetching sequential instructions (\(PC + 4\)).
- When a conditional branch evaluates as taken in the Execution stage, or when an unconditional jump (
jal,jalr) resolves its target, the speculatively fetched instructions currently in the Fetch (IF) and Decode (ID) stages are invalidated. - The Hazard Controller mitigates this by asserting flush vectors, converting the speculatively loaded slots into harmless
NOPbubbles while updating the Program Counter to point to the correct branch destination address.
Central Hazard Controller Interface
The Hazard Controller acts as an independent combinational supervisor operating adjacent to the main pipeline. It evaluates destination indices, source dependencies, and branch statuses to generate global gating signals.
Controller Inputs
| Signal | Width | Source Stage | Description |
|---|---|---|---|
ID_EX_MemRead |
1 bit | EX | Asserted high if the instruction currently in the Execute stage is a memory load. |
ID_EX_rd |
5 bits | EX | Destination register index of the instruction currently in the Execute stage. |
IF_ID_rs1 |
5 bits | ID | Source register 1 index of the instruction currently in the Decode stage. |
IF_ID_rs2 |
5 bits | ID | Source register 2 index of the instruction currently in the Decode stage. |
Branch_Taken |
1 bit | EX | Evaluation flag from the Branch Control Unit; high if a branch condition evaluates as true or a jump occurs. |
Controller Outputs
| Signal | Width | Target Module | Structural Action on Assertion (1) |
|---|---|---|---|
PC_Write |
1 bit | Program Counter | Active-Low Enable (EN): Deasserting this to 0 freezes the PC value, preventing new fetches. |
IF_ID_Write |
1 bit | IF_ID Register |
Active-High Write Enable: Deasserting this to 0 freezes the Fetch/Decode boundary register state. |
IF_ID_Flush |
1 bit | IF_ID Register |
Active-High Synchronous Clear: Overwrites the latched instruction with 0x00000000 (Zero Address/NOP). |
ID_EX_Flush |
1 bit | ID_EX Register |
Active-High Synchronous Clear: Wipes control flags and injects a pipeline bubble into execution. |
Hazard Mitigation Logic (Core Rules)
The Hazard Controller evaluates its outputs combinationally based on two independent priority rules.
Rule 1: Load-Use Hazard Interlock Evaluation
A load-use dependency is detected if an instruction in the Execute stage is a load (ID_EX_MemRead == 1) and its destination register (ID_EX_rd) matches either of the source registers currently being compiled in the Decode stage (IF_ID_rs1 or IF_ID_rs2). Register x0 is excluded from tracking as it is hardwired to zero.
When LoadUseHazard == 1:
PC_Write = 0\(\rightarrow\) Structural freeze of the active Program Counter address.IF_ID_Write = 0\(\rightarrow\) Structural freeze of the fetched instruction inside the Fetch/Decode boundary.ID_EX_Flush = 1\(\rightarrow\) Wipes the downstream control lines moving into the execution register, inserting an execution bubble.
Rule 2: Control Hazard Branch Flush Evaluation
When a conditional branch condition resolves as true or an unconditional jump executes, the instructions speculatively loaded into the pipeline behind it are invalid and must be expunged.
When Branch_Taken == 1:
IF_ID_Flush = 1\(\rightarrow\) Flushes the instruction currently in the Fetch stage.ID_EX_Flush = 1\(\rightarrow\) Flushes the instruction currently in the Decode stage.- The Program Counter multiplexer switches to route the calculated target address directly into the PC register on the next clock edge, overriding the standard sequential sequence.
Step-by-Step Operational Traces
Example 1: Handling a Load-Use Stall Sequence
Consider the following execution block:
lw x2, 12(x10) # Load memory data into register x2
sub x4, x2, x3 # Subtract uses x2 immediately - Load-Use Hazard!
- Cycle N (Instruction Fetch/Decode):
- The
lwinstruction moves into the EX stage; control logic assertsID_EX_MemRead = 1and registersID_EX_rd = 0x02. - The
subinstruction is fetched out of instruction memory and settles inside theIF_IDregister, exposingIF_ID_rs1 = 0x02andIF_ID_rs2 = 0x03to the decode bus.
- The
- Hazard Detection:
- The Hazard Controller detects that
ID_EX_MemRead == 1,ID_EX_rd != 0, andID_EX_rd == IF_ID_rs1(\(0x02 == 0x02\)). - The controller instantly pulls
PC_Write = 0,IF_ID_Write = 0, andID_EX_Flush = 1.
- The Hazard Controller detects that
- Clock Edge Transition (End of Cycle N):
- The Program Counter holds its current address, ensuring
sub's successor is not fetched yet. - The
IF_IDregister ignores the clock edge, holding the rawsubmachine code static on the decode tracks. - The
ID_EXregister processes the synchronous flush, locking all downstream control lines (RegWEn,MemWrite, etc.) to0.
- The Program Counter holds its current address, ensuring
- Cycle N+1 (Stall Execution):
- A harmless
NOPbubble propagates through the Execution stage. - The original
lwinstruction reaches the MEM stage, retrieving the data word from RAM. - The load dependency is now resolved, allowing the Forwarding Unit to bypass the fresh data word directly from the
MEM_WBboundary straight to the ALU for thesubinstruction in the next cycle.
- A harmless
Circuit Implementation Principles (Logisim)
- Purely Combinational: The Hazard Controller contains no internal registers or sequential memory clocks. It is implemented using native Logisim comparison matrices (
Bit Comparators) and basic logic gates (AND,OR,NOT) to maintain zero-latency tracking updates within the current cycle. - Glitch Containment: Hazard evaluation lines are distributed to the boundary registers via clean label tunnels. This ensures that control updates settle fully before the active positive clock edge arrives, eliminating race conditions or setup-time violations across the pipeline stages.