Subject: Re: DirectC: C layer
From: Stickley, John (john_stickley@mentorg.com)
Date: Fri Dec 13 2002 - 17:11:55 PST
Kevin and Francoise,
Kevin Cameron wrote:
>
>
>> 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.
>>
> I agree. There's a proposal for copy-in and copy-out (pass-by-value)
> returns for SV types in
> my document. Copy-out is limited to return values because that's the
> only pass-by-value output
> of a C call.
>
johnS:
So I'm afraid I have to disagree with both of you here.
Please read over my previous e-mails see if you can appreciate
why it is really important to support a pass-by-reference
mode for performance reasons. Particularly for frequently
passing aggregate data objects back and forth between
the language domains.
If it is felt by the committee that both copy-by-value
and copy-by-reference are important we may want to consider
enhanced syntax as was suggested by Kevin earlier.
His idea was to designate a '&' symbol prefix to an arg name
to let the user decide for themselves whether call-by-value
or call-by-reference should be used. But I would contend
that if this is to be adopted it should be applied at
the basic language level not only at the SV-to-C-to-SV level.
In fact, as shown in my proposal the function declaration
that gets placed in the "extern" decl should be a legal
named_function_proto as currently defined in the 3.1 spec.
Not a new duplicate function syntax of our own making.
If we think adding '&' or '*' to the SV prototype is a good
idea, the benefit should exist for SV-to-SV calls and
SV-to-C-to-SV calls alike.
Bear in mind that in Kevin's proposal there's really no
way of doing this in the C-to-SV direction anyway since
the export decl simply references an existing function definition.
However if that function definition had enhanced syntax
as did the named_function_proto then you would have complete
symetry in the feature. But I think this should be taken
up with the SV-basic committee not here.
And I'm still not convinced that this is worth doing.
In the meantime, I urge us go for something something
that's not going to inherently kill performance with
excessive memory-to-memory copies everytime functions
are called.
-- johnS
> BTW, if it is possible to call back into SV from C a lot of the extra
> functionality can be written in SV
> rather than doing it in C anyway, e.g.:
>
> SV:
> module foo (input index);
> integer index;
> struct bar {
> logic l;
> bit b;
> } arr[99:0]; /* big array of mixed type */
>
> task update(int i,bar data)
> begin
> arr[i] = data;
> end
> endtask
>
> export update;
>
> function fetch(int i);
> fetch = arr[i];
> endfunction
>
> export fetch;
>
> extern context void eval();
>
> always @ (clock) eval(index);
>
> C:
> typedef struct { /* canonical C version of SV struct */
> svcInteger l;
> unsigned int b;
> }bar;
>
> typedef struct { /* use context to save exported
> task/func */
> void (*update)(bar);
> bar (*fetch)(int);
> }my_cntxt; /* bound at link time (not shown) */
>
> void eval(handle ip,svcContext *pc,svcInteger index) {
> my_cntxt *mc = (my_cntxt *)pc->user_context.ptr;
> bar data = (*mc->fetch)(ip,index.value); /* get entry */
> .... /* do something with data */
> (*mc->update)(ip,data); /* write it back */
> }
>
> - no references/pointers need to be used for C to update the SV object,
> all
> array access is done in SV. No PLI/VPI required other than the instance
> handle.
>
> Regards,
> Kev.
>
>
>>
>>
>> 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_00
>>> #define sv_11
>>> #define sv_z2/* representation of 4-st scalar z */
>>> #define sv_x3/* 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.
>>>
> --
> National Semiconductor, Tel: (408) 721 3251
> 2900 Semiconductor Drive, Mail Stop D3-500, Santa Clara, CA 95052-8090
>
>
--This email may contain material that is confidential, privileged and/or attorney work product for the sole use of the intended recipient. Any review, reliance or distribution by others or forwarding without express permission is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies. __ ______ | \ ______________________/ \__ / \ \ H Dome ___/ | John Stickley E | a __ ___/ / \____ Principal Engineer l | l | \ / Verification Solutions Group | f | \/ ____ Mentor Graphics Corp. - MED C \ -- / / 17 E. Cedar Place a \ __/ / / Ramsey, NJ 07446 p | / ___/ | / / mailto:John_Stickley@mentor.com \ / Phone: (201)818-2585 \ / ---------
This archive was generated by hypermail 2b28 : Fri Dec 13 2002 - 17:15:20 PST