$sv-ec Re: PROPOSAL: Re: ISSUE:DirectC:DirectC i/f should supportmechanism for calling Verilog task/function from a DirectC


Subject: $sv-ec Re: PROPOSAL: Re: ISSUE:DirectC:DirectC i/f should supportmechanism for calling Verilog task/function from a DirectC
From: Kevin Cameron (Kevin.Cameron@nsc.com)
Date: Fri Oct 25 2002 - 10:31:30 PDT


"Stickley, John" wrote:

> Fellow SV-CC'ers,
>
> ...
>
> Kevin suggests something similar ...
>
> Kevin Cameron x3251 wrote:
>
>> I would suggest considering module instances as being like class
>> instances in C++. You could get the handle to a module instance
>> using the standard PLI mechanisms and then use it in C++ as a
>> class instance pointer with the tasks and functions of the module
>> as virtual functions.
>>
>> Doing this stuff in C rather than C++ is awkward because C doesn't
>> support overloading of names, so you would have to come up with
>> some name mangling scheme.
>
> Our proposal accomplishes the same thing but uses user defined
> context pointers rather than handles denoting HDL module
> instances - at least for the HDL-to-C function call direction.
> (I'll show later that for C-to-HDL, Kevin's approach is right
> on the mark.).

Thanks :-)

>
> .....
>
> C-to-HDL Function Calls: Context Pointers for Instance Specific HDL Callee Bindings
>
> In the case where the user cares about which specific instances of HDL callee
> functions are being called (which is probably most of the time), for those instances
> the user will want to pass to the C proxy function, a context pointer that refers to a
> specific HDL module instance that contains the HDL callee function.
> [Note: This is exactly what Kevin C. suggested in the previous quoted text above.]
>
> In this case a handle representing the HDL callee instance would be passed into
> the proxy function call as the void *context argument whenever the call from a
> C model is made.
>
> In order to support instance specific HDL callee function calls, the following
> API function is added to the DirectC API interface to obtain an HDL callee
> instance handle:
>
> void *
> BindHDLCallee(
> const char *callerInstanceName,
> const char *functionName );
>
> The handle returned can then be passed by the C caller code to future calls of the
> C proxy function.
>
> So, getting back to our ATM cell example described above,
> the following code is an example of how we might generate
> the context handle representing a specific instance of a
> function call in a particular module instance:
>
> void *getAtmCellContext = BindHDLCallee( "top.u1", "getAtmCell" );
> void *putAtmCellContext = BindHDLCallee( "top.u2", "putAtmCell" );
>
> These getAtmCellContext and putAtmCellContext pointers are then
> the pointers that the user must pass into the calls to the HDL functions shown
> previously. The runtime system interprets the context pointer and routes the
> function call to the appropriate HDL code.
>
> -- johnS

I prefer to go with the C++ virtual function approach because it would be possible
to swap C++ and SV implementations - particularly if they are in DLLs - and also
mix C++ and SV instances. In your example you have four "EthPortWrapper"
cells, it may be handy to be able to do one in SV and the others in C++, but
have the C++ callers of get/putAtmCell unaware of the difference.

BTW this touches on a topic I brought up at the last EC meeting on inheritance
"would you want to inherit a module from a class?". I think the answer is "yes"
because you can then match up the virtual functions reliably, e.g.:

  class atmFunc {
    virtual void getAtmCell(cell&) = 0;
    virtual void putAtmCell(cell&) = 0;
  }
  ....
  module atmCell : atmFunc (...);
    task getAtmCell(input cr) // implements atmFunc::getAtmCell
        cell cr;
    endmodule
    task putAtmCell(output co)
        cell co;
    endmodule
    ...
  endmodule
  ....
  class atmCell : public atmFunc {
     virtual void getAtmCell(cell&) {
     ...}
     virtual void putAtmCell(cell&) {
     ....};
  }

Neither the versions of atmCell need to implement all the functions in
atmFunc, unimplemented functions are inherited.
The calling C++ would be something like:

  atmFunc *ap[4];
  ap[0]= LocateAtm("top.u1"); // User Func (SV/PLI or C++)
  ap[1]= LocateAtm("top.u2");
  ap[2]= LocateAtm("top.u3");
  ap[3]= LocateAtm("top.u4");
  ...
  ap[0]->putAtmCell(cll_out);
  ap[1]->getAtmCell(cll_in);
  atmCompare(cll_out,cll_in);

If you don't use the virtual function approach you can't mix SV and C
module implementations because the there would be a name clash when
linking (it would have to be all SV instances or all C++).

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 : Fri Oct 25 2002 - 10:34:49 PDT