But what about from within the language itself? Using DPI it is possible to call functions with C linkage directly from your SystemVerilog source code. The VPI is simply a C API, so it should be possible to call these functions.
It turns out that only a subset are callable, because DPI supports only a limited set of datatypes.
// file: sv_introspect.sv
module top();
reg a;
reg b;
endmodule
program main();
`include "vpi_user.svh"
initial
begin
vpiHandle module_iter;
vpiHandle module_obj;
// iterate all the module
module_iter = vpi_iterate( vpiModule, null );
// look for the module named "top"
while (module_iter)
begin
module_obj = vpi_scan( module_iter );
if (module_obj)
begin
string module_name;
module_name = vpi_get_str( vpiName, module_obj );
$display( "module name, expect 'top': ", module_name );
if (module_name == "top")
begin
vpi_free_object(module_iter);
module_iter = null;
end
end
else
begin
module_iter = null;
end
end
if (module_obj)
begin
vpiHandle reg_iter;
vpiHandle reg_obj;
string reg_name;
// in the "top" module there are two registers.
// The first is named "a"
reg_iter = vpi_iterate( vpiReg, module_obj );
reg_obj = vpi_scan( reg_iter );
reg_name = vpi_get_str( vpiName, reg_obj );
$display( "reg name: expect 'a': ", reg_name );
// The second is named "b"
reg_obj = vpi_scan( reg_iter );
reg_name = vpi_get_str( vpiName, reg_obj );
$display( "reg name: expect 'b': ", reg_name );
end
else
begin
$display( "FAILED to find module named 'top'" );
end
end
endprogram
This code looks for a module named "top", and prints the first two
registers in it.
Using vcs, you can build and run this using:
vcs -R -sverilog +vpi +acc sv_introspect.sv
"+vpi" enables access to the vpi routines; "+acc" enables visibility into the
netlist from vpi.
`include "vpi_user.svh"
This is a file that I created from the standard vpi_user.hheader file. It's minimal content for this example is:
// file: vpi_user.svh
typedef int vpiProperty_t;
typedef chandle vpiHandle;
const vpiProperty_t vpiName = 2;
const vpiProperty_t vpiReg = 48;
const vpiProperty_t vpiModule = 32;
import "DPI" function bit vpi_free_object( vpiHandle handle );
import "DPI" function string vpi_get_str( vpiProperty_t obj_type, vpiHandle object );
import "DPI" function vpiHandle vpi_iterate( vpiProperty_t obj_type, vpiHandle reference );
import "DPI" function vpiHandle vpi_scan( vpiHandle iterator );
#!/usr/bin/env perl
# file: extract_vpi_properties.pl
use strict;
use warnings;
unless (@ARGV)
{
@ARGV = "$ENV{VCS_HOME}/include";
}
if ($ARGV[0] eq "-help")
{
print "usage: $0 -help\n";
print "usage: $0 : extrace vpi_user.h and sv_vpi_user.h from this dir (or include dir under it\n";
print "usage: $0 : implies \$VCS_HOME\n";
print "usage: $0 {files} : process these files\n";
exit 0;
}
my @files;
for my $path (@ARGV)
{
if (-f $path)
{
push @files, $path;
}
elsif (-d $path)
{
for my $file ( "vpi_user.h", "sv_vpi_user.h" )
{
if (-f "$path/$file") { push @files, "$path/$file" }
if (-f "$path/include/$file") { push @files, "$path/include/$file" }
}
}
}
my %seen;
my @enums;
for my $file (@files)
{
open my $fh, "<", $file or die "Can't read file: $file";
while (<$fh>)
{
/\#define \s+ (vpi\w+) \s+ (\d+)/x or next;
my ($name, $value) = ($1,$2);
next if $seen{$name}++;
push @enums, [$name, $value];
}
}
print <<"__EOT__";
typedef int vpiProperty_t;
typedef chandle vpiHandle;
@{[ join "\n", map { sprintf "const vpiProperty_t %s = %s;", @$_ } @enums ]}
import "DPI" function bit vpi_compare_objects( vpiHandle object1, vpiHandle object2 );
import "DPI" function bit vpi_flush( );
import "DPI" function bit vpi_free_object( vpiHandle handle );
import "DPI" function int vpi_get( vpiProperty_t obj_type, vpiHandle object );
import "DPI" function string vpi_get_str( vpiProperty_t obj_type, vpiHandle object );
import "DPI" function chandle vpi_get_userdata( vpiHandle tfcall );
import "DPI" function vpiHandle vpi_handle( vpiProperty_t obj_type, vpiHandle reference );
import "DPI" function vpiHandle vpi_handle_by_index( vpiHandle parent, int index );
import "DPI" function vpiHandle vpi_handle_by_name( string name, vpiHandle scope );
import "DPI" function vpiHandle vpi_handle_multi( vpiProperty_t obj_type, vpiHandle reference1, vpiHandle reference2 );
import "DPI" function vpiHandle vpi_iterate( vpiProperty_t obj_type, vpiHandle reference );
import "DPI" function int vpi_put_userdata( vpiHandle tfcall, chandle data );
import "DPI" function vpiHandle vpi_scan( vpiHandle iterator );
__EOT__