SystemVerilog adds many
enhancements for representing design hierarchy:
—
Packages
containing declarations such as data, types, classes, tasks and functions
—
Separate
compilation support
—
A
compilation-unit scope visible only within a compilation unit A global
declaration space, visible to all modules at all levels of hierarchy
—
Removal
of the $root global declaration space from SystemVerilog 3.1
— Nested module declarations, to aid in representing
self-contained models and libraries
Delete existing 18.2 and replace with following.
18.2 Packages
SystemVerilog packages provide an additional mechanism for sharing
parameters, data, type, task, function, sequence, and property declarations
amongst multiple SystemVerilog modules, interfaces and programs. Packages are
explicitly named scopes appearing at the outermost level of the source text (at
the same level as top-level modules and primitives). Types, variables, tasks,
functions, sequences, and properties may be declared within a package. Such
declarations may be referenced within modules, macromodules, interfaces,
programs, and other packages by either import or fully resolved name.
![Text Box: package_declaration ::= // from Annex A.1.3
{ attribute_instance } package package_identifier
[ timeunits_declaration ] { { attribute_instance } package_item }
endpackage [ : package_identifier ]
package_item ::= // from Annex A.1.10
package_or_generate_item_declaration
| specparam_declaration
| concurrent_assertion_item_declaration
| anonymous_program
| timeunits_declaration21
package_or_generate_item_declaration ::=
net_declaration
| data_declaration
| task_declaration
| function_declaration
| dpi_import_export
| extern_constraint_declaration
| extern_method_declaration
| class_declaration
| parameter_declaration ;
| local_parameter_declaration
| covergroup_declaration
| overload_declaration
anonymous_program ::= program ; { anonymous_program_item } endprogram
anonymous_program_item ::=
task_declaration
| function_declaration
| class_declaration
| covergroup_declaration](LRM_Changes_18_files/image003.gif)
Syntax 18-1--Package syntax (excerpt
from Annex A)
The package
declaration creates a scope that contains declarations intended to be shared
among one or more compilation units, modules, macromodules, interfaces, or
programs. Items within packages are generally type definitions, tasks, and
functions. Items within packages cannot have hierarchical references. It is
also possible to populate packages with parameters, variables and nets. This
may be useful for global items that aren't conveniently passed down through the
hierarchy. Variable declaration assignments within the package shall occur
before any initial, or always, always_comb, always_latch or always_ff blocks are started, in the same way as variables declared in
a compilation unit or module.
The following is an example of a package:
package ComplexPkg;
typedef struct {
float i, r;
} Complex;
function Complex add(Complex a, b);
add.r = a.r + b.r;
add.i = a.i + b.i;
endfunction
function Complex mul(Complex
a, b);
mul.r = (a.r * b.r) + (a.i
* b.i);
mul.i = (a.r * b.i) + (a.i
* b.r);
endfunction
endpackage
: ComplexPkg
18.2.1 Referencing data in packages
Packages
must exist in order for the items they define to be recognized by the scopes in
which they are imported.
One way to
use declarations made in a package is to reference them using the scope
resolution operator "::".
ComplexPkg::Complex cout = ComplexPkg::mul(a, b);
An
alternate method for utilizing package declarations is via the import
statement.

Syntax 18-2--Import syntax (excerpt
from Annex A)
The import
statement provides direct visibility of identifiers within packages. It allows
identifiers declared within packages to be visible within the current scope
without a package name qualifier. Hierarchical references to imported
identifiers are allowed as if they were defined in the importing scope. Two
forms of the import statement are provided: explicit import, and wildcard
import. Explicit import allows control over precisely which symbols are
imported:
import ComplexPkg::Complex;
import ComplexPkg::add;
An
explicit import is treated like a local declaration. An explicit import shall
be illegal if the imported identifier is declared in the same scope or
explicitly imported from another package. Importing an identifier from the same
package multiple times is allowed.
A wildcard
import allows all identifiers declared within a package to be imported provided
the identifier is not otherwise defined in the importing scope:
import ComplexPkg::*;
A wildcard
import makes each identifier within the package a candidate for import. Each
such identifier is imported only when it is neither declared nor explicitly
imported into the scope. Similarly, a wildcard import of an identifier is
overridden by a subsequent declaration of the same identifier in the same scope.
If the same identifier is wildcard imported into a scope from two different
packages, the identifier shall be undefined within that scope and result in an
error if the identifier is used.
18.2.2
Search
order Rules
Table 18.1 describes the search order rules for the declarations
imported from a package. For the purposes of the discussion below, consider the
following package declarations:
package p;
typedef enum { FALSE, TRUE }
BOOL;
const BOOL c = FALSE;
endpackage
package q;
const int c = 0;
endpackage
|
Example |
Description |
Scope containing a local declaration of c |
Scope not containing a local declaration of c |
Scope contains a declaration of c imported using
import q::c |
Scope contains a declaration of c imported as
import q::* |
u = p::c;y = p::TRUE; |
A qualified package identifier is visible
in any scope (without the need for an import clause). |
OK. Direct reference to c refers to the
locally declared c. p::c refers to the c in package p. |
OK Direct reference to c is illegal since it
is undefined. p::c refers to the c in package p. |
OK. Direct reference to c refers to the c
imported from q. p::c refers to the c in package p. |
OK. Direct reference to c refers to the c
imported from q. p::c refers to the c in package p. |
|
import p::*; . . . y = FALSE; |
All declarations inside package p become
potentially directly visible in the importing scope:
|
OK. Direct reference to c refers to the
locally declared c. Direct reference to other identifiers
(e.g., FALSE) refer to those implicitly imported from package p. |
OK. Direct reference to c refers to the c
imported from package p. |
OK. Direct reference to c refers to the c
imported from package q. |
OK / ERROR c is undefined in the importing scope.
Thus, a direct reference to c is illegal and results in an error. The import clause is otherwise allowed. |
|
import p::c; . . . if( ! c ) ... |
The imported identifiers become directly visible
in the importing scope:
|
ERROR. It shall be illegal to import an
identifier defined in the importing scope. |
OK. Direct reference to c refers to the c
imported from package p. |
ERROR. It shall be illegal to import an identifier
defined in the importing scope. |
OK / ERROR The import of p::c
makes any prior reference to c illegal. Otherwise, direct reference to c refers to
the c imported from package p. |
Table 18.1 Scoping Rules for Package Importation
When using
a wildcard import, a reference to an undefined identifier that is declared
within the package causes that identifier to be imported into the local scope.
However, an error results if the same identifier is later declared or
explicitly imported. This is shown in the following example:
module foo;
import q::*;
wire a=c; //
This statement forces the import of q::c;
import p::c; // The conflict with q::c and p::c creates an error.
endmodule
18.3 Compilation Unit
SystemVerilog supports separate compilation using compiled
units. The following terms and definitions are provided:
—
compilation unit: a collection of one or more SystemVerilog
source files compiled together
—
compilation-unit scope: a scope
that is local to the compilation unit. It contains all declarations that lie
outside of any other scope
—
$unit: the name used to explicitly access the identifiers in
the compilation-unit scope
The exact mechanism for defining which files constitute a
compilation unit is tool specific. Tools shall provide a mechanism to specify
the files that make up a compilation unit. Two extreme cases are:
1.
All
files make a single compilation unit (in which case the declarations in the
compilation-unit scope are accessible anywhere within the design)
2.
Each
file is a separate compilation unit (in which case the declarations in each
compilation-unit scope are accessible only within its corresponding file)
The
contents of files included using one or more ‘include directives become part of
the compilation unit of the file they are included within.
If there
is a declaration that is incomplete at the end of a file then the compilation
unit including that file will extend through each successive file until there
are no incomplete declarations at the end of the group of files.
The
default is that each file is a separate compilation unit.
A tool
must also provide a mechanism (such as a command line switch) that specifies
that all of the files compiled together are a single compilation unit.
There are
other possible mappings of files to compilation units and the mechanism for
defining them are tool specific and may not be portable.
The
compilation-unit scope can contain any item that can be defined within a
package. These items are in the compilation-unit
scope name space.
The
following items are visible in all compilation units: modules, macromodules,
primitives, programs, interfaces, and packages. Items defined in the
compilation-unit scope cannot be accessed by name from outside the compilation
unit. Access to the items in a compilation-unit scope can be accessed using the
PLI, which must provide an iterator to traverse all the compilation units.
In
Verilog, compiler directives once seen by a tool apply to all forthcoming
source text. This behavior shall be supported within a separately compiled
unit; however, compiler directives from one separately compiled unit shall not
affect other compilation units. This may result in a difference of behavior
between compiling the units separately or as a single compilation unit
containing the entire source.
When an
identifier is referenced within a scope, SystemVerilog follows the Verilog name
search rules:
— First, the nested scope is searched
(1364-2001 12.6) (including nested module declarations)
— Next, the compilation-unit scope is searched
— Finally, the instance hierarchy is searched
(1364-2001 12.5))
$unit is the name of the scope that encompasses a compilation
unit. Its purpose is to allow the unambiguous reference
to declarations at the outermost level of a compilation unit
(i.e., those in the compilation-unit scope). This is done via the same scope
resolution operator used to access package items.
For example:
bit b;
task foo;
int b;
b = 5 + $unit::b; // $unit::b is the one outside.
endtask
The compilation-unit scope allows users to
easily share declarations (e.g., types) across the unit of compilation, but
without having to declare a package from which the declarations are
subsequently imported. Thus, the compilation-unit scope is similar to an
implicitly defined anonymous package. Because it has no name, the
compilation-unit scope cannot be used with an import statement, and the
identifiers declared within the scope are not accessible via hierarchical
references. Within a particular compilation unit, however, the special name
$unit can be used to explicitly access the declarations of its compilation-unit
scope.
18.4 Top-level instance
The name $root is added to
unambiguously refer to a top level instance, or to an instance path starting
from the root of the instantiation tree. $root is the root of the instantiation tree.
For example:
$root.A.B
// item B within top instance A
$root.A.B.C
// item C within instance B within instance A
$root allows explicit access to the top of
the instantiation tree. This is useful to disambiguate a local path (which
takes precedence) from the rooted path. In Verilog, a hierarchical path is
ambiguous. For example, A.B.C can mean the local A.B.C or the top-level A.B.C
(assuming there is an instance A that contains an
instance B at both the top level and in the current module). Verilog addresses
that ambiguity by giving priority to the local scope, thereby preventing access
to the top level path. $root allows explicit access to the top level in those
cases in which the name of the top level module is insufficient to uniquely
identify the path.
18.3
Module declarations
SystemVerilog adds the
capability to nest module declarations, and to
instantiate modules in the $root toplevel space, outside of other modules.
module
m1(...); ... endmodule
module
m2(...); ... endmodule
module
m3(...);
m1 i1(...); //
instantiates the local m1 declared below
m2 i4(...); //
instantiates m2 - no local declaration
module
m1(...); ... endmodule // nested module
declaration,
// m1
module name is in m3’s name space
endmodule
m1 i2(...); // module instance in the $root space,
// instantiates the module m1 that is
not nested in another module
module dff_nested(input d, ck, pr, clr,
output q, nq);
wire q1,
nq1, nq2;
module ff1;
nand g1b
(nq1, d, clr, q1);
nand g1a
(q1, ck, nq2, nq1);
endmodule
ff1 i1();
module ff2;
wire q2; //
This wire can be encapsulated in ff2
nand g2b
(nq2, ck, clr, q2);
nand g2a
(q2, nq1, pr, nq2);
endmodule
ff2 i2();
module ff3;
nand g3a
(q, nq2, clr, nq);
nand g3b (nq, q1, pr, q);
endmodule
ff3 i3();
endmodule
module part1(....);
module and2(input
a, b,; input b; output z);
....
endmodule
module or2(input a, b,; input b; output z);
....
endmodule
There shall be at most one
time unit and one time precision for any module,
program, package or interface definition, or in $root any
compilation-unit scope. This shall define
a time scope. If specified, the timeunit and timeprecision declarations shall precede any other items in the current
time scope. The timeunit and timeprecision declarations can be repeated as later items, but must
match the previous declaration within the current time scope.
If a timeunit
is not specified in the module, program, package or interface definition, then the
time unit is shall be determined using the following rules of
precedence:
1) If the module or interface definition is nested, then
the time unit is shall be inherited from
the enclosing module or interface (programs and
packages cannot be nested).
2) Else, if a ‘timescale directive has been previously specified (within the compilation unit), then the time unit is shall be set to the units of the last ‘timescale
directive.
3) Else, if the compilation-unit
scope specifies $root top level has a time unit (outside all other
declarations), then the time unit is shall be set to the time units of the compilation unit root module.
4) Else, the default time unit is shall be used.
The time unit of the compilation-unit scope may only be set $root shall
only be determined by a timeunit
declaration, not a ‘timescale
directive. If it
is not specified then the default time unit shall be used.
If a timeprecision
is not specified in the current time
scope, then the time precision is shall
be determined following the same precedence as with time units.
ordered_parameter_assignment ::= expression | data_type param_expression
named_parameter_assignment ::= . parameter_identifier ( [
param_expression ] )
. parameter_identifier ( [expression ] )
| . parameter_identifier
( data_type )
name_of_instance ::= module_instance_identifier { range unpacked_dimension }
param_expression ::= mintypmax_expression
| data_type //
from Annex A.8.3
list_of_port_connections20 ::=
ordered_port_connection
{ , ordered_port_connection }
| dot_named_port_connection { ,
dot_named_port_connection }
| { named_port_connection , } dot_star_port_connection { , named_port_connection }
ordered_port_connection ::= { attribute_instance
} [ expression ]
named_port_connection ::= { attribute_instance } . port_identifier[(
[ expression ] )]
| { attribute_instance
} .*
dot_named_port_connection ::=
{ attribute_instance } .port_identifier
| named_port_connection
dot_star_port_connection ::= { attribute_instance
} .*
— A ref port shall be
connected to an equivalent variable data type. References to the port variable
shall be treated as hierarchal references to the variable it is connected to in
its instantiation. This kind of port can not be left unconnected. See section 5.8.1 Equivalent Types.
18.10
Name spaces
SystemVerilog has eight five
name spaces for identifiers, two are global (definitions name space and package name space), two are global to
the compilation unit (compilation unit
name space and text macro name space)
and four are local. Verilog’s global definitions name space collapses onto the module name
space and exists as the top-level scope, $root.
Module, primitive, package, program, and interface identifiers are local to the
module name space where there are defined. The eight five name spaces are described as follows:
1)
The definitions name space unifies all the non-nested module, macromodule,
primitive, program, and interface
identifiers defined outside of all
other declarations. Once a name is used to define a module, macromodule,
primitive, program, or interface
within one compilation unit the name shall not be used again (in any
compilation unit) to declare another non-nested module, macromodule,
primitive, program, or interface outside of all other declarations.
This is compatible with the definitions
name space as defined in IEEE 1364-2001.
2) The package name space unifies all the package identifiers defined among all compilation units. Once a name is used to define a package within one compilation unit the name shall not be used agai