Why Start with Hello World? Before you describe a counter, a FIFO or a processor, you need to know that your simulator is installed correctly and that you can compile a file, run it and read its output. A Hello World program checks the whole flow in a few seconds. In this tutorial, you'll write your first Verilog program, run it, and learn the three building blocks it uses: module, initial and $display.

It's always best to get started using a very simple example, and none serves the purpose better than "Hello World !". The program below does not describe any hardware. It is a tiny testbench, a piece of Verilog that only runs in a simulator, and it prints one line of text to the console.

4 min read | Beginner Level

What You'll Learn

  • How a minimal Verilog program is structured with module, initial and $display
  • How to compile and run a Verilog file in a simulator
  • Common mistakes that stop a first program from compiling or printing

Hello World Example

Save the code below in a file, for example tb.v. Lines starting with // are comments and are ignored by the simulator.


// Single line comments start with double forward slash "//"

// Verilog code is always written inside modules, and each module represents a digital block with some functionality
module tb;

  // Initial block is another construct typically used to initialize signal nets and variables for simulation
  initial
    // Verilog supports displaying signal values to the screen so that designers can debug whats wrong with their circuit
    // For our purposes, we'll simply display "Hello World"
    $display ("Hello World !");

endmodule

Running this file in a simulator prints the message once:

Output
$ /usr/bin/vvp simulation
Hello World !

How the Code Works

Even this short program uses the three constructs that appear in almost every testbench.

module ... endmodule

A module called tb with no input-output ports acts as the top module for the simulation. All Verilog code lives between module <name> and endmodule. In a real project, a design module (for example an adder) has ports for its inputs and outputs, while the testbench module that drives it usually has none, because nothing outside the simulation connects to it. Because no other module instantiates tb, the simulator picks it as the top of the design hierarchy.

initial

The initial block starts and executes its first statement at time 0 units, and it runs only once. Here it contains a single statement, so no begin and end are needed. When an initial block contains more than one statement, the statements must be grouped with begin ... end, as shown in the mistakes section below.

$display

$display is a Verilog system task that prints a formatted string to the console and adds a newline at the end. All system tasks start with a $ and are built into the simulator. $display is the main tool for debugging: you can print the values of signals to see what your circuit is doing at a given time.

Synthesis result: Nothing. $display cannot be synthesized into hardware, and synthesis tools ignore initial blocks that only print messages. A module like tb with no ports and no logic produces an empty netlist. This is expected: a testbench is never meant to become hardware. Some FPGA tools do read simple initial assignments to set the power-up value of registers, but that is the only hardware meaning an initial block can have.

Quick Check

How many times is "Hello World !" printed if the simulation runs for 1000 time units?

Show Answer

Once. An initial block executes only one time, starting at time 0. To print a message repeatedly, you would need a loop or an always block with a delay.

Compiling and Running the Simulation

A simulation usually takes two steps: the source files are first compiled (checked for errors and converted to an internal format), and the result is then run. With the open-source simulator Icarus Verilog, the log above comes from these two commands:

$ iverilog -o simulation tb.v     # Compile tb.v into a file called "simulation"
$ vvp simulation                  # Run the compiled simulation
Hello World !

Commercial simulators follow the same idea, although many of them combine compiling and running into a single command. If the compiler reports an error, the run step never happens, so always read the first error message carefully: later errors are often caused by the first one.

Checking a New Tool Installation

When a team sets up a new compute server, a new simulator version or a continuous integration job, the first thing they run is a tiny program like this one. If "Hello World !" appears, the license, the paths and the compile and run scripts all work. If it does not, the problem is in the setup, not in the design, which saves hours of debugging a large testbench that could never have run.

Common Beginner Mistakes

Mistake #1: Several statements in an initial block without begin and end

Wrong:


initial
  $display ("Hello");
  $display ("World");      // Not inside the initial block: compile error

Right:


initial begin
  $display ("Hello");
  $display ("World");
end

Why? Without begin ... end, an initial block contains only the next statement. The second $display then sits directly inside the module, where procedural statements are not allowed.

Mistake #2: Using single quotes for strings

Wrong: $display ('Hello World !');
Right: $display ("Hello World !");

Why? Verilog strings always use double quotes. The single quote has a different meaning in Verilog: it is part of sized numbers such as 4'b1010.

Mistake #3: Forgetting the semicolon or endmodule

Wrong: $display ("Hello World !") with no semicolon, or a file that ends without endmodule
Right: End every statement with ; and close every module with endmodule

Why? The compiler often reports the error on the line after the missing semicolon, or at the end of the file for a missing endmodule. If an error line looks correct, check the line above it.

Mistake #4: Wrong capitalization of keywords and system tasks

Wrong: Module tb;, Initial or $Display
Right: module tb;, initial and $display

Why? Verilog is case sensitive. All keywords and system tasks are lowercase, and names such as count and Count are two different variables.

Mistake #5: Expecting $display to print from real hardware

Wrong: Adding $display to a design and expecting to see messages from the FPGA or chip
Right: Use $display only to debug in simulation; in hardware, observe signals with LEDs, a logic analyzer or a UART

Why? $display is a simulation-only system task. Synthesis ignores it, so the hardware contains nothing that could print text.

Practice Exercise

Challenge: Your Own Greeting

Modify the Hello World example so that the simulation prints these two lines, in this order:

Hello Verilog !
My first simulation works
Hint

You need two $display statements in the same initial block. Remember what a block with more than one statement needs.

Solution

module tb;

  initial begin
    $display ("Hello Verilog !");
    $display ("My first simulation works");
  end

endmodule

Statements inside a begin ... end block execute one after another, so the two lines are printed in the order they are written. Without begin ... end, only the first $display would belong to the initial block, and the compiler would report an error for the second one.

Summary

In this tutorial, you learned:

  • All Verilog code is written inside a module ... endmodule, and a testbench is a module with no ports that acts as the top of the simulation
  • An initial block runs once, starting at time 0, and needs begin ... end for more than one statement
  • $display is a system task that prints a message to the console, followed by a newline
  • A simulation is compiled first and then run, and the first error message is the one to fix first
  • $display and print-only initial blocks are simulation features that synthesis ignores
Did you find what you were looking for?

Quiz

Test Your Knowledge

1 of 5 Score: 0 / 5