Section 27.1.1

LRM-132

Change (changes in red and blue):

27.1.1 Tasks and Functions

 

DPI allows direct inter-language function calls between the languages on either side of the interface. Specifically, functions implemented in a foreign language can be called from SystemVerilog; such functions are referred to as imported functions. SystemVerilog functions that are to be called from a foreign code shall be specified in export declarations (see Section 27.6 for more details). DPI allows for passing SystemVerilog data between the two domains through function arguments and results. There is no intrinsic overhead in this interface.

 

It is also possible to perform task enables across the language boundary. Foreign code may call SystemVerilog tasks, and native Verilog code may call imported tasks. An imported task has the same semantics as a native Verilog task: It never returns a value, and it may block and consume simulation time.

 

All functions used in DPI are assumed to complete their execution instantly and consume 0 (zero) simulation time, just as normal SystemVerilog functions. DPI provides no means of synchronization other than by data exchange and explicit transfer of control.

 

Every imported task and function needs to be declared. A declaration of an imported task or function is referred to as an import declaration. Import declarations are very similar to SystemVerilog task and function declarations. Import declarations can occur anywhere where SystemVerilog task and function definitions are permitted. An import declaration is considered to be a definition of a SystemVerilog task or function with a foreign language implementation. The same foreign task or function can be used to implement multiple SystemVerilog tasks and functions (this can be a useful way of providing differing default argument values for the same basic task or function), but a given SystemVerilog name can only be defined once per scope. Imported tasks and functions can have zero or more formal input, output, and inout arguments.  , and they Imported tasks always return a void value, and thus can only be used in statement context. Imported functions can return a result or be defined as void functions.

 

DPI is based entirely upon SystemVerilog constructs. The usage of imported functions is identical as for native SystemVerilog functions. With few exceptions imported functions and native functions are mutually exchangeable. Calls of imported functions are indistinguishable from calls of SystemVerilog functions. This facilitates ease-of-use and minimizes the learning curve. Similar interchangeable semantics exist between native SystemVerilog tasks and imported tasks.

Section 27.2.2

LRM-132

Change (changes in red and blue) (Please note that this becomes Annex E with the new Annex C):

 

The SystemVerilog compiler or simulator shall generate and/or use the function call protocol and argument passing mechanisms required for the intended foreign language layer. The same SystemVerilog code (compiled accordingly) shall be usable with different foreign language layers, regardless of the data access method assumed in a specific layer. Annex A E defines DPI foreign language layer for the C programming language.

Section 27.3

LRM-132

Change (changes in red and blue):

27.3 Global name space of imported and exported tasks and functions

 

Every task or function imported to SystemVerilog must eventually resolve to a global symbol. Similarly, every task or function exported from SystemVerilog defines a global symbol. Thus the tasks and functions imported to and exported from SystemVerilog have their own global name space of linkage names, different from compilation-unit scope name space. Global names of imported and exported tasks or functions must be unique (no overloading is allowed) and shall follow C conventions for naming; specifically, such names must start with a letter or underscore, and can be followed by alphanumeric characters or underscores. Exported and imported tasks and functions, however, can be declared with local SystemVerilog names. Import and export declarations allow users to specify a global name for a task or function in addition to its declared name. Should a global name clash with a SystemVerilog keyword or a reserved name, it shall take the form of an escaped identifier. The leading backslash ( \ ) character and the trailing white space shall be stripped off by the SystemVerilog tool to create the linkage identifier. Note that after this stripping, the linkage identifier so formed must comply with the normal rules for C identifier construction. If a global name is not explicitly given, it shall be the same as the SystemVerilog task or function name. For example:

 

export "DPI" foo_plus = function \foo+ ; // "foo+" exported as "foo_plus"

export "DPI" function foo; // "foo" exported under its own name

import "DPI" init_1 = function void \init[1] (); // "init_1" is a linkage name

import "DPI" \begin = function void \init[2] (); // "begin" is a linkage name

 

The same global task or function can be referred to in multiple import declarations in different scopes or/and with different SystemVerilog names, see Section 27.4.4.

 

Multiple export declarations are allowed with the same c_identifier, explicit or implicit, as long as they are in different scopes and have the same type signature (as defined in Section 27.4.4 for imported functions). Multiple export declarations with the same c_identifier in the same scope are forbidden.

Section 27.4

LRM-132

Change (changes in red and blue):

27.4 Imported tasks and functions

Section 27.4.1

LRM-132

Change (changes in red and blue):

27.4.1 Required properties of imported task or functions calls - semantic constraints

 

This section defines the semantic constraints imposed on imported tasks or functions. Some semantic restrictions are shared by all imported tasks or functions. Other restrictions depend on whether the special properties pure (see Section 27.4.2) or context (see Section 27.4.3) are specified for an imported task or function. A SystemVerilog compiler is not able to verify that those restrictions are observed and if those restrictions are not satisfied, the effects of such imported task or function calls can be unpredictable.

Section 27.4.1.1

LRM-132

Change (changes in red and blue):

27.4.1.1 Instant completion of imported functions

 

Imported functions shall complete their execution instantly and consume zero-simulation time, similarly to native functions.

 

Note that imported tasks may consume time, similar to native SystemVerilog tasks.

 

Section 27.4.1.3

LRM-132

Change (changes in red and blue):

27.4.1.3 Special properties pure and context

 

Special properties can be specified for an imported task or function: as pure or as context (see also Section 27.4.2 or 27.4.3).

 

A function whose result depends solely on the values of its input arguments and with no side effects can be specified as pure. This can usually allow for more optimizations and thus can result in improved simulation performance. Section 27.4.2 details the rules that must be obeyed by pure functions. An imported task can never be declared pure.

 

An imported task or function that is intended to call exported tasks or functions or to access SystemVerilog data objects other then its actual arguments (e.g. via VPI or PLI calls) must be specified as context. Calls of context tasks and functions are specially instrumented and can impair SystemVerilog compiler optimizations; therefore simulation performance can decrease if the context property is specified when not necessary. A task or function not specified as context shall not read or write any data objects from SystemVerilog other then its actual arguments. For tasks or functions not specified as context, the effects of calling PLI, VPI, or exported SystemVerilog tasks or functions can be unpredictable and can lead to unexpected behavior; such calls can even crash. Section 27.4.3 details the restrictions that must be obeyed by non-context tasks or functions.

Section 27.4.1.5 (New)

LRM-132

Change (changes in red and blue):

27.4.1.5 Reentrancy of imported tasks

 

Since imported tasks may block (consume time), it is possible for an imported task’s C code to be simultaneously active in multiple execution threads. Standard reentrancy considerations must be made by the C programmer. Some examples of such considerations include safe use of static variables, and ensuring that only thread-safe C standard library calls (MT safe) are used.

Section 27.4.1.6 (New)

LRM-132

Change (changes in red and blue):

27.4.1.6 C++ exceptions

 

It is possible to implement DPI imported tasks and functions using C++, as long as C linkage conventions are observed at the language boundary. If C++ is used, exceptions must not propagate out of any imported task or function. Undefined behavior will result if an exception crosses the language boundary from C++ into SystemVerilog.

Section 27.4.3

LRM-132

Change (changes in red and blue):

27.4.3 Context tasks or functions

 

Some DPI imported tasks or functions require that the context of their call is known. It takes special instrumentation of their call instances to provide such context; for example, an internal variable referring to the “current instance” might need to be set. To avoid any unnecessary overhead, imported task or function calls in SystemVerilog code are not instrumented unless the imported task or function is specified as context.

 

All DPI exported tasks or functions require that the context of their call is known. This occurs since SystemVerilog task or function declarations always occur in instantiable scopes, hence allowing a multiplicity of unique task or function instances.

 

For the sake of simulation performance, an imported task or function call shall not block SystemVerilog compiler optimizations. An imported task or function not specified as context shall not access any data objects from SystemVerilog other than its actual arguments. Only the actual arguments can be affected (read or written) by its call. Therefore, a call of a non-context task or function is not a barrier for optimizations. A context imported task or function, however, can access (read or write) any SystemVerilog data objects by calling PLI/VPI, or by calling an export task or function. Therefore, a call to a context task or function is a barrier for SystemVerilog compiler optimizations.

 

Only calls of context imported tasks or functions are properly instrumented and cause conservative optimizations; therefore, only those tasks or functions can safely call all tasks or functions from other APIs, including PLI and VPI tasks or functions or exported SystemVerilog tasks or functions. For imported tasks or functions not specified as context, the effects of calling PLI, VPI, or SystemVerilog tasks or functions can be unpredictable and such calls can crash if the callee requires a context that has not been properly set. However note that declaring an import context task or function does not automatically make any other simulator interface automatically available. For VPI access (or any other interface access) to be possible, the appropriate implementation defined mechanism must still be used to enable these interface(s). Note also that DPI calls do not automatically create or provide any handles or any special environment that can be needed by those other interfaces. It is the user’s responsibility to create, manage or otherwise manipulate the required handles/environment(s) needed by the other interfaces.

 

Context imported tasks or functions are always implicitly supplied a scope representing the fully qualified instance name within which the import declaration was present. This scope defines which exported SystemVerilog tasks or functions can be called directly from the imported task or function; only tasks or functions defined and exported from the same scope as the import can be called directly. To call any other exported SystemVerilog tasks or functions, the imported task or function shall first have to modify its current scope, in essence performing the foreign language equivalent of a SystemVerilog hierarchical task or function call.

 

Special DPI utility tasks and functions exist that allow imported tasks or functions to retrieve and operate on their scope. See Annex D for more details.

Section 27.4.4

LRM-132

Change (changes in red and blue):

 

Each imported task or function shall be declared. Such declarations are referred to as import declarations. The syntax of an import declaration is similar to the syntax of SystemVerilog task or function prototypes (see Section 10.6).

 

Imported tasks or functions are similar to SystemVerilog tasks or functions. Imported tasks or functions can have zero or more formal input, output, and inout arguments. Imported functions can return a result or be defined as void functions. Imported tasks never return a result, and thus are always declared in foreign code as void functions.

LRM-132

Change in Syntax 27-1 (changes in red and blue):

dpi_import_export ::=                                                                          // from Annex A.2.6

  import "DPI" [ dpi_function_import_property ] [ c_identifier = ] dpi_function_proto ;

| import "DPI" [ dpi_task_import_property ] [ c_identifier = ] dpi_task_proto ;

| export "DPI" [ c_identifier = ] function function_identifier ;

| export "DPI" [ c_identifier = ] task task_identifier ;

 

dpi_function_import_property ::= context | pure

 

dpi_task_import_property ::= context

 

dpi_function_proto11,12 ::= function named_function_proto

 

dpi_task_proto12 ::= task named_task_proto

LRM-132

Change (changes in red and blue):

An import declaration specifies the function or task name, function result type, and types and directions of formal arguments. It can also provide optional default values for formal arguments. Formal argument names are optional unless argument passing by name is needed. An import declaration can also specify an optional function or task property: context or pure. Imported functions can have properties context or pure; imported tasks can have property context.

 

Note that an import declaration is equivalent to defining a task or function of that name in the SystemVerilog scope in which the import declaration occurs, and thus multiple imports of the same task or function name into the same scope are forbidden. Note that this declaration scope is particularly important in the case of imported context tasks or functions, see Section 27.4.3; for non-context imported tasks or functions the declaration scope has no other implications other than defining the visibility of the task or function.

 

c_identifier provides the linkage name for this task or function in the foreign language. If not provided, this defaults to the same identifier as the SystemVerilog task or function name. In either case, this linkage name must conform to C identifier syntax. An error shall occur if the c_identifier, either directly or indirectly, does not conform to these rules.

 

For any given c_identifier (whether explicitly defined with c_identifier=, or automatically determined from the task or function name), all declarations, regardless of scope, must have exactly the same type signature. The signature includes the return type and the number, order, direction and types of each and every argument. Type includes dimensions and bounds of any arrays or array dimensions. Signature also includes the pure/context qualifiers that can be associated with an extern definition.

 

Note that multiple declarations of the same imported or exported task or function in different scopes can vary argument names and default values, provided the type compatibility constraints are met.

 

A formal argument name is required to separate the packed and the unpacked dimensions of an array.

 

The qualifier ref cannot be used in import declarations. The actual implementation of argument passing depends solely on the foreign language layer and its implementation and shall be transparent to the SystemVerilog side of the interface.

 

The following are examples of external declarations.

LRM-132

Change (changes in red and blue):

// miscellanea

import "DPI" function bit [15:0] getStimulus();

import "DPI” context function void processTransaction(chandle elem,

output logic [64:1] arr [0:63]);

import “DPI” task checkResults(input string s, bit [511:0] packet);

Section 27.4.6

LRM-132

Change (changes in red and blue):

A rich subset of SystemVerilog data types is allowed for formal arguments of import and export tasks or functions. Generally, C compatible types, packed types and user defined types built of types from these two categories can be used for formal arguments of DPI tasks or functions. The set of permitted types is defined inductively.

 

The following SystemVerilog types are the only permitted types for formal arguments of import and export tasks or functions:

 

      void, byte, shortint, int, longint, real, shortreal, chandle, and string

 

      scalar values of type bit and logic

 

      packed one dimensional arrays of type bit and logic

 

Note however, that every packed type, whatever is its structure, is eventually equivalent to a packed one dimensional array. Therefore practically all packed types are supported, although their internal structure (individual fields of structs, multiple dimensions of arrays) shall be transparent and irrelevant.

 

      enumeration types interpreted as the type associated with that enumeration

 

      types constructed from the supported types with the help of the constructs:

 

      struct

 

      unpacked array

 

      typedef

 

The following caveats apply for the types permitted in DPI:

 

                  Enumerated data types are not supported directly. Instead, an enumerated data type is interpreted as the type associated with that enumerated type.

 

      SystemVerilog does not specify the actual memory representation of packed structures or any arrays, packed or unpacked. Unpacked structures have an implementation-dependent packing, normally matching the C compiler.

 

      The actual memory representation of SystemVerilog data types is transparent for SystemVerilog semantics and irrelevant for SystemVerilog code. It can be relevant for the foreign language code on the other side of the interface, however; a particular representation of the SystemVerilog data types can be assumed. This shall not restrict the types of formal arguments of imported tasks or functions, with the exception of unpacked arrays. SystemVerilog implementation can restrict which SystemVerilog unpacked arrays are passed as actual arguments for a formal argument which is a sized array, although they can be always passed for an unsized (i.e., open) array. Therefore, the correctness of an actual argument might be implementation-dependent. Nevertheless, an open array provides an implementation-independent solution.

Section 27.7 (New)

LRM-132

Change (changes in red and blue):

27.7 Exported tasks

 

SystemVerilog allows tasks to be called from a foreign language, similar to functions. Such tasks are termed “exported tasks”.

 

All aspects of exported functions described above in section 27.6 apply to exported tasks. This includes legal declaration scopes as well as usage of the optional c_identifier.

 

It is never legal to call an exported task from within an imported function. These semantics are identical to native SystemVerilog semantics, in which it is illegal for a function to perform a task enable.

 

It is legal for an imported task to call an exported task only if the imported task is declared with the context property. See section 27.4.3 (Context tasks and functions) for more details.

 

One difference between exported tasks and exported functions is that SystemVerilog tasks do not have return value types. The return value of an exported task is an int value which indicates if a disable is active or not on the current execution thread.

 

Similarly, imported tasks return an int value which is used to indicate that the imported task has acknowledged a disable. See section 27.8 for more detail on disables in DPI.

Section 27.8 (New)

LRM-132

Change (changes in red and blue):

27.8 Disabling DPI tasks and functions

 

It is possible for a disable statement to disable a block that is currently executing a mixed language call chain. When a DPI import task or function is disabled, the C code is required to follow a simple disable protocol. The protocol gives the C code the opportunity to perform any necessary resource cleanup, such as closing open file handles, closing open vpi handles, or freeing heap memory.

 

An imported task or function is said to be in the disabled state when a disable statement somewhere in the design targets either it or a parent for disabling. Note that the only way for an imported task or function to enter the disabled state is immediately after the return of a call to an exported task or function. An important aspect of the protocol is that disabled import tasks and functions must programmatically acknowledge that they have been disabled. A task or function can determine that it is in the disabled state by calling API function svIsDisabledState().

 

The protocol is composed of the following items:

 

1. When an exported task returns due to a disable, it must return a value of 1. Otherwise it must return 0.

2. When an imported task returns due to a disable, it must return a value of 1. Otherwise it must return 0.

3. Before an imported function returns due to a disable, it must call API function svAckDisabledState().

4. Once an imported task or function enters the disabled state, it is illegal to make any further calls to exported tasks or functions.

 

Items 2, 3, and 4 are mandatory behavior for imported DPI tasks and functions. It is the responsibility of the DPI programmer to correctly implement the behavior.

 

Item 1 is guaranteed by SystemVerilog simulators. In addition, simulators must implement checks to ensure that items 2, 3, and 4 are correctly followed by imported tasks and functions. If any protocol item is not correctly followed, a fatal simulation error is issued.

 

Note that if an exported task itself is the target of a disable, its parent imported task is not considered to be in the disabled state when the exported task returns. In such cases the exported task will return value 0, and calls to svIsDisabledState() will return 0 as well.

 

When a DPI imported task or function returns due to a disable, the values of its output and inout parameters are undefined. Similarly, function return values are undefined when an imported function returns due to a disable. C programmers may return values from disabled functions, and C programmers may write values into the locations of output and inout parameters of imported tasks or functions. However, SystemVerilog simulators are not obligated to propagate any such values to the calling SystemVerilog code if a disable is in effect.