Common RTL Building Blocks
The small circuits you reuse everywhere
A handful of small circuits show up again and again in real designs. Knowing them as patterns means you can build most datapaths and control logic quickly, and they are common interview asks.
Edge detector
Detect the moment a signal changes, by comparing it to its value one cycle ago.
// One-cycle pulse when d goes from 0 to 1
reg d_q;
always @(posedge clk) d_q <= d;
wire rising = d & ~d_q; // falling edge: ~d & d_qShift register
// Serial-in shift register
always @(posedge clk)
shreg <= {shreg[WIDTH-2:0], serial_in};Priority arbiter
When several requesters compete, grant the highest-priority one. Here the lowest index wins.
always @(*) begin
grant = 4'b0000;
if (req[0]) grant = 4'b0001;
else if (req[1]) grant = 4'b0010;
else if (req[2]) grant = 4'b0100;
else if (req[3]) grant = 4'b1000;
endSynchronous FIFO, in one idea
A single-clock FIFO is a small memory with a write pointer and a read pointer. Write advances one, read advances the other, full is when they are about to collide, and empty is when they are equal. (The two-clock version, with gray-coded pointers, is the asynchronous FIFO in the CDC path.)
| Block | Used for |
|---|---|
| Edge detector | Turn a level change into a one-cycle pulse |
| Shift register | Serialize, delay, or align data |
| Arbiter | Pick one winner among requesters |
| FIFO | Buffer data between producer and consumer |
interviewers love asking you to code one of these on the spot: an edge detector, a round-robin arbiter, a FIFO. Practice writing each from memory. They are small, they reveal whether you really think in hardware, and they come up constantly.
a simple priority arbiter always favours the same requester, so a low-priority one can starve. If fairness matters, use a round-robin arbiter that rotates which requester has top priority each grant.