HDLbits
Start Practicing

RTL Design Patterns/Memories

Register File (2 Read Ports, 1 Write Port)

medium
memoryregister-filecpu

Where this shows up

Every CPU datapath — even a tiny one — needs a place to hold its general-purpose registers, and needs to read up to two operands (for a typical two-input ALU instruction) in the same cycle it decodes the instruction, while writeback from a previous instruction commits to a (possibly different) register in that same cycle. That’s exactly this module’s shape: 2 read ports for operand fetch, 1 write port for writeback, single-cycle (combinational) reads so the decode stage doesn’t stall waiting on a register value.

Interface

Signal Direction Width Description
clk/rst input — Clock and synchronous, active-high reset (clears all registers to 0).
ra1, ra2 input $clog2(NUM_REGS) Read addresses for the two read ports.
rd1, rd2 output DW Combinational read data for ra1/ra2.
we input 1 Write-enable for the single write port.
wa input $clog2(NUM_REGS) Write address.
wd input DW Write data.

Read semantics: combinational, not registered

Unlike the RAM problems in this category, reads here are combinational (assign rd1 = regs[ra1];), not registered — this is what “single-cycle read” means in the spec: present an address and see the value in the very same cycle, with no extra latency. This is the opposite convention from a block-RAM-style memory, and it’s a deliberate, common choice for register files feeding directly into combinational ALU logic within one pipeline stage.

The write-then-read-same-register hazard

Because reads are combinational and writes are synchronous, if a read address matches the currently in-flight write address in the same cycle, the read sees the old value throughout that cycle — the new value only becomes visible starting the cycle after the write’s clock edge. This module does not implement same-cycle write-to-read forwarding/bypassing; if a consuming pipeline needs a value to be visible to a dependent read in the very same cycle it’s written, that forwarding logic belongs in the surrounding pipeline (this is exactly the “RAW hazard” a real CPU’s hazard-detection/forwarding unit handles), not inside the register file itself.

Correctness constraints

  • All NUM_REGS registers must reset to 0 synchronously.
  • Both read ports must be able to read any two (possibly identical) registers independently and combinationally in the same cycle.
  • A write must take effect on the following clock edge and be visible to all subsequent reads of that register.
  • The write port must not interfere with unrelated registers — writing wa must never disturb any register other than regs[wa].