The purpose of this tutorial is introduce you to the IEEE standard hardware description language, Verilog HDL, and to the tool chain. The tool chain consists of the Modelsim simulation tool and the Synopsys synthesis tool.


The ultimate goal of chip-level design is to actually produce a chip. There are many steps involved in doing this, and this tutorial focuses on two of them: simulation and synthesis.

A simulator accepts inputs that you specify and displays what the design's anticipated outputs will be. In this tutorial, we will be doing RTL (register transfer level) simulation, in which the input to the simulator is the compiled Verilog HDL source code. Verilog HDL is a programming language for defining the structural and behavioral description of digital circuits. In RTL simulation, since no delay information is present, the simulation has no delays in it.

The simulator that you will be using is the ModelSim simulator.

Synthesis is the process of taking human-readable input such as Verilog HDL source code files and creating a low-level description which describes the design in terms of simple gates.

The synthesis tool you will be using is the Altera software package.

Below are example Verilog files.

Simple Verilog HDL

Verilog source code is plain text contained in a single file or a group of files. Verilog text files use the file extension, .v .

Four-bit Adder using an always block

Processes in Verilog are modeled with the always block. In hardware description languages, processes are blocks of statements. Processes are of two types: unclocked and clocked. An unclocked process models combinational logic; a clocked process models synchronous logic. A process is executed concurrently with respect to other processes and continuous signal assignment statements. Processes offer a variety of powerful statements and constructs that make them very suitable for high level behavioral descriptions.

The Verilog description of a 4-bit adder using a process with a sensitivity list is p4ba.v. The sensitivity list is to the right of [email protected] Generally, for an unclocked always block (no clock in the sensitivity list), signals that are read in the always construct should be placed in the sensitivity list. Since the signals, addend_one, addend_two, and carry_in are read in the process, they are included in the sensitivity list. Whenever one of the signals in the sensitivity list changes value, the always block will be executed. The assignment statements in the unclocked process use the blocking assignment operator, =. Signals written to with the blocking assignment operator are updated instantaneously. Combinational logic (unclocked always block (no clock in the sensitivity list)) should be described using the blocking assignment operator. In an unclocked always block, statements are executed sequentially. The other type of Verilog assignment operator is the non-blocking assignment operator, <=. When a signal is written to with the non-blocking assignment operator, it is scheduled to be assigned the new value at the end of the current time unit. Sequential logic (clocked always block (clock in the sensitity list)) should be described using the nonblocking assignment operator. In a clocked process using only the nonblocking assignment operator, all assignments are executed concurrently and the order does not matter. In a clocked process, only the clock and reset (if the reset is asynchronous) should be included in the sensitivity list.

In the Verilog module, sum, carry_out, and carry are declared to be of type reg because they are assigned to in the always block. No registers will be synthesized as no edge is specified in the event specification list (sensitivity list).

State Machines

A sample Verilog testbench for the moore state machine is provided: tb_moore.v.


Register File

A four 32-bit register file example is reg4.v. To read a register, the nr_w bit is set to 0; to write to a register, the nr_w bit is set to 1. The register to be read from or written to is determined by a 2-bit address. The register file module in reg4.v uses four instantiations of the 32-bit register module in the Verilog source, reg.v.

Functional RTL

Using the state machine design style 4 in moore4.v and defining the datapath operations in each state, as in the functional_rtl module in, functional.rtl.v, is a popular style of design, functional RTL style.

Some designers prefer to keep synchronous elements in a separate always block from the combinational elements. The functional_rtl module is rewritten using this style in frtl2.v. The default case in the combinational always block is needed to avoid latches being synthesized for the signals assigned to in the always block.

More State Machine Examples

  1. One unclocked always block and one clocked always block.

  2. Two always blocks and a signal assignment statement.

  3. Two clocked always blocks and one unclocked always block.

  4. One clocked always block.

  5. Two unclocked always block and one clocked always block.

Function Calls

Functions can be defined within a module. A function call can be thought of as being an inline expansion with the corresponding wire connections. Consider the following 32-bit priority encoder examples. The first priority encoder is priorityEncode32b.v. The second example breaks up the 32-bit encoder into 4 blocks of 8-bit encoders. The 8-bit encoder is called priorityEncode8.v, and the top-level 32-bit encoder is called priorityEncode32.v.

Here is another example: function_call_example.v and function_call_example_testbench.v.

In this example, we purposely use a set of function calls to illustrate the use of functions as a way to encapsulate a complex amount of logic. This encapsulated logic could then be used with non-blocking assignment statements in a clocked always statement.

Additional Examples

Here are additional examples: a4ba.v, add4.v, p4ba_alt.v, add_sub, test1.v, test2.v, test3.v, test4.v, test5.v, test6.v, test7.v, rtl_example.v, full_adder_alt.v, p4ba_alt2.v, test1_alt.v, and p4ba_alt3.v.