Subject: Re: DirectC: C layer
From: Francoise Martinolle (fm@cadence.com)
Date: Wed Dec 11 2002 - 15:29:19 PST
Andrzej,
It was very difficult today to place any word during the meeting so I am
gathering my issues/comments in this email.
I have 3 main issues with the proposal.
The first one has to do with passing by reference the simulation object
value and that
value be modified by the directC interface. When and how is the propagation
of that value
done? Wires and regs have fan out and updates to their values should cause
propagation and fanout. When does this happen? What about if there is a
force in effect on that
object? Would the value be updated by the C code?
Depending on what is your answer, we have a further problem as we are thinking
of allowing SV tasks and functions to be called from inside the C function.
What would be the values that these task/functions will see, has the value
already propagated?
My second issue is related to the first one: you pass by reference large
simulation objects
but you provide user callable functions to copy the simulator value into a
canonical representation.
The memory allocation for the canonical value being the responsibility of
the user seems
dangerous and would require them to find out the size/range of the
simulation object, thus requiring
more API functions to inquire about the object. The conclusion is that you
may pass by reference
but this requires the user to transform the value in the canonical form
before reading or writing to it.
Unless the user cares to know about the internal simulator representation
and therefore can directly
dereference the simulation value passed by reference. This leads me to the
third issue.
The third issue is related to the internal representation of wires in Verilog.
There is no common layout for wires in a single Verilog simulator. Wires
may be expanded or
vectored and depending on this the wire value may not be consecutive bits
in memory.
A scalar wire can be shared between different wire arrays. Various layouts
can apply depending on
Verilog code generation optimizations, thus invalidating the directC user code.
This tells you that in many cases you cannot pass a wire by reference and
that SV will have to
compose the value of a non scalar wire before passing the value by reference
to C and if C modifies that value then that value will have to be decomposed
back on the SV side. You may want to force the layout of the composed value
to be
similar as the one chosen for reg and variables in a given simulator but
this will have
some implication on simulation performance.
I believe that the only sound technical solution is to do copy in and copy
out. Then you don't
have the 3 issues I mentioned. Calling a directC function is in line with
the copy-in copy-out rules
of Verilog tasks and functions, commonly understood by Verilog users.
You solve the fanout/force problem, fanout occurs when the function
returns, update occurs after the
function returns.
The transformation of the value between SV and C is done on the simulator
side rather than by
a C user function, the simulator knows how much he needs to allocate.
And as a bonus this solution is always binary compatible if we agree on the
canonical representation
of the copyout value on the C side, which I think should be in a VPI vecval
structure format.
There is no C API function to manipulate the values that are passed.
I would like to know what you think about these issues.
Francoise
'
At 02:47 AM 12/7/2002 -0500, Andrzej Litwiniuk wrote:
>Team,
>
>As promised, I'm sending the proposal for the C layer of the interface.
>
>The proposal is unfinished. This is the best I managed to do before
>the deadline Friday midnight PST (technically speaking, I still have
>15 minutes :-)
>
>I hope this could be a base for a complete solution.
>
>Regards,
>Andrzej
>
>----------------------------------------------------------------------------
>
>
>C layer of SV DirectC Interface
>-------------------------------
>
>Preface.
>========
>
>The enclosed proposal addresses only restricted a subset of SV types.
>I failed to find/invent a solution that would be efficient and general at
>the same time.
>
>The proposed solution offers very efficient access, with no or very little
>overhead, although only for restricted a subset of types.
>
>I believe that such approach seems to be justified by the requirements
>for DirectC interface. Should a general solution be used, VPI or PLI
>may serve as the last resort.
>
>Let me start with presenting the reasoning that has led to the proposed
>solution.
>
>It's obvious that for each SV data type passed from SV to C, the matching
>C type has to be used in C code, if that data is to be directly accessed
>in C. An abstract access would also require a similar mapping, though perhaps
>a simpler one.
>
>The DirectC interface or an implementation, or both, must define the mapping
>from SV datypes onto C types. (The reverse mapping is by and large easier,
>assuming the existance of generic pointers.)
>
>Consider the following structure:
>
>struct {
> int a;
> T b; /* T is a data type */
> int C;
>}
>
>A compiler cannot process such a type and determine the relative offset of 'b'
>without knowing at least the size of 'T'.
>
>So, if the above structure is defined in SV, what should be the corresponding
>data type to be used in C?
>
>The answer is simple and obvious if the type 'T' has a natural mapping onto
>some C type, like the basic types 'int', 'byte' or 'real'.
>
>But what is the "natural mapping" for, say, 'logic [2:3][1:3][2:0] b [1:10]',
>i.e. an unpacked 10-element array of packed array 2 by 3 by 3 bits, 4-state
>each?
>A single element of unpacked array is 18 bits; how many bytes or words
>will it take to represent it? Verilog simulator very likely will use 2*3
>bytes
>per each 18-bit element of an array; C implementation would rather use 2
>words
>per element.
>
>So the key question is what to do with SV specific data types?
>
>A few solutions have been proposed, but none of them seems satisfactory
>and working.
>
>For example, SV compiler might generate C types for SV types (similarly
>to VCS generating headers for the external functions).
>This would solve the problem of writing a matching declaration in C; such
>declaration would be automatically generated.
>(Note the use model: user will have to start with a SV definition and then
>use a SV compiler in order to get the corresponding C definition.)
>This would not help, however, with accessing a packed part of an element
>in C code. (C does not support multi-indexing on bits level.)
>
>Another discussed solution is to standarize the representation.
>
>Any standarization of the internal data representation used by a simulator
>will sacrify the performance.
>May I here recall that we accepted 13c from "17 items"?
>[ 13c: "The layout of 2- or 4-state vectors (i.e. packed structs and arrays)
> is implementation- and platform- dependent. ]
>
>So instead we might standarize the representation visible to the C user,
>by introducing something like avalue/bvalue known from PLI.
>Actually, this idea is partly employed in my proposal.
>
>But again, what would be the "standard" representation for the example of
>array
>considered above?
>
>
>Yet another approach is to replace troublesome SV-specific data types
>with a handle and use the abstract access mode to access such troublesome data
>solely thru a handle.
>
>With that approach the structure
>
> 'struct { int a; T b; int c; }', where T is a troublesome data type
>
>would be seen in C as
>
> 'struct { int a; sv_handle b; int c; }'
>
>where sv_handle is a pointer to some descriptor of the value of type T.
>A descriptor could be standarized or left to vendors.
>
>Unfortunately, this will not work for calling SV functions from C.
>The actual arguments exist on the caller's side and it's the caller
>who creates them. How would the caller in C code create a handle for SV data
>object and how such object would be created in C?
>
>Sure, there may be some conceivable solutions. For example, if SV code exports
>a function, then SV compiler might also provide constructor functions, to be
>called from C, for creating handles for those involved types of arguments
>that
>require a handle.
>But such solution's going to be pretty complicated and the use model may got
>confusing.
>
>
>Either approach, i.e. a standarized API representation or a handle, will
>require the translation between the two representations: the one used by
>a simulator and the other one visible to C.
>Such translation may be quite expensive, if an array of structures is passed.
>
>Let me summarize the downsides of the above solutions:
>
> - both approaches will impose an overhead
> - standarized API representation will not help with complex SV types
> - handle will not work for calling SV functions from C
>
>
>Having said that, I propose a modest yet pragmatic solution.
>(It's pragmatic because it's doable :-)
>
>
>Overview of C layer
>===================
>
>Only restricted and 'normalized' SV specific types will be supported.
>
>For example, if 'logic [2:3][1:3][2:0] b [1:10]' is used in SV type,
>it will have to be defined in C as if it were declared in SV in the following
>normalized form: 'logic [17:0] b [0:9]'.
>That practically means that the packed part must be linearized and the ranges
>must be normalized.
>(Well, perhaps the range normalization requirement could be relaxed.)
>
>By and large the actual arguments will be passed by reference, with a few
>exceptions (e.g. small input arguments).
>
>There will be no copying of arguments (other than resulting from coercing)
>Please recall item 10 from "17 items"!
>[10a: "xf must not modify the values of its input args'
> 10b: "The initial values of formal output args are unspecified and may be
> implementation dependent."]
>
>The actual arguments passed by reference by and large will be passed as
>they are, without changing their representation from the one used by a
>simulator.
>(Again, there are some exceptions, mainly for the 'open' alias 'unsized'
>arrays.)
>
>Therefore there will be no overhead on argument passing because no copying or
>translation between different representations will be required.
>
>C data types will be directly accessible.
>
>SV specific types will be accessible both via the interface library
>functions,
>what grants the compatibility, and directly thru pointers, what allows for
>the simulator-specific tuning of the application.
>
>DirectC interface defines the canonical API representation of packed 2-state
>and 4-state arrays. (Actually based on PLI's avalue/bvalue for 4-state.)
>
>Library functions will provide the translation between the representation
>used in a simulator and the canonical API representation.
>
>'Open' alias 'unsized' arrays will be accessible through the abstract access
>mode, i.e. via the interface library functions.
>
>Depending on the data types used for the external (or exported) functions,
>either binary level or C source level compatibility is granted.
>
>The binary level compatibility is granted for all data types that do not mix
>C types with SV specific types, though either category separately is fine.
>For example, if a formal argument type is a C structure or a packed array
>of bit or logic, then binary level compatibility is granted.
>On the other hand, if a packed structure is embedded in an unpacked data
>type, then only a source level compatibility is granted.
>(Binary level compatibility means that an application compiled for a given
>platform shall work with every SV simulator on that platform.
>Source level compatibility means that an application will have to be
>re-compiled
>for each SV simulator and that the implementation specific definitions
>will be required for the compilation.)
>
>
>
>Data type mapping
>=================
>
>The basic SV data types will be represented as follows:
>
>int -> int
>real -> double
>shortreal -> float
>
>etc. (Actually, LRM shall provide a complete list.)
>
>SV specific data types like packed bit and logic vectors, will be discussed
>separately.
>
>
>Argument passing
>=================
>
>Actual arguments generally are passed by reference or by value and will
>be directly accessible in C code.
>
>In some cases, defined separately, an argument will be passed by handle
>and will
>be accessible via library functions (abstract acess mode).
>
>For the arguments passed by reference, their original simulator-specific
>representation will be used and a reference to the original data object
>will be passed.
>
>If an argument of type 'T' is passed by reference, than the formal argument
>shall be of the type 'T *'.
>
>Output and inout arguments are passed by reference.
>
>Input arguments are passed by value or by reference, depending on the size.
>'Small' values of formal input arguments are passed by value.
>The following data types are considered 'small':
>
> - char, byte, int, real, shortreal (have I omitted something?)
> - pointer, string
> - bit (i.e. 2-state) vectors up to 32-bit; canonical representation will
> be used, similarly for function result
>
>Input arguments of other types are passed by reference.
>
>
>
>Include files
>=================
>
>(All names are provisional and subject to discussion and improvment.)
>
>The C layer of SV DirectC interface defines two include files
>corresponding to
>the two levels of compatibility (binary level and source code level):
> - sverilog.h
> - directc.h
>
>"sverilog.h" is fully defined by the interface and is implementation
>independent.
>It defines the canonical API representation of 2-state (bit) and 4-state
>(logic)
>values, defines the types used for passing references to SV data objects,
>provides function headers and defines a number of helper macros and constants.
>
>"directc.h" provides implementation dependent definitions.
>The contens of this file, i.e. what symbols are defined (constants, macros,
>typedefs), is defined by the interface.
>The actual definitions of the symbols, however, are implementation
>specific and
>will be provided by the vendors.
>"directc.h" defines data structures for implementation specific
>representation of
>2-state and 4-state vectors, as well as a number of helper macros and
>constants.
>
>User's applications that require "directc.h" file will be only source-level
>compatible, i.e. they will have to be compiled with the version of "directc.h"
>provided for a particular implementation of SV.
>
>The applications that use only "sverilog.h" will be binary compatible with
>all SV simulators.
>
>
>The values of C-like types may be directly accessed via the corresponding
>C type definitions.
>
>The values of SV specific types, like packed arrays of bit or logic, may
>be accessed via interface functions using the canonical representation of
>2-state and 4-state vectors.
>They also may be directly accessed using the implementation representation.
>The former mode will assure binary level compatibility, the later one
>will allow for tool-specific performance oriented tuning of an application.
>
>There will be no confusion whether passing a particular data type
>is binary compatible or only source level compatible.
>The rule is straightforward: if a correcponding type definition can be
>written in C without the need to include "directc.h" file, then the binary
>compatibility is granted. Everything that requires "directc.h" is not binary
>compatible and needs recompilation for each simulator of choice.
>
>Applications that pass solely C compatible data types or standalone packed
>arrays
>(both 2-st and 4-st) will require only "sverilog.h" and therefore will be
>binary
>compatible will all simulators.
>
>Applications that pass complex data types that contain at the same time
>packed arrays and C-compatible types, will require also "directc.h" file and
>therefore will not be binary compatible will all simulators. The source level
>compatibility is, however, granted.
>
>
>
>"sverilog.h"
>=================
>
>This file contains the following definitions:
>
>/* canonical API representation */
>
>#define sv_0 0
>#define sv_1 1
>#define sv_z 2 /* representation of 4-st scalar z */
>#define sv_x 3 /* representation of 4-st scalar x */
>
>typedef unsigned char svBit; /* scalar */
>typedef unsigned char svLogic; /* scalar */
>
>/* 2-state and 4-state vectors, modelled upon PLI's avalue/bvalue */
>#define VEC32_NEEDED(WIDTH) (((WIDTH)+31)>>5)
>
>typedef unsigned int
> svBitVec32; /* (a chunk of) packed bit array */
>
>typedef struct { unsigned int c; unsigned int d;}
> svLogicVec32; /* (a chunk of) packed logic array */
>
>/* reference to a standalone packed array */
>typedef void* svBitPackedArr;
>typedef void* svLogicPackedArr;
>
> /* a handle to a generic object (actually, unsized array) */
>typedef void* svHandle;
>
>/* functions for translation between simulator's and canonical
>representations */
>
>/* s=source, d=destination, w=width */
>
>/* actual <-- canonical */
>void vcPutBitVec32 (svBitPackedArr d, svBitVec32* s, int w);
>void vcPutLogicVec32 (svLogicPackedArr d, svLogicVec32* s, int w);
>
>/* canonical <-- actual */
>void vcGetBitVec32 (svBitVec32* d, svBitPackedArr s, int w);
>void vcGetLogicVec32 (svLogicVec32* d, svLogicPackedArr s, int w);
>
>The above functions copy the whole array in either direction. User is
>responsible for providing the correct width and for allocating an array in
>the canonical
>representation.
>
>More functions may be added, for accesing individual bits or small (<=32)
>part-selects.
>
>Similarly, functions for converting packed arrays into char* strings (for
>printing) or other way round (for reading) may be provided, like in VCS
>(cf. VCS DirectC.h).
>
>
>"directc.h"
>===========
>
>This file provides implementation specific definitions.
>In particular, it defines the macros for specifying variables representing
>SV packed arrays:
>
>#define BIT_PACKED_ARRAY(WIDTH,NAME) ...
>#define LOGIC_PACKED_ARRAY(WIDTH,NAME) ...
>
>(For example, VCS might defined the later macro as follows:
> #define LOGIC_PACKED_ARRAY(WIDTH,NAME) vec32 NAME [ VEC32_NEEDED(WIDTH) ]
>)
>
>
>Example 1 - binary compatible application
>=========================================
>
>SV:
> typedef struct {int a; int b;} pair;
> extern void foo(input int i1, pair i2, output logic [63:0] o3);
>
>C:
> #include "sverilog.h"
>
> typedef struct {int a; int b;} pair;
> void foo(int i1, pair *i2, svLogicPackedArr o3)
> {
> svLogicVec32 arr[VEC32_NEEDED(64)]; /* 2 chunks needed */
>
> printf("%d\n", i1);
> arr[1].c = i2->a;
> arr[1].d = 0;
> arr[2].c = i2->b;
> arr[2].d = 0;
> vcPutLogicVec32 (o3, arr, 64);
> }
>
>
>Example 2 - source level compatible application
>=========================================
>
>SV:
> typedef struct {int a; bit [6:1][1:8] b [65:2]; int c;} triple;
> // troublesome mix od C types and packed arrays
> extern void foo(input triple i);
>
>C:
> #include "sverilog.h"
> #include "directc.h"
>
> typedef struct {
> int a;
> BIT_PACKED_ARRAY(6*8, b) [64];
> int c;
> } triple;
>
> /* Note that 'b' is defined as for 'bit [6*8-1:0] b [63:0]' */
>
> void foo(triple *i)
> {
> int j;
> svBitVec32 arr[VEC32_NEEDED(6*8)]; /* 6*8 packed bits */
>
> printf("%d %d\n", i->a, i->c);
> for (j=0; j<64; j++) {
> vcGetBitVec32(arr, (svBitPackedArr)&(i->b[j]), 6*8);
> ...
> }
> }
>
>Note that 'a', 'b', 'c' are directly accessed as fields in a structure.
>In the case of 'b', which represents unpacked array of packed arrays,
>individual element is accessed via library function vcGetBitVec32(),
>by passing its address to the function.
>
>---------------------------------------------------------------------------
>
>
>This is all that I managed to describe before midnight PST, Friday.
>
>
>The representation of open/unsized arrays and access to them (via handle,
>abstract access mode) is still missing.
>
>
>I suppose that the functions for accessing arrays may be modelled upon SV
>array
>querying functions: $left, $right, $dimension, etc.
This archive was generated by hypermail 2b28 : Wed Dec 11 2002 - 15:44:29 PST