Verilog Style for Synthesis
Good Verilog style is not decoration. It prevents latch bugs, width bugs, reset confusion, clock-domain mistakes, and simulation/synthesis mismatches.
Learning Objectives
By the end of this lesson, you should be able to:
- separate combinational and sequential logic;
- use blocking and nonblocking assignments deliberately;
- write reviewable reset and enable logic;
- create small modules that synthesize predictably.
Two-Block Habit
For control logic, a useful pattern is:
- one combinational block for next-state/output decisions;
- one clocked block for registers.
always @* begin
next_state = state;
done = 1'b0;
case (state)
IDLE: if (start) next_state = BUSY;
BUSY: begin
done = 1'b1;
next_state = IDLE;
end
endcase
end
always @(posedge clk) begin
if (rst)
state <= IDLE;
else
state <= next_state;
end
Assignment Rule of Thumb
| Context | Assignment | Why |
|---|---|---|
Combinational always @* |
blocking = |
describes immediate combinational calculation |
Clocked always @(posedge clk) |
nonblocking <= |
models flip-flops updating together |
| Continuous logic | assign |
simple wires/LUT logic |
Do not mix these randomly. When you intentionally break the rule, leave a comment explaining why.
Reset Style
Prefer clear synchronous resets unless the board or primitive requires asynchronous reset.
always @(posedge clk) begin
if (rst) begin
count <= 8'd0;
end else if (en) begin
count <= count + 8'd1;
end
end
Reset control state. Avoid resetting huge datapaths unless the design needs a known startup value.
Review Checklist
- Does every combinational output get a default value?
- Are all registers assigned only in clocked blocks?
- Are widths explicit for counters, constants, and concatenations?
- Is every clock-domain crossing named and synchronized?
- Are testbench-only constructs kept out of RTL?
- Are vendor-specific primitives isolated in wrapper modules?
Exercise
Take this buggy code and rewrite it safely:
always @* begin
if (sel)
y = a;
end
Then explain which hardware the original code might infer and why your rewrite avoids it.
Common Mistakes
- Missing default assignments in combinational blocks.
- Using
#delayin RTL. - Creating derived clocks with ordinary LUT logic.
- Leaving width warnings unresolved.
- Copying simulation-only code into design files.
Summary
Synthesizable Verilog should make hardware intent obvious. Keep combinational and clocked logic separate, use assignment types consistently, make widths explicit, and treat warnings as design feedback.
Next: Simulation and Testbenches.
Further Reading
- Verilator warnings guide
- Yosys Verilog support notes
- Vendor FPGA HDL coding guidelines