CodiodeCodiode
Home
Problem Solving
Skill Tracks
My Assignments
Contests
Leaderboard
Community
Settings
Codiode/Problems/Sequential Logic

Single Stage Forwarding Path

MediumVerilog / SystemVerilogBuild

Deeply pipelined processors suffer from data hazards when an instruction depends on the result of a recently executed instruction that has not yet been written back to the register file. A forwarding path resolves this by routing the computed execution result directly back to the decode stage. This prevents the pipeline from stalling and maintains high throughput.

This module acts as the pipeline register between the decode and execution stages, incorporating the forwarding multiplexer logic. It evaluates whether the current instruction requires operands that are currently being computed by the execution stage. If the execution stage is writing to a valid, non-zero register that matches either of the source registers, the module selects the execution stage result instead of the register file data. The chosen operands are then registered on the clock edge to feed the execution stage in the next cycle.

Timing and reset behaviour: • Clock edge: posedge • Reset type: Asynchronous • Reset polarity: Active-low (rst_n) • Output values on reset: rs1_data_out and rs2_data_out both reset to 32'b0 • Priority rules: Forwarding only occurs if ex_reg_write is asserted and the destination register is not register 0.

Worked trace: Cycle 1: rst_n=0 → rs1_data_out=0, rs2_data_out=0 (reset applied) Cycle 2: rst_n=1, rs1_addr=1, rs2_addr=2, ex_rd_addr=3, ex_reg_write=1, rs1_data_rf=10, rs2_data_rf=20, ex_alu_result=30 → rs1_data_out=10, rs2_data_out=20 (no hazard; register file data used) Cycle 3: rs1_addr=3, rs2_addr=2, ex_rd_addr=3, ex_reg_write=1, rs1_data_rf=10, rs2_data_rf=20, ex_alu_result=30 → rs1_data_out=30, rs2_data_out=20 (hazard on rs1; alu result forwarded) Cycle 4: rs1_addr=1, rs2_addr=3, ex_rd_addr=3, ex_reg_write=1, rs1_data_rf=10, rs2_data_rf=20, ex_alu_result=30 → rs1_data_out=10, rs2_data_out=30 (hazard on rs2; alu result forwarded) Cycle 5: rs1_addr=3, rs2_addr=3, ex_rd_addr=3, ex_reg_write=1, rs1_data_rf=10, rs2_data_rf=20, ex_alu_result=30 → rs1_data_out=30, rs2_data_out=30 (hazard on both; alu result forwarded to both) Cycle 6: rs1_addr=3, rs2_addr=3, ex_rd_addr=3, ex_reg_write=0, rs1_data_rf=10, rs2_data_rf=20, ex_alu_result=30 → rs1_data_out=10, rs2_data_out=20 (write disabled; no forwarding) Cycle 7: rs1_addr=0, rs2_addr=2, ex_rd_addr=0, ex_reg_write=1, rs1_data_rf=0, rs2_data_rf=20, ex_alu_result=30 → rs1_data_out=0, rs2_data_out=20 (register 0 hazard ignored; no forwarding) Cycle 8: rs1_addr=1, rs2_addr=2, ex_rd_addr=3, ex_reg_write=1, rs1_data_rf=10, rs2_data_rf=20, ex_alu_result=30 → rs1_data_out=10, rs2_data_out=20 (normal operation resumes)

{ "signal": [
  { "name": "clk",           "wave": "p......." },
  { "name": "rst_n",         "wave": "01......" },
  { "name": "rs1_addr",      "wave": "x=======", "data": ["1", "3", "1", "3", "3", "0", "1"] },
  { "name": "rs2_addr",      "wave": "x=======", "data": ["2", "2", "3", "3", "3", "2", "2"] },
  { "name": "ex_rd_addr",    "wave": "x=======", "data": ["3", "3", "3", "3", "3", "0", "3"] },
  { "name": "ex_reg_write",  "wave": "x1...011" },
  {},
  { "name": "rs1_data_out",  "wave": "==.=.=.=", "data": ["0", "10", "30", "10", "30", "10", "0", "10"] },
  { "name": "rs2_data_out",  "wave": "==..=.=.", "data": ["0", "20", "30", "20", "20"] }
], "head": { "text": "Cycle-by-cycle forwarding behavior showing hazard resolution." } }

| Signal | Direction | Width | Description | |--------|-----------|-------|-------------| | clk | input | 1 | Positive-edge triggered clock | | rst_n | input | 1 | Asynchronous active-low reset; outputs go to 0 | | rs1_addr | input | 5 | Source register 1 address | | rs2_addr | input | 5 | Source register 2 address | | rs1_data_rf | input | 32 | Source register 1 data from register file | | rs2_data_rf | input | 32 | Source register 2 data from register file | | ex_rd_addr | input | 5 | Destination register address in the execution stage | | ex_alu_result | input | 32 | Computed result from the execution stage | | ex_reg_write | input | 1 | Write enable signal from the execution stage | | rs1_data_out | output | 32 | Registered operand 1 for the execution stage | | rs2_data_out | output | 32 | Registered operand 2 for the execution stage |

Constraints

  • The module must update rs1_data_out and rs2_data_out on the positive edge of clk.
  • rst_n is asynchronous and active-low.
  • Register 0 (5'b00000) is hardwired to zero in standard architectures. Never forward data when the source address is 0 or the destination address is 0, even if they match.
  • Data must only be forwarded if ex_reg_write is high.

Topics

MultiplexersRegistersPipeliningHazard Resolution

Solve this problem

Write the module in Verilog, SystemVerilog or VHDL. Your submission is compiled and simulated against a real testbench — you get the waveform back, not a stored answer.

This problem is part of Codiode Pro. The statement above is free to read.

Sign in to solveSee what Pro unlocks

The circuit builder and code editor need a desktop screen. On a phone, read the problem here and open it on a laptop to solve.

Related problems

  • Basic D Flip FlopEasy
  • Debug: Missing Edge in Sensitivity ListMedium
  • Read After Write Hazard DetectionEasy
  • Parameterized Interface with ModportsHard
  • Struct Array PipelineHard
  • T Flip Flop from D Flip Flop TemplateEasy
  • Recursive Generate Reduction TreeHard
  • Four Stage Shift RegisterEasy

Browse all problems · Learning tracks