( ESNUG 466 Item 2 ) -------------------------------------------- [07/12/07]

Subject: Declaration gotchas

2.1 Case sensitivity

    Gotcha: Verilog is a case-sensitive language, whereas VHDL is a
            case-insensitive language.

Verilog is a case sensitive language, meaning that lowercase letters and
uppercase letters are perceived as different in identifiers and in keywords.
An identifier in Verilog and System Verilog is the user-specified name of
some object, such as the name of a module, the name of a wire, the name of
a variable, or the name of a function.

This case sensitivity is often a gotcha to engineers learning Verilog,
especially those migrating from a case insensitive language such as
VHDL.  Even experienced engineers occasionally get caught making a case
sensitivity error.

The gotcha of a case sensitive language is when an identifier is sometimes
inadvertently spelled with all lowercase characters, and in another place
with some or all uppercase characters.  For example:

  enum logic [1:0] {WAIT, LOAD, READY} State, NextState; // mixed case names

  always_comb begin
    case (state)
      WAIT: NextState = L0AD;
      ...
    endcase
  end

There are 3 gotchas in the preceding example.

One gotcha is that the enumerated variable State is declared using a mix of
uppercase and lowercase characters.  Later in the code, and, in a large
design, possibly hundreds of lines after the declaration, a signal called
state is referenced.  These identifiers read the same in English, but to a
Verilog compiler, state and State are seen as very different names.

A second gotcha is that the enumerated label LOAD is in all uppercase
letters.  But later in the code an identifier called L0AD is referenced.
Visually, these identifiers appear to be the same, but to a Verilog compiler
they are very different names.  The difference is that the enumerated label
contains an uppercase letter "O", pronounced "oh", in the name, whereas the
reference in the code body contains the number "0", or "zero" in the name.

The third gotcha in the example above is the enumerated label WAIT.  While
syntactically correct, this is a poor choice for an identifier name because
there is a Verilog keyword "wait".  A Verilog compiler won't get confused
between the keyword wait and the identifier WAIT, but someone who has to
read or maintain the code could easily confuse wait and WAIT.  (Several
examples here use a state machine with a "WAITE" state.  The identifier
"WAITE" is purposely spelled with the letter "E" on the end just to avoid
confusion with the Verilog keyword "wait".)

How to avoid this gotcha: The best way to avoid this case-sensitive gotcha
is to adopt good naming conventions within a company, and then strictly
enforce these guidelines.  When modules are instantiated, System Verilog
provides 2 convenient shortcuts that also help enforce following consistent
naming conventions.  The shortcuts are the .<name> and .* implicit port
connections.  These shortcuts infer netlist connections, but only if the
names within a design block and the names within the netlist are consistent.


2.2 Implicit net declarations

    Gotcha: Mis-typed identifiers may infer an implicit net instead
    of a syntax error.

The examples in Sec 2.1, above, contained references to the undeclared
identifiers, state and L0AD.  What does a compiler do when it encounters an
undeclared identifier?  The answer to this question depends on the context
in which the undeclared identifier is used.

 - If an undeclared identifier is used on the right or left-hand side
   of a procedural assignment, then a compilation or elaboration error
   occurs.
 - If an undeclared identifier is used on the right-hand side of a
   continuous assignment, then a compilation or elaboration error occurs.
 - If an undeclared identifier is used on the left-hand side of a
   continuous assignment, then an implicit net declaration is inferred,
   and no error or warning is reported.
 - If an undeclared identifier is used as a connection to an instance
   of a module, interface, program, or primitive, then an implicit net is
   inferred, and no error or warning is reported.

The last 2 rules above are gotchas, as illustrated here:

   module bad_adder (input  wire a, b, ci,
                    output wire sum, co);

     wire n1, n2, n3;

     xor g1 (n1, a, b);
     xor g2 (sum, nl, ci);     // GOTCHA!
     and g3 (n2, a, b, c);     // GOTCHA!
     and g4 (n3, n1, ci);
     or  g5 (co, n2, n3);
   endmodule

One gotcha in this example is the declaration of n1 ("en-one") but the use
of nl ("en-ell") in the g2 primitive instance.  Another gotcha is an extra
identifier, c, in the second g3 primitive instance.  These typos are not
syntax errors.  Instead, they infer implicit nets in the design, causing
functional errors that must be detected and debugged.  GOTCHA!

This example comes from a debugging lab in Sutherland HDL's Verilog training
course (but without the GOTCHA comments).  It is surprising how difficult
the two typos in the netlist can be to find.  Imagine how much more
difficult a simple typo would be to find in a 1,000,000 gate netlist with
several layers of design hierarchy.

Why does Verilog allow this gotcha?  Because, like many gotchas, the ability
to have implicit data types automatically inferred can be useful, when not
abused.  One of the benefits of implicit data types is that in a large,
multi-million gate design that has thousands of interconnecting wires, it is
not necessary to explicitly declare every wire.

How to avoid this gotcha: There are 2 ways to avoid this implicit data type
gotcha.  Verilog provides a `default_nettype none compiler directive.  When
this directive is set, implicit data types are disabled, which will make any
undeclared signal name a syntax error.  A limitation of this directive is
that the benefits of implicit data types are also lost.  Another limitation
is that compiler directives are not bound by design blocks, or even by
source code files.  If the `default_nettype none directive is turned on in
one file, it can affect the compilation of other files, which is yet another
GOTCHA!.  To avoid this gotcha, the directive `default_nettype wire should
be added at the end of each file where implicit nets have been turned off.

   `default_nettype none   // turn off implicit data types
   module adder (input  wire a, b, ci,
                 output wire sum, co);

   wire n1, n2, n3;

   xor g1 (n1, a, b);
   xor g2 (sum, nl, ci); // ERROR! nl is not declared
   and g3 (n2, a, b, c); // ERROR! c is not declared
   and g4 (n3, n1, ci);
   or  g5 (co, n2, n3);
   endmodule
   `default_nettype wire  // turn implicit nets back on
                          // again to avoid side-effects

System Verilog provides 2 convenient shortcuts for connecting nets to module
instances: .<name> and .*.  These shortcuts remove the repetition in Verilog
named port connections.  By reducing the number of times a signal name must
be typed, the possibility of typographical errors is also reduced.  The
.<name> and .* shortcuts also require that all nets be explicitly declared.
The shortcuts will not infer an implicit data type due to a typo.  Another
advantage of these System Verilog shortcuts is that they are local to the
module in which they are used.  The shortcuts do not affect other design
blocks, the way compiler directives can.

   module adder (input  wire a, b, ci,
                 output wire sum, co);
   ...
   endmodule

   module top;
    wire a, b, ci;
    wire s1, s2, s3, c1, c2, c3;

    adder i1 (.a(a), .b(b), .ci(ci), .sum(s1), .co(c1) );  // Verilog style
    adder i2 (.a, .b, .ci, .sum(s2), .co(c2) );  // SV .name style
    adder i3 (.*, .sum(s3), .co(c3) );  // System Verilog .* style

   endmodule


2.3 Escaped identifiers in hierarchy paths

    Gotcha: Escaped identifiers in a hierarchy path require embedded
    spaces in the path.

An identifier in Verilog and System Verilog is the name of some object, such
as the name of a module, the name of a wire, the name of a variable, or the
name of a function.  The legal characters in an identifier are alphabetic
characters, numbers, underscore or dollar sign.  All other characters, such
as +, -, (, ), [ and ], are illegal in an identifier name.

Verilog and System Verilog allow these illegal characters to be used in a
name by escaping the identifier.  A name is escaped by preceding the name
with a back slash (\) and terminating the name with a white space character.
A white space character is a space, a tab, a return, a form feed, or an
end-of-file.  Some examples of escaped identifiers are:

   module \d-flop (output q, \q~ , input \d[0] ,clk, \rst- );
     ...
   endmodule

Note in the above example that a white space character must be used before
the commas that separate an escaped identifier from the next item in the
list.  A white space is required between the last escaped name, \reset-,
and the closing parenthesis.

The gotcha is when an escaped identifier is used as part of a hierarchy
path.  The escaped identifier must be terminated by a white space.  That
white space looks like it breaks the hierarchy path into 2 identifiers, but
the terminating white space is ignored, which, in effect, concatenates the
two names into one name.

The following examples illustrate the use of white space after references to
escaped identifiers.  Module "chip" uses named port connections to escaped
port names identifiers.  The $display contains a relative hierarchy path
that contains an escaped identifier.

  module chip (output [7:0] q, input [7:0] d, input clk, rstN);

  \d-flop \d-0 (.q(q[0]), .\q~ (), .\d[0] (d[0]), .clk(clk), .\rst-(rstN));

  initial begin
    $display("d = %b", \d-0.\d[0] );   // GOTCHA! missing white space
    $display("d = %b", \d-0 .\d[0] );  // OK: white space in path
  end                                  // required; does not split
                                       // path into two names
  endmodule

Note that d[0] is a bit-select, selecting the least-significant bit of d.
The escaped \d[0] is not a bit select.  The square brackets are also
escaped, become part of the name of the port in module \d-flop.

How to avoid this gotcha: Don't use escaped names in a design, especially an
escaped name with [] brackets in the name.  Unfortunately, life is not that
simple.  Not all identifiers are user-defined.  Software tools, such as the
DC synthesis compiler, create tool-generated identifier names in the Verilog
or System Verilog code.  And, as ugly as these tool-generated identifiers
looks to users, these tools often put [] brackets in escaped identifiers.
The gotcha of having to reference escaped identifiers using hierarchy paths
is one that cannot be completely avoided.  Engineers need to know that
having a space in a hierarchy path involving escaped identifiers is not
illegal.  It may make the code harder to read, but it is how Verilog works.


2.4 Verification of dynamic data

    Gotcha: Dynamically allocated variables have no hierarchy paths.

Verilog has automatic tasks and functions, which dynamically allocate
storage each time they are called, and automatically free that storage when
they exit.  System Verilog adds many more types of dynamic storage to
Verilog, including classes for Object Oriented programming, dynamically
sized arrays, queues, automatic variables in static tasks and functions, and
local variables in an assertion.  These dynamically allocated types are
intended for -- and are very important in -- modeling test programs using
modern verification methodologies.

But, there is a gotcha with these new dynamic data types.  Unlike other
Verilog data types, dynamic types cannot be referenced hierarchically.
Hierarchically referencing nets and variables in a design is a common
verification technique.  It allows the verification code to evaluate, and
possibly stimulate, the logic deep down in the hierarchy of a design,
without having to pull those internal signals up to the testbench through
extra, verification only, module ports.

The reason that dynamic data cannot be referenced hierarchically is that
hierarchy paths are static in nature, whereas a dynamic variable or class
object comes and goes during simulation.  This gotcha places a burden on the
verification engineer.  Before using a hierarchical to reference a variable,
the verification engineer must first examine whether or not the variable is
static or dynamic.  Since System Verilog adds so many types of dynamic
storage, it can be very difficult to determine when something can be
referenced hierarchically, and when it cannot.

How to avoid this gotcha: It can not be avoided, but can be minimized.  A
good coding guideline is to only use dynamic storage in the testbench and
for automatic tasks & functions declared in $unit, packages and interfaces.
In this way, the test programs will be able to hierarchically access most
design data.  It is also helpful to establish and use naming conventions
that make dynamic variables obvious when reading the source code.


2.5 Variables declared in unnamed blocks

    Gotcha: Variables declared in an unnamed scope have no hierarchy
            paths.

System Verilog allows local variables to be declared in unnamed scopes,
including:

  - Within the definition of for loops.
  - Unnamed begin...end and fork...join blocks.
  - Unnamed loops in generate blocks

These local variables have 2 primary advantages.  First, variables can be
declared where they are needed, instead of in the midst of writing code,
having to jump back to the beginning of a module to add a new declaration.
This allows engineers to keep their train of thought as they are developing
code.  Second, local variables prevent the inadvertent Verilog gotcha of
having multiple initial or always procedural blocks write to the same
variable (this gotcha is discussed in Sec 2.8).

There is a gotcha with locally defined variables.  Variables in a for loop
declaration, in an unnamed block, or in an unnamed generate scope, cannot be
referenced hierarchically, because there is no named scope to reference in
the hierarchy path.  Once again, the verification engineer has the burden of
determining which data can be referenced hierarchically, and which cannot.

How to avoid this gotcha: Declare local variables in named begin...end
or fork...join blocks, so that they can be referenced hierarchically for
verification purposes.  The use of variables declared as part of a for
loop definition should not be a problem, as these loop control variables
seldom need to be accessed from the verification test programs.


2.6 Hierarchical references to declarations imported from packages

    Gotcha: Imported identifiers cannot be referenced hierarchically.

Hierarchy paths are a verification construct, used to access the declaration
of an object in the scope in which that object is declared.  When package
items are imported into a module, interface or test program, these items are
not locally defined within that module, interface or test program.  This
means these imported items cannot be referenced hierarchically.  In the
example below, the hierarchy path to chip.RESET is an error, because ERROR
was not declared in module chip:

   package chip_types;
     typedef enum logic [1:0] {RESET, WAITE, LOAD, READY} states_t;
   endpackage

   module top;
     chip chip (...);  // instance of design that uses the chip_types
   package
     test test (...);  // instance of test program
   endmodule

   program test (...);
     ...
   $display ("the value of RESET is %b", top.chip.RESET);  // GOTCHA!

How to avoid this gotcha: The correct way to reference package items is to
use the scope resolution operator ( :: ) instead of hierarchy paths.  For
example:

   $display ("the value of RESET is %b", chip_types::RESET);


2.7 Variables with no hierarchy path are not dumped to VCD files

    Gotcha: Changes on dynamic variables and variables in unnamed
            scopes are not saved in VCD files.

Another gotcha with dynamically and locally defined storage is that the IEEE
Verilog and System Verilog standards explicitly state that this type of
storage is not dumped out to a Value Change Dump (VCD) file.  VCD files are
used as an input to waveform displays and other design analysis tools, in
order to analyze what activity has, or has not, occurred during simulation.

As a standard, VCD files are portable, and can be used with many different
third party and in-house tools.  However, changes on dynamically allocated
and local data are not dumped to VCD files, which means waveform displays
and design analysis tools that read in VCD files do not see all the activity
that took place in simulation.

How to avoid this gotcha: There is no workaround for this VCD gotcha.  It
should be noted, though, that proprietary dump files that are part of most
waveform display tools might not have this limitation.


2.8 Shared variables in modules

    Gotcha: Variables written to by multiple processes create shared
            resource conflicts.

Syntactically, Verilog variables declared at the module level can be read or
written by any number of initial or always procedural blocks within the
module.  Reading a variable from multiple procedural blocks is fine, and
provides a way for parallel processes to pass values between themselves.
But, there is a gotcha when two or more procedural blocks write to the same
variable.  The effect is that the same piece of storage is shared by all the
procedural block.  Since these procedural blocks run concurrently, it is
possible -- and likely -- that the code within the blocks will collide, and
interfere with each other's functionality.

The following example shows a common -- and perhaps not obvious in large
models -- Verilog gotcha, where the variable i is shared by two concurrent
always procedural blocks.

   module chip (...);
     integer i;    // for-loop control variable

     always @(a or b) begin
       for (i=0; i<15; i=i+1)     // this process uses i
         ...
     end

     always @(c or d) begin
       for (i=0; i<15; i=i+1)     // this process also uses i
         ...
     end
   endmodule

How to avoid this gotcha: It all depends on whether your code is for a
synthesizable RTL model or for verification.  For RTL models, the preferred
way to avoid this gotcha is to use System Verilog's always_comb, always_ff,
always_comb, and continuous assign to a variable.  These processes make it
a syntax error if a variable is written to by multiple processes.  If the
code is for verification or an abstract bus functional model, the way to
avoid this gotcha is to use process synchronization (flags, event triggers,
semaphores or mailboxes) so that concurrent processes are not writing to the
same variable at the same time.

For the example above, there is another way to avoid this shared variable
gotcha.  System Verilog allows local variables to be declared as part of a
for loop definition.  This solution has its own gotcha, however, as was
discussed in Sec 2.5.


2.9 Shared variables in interfaces, packages, and $unit

    Gotcha: Interface, package and global variables written to by multiple
            design/verification blocks create shared resource conflicts.

System Verilog compounds the Verilog shared variable gotcha described in
Sec 2.8 by providing more places where shared variables can be declared
(or obfuscated).  In System Verilog, variables can be declared in external
spaces outside of a module.

These external declaration spaces are user-defined packages, $unit (a
built-in package), and interfaces.  These externally declared variables can
then be referenced by multiple modules, creating a shared variable.  Any
initial and always procedural blocks that write to these shared variables
will likely interfere with each other.  These procedural blocks can be in
different design and verification blocks, which are generally in different
files.  This can make it very difficult to find and debug shared variable
conflicts.

How to avoid this gotcha: For RTL models, System Verilog's always_comb,
always_ff, always_comb, and continuous assign to variables, should be used.
These processes make it a syntax error if a variable is written to by
multiple processes, even when these processes are in different modules.
For verification, or abstract bus functional models, this gotcha can be
avoided through the use of process synchronization (flags, event triggers,
semaphores or mailboxes).


2.10 Shared variables in tasks and functions

     Gotcha: Variables in tasks and functions contained in interface,
             package and global variables create shared resource conflicts.

System Verilog allows tasks and functions to be defined in $unit, packages,
and interfaces.  These tasks and functions can then be called from multiple
modules.  Any static storage in these tasks and functions is shared by all
places from which the task or function is called.

How to avoid this gotcha: Declare tasks and functions in $unit, packages, or
interfaces as automatic, with no static storage within the task or function.
Each call to an automatic task or function will allocate unique storage for
that call, instead of sharing the task/function storage.

An exception to this guideline is a task or function within an interface
that is only called from within the interface.


2.11 Importing enumerated types from packages

     Gotcha: Importing an enumerated type does not import the enumerated
             labels.

Enumerated type definitions defined in a package can be explicitly imported
into a design or verification block.  For example:

   package chip_types;
     typedef enum logic [1:0] {RESET, WAITE, LOAD, READY} states_t;
   endpackage

   module chip (...);
     import chip_types::states_t;  // explicit import of states_t type
     states_t state, next_state;

     always_ff @(posedge clock, posedge reset)
       if (reset) state <= RESET;  // GOTCHA: RESET has not been imported
       else       state <= next_state;
     ...
   endmodule

How to avoid this gotcha: wildcard importing the package.  In this way, both
the enumerated type definition and the enumerated labels are imported.

   module chip (...);
     import chip_types::*;   // wildcard import of package declarations

However, wildcard imports have a gotcha if multiple packages are used in a
design block, as discussed in Sec 2.12, which follows.


2.12 Importing from multiple packages

     Gotcha: Wildcard imports from multiple packages can cause name
             collisions.

Large designs, and designs that use IP models, can divide declarations into
multiple packages.  A common modeling style is to wildcard import these
packages into a design block, or into the $unit global declaration space.
Wildcard imports are convenient, as they can save considerable typing over
explicitly importing each item from each package.  However, wildcard imports
of multiple packages can lead to another gotcha, as illustrated:

   package bus1_types;
     parameter SIZE = 32;
     ...
   endpackage

   package bus2_types;
     parameter SIZE = 64;
     ...
   endpackage

   module chip (...);
     import bus1_types::*;  // wildcard import of a package
     import bus2_types::*;  // wildcard import of another package
     logic [SIZE-1:0] a;    // GOTCHA! SIZE has more than one definition
     ...

How to avoid this gotcha: The gotcha with wildcard package imports occurs
when there are some identifiers common to more than one package.  In this
case, at most only one of the packages with duplicate identifiers can be
wildcard imported.  Any references to a duplicate identifier in another
package must be explicitly referenced, using its package name each place
the identifier is referenced.  For example:

   import bus1_types::*; // wildcard import of a package

   logic [bus2_types::SIZE-1:0] a; // explicit reference to diff package
Index    Next->Item








   
 Sign up for the DeepChip newsletter.
Email
 Read what EDA tool users really think.


Feedback About Wiretaps ESNUGs SIGN UP! Downloads Trip Reports Advertise

"Relax. This is a discussion. Anything said here is just one engineer's opinion. Email in your dissenting letter and it'll be published, too."
This Web Site Is Modified Every 2-3 Days
Copyright 1991-2024 John Cooley.  All Rights Reserved.
| Contact John Cooley | Webmaster | Legal | Feedback Form |

   !!!     "It's not a BUG,
  /o o\  /  it's a FEATURE!"
 (  >  )
  \ - / 
  _] [_     (jcooley 1991)