Skip to content

Simulation vs Synthesis Code in Verilog

Introduction

When designing digital circuits using Verilog, you’ll often hear two important terms — simulation and synthesis.
Both are essential steps in a hardware design flow, but they serve very different purposes.

  • Simulation verifies how your Verilog code behaves before hardware is built.
  • Synthesis converts your Verilog code into real hardware logic that can be implemented on an FPGA or ASIC.

This article explains the difference between simulation and synthesis code in Verilog, which constructs are synthesizable, which are not, and how to write code that works for both worlds.

Simulation vs Synthesis

Aspect Simulation Synthesis
Purpose To verify logical behavior of design To generate gate-level hardware implementation
Tool Type Verilog simulator e.g., ModelSim, Icarus Verilog, Verilator Synthesis tool e.g., Synopsys Design Compiler (ASIC), Yosys (ASIC), Xilinx Vivado (FPGA), Intel Quartus (FPGA)
Output Waveforms, logs, functional verification Netlist (gates, flip-flops, connections)
Speed Software-based, slower Hardware implementation, actual circuit
Timing Simulated using delays or clock cycles Determined by real hardware constraints
Scope Any Verilog code can simulate Only synthesizable subset of Verilog supported

In short:

  • Simulation = “How can I verify and initialize my design before hardware implementation?”
  • Synthesis = “Can my design be built in hardware?”

What Happens During Simulation?

Simulation is the process of running your Verilog code on a software simulator to check its functional correctness.

A simulator interprets your code like a program — it executes procedural statements, tracks signal changes, and outputs waveforms over time.

Example

module counter_tb;
  reg clk, rst;
  wire [3:0] count;

  counter dut (.clk(clk), .rst(rst), .count(count));

  initial begin
    clk = 0;
    forever #5 clk = ~clk;  // Toggle every 5 ns
  end

  initial begin
    rst = 1;
    #10 rst = 0;
    #100 $finish;
  end
endmodule
- Here, the testbench uses delays (#5), system tasks ($display, $finish), and initial blocks — all purely simulation constructs. - None of these statements can be turned into real hardware, but they are essential for verifying logic behavior before synthesis.

What Happens During Synthesis?

Synthesis translates Verilog RTL (Register Transfer Level) code into actual hardware — gates, flip-flops, and multiplexers.

The synthesis tool:

  1. Reads your RTL code.
  2. Infers the intended hardware (based on always @(posedge clk) and combinational logic).
  3. Maps it to technology cells available in a target library (FPGA or ASIC).
  4. Generates a netlist (a gate-level representation).

Example

module counter (
  input clk, rst,
  output reg [3:0] count
);
  always @(posedge clk or posedge rst) begin
    if (rst)
      count <= 0;
    else
      count <= count + 1;
  end
endmodule

This is synthesizable RTL — it describes hardware directly (a 4-bit counter). The synthesizer infers flip-flops for count and an adder for count + 1.

Simulation-Only vs Synthesizable Constructs

Verilog contains many constructs that simulators understand but synthesizers ignore or reject. Here’s a comparison of simulation-only and synthesizable code:

Type Simulation-Only (Ignored by Synthesis) Synthesizable (Hardware-Realistic)
Delays #10 a = b; "#10" is Non-synthesizable
Timing controls @(posedge clk) in testbench In sequential always block
Initial blocks initial begin ... end For testbench only. Non-synthesizable for ASIC implementation
System tasks $display, $monitor, $finish, $random Simulation only
Force/Release force a = 1; Simulation only
File I/O $readmemb, $writememh Simulation-only (some allowed for memory initialization)
Continuous assignments assign y = a & b; Synthesizable
Combinational always block always @(*) Synthesizable
Sequential always block always @(posedge clk) Synthesizable
Blocking/Non-blocking = and <= Synthesizable (used properly)

Examples

Let’s see how the same construct behaves differently under simulation and synthesis.

Using delays

always @(posedge clk)
  #5 q <= ~d;  // delay by 5 ns

Simulation Delays q assignment by 5 ns. Synthesis Ignores the #5 completely. Hardware flip-flops delay depends on real clock and propagation time and cannot be programmed to 5ns.

Using $display

always @(posedge clk)
  $display("Value = %b", data);

Simulation Prints value of data to the console. Synthesis $display is ignored. Use $display only in testbenches, not in design modules.

Non-synthesizable Loops

integer i;
initial begin
  for (i = 0; i < 10; i = i + 1)
    #10 $display("i = %d", i);
end

Simulation Loops execute with 10 ns delay each iteration. Synthesis Entire initial block ignored; initial and delays are non-synthesizable.

Synthesizable Loops

always @(*) begin
  for (i = 0; i < 8; i = i + 1)
    sum[i] = a[i] & b[i];
end
This will synthesize to 8 AND gates.

Writing Synthesizable Verilog Code

To ensure your Verilog code synthesizes properly, follow these guidelines:

Do

  1. Use always @(posedge clk) for sequential logic.
  2. Use always @(*) or assign for combinational logic.
  3. Provide default assignments in combinational blocks to avoid unintended latches.
  4. Use non-blocking (<=) assignments in sequential logic.
  5. Keep loops bounded (finite iterations).
  6. Define resets for registers.

Don't

  1. Don’t use initial, #delay, $display, $finish, $random in synthesizable modules.
  2. Don’t mix blocking and non-blocking assignments in the same block.
  3. Don’t rely on simulation timing (#10, #100) — use real clocks.
  4. Don’t use dynamic constructs (e.g., while with variable bounds, file I/O).

Simulation-Only Testbench vs Synthesizable Design

module adder_4bit (
  input [3:0] a, b,
  output [4:0] sum
);
  assign sum = a + b;
endmodule
module tb_adder_4bit;
  reg [3:0] a, b;
  wire [4:0] sum;

  adder_4bit dut (.a(a), .b(b), .sum(sum));

  initial begin
    $display("Testing 4-bit adder");
    a = 4'b0011; b = 4'b0101;
    #10 $display("Sum = %b", sum);
    #10 $finish;
  end
endmodule
  1. The adder can be synthesized to real hardware.
  2. The testbench cannot — it’s meant for functional verification only.

Common Simulation vs Synthesis Mismatches

Issue Cause Result
Simulation works, hardware fails Used delays or initial blocks Synthesizer ignored them
Latch inferred unintentionally Missing else in always @(*) Different logic than expected
Wrong assignment behavior Used blocking = in sequential logic Race conditions
Uninitialized signals Relied on initial values Hardware starts with unknown state
Infinite loops Unbounded while loop Synthesis error or hang

Always verify both functional correctness (via simulation) and synthesizability (via synthesis reports).

Key Takeaways

  1. Simulation lets you verify your logic before hardware implementation.
  2. Synthesis turns Verilog RTL into actual logic gates.
  3. Only a subset of Verilog is synthesizable — delays, system tasks, and initial blocks are not.
  4. Always separate design code and testbench code.
  5. Test thoroughly in simulation, then verify synthesis reports before implementation.