Subject: RE: DirectC: C Layer - another revision
From: Warmke, Doug (doug_warmke@mentorg.com)
Date: Wed Jan 15 2003 - 10:46:59 PST
Andrzej,
Please search for an embbedded DOUG: deep down.
You will find one simple suggestion for clarification.
After I more carefully read through the examples, I have
some other embedded questions prefixed by DOUG:.
Please check them out below.
***
There is one other thing that may seem obvious to many of us,
but perhaps needs to be added to the LRM text for clarity.
That is, there are actually 3 places at which arguments appear.
(Let's only consider SV-calls-C for simplicity of discussion -
same should apply to the other direction.)
1) The C code
2) The declaration site of the external function
3) The call site(s) of the external function
When you talk about lining up SV l and r bounds with C indexing,
I believe that you are referring to the l and r bounds of the
argument at the declaration site of the external function in SV.
*Not* the l and r bounds of the actual argument at the call site.
Normal SV rules would apply for mapping call site actual arguments
onto the formal arguments at the declaration site. Then, the mapping
you discuss in this document applies for the transformation from
the formal argument at the SV declaration site to the formal
argument on the C side. It's a kind of transitive association.
Please let me know if my understanding is correct, and if it is,
please add such a clarification paragraph somewhere in the intro
sections of your document.
Thanks and regards,
Doug
> -----Original Message-----
> From: Andrzej Litwiniuk [mailto:Andrzej.Litwiniuk@synopsys.com]
> Sent: Tuesday, January 14, 2003 6:11 PM
> To: sv-cc@server.eda.org
> Subject: DirectC: C Layer - another revision
>
>
> Enclosed is another revision of DirectC C Layer.
> It includes the following changes:
> - clarifies the indexing for sized and unsized arrays
> - 'const' qualifier for input arguments, also for interface functions
> - simplified names for open array quering functions
> - covers C-to-SV calls (cf. examples 1 and 2)
> - corrected oversights (mainly "U")
>
>
> Names of include files and functions are still subject to
> modifications.
>
>
> Andrzej
>
> ==============================================================
> ================
> Andrzej I. Litwiniuk, PhD Principal Engineer VCS R&D
> Synopsys, Inc TEL: (508) 263-8056
> 154 Crane Meadow Road, Suite 300, FAX: (508) 263-8069
> Marlboro, MA 01752, USA
> ==============================================================
> ================
>
>
> ------------------------ DirectC C Layer
> --------------------------------------
>
> This document addresses both SV-to-C calls and C-to-SV calls.
>
>
> Overview of C layer
> ===================
>
>
> Representation of the data
> --------------------------
>
> The following is assumed about the representation of SV data:
>
> a) representation of packed types is implementation dependent
>
> b) basic integer and real data types are represented as
> defined in LRM 3.3,
> 3.4.2, see also "Data type mapping" below.
>
> c) layout of unpacked structures is same as used by C
> compiler (LRM 3.7)
>
> d) layout of sized unpacked arrays is same as used by C compiler;
> this includes arrays embedded in structures and the
> standalone arrays
> (i.e. not embedded in any structure)
>
> Note that this is a restriction imposed on the SV side of
> the interface!
> Depending on the implementation, a particular array may or
> may be not
> accepted as an actual argument for the formal argument
> which is a sized
> array (it will be always accepted for unsized array).
>
> A natural order of elements is assumed for each dimension
> in the layout of
> an unpacked array, i.e. elements with lower indices go first.
> In other words, for SV range [l:r], the element with SV
> index min(l,r) will
> have C index 0, and the element with SV index max(l,r)
> will have C index
> abs(l-r).
>
> e) layout of the unsized (aka open) standalone unpacked arrays
> is implementation dependent with the following restriction:
> an element of an array must have the same representation as
> individual a value of the same type, with the exception
> of scalars
> (bit or logic) and packed arrays as a type of an element.
> Hence array's elements other than scalars or packed
> arrays can be
> accessed via pointers similarly to individual values.
>
>
> Note that d) actually does not impose any restrictions on how
> unpacked arrays are implemented; it says only that an array
> that does not satisfy d) may not be passed as an actual
> argument for the formal argument which is a sized array; it
> may be passed, however, for unsized array. Therefore, the
> correctness of an actual argument may be implementation
> dependent. Nevertheless an open array provides implementation
> independent solution. This seems to be a reasonable trade-off.
>
> Data type mapping
> -----------------
>
> The basic SV data types are represented as follows:
>
> char -> char
> shortint -> shortint
> int -> int
> longint -> long long
> byte -> char
> real -> double
> shortreal -> float
> 'opaque pointer'-> void*
> 'string' -> char*
>
> Representation of SV specific data types like packed bit and
> logic vectors is implementation dependent and generally
> transparent to the user. Nevertheless, for the sake of
> performance, applications may be tuned for a
> specific implementation and make use of the actual
> representation used by that
> implementation; such applications will not be binary
> compatible, however.
>
> Access to data
> --------------
>
> 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.
>
> Abstract access is provided only for the unsized (open)
> packed and unpacked arrays. All other objects are directlly
> accessible.
>
> C compatible data types are accessed either directly or
> through pointers.
>
> Packed arrays are accessible via canonical representation;
> interface provides functions for moving data between
> implementation representation and canonical representation,
> any necessary convertion is performed on the fly. There are
> also functions for bit selects and limited (up to 32 bits)
> partial bit selects ("partial bit selects" refer here to
> slices of packed arrays of types 'bit' or 'logic').
>
> Array slices are not supported for unpacked arrays.
>
> For unsized (open) arrays the original SV ranges are used in indexing.
>
> For sized arrays normalized ranges are assumed.
> Normalized ranges mean [n-1:0] indexing for the packed part,
> and [0:n-1] indexing for the unpacked part of an array.
> Therefore a packed array of range [l:r] will be normalized as
> [abs(l-r):0], its most significant bit will have a normalized
> index abs(l-r), and its least significant bit will have a
> normalized index 0.
>
> 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.
DOUG: Here is my suggestion for clarification:
"Note that the above range mapping from SV to C applies
to calls made in both directions, i.e. SV-calls-C and C-calls-SV."
>
>
> 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.
>
> '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.)
>
>
>
> Argument passing
> =================
>
> Actual arguments generally are passed by reference or by
> value and will be directly accessible in C code; open arrays
> are the exception.
>
> Arguments specified as open (unsized) arrays are always
> passed by handle, regardless of direction, and will be
> accessible via library functions
> (abstract acess mode).
>
> The rest of this paragraph refers only to arguments which are
> not open arrays.
>
> 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 should always have 'const' qualifier.
> 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.
>
> There is no difference in argument passing between calls from
> SV to C and calls from C to SV. Note that the functions
> exported from SV may not have open arrays as arguments.
> Otherwise the same types of formal arguments may be declared
> in SV both for
> the exported functions and for the external functions.
> A function exported from SV will have the same function
> header as the external function with the same function result
> type and same formal argument list. In the case of arguments
> passed by reference, an actual argument to SV function called
> from C must be allocated on C side using the same layout of
> data as SV would use for that type of argument.
>
>
>
>
> 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):
> - "svc_bin.h"
> - "svc_src.h"
>
> "svc_bin.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.
>
> "svc_src.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.
>
> "svc_src.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 "svc_src.h" file will be
> only source-level
> compatible, i.e. they will have to be compiled with the
> version of "svc_src.h" provided for a particular implementation of SV.
>
> The applications that use only "svc_bin.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
> "svc_src.h" file, then the binary compatibility is granted.
> Everything that requires "svc_src.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 "svc_bin.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 "svc_src.h" file and therefore will not be binary
> compatible will all simulators. The source level
> compatibility is, however, granted.
>
>
>
> "svc_bin.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 */
>
> /* common type for 'bit' and 'logic' scalars. */
> typedef unsigned char svScalar;
>
> typedef svScalar svBit; /* scalar */
> typedef svScalar 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;} /* as in VCS */
> 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 svPutBitVec32 (svBitPackedArr d, const svBitVec32*
> s, int w);
> void svPutLogicVec32 (svLogicPackedArr d, const svLogicVec32*
> s, int w);
DOUG: I can't understand why the svBitPackedArr and svLogicPackedArr
are not pointer types. Take svBitPackedArr as an example. It is
typedef'd to "int".
These functions are intended to work on only one "chunk"
of the canonical representation at a time. (We should add
a note to that effect in a comment above them). Now, since
the "d" argument of svPutBitVec32 is not a pointer type, how
is the caller of the function supposed to get the result?
The function returns void and the d argument is a C "input"
parameter, passed by value.
There is a little more on this embedded in the code of Example 1.
>
> /* canonical <-- actual */
> void svGetBitVec32 (svBitVec32* d, const svBitPackedArr
> s, int w);
> void svGetLogicVec32 (svLogicVec32* d, const svLogicPackedArr
> s, int w);
DOUG: These appear to be fine, no such doubts as I have with
the "put" functions.
>
> 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.
>
> Although the put/get functionality provided for 'bit' and 'logic'
> packed arrays is sufficient yet basic, it requires
> unnecessary copying of
> the whole packed array when perhaps only some bits are needed.
>
> For the sake of the convenience and improved performance, the
> bit selects and
> limited (up to 32 bits) part-selects are also supported.
>
> Functions for part-select allow to access (read/write) only a
> narrow subranges of up to 32 bits. A canonical representation
> will be used for such narrow vectors.
>
> For the sake of symmetry a single chunk of an array in the canonical
> representation is used both for 'logic' and 'bit'.
> One may argue, however, that in the case of 'bit' such small
> vector is actually a single int, so perhaps a more intuitive
> signature could be used.
>
>
> /* functions for bit-select and limited width part-select */
>
> /* Packed arrays are assumed to be indexed n-1:0,
> where 0 is the index of least significant bit */
>
> /* functions for bit-select */
> /* s=source, d=destination, i=bit-index */
>
> svScalar svGetSelectBit(const svBitPackedArr s, int i);
> svScalar svGetSelectLogic(const svLogicPackedArr s, int i);
>
> void svPutSelectBit(svBitPackedArr d, int i, scalar s);
> void svPutSelectLogic(svLogicPackedArr d, int i, scalar s);
DOUG: Same point on how the user should access the results
of these functions if d is not passed as a pointer type.
>
>
> /*
> * functions for part-select
> *
> * a narrow (<=32 bits) part select is copied between
> * the implementation representation and a single chunk of
> * canonical representation
> *
> * s=source, d=destination, i=starting bit index, w=width
> * like for variable part selects; limitations: w <= 32
> */
>
> Please note that for the sake of symmetry a canonical
> representation (i.e. an array) is used both for 'bit' and
> 'logic', though a simpler int could be used for 'bit' part
> selects <= 32-bit.
>
>
> void svGetPartSelectBit(svBitVec32* d, const svBitPackedArr
> s, int i, int w);
> void svGetPartSelectLogic(svLogicVec32* d, const
> svLogicPackedArr s, int i, int w);
>
> /*
> * for 'bit' type a part select <= 32-bit is really an int
> * so a function could be used:
> * int svGetPartSelectBit(svBitPackedArr s, int i, int w);
> */
>
>
> void svPutPartSelectBit(svBitPackedArr d, const
> svBitPackedArr s, int i, int w); void
> svPutPartSelectLogic(svLogicPackedArr d, const
> svLogicPackedArr s, int i, int w);
DOUG: Same basic issues on visibility of function result.
>
> /*
> * for 'bit' type a part select <= 32-bit is really an int
> * so simpler arg could be used:
> * svPutPartSelectBit(svBitPackedArr d, int up_to_32-bits,
> int i, int w);
> */
>
>
> More functions may be added, for example, for converting
> packed arrays into
> char* strings (for printing) or other way round (for
> reading), like in VCS (cf. VCS DirectC.h).
>
>
> "svc_src.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);
>
> export extern $root.exported_sv_func; // whatever is
> the syntax ...
>
> function void exported_sv_func(input int i, output int o [0:7]);
> begin ... end endfunction
>
> C:
> #include "svc_bin.h"
>
> typedef struct {int a; int b;} pair;
>
> extern void exported_sv_func(int, int *); /* imported from SV */
>
> void foo(const int i1, const pair *i2, svLogicPackedArr o3)
DOUG: The o3 argument is passed by value into C.
Thus how can it be changed by the C code?
It seems like it should be passed by reference, i.e. as a pointer.
> {
> svLogicVec32 arr[VEC32_NEEDED(64)]; /* 2 chunks needed */
> int tab[8];
>
> printf("%d\n", i1);
> arr[1].c = i2->a;
> arr[1].d = 0;
> arr[2].c = i2->b;
> arr[2].d = 0;
> svPutLogicVec32 (o3, arr, 64);
DOUG: Once again, this function's signature has the d argument
passed by value. Even if o3 above is a pointer, how could this
function influence its value?
In order to really make clear the use of indexing from the C side
to SV side, I would suggest complicating the o output type with
a 1-dimensioned packed part and a 1-dimensioned unpacked part.
That would give more clarity to the indexing rules described
in the intro part of the document.
<EOM>
>
> /* call SV */
> exported_sv_func(i1, tab); /* tab passed by reference */
> ...
> }
>
>
> 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);
>
> export extern $root.exported_sv_func; // whatever is
> the syntax ...
>
> function void exported_sv_func(input int i, output
> logic [63:0] o);
> begin ... end endfunction
>
> C:
> #include "svc_bin.h"
> #include "svc_src.h"
>
> typedef struct {
> int a;
> BIT_PACKED_ARRAY(6*8, b) [64]; /*
> implementation specific representation */
> int c;
> } triple;
>
> /* Note that 'b' is defined as for 'bit [6*8-1:0] b [63:0]' */
>
> extern void exported_sv_func(int, svLogicPackedArr); /*
> imported from SV */
>
> void foo(const triple *i)
> {
> int j;
>
> /* canonical representation */
> svBitVec32 arr[VEC32_NEEDED(6*8)]; /* 6*8 packed bits */
> svLogicVec32 aL[VEC32_NEEDED(64)];
>
> /* implementation specific representation */
> LOGIC_PACKED_ARRAY(64, my_tab);
>
> printf("%d %d\n", i->a, i->c);
> for (j=0; j<64; j++) {
> svGetBitVec32(arr, (svBitPackedArr)&(i->b[j]), 6*8);
> ...
> }
> ...
> /* call SV */
> exported_sv_func(2, (svLogicPackedArr)&my_tab); /* by
> reference */
> svGetLogicVec32(aL, (svLogicPackedArr)&my_tab, 64);
> ...
> }
>
> 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 svGetBitVec32(), by passing its address to
> the function.
>
>
>
> Open (Unsized) Arrays and Abstract Access - Overview
> ====================================================
>
> All open arrays, packed (i.e. vectors) and unpacked (i.e.
> arrays per se) will be passed by handle and accessed mainly
> via accessory functions (abstract access).
>
> Abstract access for open arrays will allow inquires about the
> dimensions and the original boundaries of SV actual argument
> and will allow to access the elements of an open array using
> the same range of indices as in SV.
>
> The programmer will always have a choice, whether to specify
> a formal argument as a sized array or as an open (unsized) array.
>
> In the former case all indices will be normalized on the C
> side (i.e. 0 and up) and the programmer is assumed to know
> the size of an array. Programmer is also assumed to be
> capable of figuring out how the ranges of the actual argument
> will map onto C-style ranges.
> Hint: programmers may decide to stick to [n:0]name[0:k] style
> ranges in SV.
>
> In the later case, i.e. open array, the abstract access mode
> will be used,
> what would facilitate SV-style of indexing with the original
> boundaries of
> the actual argument, all this for the price of some overhead.
>
> Note that this provides some degree of flexibility and allows
> programmer to control the trade-off of performance vs.
> convenience. If a formal argument is specified as a sized
> array, then it will be passed
> by reference, with no overhead, and will be directly
> accessible as a normalized array.
> If a formal argument is specified as a open (unsized) array,
> then it will be
> passed by handle, with some overhead, and will be accessible
> mostly indirectly, again with some overhead, although with
> the original boundaries.
>
> The following example shows the use of sized vs. unsized
> ararys in SV code:
>
> // both unpacked arrays are 64 by 8 elements, packed
> 16-bit each
> logic [15: 0] a_64x8 [63:0][7:0];
> logic [31:16] b_64x8 [64:1][-1:-8];
>
> extern void foo(input logic [] i [][]);
> // 2-dimensional unsized unpacked array of
> unsized packed logic
>
> extern void boo(input logic [31:16] i [64:1][-1:-8]);
> // 2-dimensional sized unpacked array of
> sized packed logic
>
> foo(a_64x8);
> foo(b_64x8); // C code may use original ranges
> [31:16][64:1][-1:-8]
>
> boo(b_64x8); // C code must use normalized ranges
> [15:0][0:63][0:7]
>
>
> Unsized formal arguments
> ========================
>
> For input, output and inout arguments that are declared as
> open array, the corresponding formal argument in C will be of
> type svHandle.
>
> Type svHandle denotes an opaque pointer to a descriptor
> generated by SV compiler for an actual argument. Descriptor
> will provide comprehensive information about an actual
> argument. The internal structure of a descriptor is
> implementation dependent and fully irrelevant to the user.
>
> Limitations
> ===========
>
> The unpacked part of an open array may be multidimensional.
> The packed part, however, is restricted to a single dimension.
>
> Note that any packed data type in SV is eventually equivalent
> to a one-dimensional packed array. Hence the above limitation
> is practically not restrictive.
>
> Open array querying functions
> =============================
>
> These functions are modelled upon SV array querying
> functions, with the same semantics (cf. LRM 16.3).
>
> If the dimension is 0, then the query refers to the packed
> part (which has been
> already assumed to be 1-dimensional) of an array, and
> dimensions > 0 refer to
> the unpacked part of an array.
>
> /* h= handle to open array, d=dimension */
> int svLeft(const svHandle h, int d);
> int svRight(const svHandle h, int d);
> int svLow(const svHandle h, int d);
> int svHigh(const svHandle h, int d);
> int svIncrement(const svHandle h, int d);
> int svLength(const svHandle h, int d);
> int svDimensions(const svHandle h);
>
>
>
> Open array access functions
> =============================
>
> Similarly to sized arrays, there are functions for copying
> data between the simulator representation and the canonical
> representation.
>
> It will be also possible to get the actual address of SV data
> object or of an individual element of an unpacked array. This
> may be useful for the simulator-specific tuning of the application.
>
> Depending on the type of an element of an unpacked array,
> different access methods are used:
> - packed arrays ('bit' or 'logic') are accessed via copying
> to or from
> the canonical representation
> - scalars (1-bit value of type 'bit' or 'logic') are accessed directly
> - other types of values (e.g. structures) are accessed via
> generic pointers;
> a library function calculates an address and the user should provide
> the appropriate casting
> - all types but scalars may be accessed via pointers, as
> described above
>
> SV allows arbitrary dimensions and hence an arbitrary number
> of indices. To facilitate this, a variable argument list
> functions will be used. For the sake of performance the
> specialized versions of all indexing functions
> are provided for 1, 2 and 3 indices.
>
>
> Access via canonical representation
> -----------------------------------
>
> This group of functions is meant for accessing elements which
> are packed arrays ('bit' or 'logic').
>
> The following functions will copy a single vector from a canonical
> representation to an element of an open array or other way round.
>
> Element of an array is identified by indices bound by the
> ranges of the actual argument. In other words, original SV
> values are used for indexing.
>
>
> /* functions for translation between simulator's and canonical
> representations */
>
> /* s=source, d=destination */
>
> /* actual <-- canonical */
> void svPutBitArrElemVec32 (const svHandle d, const
> svBitVec32* s, int indx1, ...); void
> svPutBitArrElem1Vec32(const svHandle d, const svBitVec32* s,
> int indx1); void svPutBitArrElem2Vec32(const svHandle d,
> const svBitVec32* s, int indx1, int indx2); void
> svPutBitArrElem3Vec32(const svHandle d, const svBitVec32* s,
> int indx1, int
> indx2, int indx3);
>
> void svPutLogicArrElemVec32 (const svHandle d, const
> svLogicVec32* s, int indx1, ...); void
> svPutLogicArrElem1Vec32(const svHandle d, const svLogicVec32*
> s, int indx1); void svPutLogicArrElem2Vec32(const svHandle d,
> const svLogicVec32* s, int indx1, int indx2); void
> svPutLogicArrElem3Vec32(const svHandle d, const svLogicVec32* s,
> int indx1,
> int indx2, int indx3);
>
> /* canonical <-- actual */
> void svGetBitArrElemVec32 (svBitVec32* d, const svHandle s,
> int indx1, ...); void svGetBitArrElem1Vec32(svBitVec32* d,
> const svHandle s, int indx1); void
> svGetBitArrElem2Vec32(svBitVec32* d, const svHandle s, int
> indx1, int indx2); void svGetBitArrElem3Vec32(svBitVec32* d,
> const svHandle s,
> int indx1, int
> indx2, int indx3);
>
> void svGetLogicArrElemVec32 (svLogicVec32* d, const svHandle
> s, int indx1, ...); void
> svGetLogicArrElem1Vec32(svLogicVec32* d, const svHandle s,
> int indx1); void svGetLogicArrElem2Vec32(svLogicVec32* d,
> const svHandle s, int indx1, int indx2); void
> svGetLogicArrElem3Vec32(svLogicVec32* d, const svHandle s,
> int indx1,
> int indx2, int indx3);
>
> The above functions copy the whole packed array in either direction.
> User is responsible for providing the correct width and for
> allocating an array
> in the canonical representation.
>
>
> Access to scalars ('bit' and 'logic')
> -------------------------------------
>
> Another group of functions is needed for scalars (i.e. when
> an element of an array is a simple scalar, 'bit' or 'logic':
>
> svBit svGetBitArrElem (const svHandle s, int indx1, ...);
> svBit svGetBitArrElem1(const svHandle s, int indx1);
> svBit svGetBitArrElem2(const svHandle s, int indx1, int indx2);
> svBit svGetBitArrElem3(const svHandle s, int indx1, int
> indx2, int indx3);
>
> svLogic svGetLogicArrElem (const svHandle s, int indx1, ...);
> svLogic svGetLogicArrElem1(const svHandle s, int indx1);
> svLogic svGetLogicArrElem2(const svHandle s, int indx1, int
> indx2); svLogic svGetLogicArrElem3(const svHandle s, int
> indx1, int indx2, int indx3);
>
> void svPutLogicArrElem (const svHandle d, svBit value, int
> indx1, ...); void svPutLogicArrElem1(const svHandle d, svBit
> value, int indx1); void svPutLogicArrElem2(const svHandle d,
> svBit value, int indx1, int indx2); void
> svPutLogicArrElem3(const svHandle d, svBit value, int indx1,
> int indx2, int indx3);
>
> void svPutBitArrElem (const svHandle d, svLogic value, int
> indx1, ...); void svPutBitArrElem1(const svHandle d, svLogic
> value, int indx1); void svPutBitArrElem2(const svHandle d,
> svLogic value, int indx1, int indx2); void
> svPutBitArrElem3(const svHandle d, svLogic value, int indx1,
> int indx2, int indx3);
>
>
> Access to the actual representation
> -----------------------------------
>
> The following functions provide an actual address of the
> whole array or of its individual element. These functions
> will be used for accessing elements of the arrays of types
> compatible with C.
>
> These functions will be also usefull for the vendors, because
> they provide access to the actual representation for all
> types of arrays.
>
> If the actual layout of the SV array passed as an argument
> for an open unpacked array is different than C layout, then
> it will not be posssible to access such
> array as a whole and therefore the address and size of such
> array will be undefined (zero, to be exact).
> Nonetheless the adresses of individual elements of an array
> will be always
> supported.
>
> Note that no specific representation of an array is assumed
> here, hence all functions use a generic pointer void *.
>
>
> /* a pointer to the actual representation of the whole array
> of any type */
> /* NULL if not in C layout */
> void *svGetArrayPtr(const svHandle);
>
> int svSizeOfArray(const svHandle); /* total size in bytes or
> 0 if not in C layout */
>
> /* Return a pointer to an element of the array
> or NULL if index outside the range or null pointer */
>
> void *svGetArrElemPtr(const svHandle, int indx1, ...);
>
> /* specialized versions for 1-, 2- and 3-dimensional
> arrays: */ void *svGetArrElemPtr1(const svHandle, int indx1);
> void *svGetArrElemPtr2(const svHandle, int indx1, int indx2);
> void *svGetArrElemPtr3(const svHandle, int indx1, int indx2,
> int indx3);
>
>
> Access to array elements of other types
> ---------------------------------------
>
> If array's elements are of a type compatible with C, then
> there is no need to use the canonical representation. In such
> situations the elements will be accessed via pointers, i.e.
> the actual address of an element will be computed first and
> then used to access the desired element.
>
>
> Example 3 - open array
> ======================
>
> SV:
> typedef struct {int i; ... } MyType;
>
> extern void foo(input MyType i [][]);
> // 2-dimensional unsized unpacked array
> of MyType
>
> MyType a_10x5 [11:20][6:2];
> MyType a_64x8 [64:1][-1:-8];
>
> foo(a_10x5);
> foo(a_64x8);
>
>
> C:
> #include "svc_bin.h"
>
> typedef struct {int i; ... } MyType;
>
> void foo(const svHandle h)
> {
> MyType my_value;
> int i, j;
> int lo1 = svUnpackedLow(h, 1);
> int hi1 = svUnpackedHigh(h, 1);
> int lo2 = svUnpackedLow(h, 2);
> int hi2 = svUnpackedHigh(h, 2);
>
> for (i = lo1; i <= hi1; i++) {
> for (j = lo2; j <= hi2; j++) {
>
> my_value = *(MyType *)svGetArrElemPtr2(h, i, j);
> ...
> *(MyType *)svGetArrElemPtr2(h, i, j) = my_value;
> ...
> }
> ...
> }
> }
>
>
>
> Example 4 - open array
> ======================
>
> SV:
> typedef struct { ... } MyType;
>
> extern void foo(input MyType i [], output MyType o []);
>
> MyType source [11:20];
> MyType target [11:20];
>
> foo(source, target);
>
>
> C:
> #include "svc_bin.h"
>
> typedef struct ... } MyType;
>
> void foo(const svHandle hin, svHandle hout)
> {
> int count = svUnpackedLength(hin, 1);
> MyType *s = (MyType *)svGetArrayPtr(hin);
> MyType *d = (MyType *)svGetArrayPtr(hout);
>
> if (s && d) { /* both arrays have C layout */
>
> /* an efficient solution using poiter arithmetics */
> while (count--)
> *d++ = *s++;
>
> /* even more efficient:
> memcpy(d, s, svSizeOfArray(hin));
> */
>
> } else { /* less efficient yet implementation independent */
>
> int i = svUnpackedLow(hin, 1);
> int j = svUnpackedLow(hout, 1);
> while (i <= svUnpackedHigh(hin, 1)) {
> *(MyType *)svGetArrElemPtr1(hout, j++) =
> *(MyType *)svGetArrElemPtr1(hin, i++);
> }
>
> }
>
> }
>
>
> Example 5 - access to packed arrays
> ===================================
>
> SV:
> extern void foo(input logic [127:0]);
> extern void boo(input logic [127:0] i []); // open
> array of 128-bit
>
>
> C:
> #include "svc_bin.h"
>
> /* one 128-bit packed vector */
> void foo(const svLogicPackedArr packed_vec_128_bit)
> {
> svLogicVec32 arr[VEC32_NEEDED(128)]; /* canonical
> representation */
>
> svGetLogicVec32(arr, packed_vec_128_bit, 128);
> ...
> }
>
>
> /* open array of 128-bit packed vectors */
> void boo(const svHandle h)
> {
> int i;
> svLogicVec32 arr[VEC32_NEEDED(128)]; /* canonical
> representation */
>
> for (i = svLow(h, 1); i <= svHigh(h, 1); i++) {
>
> svLogicPackedArr ptr =
> (svLogicPackedArr)svGetArrElemPtr1(h, i);
> /* user need not know the vendor representation! */
>
> svGetLogicVec32(arr, ptr, 128);
> ...
> }
> ...
> }
>
> ------------------------ End Of C Layer
> --------------------------------------
>
This archive was generated by hypermail 2b28 : Wed Jan 15 2003 - 10:48:15 PST