Procedural Blocks in Verilog
Procedural blocks are the primary mechanism for describing behavior in Verilog. They contain sequential statements that execute in order, unlike continuous assignments which are always active.
Verilog has two procedural block types: initial and always.
initial Block
An initial block executes once at simulation time zero and then terminates.
It is used in testbenches to set up initial conditions and apply stimulus. Initial
blocks are not synthesizable and should not appear in RTL design files.
module tb_example;
reg a;
reg b;
initial begin
a = 0;
b = 0;
#10 a = 1;
#10 b = 1;
#10 $finish;
end
endmodule
Multiple initial blocks can coexist in a module; they all start at time zero
and execute concurrently.
always Block
An always block executes repeatedly whenever its sensitivity list is
triggered. If there is no sensitivity list, it runs forever (useful for clock
generation in testbenches, not in RTL).
// Clock generator (testbench only)
reg clk = 0;
always #5 clk = ~clk; // Toggle every 5 ns → 10 ns period
Sensitivity Lists
The sensitivity list after @ specifies what triggers the always block.
Edge-sensitive — triggers on a signal transition:
always @(posedge clk) // Rising edge of clk
always @(negedge clk) // Falling edge of clk
always @(posedge clk or posedge reset) // Either event
Level-sensitive (combinational) — triggers when any listed signal changes:
always @(a or b or sel) // Explicit list
always @(*) // Implicit: all signals read in the block
Using @(*) for combinational logic is strongly preferred — it is less
error-prone because you cannot accidentally omit a signal.
Blocking Assignment (=)
A blocking assignment executes immediately and blocks the next statement until it completes. Statements execute one after another, like software.
always @(*) begin
temp = a & b; // Executes first
y = temp | c; // Executes after temp is updated
end
Use blocking assignments in combinational logic blocks.
Warning
Using blocking assignments inside a clocked always block can cause
simulation mismatches with synthesized hardware. Avoid this pattern.
Non-Blocking Assignment (<=)
A non-blocking assignment schedules an update to happen at the end of the current time step. All right-hand sides are evaluated first, then all left-hand sides are updated simultaneously.
always @(posedge clk) begin
a <= b; // Both right-hand sides evaluated first
b <= a; // Then both left-hand sides updated → swap without temp
end
Use non-blocking assignments in clocked (sequential) logic blocks.
Combinational Logic with always
An always @(*) block models combinational logic when every output is assigned
under every possible condition (no latches inferred).
reg y;
always @(*) begin
case (sel)
2'b00: y = d0;
2'b01: y = d1;
2'b10: y = d2;
2'b11: y = d3;
default: y = 1'bx;
endcase
end
Warning
If a signal is not assigned in all branches of an always @(*) block, the
synthesizer infers a latch. Always include a default case or assign
default values at the top of the block.
Sequential Logic with always
A clocked always block captures state — it synthesizes to flip-flops.
module d_flip_flop (
input wire clk,
input wire reset,
input wire d,
output reg q
);
always @(posedge clk or posedge reset) begin
if (reset)
q <= 1'b0;
else
q <= d;
end
endmodule
The structure above is the standard pattern for an asynchronous active-high reset D flip-flop.
Assignment Rule Summary
Context |
Use |
Reason |
|---|---|---|
Combinational |
Blocking |
Executes sequentially like software logic |
Clocked |
Non-blocking |
Models flip-flop sampling correctly |
Testbench |
Either (blocking is common) |
Simulation only; no synthesis concern |
See Also
Verilog Data Types —
wireandregtype rules.Finite State Machines in Verilog — Applying procedural blocks to state machine design.
Verilog Testbenches — Using
initialandalwaysin simulation.