User Guide: DSim Language Conformance Options

Modified on Thu, 11 Jul at 11:43 AM

User Guide: DSim Language Conformance Options

SystemVerilog is not rigorously defined, and it has evolved over the years. Unfortunately, a good many testbenches, including the reference implementation of UVM itself, will not compile on a strictly conforming SystemVerilog compiler. For this reason DSim provides switches to relax its interpretation of the SV-LRM.

Option Description
-shared-unit-scope Use single compilation-unit scope shared by all compilation units
-separate-unit-scopes Give each compilation unit its own compilation-unit scope
-all-class-spec Create default specializations for all parameterized classes
-all-pkgs Generate code for all packages, even those not referenced
-allow-int-enum-assign Allow assignment from integral expression to enum without a cast
-allow-string-int-assign Allow assignment between strings and integers without a cast
-implicit-bitstream-assign Allow assignment between any bitstream types without a cast
-int-time-literal Treat time literals as integers
-allow-ext-vif Allow implicitly specialized virtual interfaces, with restrictions
-allow-self-vif Allow use of bare interface identifier as self virtual interface reference
-allow-fwd-pkg Allow references to items in packages declared later in the code

Treatment of Compilation Unit Scope

Each file referenced on the dsim or dvlcom command line, together with everything the file transitively includes is treated as a potential compilation unit. The "compilation unit scope" is a scope that surrounds the compilation unit. Clause 3.12.1 of the SV-LRM requires that tools support both of the following options:

  • A single compilation unit scope that encloses all files in the design. This option is selected with -shared-unit-scope and is the default.
  • A separate scope for each potential compilation unit. This option is selected with -separate-unit-scopes.

Treatment of Unreferenced Packages and Classes

By default, DSim will compile the code for a package into the final image only if the package is referenced by the rest of the design in some way - either through use of an identifier using pkg_name::id_name syntax, or through a package import.

However, it is possible to define a package having a class that has a static initializer that calls some method:


package P;
  class C;
    static bit foo = other_pkg::other_class#(C)::do_something();


If nothing else references package P then the package will not be compiled by default. However, some testbenches may expect P to be compiled, and at run time, the static initializer calls do_something() which may result in creation of an instance of C. UVM tests work this way: when you write `uvm_component_utils(test) you are creating a static initializer that registers the class with the UVM factory, from where it can be instantiated if selected on the command line. In order to get this style to work, the -all-pkgs option is provided, which will force all packages to be compiled.

Along similar lines:


class C#(type T = int);
  static bit foo = other_pkg::other_class#(C)::do_something();


By default, DSim will not create a default specialization for a parameterized class. Instead, it will create specializations only for what is actually referenced. Again, any static initializers in parameterized classes that are not instantiated will not get run. The option -all-class-spec will override this behavior and force the creation of the default specialization.

Cast Permissiveness

The SV-LRM prohibits assignment of an integer to an enum without an explicit cast. Nevertheless, it appears that other tools do permit this, and legacy testbenches or third-party verification IP code may rely on this. The -allow-int-enum-assign switch will suppress this check, making enums almost useless (you have the enum methods, but no type safety) but allowing broken code to compile.

Similarly, other tools seem to permit arbitrary assignment between integers and SystemVerilog strings without an explicit bitstream cast. We believe this to be extremely dangerous, as code errors will not be caught. More generally, some tools permit any bitstream type to be assigned to any other bitstream type without an explicit cast! The -allow-int-string-assign will permit cast-free assignments between SystemVerilog strings and integers; -implicit-bitstream-assign permits any bitstream cast without an explicit cast.

Integral Time Literals

The SV-LRM specifies that a time literal such as 1us is a realtime (floating point) value, scaled to the time unit currently in effect for the containing design element. Consequence: time literals cannot be used in constraints, as constraints must involve integral values only (at least for bidirectional solving). At least one tool seems to support real-valued constraints, and therefore allows time literals in constraints.

The -int-time-literal switch causes time literals to be compiled as integral values, thereby permitting use in constraints. However, the user must ensure that the final scaled value of any such literal does not have a fractional portion, as the fraction will be lost.

Implicitly Specialized Virtual Interfaces

The SV-LRM prohibits any interface having interface ports, or hierarchical references that leave the scope of the interface, from being used as a virtual interface. DSim depends on this restriction to allow optimum code generation.

For best code generation, DSim compiles each specialization of a module or interface separately. For example, foo#(4) is a completely separate compiled entity from foo#(8). If the parameter is used to select the width of a data object then separate compilation permits optimal code for each to be generated. This is straightforward, as the parameterization is explicit.

However, there are other conditions that cause specialized compilation. We refer to these as "implicit specialization" because no explicit parameters are involved.

Interface ports


interface foo(interface ii);
initial $display(ii.x);

module top;
other_if oo();
other_if2 oo2();
foo u1(oo), u2(oo2);


This example shows an interface foo having a generic interface port. There are two instantiations of foo: one using other_if and the other using other_if2. Clearly, if other_if and other_if2 are two different interfaces, one cannot efficiently use the same code for both instances of foo.

External Hierarchical References


interface foo;
initial $display(upward.x);


Another cause of implicit specialization: upward hierarchical references. Clearly, if there were two instances of foo somewhere in the hierarchy, then upward.x may refer to two completely different objects. Again, it is not reasonable to have one body of compiled code for both cases.

Virtual Interfaces

In SystemVerilog, a virtual interface handle is a variable that can point to any compatible instance of the interface.

Variables and nets may be accessed. Tasks and functions may be called. However, an underlying assumption is that all instances of the interface that the handle can possibly point to are equivalent, compiled in exactly the same way. This is not true for implicitly specialized interfaces, justifying the SV-LRM restriction.

However, it turns out that other simulators do seem to allow this. The -allow-ext-vif switch can be used to recover some compatibility in this case. When DSim detects implicitly-specialized interfaces being used as a virtual interface, it will generate alternate (but less efficient) code for task/function calls to allow these calls to work. Direct access to any other object is still prohibited.

Virtual Interface Self-Reference

Some tools allow the use of a virtual interface identifier as a self-reference:


class registry#(type T = int);
virtual void set(T item);

interface foo;
initial registry#(virtual foo)::set(foo); // Register myself


This treatment breaks standard Verilog syntax in the case where an implicit wire would have the same name as its containing interface:


interface suba(wire clk);

interface subb(wire clk);

interface clk;
    suba u1(clk);
    subb u2(clk);


A classic SystemVerilog compiler would need to bind the references to clk to an implicit wire. Treating these references as interface self-references would break this function.

DSim supports interface self-references if -allow-self-vif is given. This achieves compatibility with vendor extensions for testbenches that require it, but breaks implicit wires. The default is to preserve compatibility with implicit wires.

Seed Argument

The SV-LRM requires that the seed argument to $random() be an integer variable. DSim permits the passing of a constant. However, behavior may differ compared to other simulators.

Static / Automatic Class Methods

The SV-LRM requires that all class methods have automatic lifetime. However, some user code appears to rely on support for static methods.

One point of clarification: the keyword static is overloaded: it can be used to indicate a storage lifetime, and it can also be used to indicate a method that can be invoked without an instance variable (i.e. no value of this). The order of declaration matters:


class C;
    // case (1): instance method whose arguments and local variables
    // have static lifetime
    task static foo();

    // case (2): non-instance method whose variables
    // have automatic lifetime
    static task foo();


The SV-LRM prohibits case (1). DSim permits it. Note that pure or virtual methods must have automatic lifetime.

Was this article helpful?

That’s Great!

Thank you for your feedback

Sorry! We couldn't be helpful

Thank you for your feedback

Let us know how can we improve this article!

Select at least one of the reasons
CAPTCHA verification is required.

Feedback sent

We appreciate your effort and will try to fix the article