Subject: ISSUE:DirectC - proposal to be discussed today
From: Andrzej Litwiniuk (Andrzej.Litwiniuk@synopsys.com)
Date: Tue Oct 29 2002 - 09:04:15 PST
Fellow SV-CC'ers,
I've been reading the recent discussions about HDL-to-C and C-to-HDL funcion
and/or task calling and realized that we got into technical (and interesting:-)
issues [with a lot of C++ bias] while kind of deviating from the original
requirements.
The disccusion on requirements started in early August, added C-calls-HDL functionality
and then seemed to cease without any decided conlucions.
The requirements seem to have been neither accepted nor rejected.
Anyway, I believe there is some consensus on some "kernel" functionality at least.
DirectC SV-nonSV interface may be roughly divided into the four functionality
classes:
(1) SV call nonSV function (non-blocking, i.e. func. with no timing control)
(2) SV call nonSV task (blocking, i.e. func. that may contain timing control)
(3) nonSV call SV function (or a task with no timing control)
(4) nonSV call SV task (blocking)
Apart from this classification there is the separate issue of what data types
can be exchanged between the two domains.
The "kernel" functionality for sure includes (1).
In order to have something done, I'm proposing to discuss and accept this basic
functionality.
I tried to separate and isolate different issues, so they could be decided
independently, from less controversial to perhaps more controversial.
That way we might proceed gradually and find the agreement upon the
small technical issues one by one, rather than all of them at once.
That will leave the other three classes of functionality still open, but at least
we'll make some visible progress.
Observation:
-----------
There are two facets of the interface: SV side and a foreign language side.
IMO these two sides can be defined separately; the foreign programming language
and the actual function call protocol and argument passing mechanism should be
transparent to SV.
Proposition:
-----------
The SV side of the interface may and should look identical regardless of
what the foreign side of the interface will be eventually decided.
The specifics of the argument passing may be eventually reflected in tiny
modifications of the syntax agreed upon, similarly to VCS DirectC variations
of 'extern', 'extern "C"', 'extern "A"'.
(1) DirectC interface includes as a minimum the capability to call non-SV functions
and void functions (i.e. functions that return no result) from SV code.
Such functions will be hereinafter refered to as external functions (xf).
Note:
A symmetrical functionality, i.e. the capability of calling SV functions and tasks
from a non-SV domain is not precluded; it's merely not addressed in this proposal.
(2) xf executes in 0 time. In other words, no simulation time passes during
the execution of xf. Xf must not contain timing control.
Note:
The above property does not preclude calling foreign tasks, i.e. functions with
timing control.
Such functionality is simply not addressed in this proposal and may be added
as a next feature.
(3) The usage and syntax for calling xf is identical as for native SV functions
and tasks.
(a) any xf can be called as a void function, i.e. its call may occur as a statement,
and a result, if any, will be discarded.
(b) xf may have zero or more formal arguments.
(c) xf may have input, output and inout formal arguments.
(Types of a result and formal args will be discussed later.)
(d) The evaluation order of formal args follows general SV rules (is unspecified).
(4) xf may access only SV data objects explictly passed as actual arguments to
a xf call (must not acces data objects that have been not passed explicitly as
arguments of the particular call)
(5) Each xf must be declared. Such declaration will be further refered to as
external declarations.
(a) An external declaration specifies function name, optional function result
and types and directions of formal args.
It may also provide optional names for formal args. Formal arg names serve only
as comments and are otherwise meaningless.
(b) Escaped names are not allowed for xf.
(6) A scope of an external declaration is the whole design.
External declarations may occur anywhere in $root scope, ie. outside of modules,
interfaces, functions and tasks.
A name of xf should not classh with any name declared in $root scope.
An external declaration of xf need not to precede an invocation of that xf.
Regular name resolving rules apply to xf. Therefore local names declared
inside a module (or interface) will obscure xf name; $root.xf_name may be used
to resolve to global name.
Note:
Since xf may not be declared inside a module, currently there is no way to specify
xf as a part of a module intended to be a library module.
In Verilog a library module is self-contained in a sense that it does not refer
to non-local definitions other that the other modules.
In SV some new mechanism seems to be needed that would allow to link definitions
referenced in a library module with that module; such definitions include typedefs,
interfaces, external functions. Such mechanism should also provide means for linking
the external code (in a source or in an object form) with a library module.
(7) xf may have multiple declarations as long as they are all equivalent.
Two declarations are equivalent if they specify the same function result type,
the same number of formal args, and for each arg respectively, the same
direction and type.
Note:
The above definition of 'equivalence' is vague about ranges of packed
and unpacked structures and arrays (absolute bounds and the slope).
The question is which of the following forms will be considered as equivalent:
[8:1], [1:8], [7{0]. [0:7].
We may require the exact match or relax it and require only the same number of
elements.
(8) Syntax of an external declaration
An external declaration follows SV rules: arg direction defaults to input,
direction may be specified for a group of args.
external_declaration:
'extern' optional_function_type function_name '(' optional_arg_list ')' ';'
optional_function_type: 'void' | func_result_type
function_name: identifier
optional_arg_list: optional_direction group_of_args optional_groups_of_args
optional_direction: /*empty*/ | direction
direction: 'input' | 'output' | 'inout'
group_of_args: formal_arg | formal_arg ',' group_of_args
formal_arg: formal_arg_type optional_name
optional_name: /*empty*/ | identifier
optional_groups_of_args: /*empty*/
| direction group_of_args optional_groups_of_args
func_result_type and formal_arg_type will be discussed later.
(9) Arguments passing for xf is ruled by WYSIWYG principle:
What You Specify Is What You Get.
(The possible exceptions for packed and unpacked ranges will be discussed
later.)
If the actual arg does not match exactly the formal one, a temporary variable
of the type specified for the formal arg is created and passed as an actual arg.
For input and inout args, such temporary is initialized with the value of actual
arg with the appropriate conversion; for the output or inout arg, the value of
the temporary is assigned to the actual arg with the appropriate conversion.
The assignments between a temporary and the actual arg follow general SV rules
for assignments and automatic convertion.
(10) For the SV side of the interface, the semantics of arguments passing is as
if input args were passed by "copy-in", output args were passed by "copy-out"
and inout args were passed by "copy-in, copy-out".
The actual implementation of argument pasing is transparent and irrelevant
to the SV side of the interface.
(a) xf must not modify the values of its input args
(b) The initial values of formal output args are unspecified and may be
implementation dependent.
(c) For output and inout args the value propagation (i.e. value change events)
happens as if an actual arg was assigned a formal arg immediately after
control returns from xf.
Types of formal arguments and function result
----------------------------------------------
Note: Ideally, any SV data type would be allowed.
I'm not sure this is feasible, however.
(11) As the minimum the following basic types are allowed for function result type
and formal arguments:
- basic types: int, real, byte, type, short.
- scalars of types bit, logic
- new primitive types, to be introduced to SV: pointer, string
These are the minimal requirements; other types will be discussed later.
(12) New primitive types: pointer, string.
These types are meant solely for DirectC interface and are intended for passing
values from non-SV domain back into that domain, with ability to store them in
the interim on SV variables.
They do not introduce the dynamic data types into SV and generally have no
interpretation on the SV side.
Therefore only a minimal set of rudimentary features is proposed here.
The proposition to introduce these new types does not preclude full-fledged pointers,
should the committee decide to introduce them into SV.
Type 'pointer' represents a generic pointer, 'string' represent a pointer to
C-like string.
Note that typedef allows to define different pointer types, e.g.:
typedef pointer list;
typedef pointer queue;
The use of the types pointer and string is restricted as follows:
- pointer/string may be used as types of function result and formal arguments
of external functions as well as SV functions and tasks or as types of variables
- may not be used as types of module or interface ports
- may not occur in packed structs or unions
- may be used in assignments (if both sides are of the same type)
and as actual args to function/task calls
- 0 (unsized constant zero) may be used as a value compatible with any pointer or
string type
- the only applicable operations for the values of these types are comparisons
!=, == with 0 (unsized constant zero) or other values of the same type;
no arithmetic operations or other realtional operators are allowed on them
- may not be used in explicit or implicit sensitivity lists or posedge/negedge
or in continupos assignments
- the initial value of a variable of type pointer/string is 0 (unsized constant).
- a string literal, i.e. characters in quotes, e.g. "a text" occuring as an actual
argument for a formal arg of type string is interpreted as C-style string
rathet than as SV encoding of a bit vector.
(This rule may be enhanced to allow string literals in assignments to
variables of type string.)
More on types of result and formal args of xf
----------------------------------------------
Ideally, any SV and C/C++ data type would be allowed.
This would require that every SV data type is mapped upon some type in the
foreign language, and similarly, any C/C++ type is mapped upon some type in SV.
There is no obvious 1-to-1 correspondence between SV data types and C types.
Contrary to popular belief (?), there are no common types between SV and C
other than basic arithmetic types.
SV inherits from C but is not a superset of C.
Structures defined in C by and large are not valid SV structures.
[VCS DirectC avoids the problem by generating headers that map V types onto
C types, and by restricting function result types.]
Of course, it's possible to define inductively the set of data types that
would be valid and semantically equivalent in both languages.
It would be, however, impractical and confusing.
Commonly, definitions in C are convoluted, refer to #define constants, involve
conditional compilation, differently specify array's size, etc.
SV parser might support full C or C++ syntax, but this will only add the burden.
A type of a formal arg or func result of xf usually will not be be useful, if user
cannot declare her/his variable of that type (unless a clear rule is provided
for conversion between SV and non-SV types) that could be used as an actual arg.
So, are we to allow imported types in SV code?
(13) DirectC interface should not impose any constraints on how SV data types
are actually implemented.
We may specify that the layout of SV structs should be the same as the layout
used by a C compiler on the corresponding C structs.
We shouldn't specify the layout of 2- or 4-state vectors, as this may be
platform dependent.
(14) I propose to restrict the types allowed for formal args and func result
- in addition to the basic types listed in (22) - to:
- scalars of type bit and logic
- packed 1-dimensional vectors of type bit/logic
- unpacked 1-dimensional arrays of the above.
(15) All vectors/arrays will be normalized to [n:0] regardless of the original range and increasing or decreasing order of indexing.
For example [1:8], [8:1], [7:0] will be equivalent declarations of the size of
packed a vector or unpacked an array.
(16) For the convenience, the size of the packed dimension or the unpacked
dimension
or both dimension may remain unspecified; such cases will be refered to as open
vectors and open arrays.
This will allow to write a generic code good for different sizes.
If a formal argument is specified as an open vector or an open array, then the
actual
arg will match the formal one regardless of the size of its, respectively,
linearized packed or unpacked dimensions.
Here are the examples of types of formal args:
bit
logic
bit [8:1]
logic [0:31]
bit[]
bit [7:0] array [1:10]
logic array [1:10]
logic [31:0] array[]
logic [] array [3:1]
bit [] array []
Comment: empty [] denotes open vector or open array.
Keyword 'array' separates packed and unpacked dimension (refered here as a
vector and an array).
(17) I propose to further restrict the types of function result to "small"
values: logic, bit, or bit [n:1], n<=32,
plus basic types discussed earlier.
Andrzej
This archive was generated by hypermail 2b28 : Tue Oct 29 2002 - 09:04:47 PST