Type Range example with multi-dimensional arrays

From Verific Design Automation FAQ
Revision as of 16:07, 13 November 2020 by Hoa (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

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;
}