Table of ContentsPreviousNextIndex

Put your logo here!

FPGA Simulation

A SystemVerilog Primer for VHDL Coders

Ray Salemi

Please feel free to share this primer.

To download a PDF version of this primer and receive updated versions sign up for my Email Newsletter.

Version 1.0

June 22, 2009

Ray Salemi, 2009

The debate between Verilog and VHDL has raged for twenty years, and as an AE for Mentor Graphics I still get questions about which is the better language. The answer to this question has become clear: both languages work for RTL design.

I say this because if there were a clear winner, the market would have shaken it out by now. But because both languages still exist for RTL design, one has to conclude that either can be used to design logic successfully. The same cannot be said in the world of verification. When it comes to writing test benches and simulating complex designs, the clear winner is SystemVerilog.

SystemVerilog is an extension of Verilog. It delivers features such as randomization, functional coverage, and assertions, which allow engineers to create powerful test benches.1 SystemVerilog allows users to create objects and implement object-oriented libraries. Object-oriented programming allows engineers to encapsulate complex behaviors in easy-to-use objects and reuse them. The Open Verification Methodology (OVM) is one such library.

SystemVerilog is an open language that is replacing the proprietary language e, which was the grand-daddy of all verification languages. Engineers learning how to do modern verification are learning how to write in SystemVerilog.

This primer teaches VHDL users about SystemVerilog in the terms of VHDL. People learn faster when they can anchor new concepts to existing concepts. It's easier to say that "a softball is like a baseball, only bigger," than to describe the specifications of a softball from scratch. Likewise, it's much easier for a VHDL engineer to learn SystemVerilog if the latter is described in terms of VHDL.

This primer is not a complete description of SystemVerilog. (The Language Reference Manual for SystemVerilog is over 1400 pages long.) Instead, it describes the basic features of SystemVerilog and provides enough SystemVerilog information so that a VHDL engineer could create test benches like those in FPGA Simulation: A Complete Step-by-Step Guide.

You'll probably have more questions about SystemVerilog after reading this primer than you had before reading it. The website hosts forums where you can ask those questions and learn more about SystemVerilog. Also, members of the FPGA Simulation newsletter will receive new versions of this primer as I update it based on feedback.

1 A Matter of Philosophy

The biggest controversy between Verilog and VHDL has been a matter of philosophy. Specifically, how much should the compiler protect the programmer from stupid errors? VHDL represents one side of the argument. The VHDL (and ADA and Pascal) approach says that a language should capture as much of the designer's intent in the language's syntax and semantics. The VHDL philosophy requires designers to be very clear when describing the data in the design, as well as the way that data gets moved around.

Verilog represents the other side of the argument. The Verilog (and C and Perl) approach says that a language should make common assumptions about intent and that the designer is responsible for understanding those assumptions so that the code can be kept relatively sparse, or "terse."

Let's look at an example of these philosophies by implementing an adder in both languages and comparing the code. The adder looks like this in the Precision RTL synthesis tool from Mentor Graphics:

FIGURE 1. A Simple Adder

This adder takes two 8-bit inputs and adds them together on the positive edge of the clock. It produces an 8-bit sum and a carry bit. It is reset asynchronously when the reset is low.

Let's see how we implement this in VHDL and Verilog.

1.1 VHDL Adder

Here is the code for the VHDL Adder:

FIGURE 2. The VHDL Adder

This VHDL code demonstrates something important about VHDL: nothing is left to be handled by the simulator. Every aspect of this adder is clearly defined in the code.

First, the IEEE libraries we are using are clearly defined. You can look up their definitions and fully understand what the std_logic and std_logic_vector data types do and how they work. You can even look up what the + and & operators mean.

We can see another sign of clarity in VHDL when we look at lines 19-27. These lines handle the fact that we are taking two 8-bit operands and creating a 9-bit result. Line 27 does the actual summation, and sum_int is a 9-bit number. This means we need to extend the 8-bit A and B inputs so their data can be used in a 9-bit addition.

Notice also that VHDL separates a component's interface (the entity) from its implementation (the architecture). This allows us to change architectures without changing the interface to the block. Finally, notice that we explicitly set the carry and sum outputs when the clock goes high. Let's compare this to a SystemVerilog module.

1.2 The SystemVerilog Adder

Here is the code for the SystemVerilog Adder:

FIGURE 3. SystemVerilog Adder

The first thing we notice about the SystemVerilog description is its terseness. Where the VHDL adder takes 39 lines, the SystemVerilog adder takes 14. This is because SystemVerilog assumes that the user is engaged in a specific task (describing hardware) and has shared assumptions about how the language works.

The first assumption is that there is no separation between the interface to the module and its implementation. The port list on lines 2-7 apply only to the code below. If we wanted a different implementation of the adder (for example, at the gate level), we would need to compile a different version of the adder.

The biggest difference between the descriptions is that SystemVerilog makes assumptions about the size of the values in this design and they way they are extended and truncated. The addition on line 13 uses the concatenation operators "{}" to create a 9-bit output. Then it adds two 8-bit numbers and places the result in the 9-bit output.

SystemVerilog relies upon the user to understand how the + operator works and whether it will create a 9-bit output. Of course, it works fine in this case, because that is exactly how addition works. If A and B were being multiplied, then the result would get truncated to fit in 9 bits.

This is the crux of the debate over using VHDL or Verilog for RTL design. VHDL designers are horrified by Verilog's cavalier attitude about its data types and how they are used. They don't like relying upon the simulator to "do the right thing." Instead, they want to see what's happening and control it.

The Verilog designers are horrified by the amount of code VHDL takes to do "simple" tasks. They want to use the fact that they understand the simulator's behavior in order to write shorter code that (they feel) does not obscure the design's "intent."

As we can see, this is mostly an argument over taste and personal preference. Both approaches obviously work. The one that appeals to you depends upon factors such as your upbringing, your personality type, and which language you learned first.

Now that we've seen the basic philosophical differences, let's look at the details of SystemVerilog, by using VHDL as a springboard.

2 SystemVerilog is Case Sensitive

It's worth giving a page to this fact. SystemVerilog is case sensitive, so CLK is different from clk.

All keywords must be in lower case.

Variables with different cases are different variables.

This is, of course, "opposite the case" with VHDL, which is case insensitive.

3 Processes and Sensitivity Lists

VHDL and SystemVerilog create threads to simulate simultaneous behavior. VHDL does this by using the process block. Verilog uses always blocks and initial blocks. In both languages, the simulator launches the blocks in a random order at time zero.

3.1 A VHDL Process Block

For example, here is the primary process in the VHDL adder:

FIGURE 4. A VHDL Process Block

This process demonstrates the basics of VHDL processes. It does the following:

Because process blocks loop continually, we need to use a wait statement to force them to execute only once.

3.2 SystemVerilog always Blocks and initial Blocks

The first difference between Verilog and VHDL is that Verilog has two flavors of processes:

Both initial and always blocks use begin and end statements to contain multiple statements. SystemVerilog allows you to put a single statement into a block without the begin and end.

Here is the always block from the SystemVerilog adder:

FIGURE 5. SystemVerilog always Block

This always block acts exactly like the VHDL one in Figure 4. It loops continuously and waits for the sensitivity list in order to start running. We'll discuss the sensitivity list in the next subsection.

The reader may notice that this example has a begin on line 10 and an end on line 15. Because the if statement is considered a single statement, the begin and end were not strictly necessary in this block; however, if you use them you will not run into syntax errors.

Like an always block, an initial block starts at time zero, but the latter executes only once.2 Here is the initial block from the module that tests the adders:

FIGURE 6. SystemVerilog Initial Block

This block starts at time zero and sets the clk and rst_n signals to 0 along with the input data. Then it waits for the positive edge of the clock to arrive twice, raises the rst_n signal, and exits. Once it is finished, it is removed from the simulation. This is just like a VHDL process with an infinite wait statement at the end of it.

Lines 14 and 15 bring us to the issue of waiting and sensitivity lists. This is the topic of our next section.

4 Waiting for Time and Events

VHDL has a wait statement that we can use to wait for signals to achieve a value, or for a certain amount of time to pass. SystemVerilog also allows you to wait for things to happen. There are three types of delay in SystemVerilog:

All three of these approaches can control looping through an always block, or control execution in an initial block. We'll look at each in turn.

4.1 Time Delays

SystemVerilog uses the # operator to specify time. Here is a simple example that creates a clock:

FIGURE 7. SystemVerilog Clock Generator

This example demonstrates basic time control in SystemVerilog. There are additional controls that manage the simulation precision. Those are discussed at

4.2 Event Delays

SystemVerilog events take zero time to execute, as they just represent changes to a signal's value. Signals can change in two ways: they can go up, generating a positive edge event, or go down, generating a negative edge event.

We use the @(<event>) construct to wait for events. Here is a piece of SystemVerilog code that demonstrates event delays:

FIGURE 8. Event Delays in SystemVerilog

Event delays such as these can go anywhere in your procedural code. They are useful for creating monitors that watch busses and respond to protocol signals.

When we run the code we see the following:

FIGURE 9. Watching Events in SystemVerilog

We can see here that the @(clk) always block triggers with every clock edge. The other two always blocks are limited to triggering on the positive or negative edge. Notice that we can't control which always block will trigger first. In this example, the posedge and negedge blocks triggered first, but that might not always be the case with a different simulator or a different version of this simulator.

You can combine various events with the or keyword. This is the same as using a comma in a VHDL sensitivity list.

4.3 Boolean Condition Delays

The SystemVerilog wait statement is equivalent to the VHDL wait until statement. The SystemVerilog wait blocks execution until its argument is nonzero, and then continues. SystemVerilog does not strongly separate boolean operations from conditional operations. Consequently, you can use any statement in the test as long as it returns a zero or nonzero value. For example:

FIGURE 10. Waiting for a 0

When we run the code it looks like this:

FIGURE 11. Waiting for x to reach 0.

Now that we've studied the different ways to wait in SystemVerilog, we can look at sensitivity lists.

5 Sensitivity Lists in SystemVerilog

SystemVerilog and VHDL have similar ways of handling sensitivity lists, but with one big difference. VHDL sensitivity lists respond to every change on their signals, and then the programmer uses if statements to sort out the clock edge. SystemVerilog sensitivity lists can limit their responses to a particular edge. Here is a simple D flip-flop in both VHDL and Verilog:

FIGURE 12. Figure 12: Sensitivity Models in SystemVerilog and VHDL

Both of these models create the same design, a simple D flip-flop. Each model has a process that has two signals in the sensitivity list.

The first thing to notice is that SystemVerilog always and initial blocks allow you to place a sensitivity list right after the always or initial keyword. In fact, an always block with no delay or sensitivity list will hang the simulator, as it causes it to spin infinitely.

The VHDL design has a process with clk and rst on the sensitivity list. This means that this process will suspend until clk or rst changes. Then the process will use if statements to check whether the rst is low or clk has just risen.

The SystemVerilog sensitivity list works differently. It uses the edge of the clock as part of the sensitivity. Consequently, it will start running only at the positive edge of clk or the negative edge of rst. It still needs to check whether rst low; however, after that it can assume that clk has just risen, because of the posedge keyword.

This additional qualification on the sensitivity list is the primary difference between VHDL and SystemVerilog. Notice also that SystemVerilog uses the or keyword to create a list of events on a sensitivity list, whereas VHDL uses a comma.

6 SystemVerilog Data Values

Now that we can create processes in SystemVerilog, we are ready to talk about data types. Here too, SystemVerilog and VHDL have very different philosophies.

VHDL was written to allow future users to create a wide variety of descriptions. Therefore, it allows its users to define anything they want as data types. You could have a data type in VHDL with values such as "red" and "yellow." You could even create a "+" operator for these values, so that

color:= red + yellow 

is a legal statement, and color can take on the value of orange.

This means that if you want to use VHDL for hardware design, you need to create a set of data types that describe hardware. Fortunately, because it would be bad for each developer to create a different set of values, the IEEE stepped in and created std_logic, std_logic_vector, and all the other libraries.4

As with most things, SystemVerilog took a different approach. SystemVerilog assumes that you are designing or describing hardware, so it has built in four data values that can be used for hardware design:

(Notice that there are no quotes around these numbers.)

All SystemVerilog values are a combination of these values on a bit-wise basis. SystemVerilog converts every integer to a set of these values.

6.1 Multi-Bit Values

VHDL has std_logic for single-bit values and std_logic_vector for multi-bit values, where a single-bit value looks like '0' and a multi-bit value looks like "00000000". (Both of these values are assumed to be in a binary radix.)

SystemVerilog allows you to combine the radix, the width, and the value into a single string. Constants in SystemVerilog look like this:



Here are some examples of legal SystemVerilog numbers:

TABLE 1-1. SystemVerilog Values
32-bit hexadecimal number
24-bit hexadecimal number
Same as `d48. A decimal integer, 32-bits wide.
Illegal. Numbers with no radix designator must be decimal.
One hundred and one in decimal
A 3-bit binary number representing the value 5.
"00011000" as a VHDL std_logic_vector.
`1' in VHDL std_logic
This is a 32-bit value with 31 zeros and a single bit set. You can put it into a single-bit value, as we'll see below, so it acts like `1'.
An 8-bit octal number (8'b1001_1010). Notice that the underscore is legal in a number in SystemVerilog
Illegal1 binary value.
Binary number with one bit unknown.
Driving high-impedance to a 16-bit bus.

Notice that unlike std_logic_vector, or std_logic, these numbers are not strings of bits. There is no need to encase them in quotes, because they are just numbers in the program.

Of course, you can't just write programs with numbers. You need variables, and that brings us to the SystemVerilog data types.

7 SystemVerilog Data Types

Creating hardware, or programs that interact with hardware, requires a four-state data model. You need to be able to handle the values 1, 0, X, and Z. VHDL implements this with the IEEE data types such as std_logic and std_logic_vector. SystemVerilog inherently delivers these data types, so there is no need for additional libraries.

There are two basic kinds of data types. There are 2-state types that can only hold 0s and 1s, and there are four-state types that can hold 0s,1s, Xs, and Zs.

7.1 4-State Data Types

The 4-state data types are similar to the data types you'd use for a VHDL signal, usually a std_logic or std_logic_vector type. There are four of these types:

Most designs you see will use the logic and reg data types to store data in procedural SystemVerilog.

7.1.1 4-State Data Types

The logic, reg, integer, and time data types can store values in procedural code within always blocks. The bits in these data types can take on the values 0, 1, X, and Z.

The wire, logic, and reg data types can also be used to connect modules. Variables that connect modules vary their value based on how they are driven from their module blocks. These types take on the value of X if they are not driven.

If two or more modules drive the same signal, then the simulator figures out the value. In the default case of logic, reg, or wire the following table applies:

TABLE 1-2.
Default Conflict Resolution in SystemVerilog

The default conflict in SystemVerilog acts as you would expect a wire to act. SystemVerilog has other resolution behaviors that you can control with different wire types such as wor, and wand, and with different drive strengths. But these are beyond the scope of this primer.

7.1.2 2-State Data Types

The 4-state data types can handle the unknown values of X and Z, but they take more memory and run more slowly than 2-state data types. The 2-state data types can only handle 1 and 0, but they need fewer resources, so some people prefer to use them if it isn't necessary to handle unknowns.

The 2-state data types can be further broken down in integral data types and floating-point data types. Here are the integral data types:

7.1.3 Signed and Unsigned

By default, all the 2-state variables (except bit) are signed. So a byte variable set to 8'b11111111 is equal to -1, not 255. A signed 8-bit variable can take the values of -127 to 128, while an unsigned 8-bit value can take the values from 0 to 255.

We change our signed variables into unsigned variables with the unsigned keyword, like this:

FIGURE 13. Defining a Variable as Unsigned

This code gives the following result when we run it:

FIGURE 14. Results of signed and unsigned

7.2 Defining Data Widths and Depths

The logic (and reg) data types are one bit wide by default. Of course, there are very few one-bit registers in a design, and we have memories, so we need to be able to define width and depth when we define data.

As an example let's define a register and a memory:

FIGURE 15. Declaring Registers and Memories in VHDL

This little example shows how VHDL declares registers and arrays. Here's how SystemVerilog declares the same register and memory:

FIGURE 16. Declaring Registers and Memories in SystemVerilog
FIGURE 17. Bit Select Example

Here is what happens when we run this example:

FIGURE 18. Bit Select in Action

8 Variable Assignments

Now it's time to take these variables and start moving them around in programs. While both VHDL and Verilog have similar assignment approaches, their philosophy around legal assignments, and what the simulator will do for you, are worlds apart. In this section we'll discuss three topics:

We'll start by talking about type conversion, because this affects all other assignments.

8.1 Type Conversion and Width Management

SystemVerilog was designed to create hardware, and so the simulator automatically implements type conversion and width management policies that match the needs of hardware developers. This is disconcerting to VHDL writers, because a lot of what happens in a SystemVerilog program consists of hidden magic, whereas VHDL requires developers to define the conversions explicitly.

This discussion focuses on the integral data types. Engineers use these types to describe logic or create test benches. Because all these data types describe strings of bits, SystemVerilog simply allows you to assign them to each other. There is no need to explicitly cast an int to a reg, for example. SystemVerilog simply "does the right thing" here by moving the bits over.

8.1.1 Boolean Operations and Conditionals

SystemVerilog has no explicit boolean data type. Instead, all conditionals follow the same rule:

FIGURE 19. Boolean Conversions in Action

This snippet of code is part of a cache's state machine. The cache checks for two signals:

Neither of these signals was declared as a boolean; in fact, they are both wire types. SystemVerilog treats these signals as boolean operators in this context; they are true if they are nonzero.

In VHDL we would have explicitly written ("cpuwait='1') or (cpu_wr='1') to implement the same behavior.

8.1.2 Width Conversion

SystemVerilog allows you to make assignments where the number of bits on the right-hand side (RHS) of the assignment is different from the number of bits on the left-hand side (LHS) of the assignment. The simulator automatically manages the width differences by following these rules:

This automatic width management can create some surprises for the programmer. For example, if you try to put the constant 4'h8 into a 3-bit value, you'll get 3'h0 instead, because the top bit will be cut off.

Here is an example from the book FPGA Simulation: A Complete Step-by-Step Guide that demonstrates truncation and extension:

FIGURE 20. Truncation and Extension
FIGURE 21. Truncation and Extension in Action

The biggest difference between SystemVerilog and VHDL in the area of assignments is that Verilog tries to do the right thing (and usually succeeds) when you assign data, and VHDL makes you connect all the dots syntactically.

8.2 Concurrent Assignments

Both VHDL and SystemVerilog allow you to define expressions that the simulator evaluates continuously. We call these concurrent assignments in VHDL, and we call them continuous assignments in SystemVerilog. SystemVerilog uses the assign keyword to define continuous assignments.

For example, here is a MUX defined in VHDL with a concurrent assignment:

FIGURE 22. VHDL MUX with Concurrent Assignment

We see that the architecture consists only of the concurrent assignment. We use the conditional assignment to implement the MUX functionality.

Here is the same design in SystemVerilog:

FIGURE 23. SystemVerilog MUX with Continuous Assignment

We can see Verilog's C heritage in the conditional assignment operator. This continuous assignment, with the assign keyword, is just like the concurrent assignment in VHDL.

8.3 Blocking and Nonblocking Procedural Assignments

Both VHDL and Verilog allow you to create assignments that either (1) happen all together in the same clock edge, to simulate assigning values to a register (nonblocking); or (2) happen sequentially, to implement an algorithm (blocking).

Both languages use the <= operator to indicate a nonblocking assignment. The difference is that SystemVerilog can use any type for nonblocking assignments, whereas VHDL requires that you use the variable type for nonblocking assignments.

Here is an example of a multiply/ADD circuit with blocking and nonblocking assignments in VHDL:

FIGURE 24. Multiply Add with VHDL

This VHDL design demonstrated both blocking and nonblocking assignments. We used blocking assignments, implemented with the:= operator, in a combinatorial process to create the multiply/add value. Then we used nonblocking assignments, implemented with the <= operator, in a clocked process to assign the value to a register. This is a good coding style that avoids race conditions.

Now let's implement the same code in SystemVerilog:

FIGURE 25. Multiply/Add in SystemVerilog

In this section we learned how to implement blocking and nonblocking behavior in SystemVerilog. We saw that SystemVerilog controls this behavior entirely through the operators = (blocking) and <= (nonblocking).

Now we'll put all this information together in a test bench example.

9 Example Test Bench

As we've discussed, SystemVerilog is a new language targeted at creating test benches. In this primer, we saw how SystemVerilog works by using the concepts from VHDL. We'll now put those concepts together in an sample test bench. We are going to test our multiplier from Chapter 8. You can find this code in the folder systemverilog_primer/assignments/blocking_non_blocking.

We will create a test bench that ensures that the VHDL and SystemVerilog multipliers give the same results, and that those results are correct. You could use a similar test bench to check whether your Verilog gate-level simulation gives the same results as your VHDL RTL.6

This test bench demonstrates two features of advanced test benches, even though it is relatively simple. It generates its own stimulus, and it checks its own results.

FIGURE 26. SystemVerilog Test Bench for Multiply/Add

When we run the simulation we get the following result:

FIGURE 27. Results of Multiply/Add Test Bench

You can see the $monitor statement in action here. It prints twice for each test value, once when the inputs change, and again when the outputs change. $monitor always runs at the end of a time step. Notice that the prediction happens in the same timestep in which the inputs change, and then the outputs follow the prediction.

10 Why Learn SystemVerilog?

This primer has covered the basic structure of SystemVerilog in the context of VHDL. While it is far from a complete description of SystemVerilog (the SystemVerilog Language Reference Manual is over 1400 pages long), it does give you enough to get started with SystemVerilog. It also brings us to the question of why you should bother to learn SystemVerilog.

SystemVerilog is worth learning because the industry, that amorphous group of all of us that makes a bandwagon, has decided it is the future of RTL verification. While VHDL can do many of the things that are possible in SystemVerilog (though not some crucial ones such as covergroups), VHDL does not have the industry behind it, and so VHDL does not have free class libraries designed to support RTL verification.

While different EDA companies tout different class libraries (Synopsys supports the VMM, while Cadence and Mentor support the OVM), all three companies support SystemVerilog as their language of choice for verification.

This means that verification libraries and verification IP will soon appear exclusively in SystemVerilog. This is already happening. The Open Verification Library (OVL), which supplies assertions to engineers, has 50 assertions written in SystemVerilog but only eight that are written in VHDL. This trend continues in other areas. This industry support makes it well worth learning SystemVerilog.

I hope that this primer has helped you get started down the path to learning SystemVerilog. If you have any questions about the topics in this primer, please post them at I will answer them there, and use them to create future versions of this primer. I'll notify you of updates on the FPGA Simulation email newsletter.

11 Revisions

TABLE 1-3. SystemVerilog Primer Revisions
0.1 Beta
Test release.
Revisions from Michael Meyer
Initial release

Quadralay Corporation
Voice: (512) 719-3399
Fax: (512) 719-3606
Table of ContentsPreviousNextIndex