Type Range example with multi-dimensional arrays
From Verific Design Automation FAQ
For a design with multidimensional arrays, the application needs to create a data structure for mapping NetBus to TypeRange.
C++:
#include <iostream>
#include "veri_file.h"
#include "DataBase.h"
#include "Map.h"
#ifdef VERIFIC_NAMESPACE
using namespace Verific ;
#endif
void CreateTypeRangeMapping(const Netlist *nl, Map &net_bus_vs_tr)
{
if (!nl) return ;
// Get the Verilog id name vs Set of Net or NetBus created.
// Runtime flag 'db_add_id_vs_netbus_map' needs to be set while elaborating the design:
const Map *id_vs_nets = nl->GetIdNetsTable() ;
const Map *id_vs_tr = nl->GetTypeRangeTable() ; // Get the Verilog id name vs its TypeRange
if (!id_vs_tr) return ;
MapIter mi ;
const char *id_name ;
const Set *net_or_netbus ;
const TypeRange *tr ;
FOREACH_MAP_ITEM(id_vs_nets, mi, &id_name, &net_or_netbus) {
tr = (TypeRange *)id_vs_tr->GetValue(id_name) ;
if (!tr) continue ;
SetIter si ;
DesignObj *obj ;
FOREACH_SET_ITEM(net_or_netbus, si, &obj) {
// Only insert for NetBusses, we do not need Nets:
if (obj->IsNetBus()) (void) net_bus_vs_tr.Insert(obj, tr) ;
}
}
}
int main(int argc, const char **argv)
{
RuntimeFlags::SetVar("db_preserve_user_nets", 1) ;
RuntimeFlags::SetVar("db_add_id_vs_netbus_map", 1) ;
if (!veri_file::Read("test.v", "work", veri_file::SYSTEM_VERILOG)) return 1 ;
Netlist *netlist = Netlist::PresentDesign() ;
Map net_bus_vs_tr(POINTER_HASH) ;
CreateTypeRangeMapping(netlist, net_bus_vs_tr) ;
MapIter mi ;
Net *net ;
const TypeRange *tr ;
FOREACH_NET_OF_NETLIST(netlist, mi, net) {
if (!net || (net->IsUserDeclared() == 0)) {
continue;
}
if (net->Bus()) {
const char *name = net->Bus()->Name();
tr = (const TypeRange *)net_bus_vs_tr.GetValue(net->Bus()) ;
if (!tr) continue ; // Something wrong happened
// Find if it has unpacked and/or packed dimensions: if it is unpacked, it must be the last dimension:
unsigned has_unpacked_dim = (tr->IsTypeArray() && tr->IsPackedDimensionRange()) ? 0 : 1 ;
// Packed dimensions may be there after the unpacked dimensions, find if there:
unsigned has_packed_dim = (tr->IsTypeArray() && tr->IsPackedDimensionRange()) ? 1 : 0 ; // Don't forget the last one
const TypeRange *tr_run = tr ;
while ((tr_run = tr_run->GetNext()) != 0) {
if (tr_run->IsTypeArray() && tr_run->IsPackedDimensionRange()) {
has_packed_dim = 1 ; // Found a packed dimension
break ;
}
}
if (has_packed_dim && !has_unpacked_dim) {
net->Info("Net: %s (%s) : data1", name, net->Name()) ;
} else if (!has_packed_dim && has_unpacked_dim) {
net->Info("Net: %s (%s) : data2 or data4", name, net->Name()) ;
} else if (has_packed_dim && has_unpacked_dim) {
net->Info("Net: %s (%s) : data3", name, net->Name()) ;
}
}
}
return 0 ;
}
test.v:
module test(); reg data0; reg [2:0] data1; reg data2 [2:0]; reg [2:0] data3 [2:0]; reg data4 [2:0][0:2]; endmodule
Run:
$ test-linux -- Analyzing Verilog file 'test.v' (VERI-1482) test.v(1): INFO: compiling module 'test' (VERI-1018) test.v(3): INFO: Net: data1 (data1[2]) : data1 test.v(3): INFO: Net: data1 (data1[1]) : data1 test.v(3): INFO: Net: data1 (data1[0]) : data1 test.v(4): INFO: Net: data2 (data2[2]) : data2 or data4 test.v(4): INFO: Net: data2 (data2[1]) : data2 or data4 test.v(4): INFO: Net: data2 (data2[0]) : data2 or data4 test.v(5): INFO: Net: data3[2] (data3[2][2]) : data3 test.v(5): INFO: Net: data3[2] (data3[2][1]) : data3 test.v(5): INFO: Net: data3[2] (data3[2][0]) : data3 test.v(5): INFO: Net: data3[1] (data3[1][2]) : data3 test.v(5): INFO: Net: data3[1] (data3[1][1]) : data3 test.v(5): INFO: Net: data3[1] (data3[1][0]) : data3 test.v(5): INFO: Net: data3[0] (data3[0][2]) : data3 test.v(5): INFO: Net: data3[0] (data3[0][1]) : data3 test.v(5): INFO: Net: data3[0] (data3[0][0]) : data3 test.v(6): INFO: Net: data4[2] (data4[2][0]) : data2 or data4 test.v(6): INFO: Net: data4[2] (data4[2][1]) : data2 or data4 test.v(6): INFO: Net: data4[2] (data4[2][2]) : data2 or data4 test.v(6): INFO: Net: data4[1] (data4[1][0]) : data2 or data4 test.v(6): INFO: Net: data4[1] (data4[1][1]) : data2 or data4 test.v(6): INFO: Net: data4[1] (data4[1][2]) : data2 or data4 test.v(6): INFO: Net: data4[0] (data4[0][0]) : data2 or data4 test.v(6): INFO: Net: data4[0] (data4[0][1]) : data2 or data4 test.v(6): INFO: Net: data4[0] (data4[0][2]) : data2 or data4 $
And here is a Perl script doing similar things, and a bit more:
#!/usr/bin/perl
push (@INC,"../pm");
require "Verific.pm";
$file_name = "test.sv";
if (!Verific::veri_file::Analyze($file_name, $Verific::veri_file::SYSTEM_VERILOG)) {
exit(1) ;
}
Verific::RuntimeFlags::SetVar("db_verilog_writer_write_internal_data", 1);
Verific::RuntimeFlags::SetVar("db_add_id_vs_netbus_map", 1);
if (!Verific::veri_file::ElaborateAll()) {
exit(1) ;
}
Verific::veri_file::RemoveAllModules() ;
# Get a handle to the top-level netlist
$top = Verific::Netlist::PresentDesign() ;
if (!$top) {
print "Cannot find any handle to the top-level netlist\n";
exit(1) ;
}
# Print out module that we have handle to
vfcprintf("INFO: last elaborated design is %s(%s)",$top->Linefile(),$top->Owner()->Name(), $top->Name());
$veriWriter = Verific::VeriWrite->new();
$veriWriter->WriteFile("netlist1.v", $top) ;
my $net_vs_tr = new Verific::Map($Verific::POINTER_HASH) ;
CreateTypeRangeMapping ($top, $net_vs_tr);
my $net_vs_tr_mapiter = new Verific::MapItemIter($net_vs_tr);
$map_item = $net_vs_tr_mapiter->First();
while ($map_item) {
$net = $map_item->Key();
bless $net, Verific::Net;
$name = $net->Name();
if ($net->IsNetBus()) {
print ">>> netbus name: $name\n";
} else {
print ">>> net name: $name\n";
}
$map_value = $map_item->Value();
bless $map_value, "Verific::TypeRange";
$id = Verific::void_to_string($map_key);
# print ">>>0 id: $id - typerange: $map_value\n";
ExploreTypeRange($map_value);
$map_item = $net_vs_tr_mapiter->Next();
}
print "<<< out now >>>\n";
exit(0) ;
sub ExploreTypeRange {
my ($tr) = @_;
return if (!defined $tr);
if ($tr->IsTypeScalar()) {
print " IsTypeScalar\n";
}
my $dump = $tr->Dump();
my $typename = $tr->GetTypeName();
print " typename: $typename\n";
if ($tr->IsTypeArray()) {
print " IsTypeArray\n";
bless $tr, "Verific::TypeRangeArray";
if ($tr->IsPackedDimensionRange()) {
print " packed dimension ";
} else {
print " unpacked dimension ";
}
my $dim = $tr->Dimension() - 1;
print "#$dim: ";
my $left = $tr->LeftRangeBound();
my $right = $tr->RightRangeBound();
print "left: $left - right: $right\n";
my $tr_run = $tr->GetNext();
while (($tr_run != 0)) {
ExploreTypeRange($tr_run);
$tr_run = $tr_run->GetNext();
}
}
if ($tr->IsTypeStructure()) {
print " IsTypeStructure\n";
my $element_map_iter = new Verific::MapItemIter($tr->GetElementTypeRangeMap());
return if (!defined $element_map_iter);
$map_item = $element_map_iter->First();
while ($map_item) {
$map_key = $map_item->Key();
$element_name = Verific::void_to_string($map_key);
print " element_name: $element_name\n";
$map_value = $map_item->Value();
bless $map_value, "Verific::TypeRange";
ExploreTypeRange ($map_value);
$map_item = $element_map_iter->Next();
}
}
if ($tr->IsTypeEnum()) {
print " IsTypeEnum\n";
print " You're on your own.\n";
}
}
sub CreateTypeRangeMapping {
my ($nl, $net_vs_tr) = @_ ;
return if (!defined $nl);
my $netlistname = $nl->Name();
my $cellname = $nl->Owner()->Name();
my $id_vs_tr_mapiter = new Verific::MapItemIter($nl->GetTypeRangeTable());
return if (!defined $id_vs_tr_mapiter);
$map_item = $id_vs_tr_mapiter->First();
while ($map_item) {
$map_key = $map_item->Key();
$map_value = $map_item->Value();
bless $map_value, "Verific::TypeRange";
$id = Verific::void_to_string($map_key);
$map_item = $id_vs_tr_mapiter->Next();
}
my $id_vs_tr = $nl->GetTypeRangeTable();
my $id_vs_nets_mapiter = new Verific::MapItemIter($nl->GetIdNetsTable());
return if (!defined $id_vs_nets_mapiter);
my $map_key ;
my $map_item = $id_vs_nets_mapiter->First();
while ($map_item) {
$map_key = $map_item->Key();
$map_value = $map_item->Value();
bless $map_value, "Verific::Set";
my $id = Verific::void_to_string($map_key);
$design_obj_set = new Verific::DesignObjSetIter($map_value);
$obj = $design_obj_set->First();
while ($obj) {
my $tr = $id_vs_tr->GetValue($map_key);
$net_vs_tr->Insert($obj, $tr) ;
$obj = $design_obj_set->Next();
}
$map_item = $id_vs_nets_mapiter->Next();
}
}
sub vfcprintf {
my ($format) = (@_[0]);
my ($lf) = (@_[1]);
my @PARAMS;
for (my $i = 2; $i < scalar(@_); $i++) {
push(@PARAMS,"@_[$i]");
}
my $lf_format = "";
if (Verific::LineFile::GetFileName($lf) && Verific::LineFile::GetLineNo($lf)) {
my $lf_format = sprintf("%s(%s)",Verific::LineFile::GetFileName($lf), Verific::LineFile::GetLineNo($lf));
printf "%s: $format\n",$lf_format,@PARAMS;
} else {
printf "$format\n",@PARAMS;
}
return 0;
}