Edit Proposal | Edit Class, Environment, or Release |
Number | 432
|
Category | enhancement
|
Synopsis | Add shared declaration mechanism to Verilog - packages
|
State | proposal
|
Class | enhancement
|
Arrival-Date | Aug 22 2003
|
Originator | Jay Lawrence - Cadence Design Systems
|
Release | 2001b
|
Environment |
|
Description |
The addition of data types in Verilog as proposed in enhancement number 357 creates the need for a further enhancement to create a place where types and the tasks/functions that operate on them can be declared and shared by all parts of a description that need to use the type. This enhancement proposes that a 'package' mechanism be adopted to create a new description that provides for shared content. The package mechanism also provides an excellent means through which the language itself can be extended by standardizing packages as a part of the language. The data type proposal states that hierarchical references to a type are not permitted. For instance the following would be illegal. module types; typedef bool [ 63:0 ] long2; endmodule module m; reg types.long2 l; // hierarchical reference to type name endmodule This restriction was included in proposal 357 because of the possibility of circular references in parameters when they are typed and because the implementation complexity of "late binding of types". When a type is seen, it is necessary to have already parsed the declaration of the type to implement it efficiently. (Note: This restriction also exists in the SystemVerilog type system.) This lack of hierarchical reference is in conflict with the desire to declare a type, the functions and tasks that operate on it, and any static data needed by those tasks and functions. At first look, defining the types and tasks/functions in a file and then using `include of the file would be considered. However by examining the possible placements of `include this solution doesn't work. file types.vh -------------- typedef bool [ 63:0 ] long2; function bool parity; input long2 l; parity = ^l; endfunction; 1) If the the `include is outside a module, then the tasks/functions declared would also be outside the module and this is currently illegal. Adding other declarations in the "global" scope creates serious IP reuse and separate compilation issues that argue against allowing more declarations outside of modules. (Note: This would introduce the SystemVerilog concept of $root) `include "types.vh" // function parity is outside of module module m (input long2 lp); endmodule 2a) If the `include is inside a module, then the types declared in the file are not available for ANSI-style parameter/port lists. module m (input long2 lp); // long2 is not yet visible `include "types.vh" endmodule 2b) A second issue with the previous example is that the function "parity" is now local to the module m. The result of this is that the function will be declared over and over again in each module where the file is included. This creates capacity issues (because it is repeated), and debuggability issues (because you can't easily tell that it is the same function over and over again when debugging). To summarize the requirements: 1) Types must be parsed prior to their use to avoid parameter circularity and allow for efficient implementation. 2) It is desirable to declare types and functions/tasks on a type in the same location. This allows them to be shared by all users of the type. 3) Type names must be available prior to parameter and port declarations on a module. |
Fix |
The following text is proposed as either a subclause of the current clause 12. Hierarchical Structures, or as an entirely new clause. For this description it will be referred to as 12a. 12a. Shared Declarations The Verilog HDL supports sharing declarations through the package mechanism. The purpose of a package is to allow for the sharing of a set of related declarations. In particular, they are intended for the declaration of types and the tasks and functions that operate on that type. Static data required by those tasks and functions may also be declared and initialized. A package is distinct from a module because there is only ever one copy of a package in a description and that copy is shared by all design units that reference it. It is also distinct in that only limited HDL constructs can be declared in a package. A package has the additional characteristic that it must be explicitly made visible to another description by the use of an import statement. This import of the package ensures declaration before use of the contents of the package. 12a.1 Packages This clause gives the formal syntax for a package definition and then gives the syntax for referencing a package in a module or another package. A package definition shall be enclosed between the keywords package and endpackage. The identifier following the keyword package shall be the name of the package being defined. Note: The following productions modify the current Verilog grammar and introduce the following new keywords: package, endpackage, and import. Note: The following productions assume that data types have been added to Verilog as they motivate the need for packages. The grammar below will need to be kept in sync with any approved proposal on data types. description ::= ... | package_declaration Note: The { import_directive } has been added before module. module_declaration ::= { import_directive } { attribute_instance } module_keyword module_identifier [ module_parameter_port_list ] [ list of ports ] ; { module_item } endmodule | { import_directive } { attribute_instance } module_keyword module_identifier [ module_parameter_port_list ] [ list of port_of_port_declarations ] ; { non_port_module_item } endmodule package_declaration ::= { import_directive } { attribute_instance } package package_identifier { package_item } endpackage package_identifier ::= identifier package_item ::= { attribute_instance } package_item_declaration | { attribute_instance } initial_construct package_item_declaration ::= | variable_declaration | local_parameter_declaration | task_declaration | function_declaration | data_type_declaration import_directive ::= import list_of_imported_packages; list_of_imported_packages ::= imported_package { , imported_package } imported_package ::= package_identifier [ . visibility_filter ] visibility_filter ::= * | identifier | ( visibility_list ) visibility_list ::= identifier { , identifier } The declarations in a package are independent of the structural design hierarchy. Packages do not contain hierarchy, nor do they contain references to items declared in modules or primitives. A package name is part of the global definitions name space. A package declaration introduces a new kind of local name space, the package name space. The package name space unifies the definition of types, variables, local parameters, tasks, functions, and named initial blocks that are declared within the package. The declarations in a package are independent of the structural design hierarchy. Packages do not contain hierarchy, nor do they contain references to items declared in modules or primitives. It shall be illegal for a package to contain a hierarchical reference to any object other than an object made visible from another package via an import statement. A common use of a package is to group a type declaration and a set of tasks/functions that operate on that type. In this scenario, a module could then declare objects of the type and use the package tasks/functions to operate on the object data. This is the classic idea of grouping types and sets of operations on those types. For example: package ComplexNumber; typedef struct { real r, i; } Complex; localparam Complex zero = {0.0; 0.0}; function Complex add; input Complex a, b; add.r = a.r + b.r; add.i = a.i + b.i; endfunction function Complex mul; input 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 import ComplexPkg.*; module cadder(input Complex a, b, output Complex z); assign z = add(a, b); endmodule 12a.2 Import directive A package declaration shall appear in a description before it can be imported. An import directive creates a compilation dependency. This means that the package being imported must have been previously seen by the compiler and that if the package changes then previous compilations of its importers become invalid. Package use does not create compilation dependencies between modules. A package provides compile-time visibility of its constituents. The import statement occuring immediately before a design unit declaration indicates that some or all of the package contents are visible to the design unit as determined by the visibility filter in the import statement. The level of visibility can be full direct visibility, limited direct visibility, or no direct visibility. If the .* filter is present then all items in the package are directly visible and can be accessed by their simple names. package global_types typedef bool enum { FALSE, TRUE } boolean; typedef enum { H=1'b1, L=1'b0, Z=1'bz, X=1'bx } logic_state; endpackage import global_types.*; module error_checks ... boolean suppress_warnings = FALSE; // direct visibility of boolean logic_state clk = L; // direct visibility of logic_state ... endmodule If the import directive contains a single identifier or visibility list then that identifier or those identifiers in the list are directly visible, and the remaining package items are not (and hence must be accessed hierarchically). If an enumeration type appears in the visibility list then the names of the enumeration constants are directly visible as well. In the example below, the "boolean" type is directly visible, but the "logic_state" type is not. import global_types.boolean; module error_checks ... boolean suppress_warnings = FALSE; global_types.logic_state initial_state = global_types.X; ... endmodule If there is no visibility filter then the items in the package are not directly visible, and hence must be accessed through a hierarchical name. The directly visible items in a package overlap the local name space of the importing module or package. It is an error if that overlap results in two items with the same name. 12a.3 Initial blocks in packages Initial blocks in packages are provided to initialize static variables declared in a package. The example below uses a package to define a utility for common error messages. This package makes use of persistent state and non-reentrancy in its implementation. Variables local to the package are used to maintain this state, and an initial block is used to initialize them. package messages; typedef bool [80*8:1] message_type; integer error_count; integer warning_count; integer error_limit; task report_warning; input message_type message; begin $display("Warning at %0t: %0s", $time, message); warning_count = warning_count + 1; end endtask task report_error; input message_type message; begin $display("Error at %0t: %0s \n", $time, message); errors = errors + 1; if (errors == error_limit) end_simulation; end endtask task end_simulation; begin $display (" !! ERROR LIMIT EXCEEDED !!"); $display (" Warnings: %d Errors: %d\n", warning_count, error_count); $finish; end endtask initial begin error_count = 0; warning_count = 0; error_limit = 1; end endpackage |
Audit-Trail |
|
Unformatted |
|
Hosted by Boyd Technology