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 endprogramThis 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__