Re: Extended (dynamic) linking


Subject: Re: Extended (dynamic) linking
From: Kevin Cameron (Kevin.Cameron@nsc.com)
Date: Mon Dec 02 2002 - 10:26:35 PST


"Stickley, John" wrote:

> Kevin,
>
> I would like to address a number of issues that you've raised and then
> show how, aside from dynamic binding, those issues might already be
> handled with my proposal.
>
> Comments embedded.

Likewise (in red if you're viewing HTML).

>
> Kevin Cameron x3251 wrote:
>
>> [http://www.eda.org/sv-cc/hm/att-0380/]
>>
>> The basic (C) linking functionality of my proposal is the same as John's except that
>> I don't have an optional context on calls from C to SV (it's always the pli handle of
>> the instance - which may be $root). The use of '*' in extern argument lists does not
>> imply that SV supports pointers in general, only that it understands what a C call's
>> interface is (it would be nice to use the same definitions as C so that there is no
>> need to copy and edit), once the EC agrees on how to do references we can finalize
>> that syntax (noting references are part of the testbench donation, but the syntax is
>> inconsistent).
>
> johnS:
> So the point you're making is that we don't need optional context on C-to-SV calls.
>
> I think I also agree that this is not necessary (see my e-mail earlier this
> week to Andrezj). A call from C-to-SV always requires some context.
> Most of the time it will be instance specific PLI handles. "Free functions"
> are equivalent to calling and SV function in root context which will have its
> own PLI handle.
>
> Kevin Cameron x3251 wrote:
>
>> The "extended" linking behavior allows linking of foreign languages that do not
>> have standard C entry points e.g. C++ which mangles names so that routines have
>> a unique entry-point for each (overloaded) argument set. Since the name mangling
>> in C++ is different for different compilers it is difficult to predicate what the "C"
>> name should be for binding at link time.
>
> johnS:
> I thought some more about this. The good news is that I think you can
> still have C++ linkeage and support argument overloading even with
> a static linking approach.
>
> The SV compiler will need to generate some C code wrapper that actually
> makes the C call (in SV-to-C direction). Either scheme requires that.
> So suppose the user's C++ compiler, say g++ is used to compile that SV
> compiler generated code wrapper. In making the call to the C function the
> code wrapper will generate a reference to the appropriately mangled symbol
> since g++ automatically makes this happen based on the call site.

I think I suggested that way back - http://www.eda.org/vlog-pp/sv-cc/hm/0005.html .
However, it has a couple of problems:

a) You need different compiles for each C++ compiler.

b) Anything bound at link-time cannot be instance specific.

> Therefore linkage would occur correctly and naturally using whatever
> name mangling scheme that compiler happens to use.
>
> By doing this, C++ linkage could be automatically supported. So we can
> then allow C functions called from SV to actually have private access to
> user defined C++ model classes (what you called "shadow_class" in
> your example) by using friend functions.

> I've revised your example so show how this can be done.
>
> C Code:
>
> class shadow_class {
> private:
> void method( int data );
>
> friend void friend_cpp_method( int data );
> };
>
> void friend_cpp_method( int data ){
> shadow_class *me = (shadow_class *)tf_igetworkarea( tf_getinstance() );
> me->method(data);
> }
>
> I will argue that, if implemented properly, this is just as efficient as the dynamic
> variant that you show here:
>
> Kevin Cameron x3251 wrote:
>
>> The dynamically bound routine can skip the context test (which is handled during
>> binding) and can find a per-instance version of cpp_method so the code is like:
>>
>> void cpp_method_2(handle ip,svcContext *p_context,int data)
>> {
>> shadow_class_2 *cp = (shadow_class_2 *)p_context.user_context.ptr;
>> cp->method(data); // call method (direct)
>> }
>>
>> Since the class shadow_class_2 is specific to the instance "method" does not
>> have to be virtual.
>
> johnS:
> Here's the associated SV code that shows a declaration that supports C++ linkage:
>
> SV Code:
>
> extern void cpp_method( input integer data ) “friend_cpp_method”;
>
> The SV compiler generates a wrapper with a direct call to
> friend_cpp_method() with an appropriate argument profile that is declared
> as follows (translated using implied type mapping from SV extern declaration):
>
> extern void friend_cpp_method( int data );
>
> The wrapper then makes the call to this function passing the appropriate
> argument data.
>
> The user's C++ compiler that compiles the wrapper will
> naturally perform appropriate mangling, arg overloading, and external
> symbol referencing.
>
> Furthermore it will automatically type check the arguments since, if there is no
> match, an unresolved symbol will occur at link time.
>
> Kevin Cameron x3251 wrote:
>
>> The sequence for dynamic linking (with VCS) is something like:
>
>>
>> Compile Verilog:
>>
>> Compiler will note external calls.
>>
>> Link code:
>>
>> Use a C++ linker if foreign code is C++ (SystemC)
>>
>> Run simulation:
>>
>> C++ static constructors get called for permanent data (see test below),
>> register binders.
>>
>> Simulator main() gets called.
>>
>> Elaborate design. Call "binder" function for foreign routines as encountered
>> (per instance) or post elaboration.
>>
>> Start simulation.
>>
>> The "binder" functions may be C++ functions (name mangled) since they are
>> passed through the C registration interface as pointers. When the binder functions
>> are called they can use the call arguments to ensure an exact match between
>> SV and C and to select between multiple (overloaded) versions of calls.
>
> johnS:
> So this really gets down to the one big difference in our proposals:
>
> Is dynamic binding needed ?
>
> First of all, I would like to say that if it is needed, that we add it
> as a capability on top of static binding as I've proposed, which is
> what I think you've already stated.
>
> Secondly, if the answer is yes, then we must conceed that this requires
> a brand new API call where one never existed before. So far, with
> everything I've proposed including the latest stuff shown above, still no
> new API call is required.
>
> Thirdly, I would like to suggest the the dynamic "binder" function,
> if we agree it is necessary, is something more minimalist like this:
>
> void SvccBindSVtoCFunc( "MySvModule::cpp_method", friend_cpp_method );
>
> Conceptually this allows the C side to perform the aliasing instead of the "cname"
> part of the extern declaration on the SV side.

Stand-alone that doesn't allow argument checking (or binding overloaded functions), and
it's not per-instance either. How would the aliasing work?

> It really needs no more than this. I think you can still do context pointer
> handling the same way that I do it in the static binding proposal (i.e.
> using tf_getinstance(), etc.).
>
> So really all we're doing is specifying a pointer in place of a dynamic
> symbol reference.
>
> One thing that gets tricky however, is how does the SV compiler know
> to generate a dynamic call or a static call in its wrapper ? Do we need another
> extern attribute called dynamic ?

My proposal uses "static" (in the C sense: there is no global symbol) to imply
binding is dynamic (but that was just to avoid adding a new keyword).

> Actually now that I think about it, perhaps it is as simple as this:
>
> We say if "cname" exists, static binding is implied.
> If it does not exist, dynamic binding is implied.
>
> Does this work ?
>
> Admittedly, dynamic binding probably has some merits. But, as I said,
> we would have to conceed to creating an API where one did not
> otherwise exist.
>
> Also, one thing you state here:
>
> Kevin Cameron x3251 wrote:
>
>> So the benefits of the dynamic binding mechanism are a) handles non-C
>> foreign languages, b) arguments can be checked for compatibilty, c) more
>> efficient run-time calling with instance specific functions, d) doesn't add
>> exported names to C name space (less chance of a name clash).
>
> johnS:
> It's not quite clear to me how b) works. It seems to me
> that in the description I gave above using static binding,
> you can rely on the C compiler to automatically check
> arguments. But how do you do that in b) ?

Checking arguments is left up to the user in the dynamic binding scheme, but
it is supported in that the information is passed to the binding routines. If you
know which C++ compiler the code was built with (which presumably built
the binder routine too) you can generate the mangled C++ name from the
arguments and use (e.g.) the SYSV dl* routines to locate the appropriate code.

> johnS:
> Finally one other point I would like to note is that I replaced your
> svcContext struct with just a plain opaque void context pointer that is fully
> user interpreted. I this it is better not add all the info you show in a special
> C struct. Since most of the time this info is not needed and when it is, it can be
> retreived through the VPI. This makes the interface easier to understand
> and explain (in under 5 minutes ;-).
> -- johnS
>
The svcContext struct was originally the equivalent of an opaque pointer, however
after your own comments and other peoples' I revised it to be a more complex
structure - it allows more efficient access to call specific data than tf_igetworkarea().
The "user_context.ptr" field is an opaque pointer.

Note: the structure can be cut back to the "capabilties" field as a minimum and then
extra fields can be enabled at compile time or by attributes if required (I may make
that change to my proposal).

Can you explain VPI in 5 minutes? :-) (I've not used it)

Kev

--
National Semiconductor, Tel: (408) 721 3251
2900 Semiconductor Drive, Mail Stop D3-500, Santa Clara, CA 95052-8090



This archive was generated by hypermail 2b28 : Mon Dec 02 2002 - 10:26:55 PST