A register is a vector of flip-flops with a shared clock (and usually shared reset/enable). Pipelines are just registers in series with combo between stages.
Bank / bus register
logic [31:0] data_q, data_d;
always_comb begin
data_d = data_q;
if (load) data_d = writedata;
end
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) data_q <= '0;
else data_q <= data_d;
end
Name _q / _d (or _r / _next) so intent stays obvious.
Pipeline stage
always_ff @(posedge clk) begin
if (stall) begin
/* hold */
end else begin
s1 <= s0;
s2 <= s1;
end
end
When stalling, hold all stages that must stay coherent — or use valid bits per stage.
Valid / ready pairing
Data registers alone are not a protocol. Pair with:
valid— “payload is meaningful this cycle”ready— “receiver can accept”
Fire when valid && ready. Skid buffers and FIFOs are patterned solutions when both sides can stall.
Enable vs clock gate
| Approach | Typical use |
|---|---|
if (en) q <= d |
Datapath clock enables (CE pins) |
| Integrated clock gate | Power optimization at physical design |
In RTL courses and FPGA soft logic, prefer enables.
Tips
- Reset only what must wake in a known state (control, pointers); large datapaths sometimes skip reset for area.
- Don’t read and write the same flop with combo loops — that’s latch/loop territory.
- Document pipeline latency in comments (
// +2 cycles).