verilog module-1module-2
assign vs. always: When to Use Each
A quick reference for choosing between continuous assignment (assign) and procedural blocks (always) in synthesizable RTL.
Updated 2026-04-30
The core rule
Use assign for combinational wires that are driven by an expression.
Use always @(*) (or always_comb in SystemVerilog) for combinational logic that needs sequential statements (if, case).
Use always @(posedge clk) for registered (sequential) logic.
assign — continuous assignment
wire y;
assign y = a & b; // y is always (a AND b)- The right-hand side is re-evaluated whenever any input changes.
- Left-hand side must be a
wire(orlogicin SV). - Cannot be used inside a procedural block.
- Good for: simple combinational gates, muxes, arithmetic.
always @(*) — combinational procedural block
reg y;
always @(*) begin
if (sel)
y = a;
else
y = b;
end@(*)means "re-execute whenever any signal in the sensitivity list changes".- Left-hand side must be a
reg(orlogicin SV). - Enables
if/else,case, loops. - Good for: priority encoders, decoders, complex muxes.
always @(posedge clk) — sequential (registered) logic
always @(posedge clk or posedge rst) begin
if (rst)
q <= 0;
else
q <= d;
end- Captures state on the rising edge of the clock.
- Use non-blocking assignments (
<=) to avoid race conditions. - Good for: flip-flops, registers, state machines.
Summary table
| Construct | Sensitivity | Target type | Use for |
|---|---|---|---|
assign |
continuous | wire |
simple combinational expressions |
always @(*) |
combinational | reg |
conditional combinational logic |
always @(posedge clk) |
clock edge | reg |
registers, state machines |
Common mistakes
- Driving a wire with
always:alwaysmust targetreg; useassignforwire. - Missing signals in
@(*): Use@(*)instead of listing signals manually — the synthesizer will detect all inputs automatically. - Mixing
<=and=in a clocked block: Use<=(non-blocking) inalways @(posedge clk)and=(blocking) inalways @(*).