Skip to content

Always and Initial block in Verilog

Introduction

In Verilog, two fundamental procedural constructs control how simulation and hardware behavior are described — the and blocks. While they look similar syntactically, they serve very different purposes in RTL design.

This article explains in detail the difference, syntax, use cases, and best practices of always and initial blocks in Verilog.

What Are Procedural Blocks?

Procedural blocks describe behavioral code — statements that execute in time order (unlike continuous assignments that model combinational logic directly).

There are two kinds:

  • always block → can execute repeatedly throughout simulation.
  • initial block → executes only once at the start of simulation.

Both blocks contain procedural statements such as if, case, for, and procedural assignments (= and <=).

The initial Block

Purpose

The initial block is used for code that should run only once at the beginning of simulation. It is not synthesizable in most designs (with exceptions like FPGA initialization).

Syntax

initial begin
  // statements
end

Behavior

  • Executes once at time 0.
  • Used for testbenches, initialization, or stimulus generation.
  • Can contain time delays (#), loops, and display statements.

Example: Testbench Initialization

module tb;
  reg clk, reset;

  initial begin
    clk = 0;
    reset = 1;
    #10 reset = 0;   // release reset after 10 time units
  end

  always #5 clk = ~clk; // clock generation
endmodule

In this example:

  • The initial block runs once to initialize signals.
  • The always block toggles the clock every 5 units.
initial begin
  #10 data = 8'hFF;  // delay — simulation only
end

Delays (#) are not synthesizable.

Key Use Cases

  • Testbench stimulus
  • Setting initial register values
  • Generating files or logs with $display, $fwrite, etc.

The always Block

Purpose

always blocks describe repetitive behavior — they keep executing whenever signals in the sensitivity list change or when triggered by clock edges. A sensitivity list is a list of signals or events that trigger the execution of a procedural block, such as an always block. The list controls when the statements inside the block are re-evaluated by the simulator. The sensitivity list is declared after the @ symbol, as in always @(sensitivity_list).

Syntax

always @(sensitivity_list) begin
  // procedural statements
end

For always blocks that model combinational logic, the sensitivity list must include all input signals to prevent a mismatch between simulation and synthesis.

always @(a, b, c)
  out = a & b | c;

A better alternative featuring wildcard/automatic (*) sensitivity list is mentioned below. It includes all the signals.

always @(*) 
  out = a & b | c;

A problematic sensitivity list

always @(a, b) 
  out = a & b | c;

It leaves out c which can cause unexpected synthesis.

Sensitivity List Types

  1. Combinational Logicalways @(*)
  2. Sequential Logicalways @(posedge clk) or @(negedge clk)

Example: Sequential Logic (Flip-Flop)

always @(posedge clk or posedge reset) begin
  if (reset)
    q <= 0;
  else
    q <= d;
end

This block executes on every rising edge of the clock or reset.

Example: Combinational Logic (Mux)

always @(*) begin
  if (sel)
    y = a;
  else
    y = b;
end

This executes whenever any input changes.

Key Use Cases

  • Modeling combinational and sequential logic
  • Describing RTL behavior
  • Synthesizable hardware design

Difference Between always and initial

Feature initial Block always Block
Execution Runs once at start of simulation Runs continuously whenever triggered
Sensitivity Implicit (starts at time 0) Explicit sensitivity list required
Synthesizable Generally no Yes (with correct style)
Common use Testbenches, stimulus RTL logic, clocks, registers
Timing controls Allowed (#5, wait) Allowed, but not in synth code
Number of blocks Usually one or few Often many (per logic group)
Typical location Testbench files RTL design modules

Example: initial + always Together in Testbench

module tb_counter;
  reg clk, reset;
  wire [3:0] count;

  // DUT instance
  counter uut (.clk(clk), .reset(reset), .count(count));

  // Generate clock
  always #5 clk = ~clk;

  // Apply reset and monitor
  initial begin
    clk = 0;
    reset = 1;
    #10 reset = 0;
    #100 $finish;
  end

  // Display output values
  initial begin
    $monitor("Time=%0t Count=%0d", $time, count);
  end
endmodule

Here:

  • The `` block generates a clock signal forever.
  • The `` block provides stimulus (reset, finish).

Multiple Procedural Blocks

You can have multiple initial and always blocks in one module. Each runs independently and concurrently — similar to multiple parallel processes.

initial clk = 0;
always #5 clk = ~clk;

initial begin
  #100 $finish;
end

All start at time 0 and execute in parallel.

Synthesizable vs Non-Synthesizable Context

Construct Simulation Synthesizable Typical Use
initial begin #10; end Yes No Testbench
always @(posedge clk) Yes Yes RTL logic
always @(*) Yes Yes Combinational logic
initial begin value = 0; end Yes depends on FPGA Register init

FPGA synthesis tools sometimes allow initializing registers using initial (e.g., Xilinx Vivado). ASIC tools usually do not.

Blocking vs Non-Blocking Assignments in These Blocks

  • Inside combinational always @(*) → use blocking (=).
  • Inside sequential always @(posedge clk) → use non-blocking (<=).

Example:

initial begin
  a = 0;
  b = 1;
  c <= 2; // fine, executes once
end

Common Mistakes

Mistake Description Consequence
Using initial for synthesizable timing Non-synthesizable Ignored by tools
Missing sensitivity list in always Incomplete simulation Wrong behavior
Using # delay in RTL Not synthesizable Hardware mismatch
Mixing = and <= incorrectly Race conditions Unpredictable results

Summary

Concept initial always
Executes Once at time 0 Repeats on trigger
Used in Testbench Design logic
Synthesizable Usually no Yes
Typical purpose Initialization, stimulus Combinational / Sequential logic
Delay allowed Yes No (for synth)
Example initial clk = 0; always @(posedge clk)

Key Takeaways

  • initial executes once; always executes forever.
  • Only always blocks can infer flip-flops or logic during synthesis.
  • Both blocks run concurrently in simulation.