Subject: Re: Modified Proposal for Context Sensitive Function Calls
From: Stickley, John (john_stickley@mentorg.com)
Date: Tue Nov 19 2002 - 14:58:16 PST
Kevin,
This is very similar to my proposal for C-to-SV as of the version I
sent
out today except for 2 key differences:
1. Your proposal requires new, currently non-existent API calls,
while mine uses existing VPI or PLI calls.
2. Your proposal uses dynamic binding to retreive an exported function
pointer whereas mine uses static "matched name" bindings.
Regarding item #1, at Joao's urging, if it is at all possible, we should
avoid inventing new API calls if we can reuse existing ones. By doing
so we keep the new DirectC standard as strictly SV syntax extensions
and no new API calls. Probably a worthy goal.
However, regarding item #2, after reading your proposal, it occurs
to me that there's a potential problem with using non-scoped static
"matched name" bindings as per my proposal, and that is that you
cannot simply reference a scoped SV task or function from C by
simple name match. The reason is that the same task name can
be used in multiple module scopes.
Your approach solves this problem, however I think a more elegant
way to solve it is, rather than to use dynamic binding as you suggest,
to have a globally scoped "C name" indication as part of the the
export declaration. This would be more consistent with the global
scoping used counterpart extern declarations for the SV-to-C
direction as was outlined by Andrezj today.
Here's a suggested modification of my proposal to handle this.
Basically I've added an "as clause" to the basic export declaration
to declare globally scoped C alias to a locally scoped Verilog task:
export_decl ::=
export access_mode ? attribute (, attribute) * ?
function | task [modulename::]fname as cname;
access_mode ::= ( "A" | "C" )
attribute ::= pure | context
Example SV code:
// Declare a C callable, context specific, SV task
export "C" context task MySvModule::MySvTask as MySvModule_MySvTask;
module MySvModule( ... );
...
task MySvTask;
input int portID;
output int mappedID;
mappedID = map(portID);
endtask
...
endmodule
Note that the MySvModule:: prefix is not necessary if the export
declaration
is located in module scope. It is only necessary only at $root scope. In
either
case, the declared C name identifier, MySvModule_MySvTask is always
global scope regardless of where the declaration is, as is the case with
C names in counterpart extern declarations used for the SV-to-C
direction.
Note also that we can still use tf_*() or VPI calls to establish context
as I
originally proposed:
Example C code:
// During initialization, establish a context handle
// to the SV callee instance:
void MyCModel::Init( ){
svContext = tf_mipname( "top.u1" );
}
// Now at run-time call the exported SV function from C passing the
context
// handle as the first argument:
void MyCModel::RunTest( int portID ){
MySvModule_MySvTask( svContext, portID, &mappedID );
. . .
}
The beauty of this is that we've continued to keep new API calls
out of the specification yet we've solved the C-to-SV scoping issue
and can still use static name match style binding, thus avoiding the
use of function pointers and dynamic binding.
-- johnS
Kevin Cameron x3251 wrote:
I just resent a couple of emails that I'd forgotten to send
to the reflector, the first one ( http://www.eda.org/sv-cc/hm/0332.html
<http://www.eda.org/sv-cc/hm/0332.html> )
has an alternative method for binding/calling an SV task/function
which should be more efficient since it avoids having to decoded
the task/context on every call - i.e. a task may have a per-instance
implementation so the call -
<task name>(<sv context>,...)
- from C to SV requires a lookup on the context to obtain an entry-point
to the actual code. Decoding the actual entry-point at setup time avoids
the lookup overhead on later calls, and avoids the exported
task/function
having to appear in the C routine name space (for linking).
The converse mechanism could be used to link module (class) specific
routines to module instances, i.e. if a module declares an XF (rather
than in $root) it would be bound to a C/C++ function pointer at
elaboration
by calling a user-supplied (PLI) routine e.g.:
pointer ($)svcGetXF(<module name>,<module instance name>,<function
name>,
{,<argument type>});
The XF would then be called as:
(*xf_pointer)(<instance pli handle>,<context pointer>,...);
Note: since multiple C/C++ libraries may be involved from different
sources
it would probably be better to allow multiple "svcGetXF" functions by
providing a registration mechanism in SV, e.g.:
bool svcXFlocater(<function name>,
<locater context>,
<module name regexp>); // returns false if
registration fails
Which would lead to code like the following to bind a class method:
static pointer myBinder(void *,char *,char *,char *,void **,...);
class foo {
bind(char *,char *,char *);
my_class() { svcXFlocater(myBinder,
this,"foo"); // XF locater for module
"foo"
... }
}
static pointer myBinder(void *context,char *modname,char
*inst_name,char *rtn_name,
void **p_context,...)
{
pointer rtn_addr = ((foo
*)context)->bind(modname,inst_name,rtn_name);
if (rtn_addr) *p_context = this; // set context for future calls.
return rtn_addr;
}
The module name (regexp) with the svcXFlocater call is necessary to
limit the scope
of the binding (and speed it up).
The locater function could create all the class/context data on the fly
so
that it is only created if the calling module is instanced (maybe
indicated
by a null locater context).
Kev.
--__
______ | \
______________________/ \__ / \
\ 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 <mailto:John_Stickley@mentor.com> \ /
Phone: (201)818-2585 \ /
---------
This archive was generated by hypermail 2b28 : Tue Nov 19 2002 - 15:02:29 PST