Difference between revisions of "Process -f file and explore the Netlist Database (C++)"

From Verific Design Automation FAQ
Jump to: navigation, search
(Created page with " <nowiki> #include <iostream> #include <fstream> #include "veri_file.h" #include "VeriModule.h" #include "VeriId.h" #include "VeriScope.h" #include "Set.h" using namespace...")
 
Line 1: Line 1:
 
  <nowiki>
 
  <nowiki>
#include <iostream>
+
#include "Map.h"        // Make associated hash table class Map available
#include <fstream>
+
#include "Array.h"      // Make associated hash table class Array available
 
+
#include "Set.h"         // Make associated hash table class Set available
#include "veri_file.h"
+
#include "Message.h"     // Make message handlers available
#include "VeriModule.h"
+
#include "veri_file.h"   // Make verilog reader available
#include "VeriId.h"
+
#include "DataBase.h"   // Make (hierarchical netlist) database API available
#include "VeriScope.h"
+
#include "RuntimeFlags.h"
 
+
#include <string.h>
#include "Set.h"
+
#include <stdio.h>
 
+
using namespace std ;
+
  
 
#ifdef VERIFIC_NAMESPACE
 
#ifdef VERIFIC_NAMESPACE
Line 16: Line 14:
 
#endif
 
#endif
  
int main(int argc, const char **argv)
+
void Accumulate(Netlist *netlist, Set &done) ;
 +
void PrintInstances(Netlist *netlist) ;
 +
void PrintInterface(Netlist *netlist) ;
 +
 
 +
int main(int argc, char **argv)
 
{
 
{
    const char *file = (argc > 1) ? argv[1] : "test.v" ;
 
  
     // Analyze the files (AnalyzeMultipleFiles API is the recommended one):
+
     if (argc < 2) Message::PrintLine("Default input -f file: files.f. Specify command line argument to override") ;
    Array files(1) ;
+
    files.InsertLast(file) ;
+
    if (!veri_file::AnalyzeMultipleFiles(&files, veri_file::SYSTEM_VERILOG)) return 1 ;
+
  
     // Get the module by name:
+
     ///////////////////
     VeriModule *test = veri_file::GetModule ("test");
+
     // F-file processing
     if (!test) return 2 ;
+
     ///////////////////
  
     // Get the scope of the module:
+
     const char *f_file_name = 0 ;
    VeriScope *scope = test->GetScope() ;
+
  
     std::ofstream f("test_out.v", std::ios::out) ;
+
     if (argc>1) {
 +
        f_file_name = argv[1] ; // Set the file name as specified by the user
 +
    } else {
 +
        f_file_name = "files.f" ; // Set default file name
 +
    }
  
     // Get the scope that this module/scope is using:
+
     // NO_MODE: mode keyed off the file dialect - MFCU Verilog 2000 and SFCU for SystemVerilog
    // This also includes the compilation unit in the list, if any/required:
+
     unsigned cu_mode = veri_file::NO_MODE ;
     Set *using_scopes = (scope) ? scope->GetUsing() : 0 ;
+
  
     // Print all those scopes/modules before printing the module itself:
+
     // UNDEFINED: dialect keyed off the file extension - .v for Verilog 2000 and .sv for SystemVerilog
     SetIter si ;
+
    unsigned f_analysis_mode = veri_file::UNDEFINED ;
     VeriScope *using_scope ;
+
     Array *file_names = veri_file::ProcessFFile(f_file_name, veri_file::F_FILE_NONE /* or veri_file::F_FILE_CAPITAL */, f_analysis_mode) ;
     FOREACH_SET_ITEM(using_scopes, si, &using_scope) {
+
     if (!file_names) return 1 ; // Failed to process the F file
         VeriIdDef *mod_id = using_scope->GetContainingModule() ;
+
 
         VeriModule *mod = (mod_id) ? mod_id->GetModule() : 0 ;
+
    Array veri_files ;
        if (!mod) continue ;
+
 
        f << "// Printing module " << mod->Name() << endl ;
+
    unsigned i ;
        mod->PrettyPrint(f, 0) ;
+
    char *file_name ;  
 +
     FOREACH_ARRAY_ITEM(file_names, i, file_name) {  
 +
         if (strstr(file_name, ".v") || strstr(file_name, ".sv")) {
 +
            veri_files.InsertLast(file_name) ;
 +
         } else {
 +
            printf("File %s has an invalid extension - ignored.\n", file_name) ;
 +
        }
 +
    }
 +
   
 +
    // Next, check whether the analysis mode is set from -f file:
 +
    if (f_analysis_mode == veri_file::UNDEFINED) {
 +
      // Default to Verilog 2001:  
 +
      f_analysis_mode = veri_file::VERILOG_2K ;  
 +
      // But treat .sv files as SystemVerilog:
 +
      veri_file::AddFileExtMode(".sv", veri_file::SYSTEM_VERILOG) ;
 +
    }
 +
   
 +
    ///////////////////
 +
    // Analysis
 +
    ///////////////////
 +
 
 +
    // Analyze all the Verilog files at-once 
 +
    if (!veri_file::AnalyzeMultipleFiles(&veri_files, f_analysis_mode, "work", cu_mode)) return 1 ;  
 +
 
 +
    // Everything is done, clean up the file names and the allocated array:
 +
    while (file_names->Size()) Strings::free((char *)file_names->RemoveLast()) ;
 +
    delete file_names ;
 +
   
 +
    ///////////////////
 +
    // Elaboration
 +
    ///////////////////
 +
 
 +
    // Optional:
 +
    // This will do a "lightweighed" RTL elaboration, skipping all "always" constructs.
 +
    // It's faster than full elaboration and will ignore many errors.
 +
    RuntimeFlags::SetVar ("veri_ignore_always_constructs", 1) ;
 +
 
 +
    if (!veri_file::ElaborateAll("work")) {
 +
        // Here, design analysis and elaboration failed
 +
        return 1 ;
 
     }
 
     }
 +
   
 +
    ///////////////////
 +
    // Exploring the netlist database
 +
    ///////////////////
  
     // Now  print the module:
+
     // Get a handle to the top-level netlist
     f << "// Printing module " << test->Name() << endl ;
+
    Netlist *top = Netlist::PresentDesign() ;
     test->PrettyPrint(f, 0) ;
+
     if (!top) {
    f.close() ;
+
        Message::PrintLine("Cannot find any handle to the top-level netlist") ;
 +
        return 4 ;
 +
    }
 +
 
 +
    // Print out module that we have handle to
 +
    Message::Msg(VERIFIC_INFO, 0, top->Linefile(), "top level design is %s(%s)",
 +
                top->Owner()->Name(), top->Name()) ;
 +
 
 +
     // Lets accumulate all netlist
 +
    Set netlists(POINTER_HASH) ;
 +
    Accumulate(top, netlists) ;
 +
 
 +
    // Names of netlists along with the instantiation reference count.
 +
    Netlist *netlist ;
 +
    SetIter si ;
 +
    Message::PrintLine("") ;
 +
    FOREACH_SET_ITEM(&netlists, si, &netlist) {
 +
        if (netlist->IsUserDeclared()) { // only report user-declared modules
 +
        Message::PrintLine("") ;
 +
            Message::Msg(VERIFIC_INFO, 0, netlist->Linefile(), "module %s was instantiated %d times",
 +
                    netlist->Owner()->Name(), netlist->NumOfRefs()) ;
 +
            PrintInterface(netlist) ;
 +
            PrintInstances(netlist) ;
 +
        }
 +
    }
  
 
     return 0 ;
 
     return 0 ;
 +
}
 +
 +
// This function is recursive in nature, and collects all other
 +
// netlists that the incoming netlist depends on in a container.
 +
void Accumulate(Netlist *netlist, Set &done)
 +
{
 +
    if (!netlist) return ; // Ignore NULL netlists
 +
 +
    SetItem *item = done.GetItem(netlist) ;
 +
    if (item) {
 +
        return ; // We've already been here
 +
    }
 +
 +
    Instance *inst ;
 +
    MapIter mi ;
 +
    FOREACH_INSTANCE_OF_NETLIST(netlist, mi, inst) {
 +
        // Now go into the netlist associated with the instance
 +
        Accumulate(inst->View(), done) ;
 +
    }
 +
 +
    // Insert the traversed Netlist
 +
    done.Insert(netlist) ;
 +
}
 +
 +
// Print all instances of the netlist
 +
void PrintInstances (Netlist *netlist)
 +
{
 +
    if (!netlist) return ; // Ignore NULL netlists
 +
    if (!netlist->IsUserDeclared()) return ; // Ignore Verific operators and primitives
 +
    Instance *inst ;
 +
    MapIter mi ;
 +
    FOREACH_INSTANCE_OF_NETLIST(netlist, mi, inst) {
 +
        if (inst->IsUserDeclared()) {
 +
            Message::Msg(VERIFIC_NONE, 0, 0, "Instance %s of module %s", inst->Name(), inst->View()->Owner()->Name()) ;
 +
        }
 +
    }
 +
}
 +
 +
// Print all ports of the netlist
 +
void PrintInterface (Netlist *netlist)
 +
{
 +
    if (!netlist) return ; // Ignore NULL netlists
 +
    if (!netlist->IsUserDeclared()) return ; // Ignore Verific operators and primitives
 +
    Port *port ;
 +
    MapIter mi ;
 +
    FOREACH_PORT_OF_NETLIST(netlist, mi, port) {
 +
        if (!port) continue ;
 +
        if (port->Bus()) continue ;
 +
        if (port->IsInout()) {
 +
            Message::Msg(VERIFIC_NONE, 0, 0, "Inout port %s", port->Name()) ;
 +
        }
 +
        if (port->IsOutput()) {
 +
            Message::Msg(VERIFIC_NONE, 0, 0, "Output port %s", port->Name()) ;
 +
        }
 +
        if (port->IsInput()) {
 +
            Message::Msg(VERIFIC_NONE, 0, 0, "Input port %s", port->Name()) ;
 +
        }
 +
    }
 +
    PortBus *port_bus ;
 +
    FOREACH_PORTBUS_OF_NETLIST(netlist, mi, port_bus) {
 +
        if (!port_bus) continue ;
 +
        if (port_bus->IsInout()) {
 +
            Message::Msg(VERIFIC_NONE, 0, 0, "Inout port_bus %s[%d:%d]", port_bus->Name(), port_bus->LeftIndex(), port_bus->RightIndex()) ;
 +
        }
 +
        if (port_bus->IsOutput()) {
 +
            Message::Msg(VERIFIC_NONE, 0, 0, "Output port_bus %s[%d:%d]", port_bus->Name(), port_bus->LeftIndex(), port_bus->RightIndex()) ;
 +
        }
 +
        if (port_bus->IsInput()) {
 +
            Message::Msg(VERIFIC_NONE, 0, 0, "Input port_bus %s[%d:%d]", port_bus->Name(), port_bus->LeftIndex(), port_bus->RightIndex()) ;
 +
        }
 +
    }
 
}
 
}
 
  </nowiki>
 
  </nowiki>

Revision as of 17:16, 1 March 2019

#include "Map.h"         // Make associated hash table class Map available
#include "Array.h"       // Make associated hash table class Array available
#include "Set.h"         // Make associated hash table class Set available
#include "Message.h"     // Make message handlers available
#include "veri_file.h"   // Make verilog reader available
#include "DataBase.h"    // Make (hierarchical netlist) database API available
#include "RuntimeFlags.h"
#include <string.h>
#include <stdio.h>

#ifdef VERIFIC_NAMESPACE
using namespace Verific ;
#endif

void Accumulate(Netlist *netlist, Set &done) ;
void PrintInstances(Netlist *netlist) ;
void PrintInterface(Netlist *netlist) ;

int main(int argc, char **argv)
{

    if (argc < 2) Message::PrintLine("Default input -f file: files.f. Specify command line argument to override") ;

    ///////////////////
    // F-file processing
    ///////////////////

    const char *f_file_name = 0 ;

    if (argc>1) {
        f_file_name = argv[1] ; // Set the file name as specified by the user
    } else {
        f_file_name = "files.f" ; // Set default file name
    }

    // NO_MODE: mode keyed off the file dialect - MFCU Verilog 2000 and SFCU for SystemVerilog
    unsigned cu_mode = veri_file::NO_MODE ;

    // UNDEFINED: dialect keyed off the file extension - .v for Verilog 2000 and .sv for SystemVerilog
    unsigned f_analysis_mode = veri_file::UNDEFINED ; 
    Array *file_names = veri_file::ProcessFFile(f_file_name, veri_file::F_FILE_NONE /* or veri_file::F_FILE_CAPITAL */, f_analysis_mode) ;
    if (!file_names) return 1 ; // Failed to process the F file 

    Array veri_files ; 
   
    unsigned i ; 
    char *file_name ; 
    FOREACH_ARRAY_ITEM(file_names, i, file_name) { 
        if (strstr(file_name, ".v") || strstr(file_name, ".sv")) { 
            veri_files.InsertLast(file_name) ;  
        } else { 
            printf("File %s has an invalid extension - ignored.\n", file_name) ; 
        } 
    } 
    
    // Next, check whether the analysis mode is set from -f file: 
    if (f_analysis_mode == veri_file::UNDEFINED) { 
      // Default to Verilog 2001: 
      f_analysis_mode = veri_file::VERILOG_2K ; 
      // But treat .sv files as SystemVerilog: 
      veri_file::AddFileExtMode(".sv", veri_file::SYSTEM_VERILOG) ; 
    } 
    
    ///////////////////
    // Analysis
    ///////////////////

    // Analyze all the Verilog files at-once  
    if (!veri_file::AnalyzeMultipleFiles(&veri_files, f_analysis_mode, "work", cu_mode)) return 1 ; 
   
    // Everything is done, clean up the file names and the allocated array: 
    while (file_names->Size()) Strings::free((char *)file_names->RemoveLast()) ; 
    delete file_names ; 
    
    ///////////////////
    // Elaboration
    ///////////////////

    // Optional:
    // This will do a "lightweighed" RTL elaboration, skipping all "always" constructs.
    // It's faster than full elaboration and will ignore many errors.
    RuntimeFlags::SetVar ("veri_ignore_always_constructs", 1) ;

    if (!veri_file::ElaborateAll("work")) {
        // Here, design analysis and elaboration failed
        return 1 ;
    }
    
    ///////////////////
    // Exploring the netlist database
    ///////////////////

    // Get a handle to the top-level netlist
    Netlist *top = Netlist::PresentDesign() ;
    if (!top) {
        Message::PrintLine("Cannot find any handle to the top-level netlist") ;
        return 4 ;
    }

    // Print out module that we have handle to
    Message::Msg(VERIFIC_INFO, 0, top->Linefile(), "top level design is %s(%s)",
                 top->Owner()->Name(), top->Name()) ;

    // Lets accumulate all netlist
    Set netlists(POINTER_HASH) ;
    Accumulate(top, netlists) ;

    // Names of netlists along with the instantiation reference count.
    Netlist *netlist ;
    SetIter si ;
    Message::PrintLine("") ;
    FOREACH_SET_ITEM(&netlists, si, &netlist) {
        if (netlist->IsUserDeclared()) { // only report user-declared modules
        Message::PrintLine("") ;
            Message::Msg(VERIFIC_INFO, 0, netlist->Linefile(), "module %s was instantiated %d times",
                     netlist->Owner()->Name(), netlist->NumOfRefs()) ;
            PrintInterface(netlist) ;
            PrintInstances(netlist) ;
        } 
    }

    return 0 ;
}

// This function is recursive in nature, and collects all other
// netlists that the incoming netlist depends on in a container.
void Accumulate(Netlist *netlist, Set &done)
{
    if (!netlist) return ; // Ignore NULL netlists

    SetItem *item = done.GetItem(netlist) ;
    if (item) {
        return ; // We've already been here
    }

    Instance *inst ;
    MapIter mi ;
    FOREACH_INSTANCE_OF_NETLIST(netlist, mi, inst) {
        // Now go into the netlist associated with the instance
        Accumulate(inst->View(), done) ;
    }

    // Insert the traversed Netlist
    done.Insert(netlist) ;
}

// Print all instances of the netlist
void PrintInstances (Netlist *netlist)
{
    if (!netlist) return ; // Ignore NULL netlists
    if (!netlist->IsUserDeclared()) return ; // Ignore Verific operators and primitives
    Instance *inst ;
    MapIter mi ;
    FOREACH_INSTANCE_OF_NETLIST(netlist, mi, inst) {
        if (inst->IsUserDeclared()) {
            Message::Msg(VERIFIC_NONE, 0, 0, "Instance %s of module %s", inst->Name(), inst->View()->Owner()->Name()) ;
        }
    }
}

// Print all ports of the netlist
void PrintInterface (Netlist *netlist)
{
    if (!netlist) return ; // Ignore NULL netlists
    if (!netlist->IsUserDeclared()) return ; // Ignore Verific operators and primitives
    Port *port ;
    MapIter mi ;
    FOREACH_PORT_OF_NETLIST(netlist, mi, port) {
        if (!port) continue ;
        if (port->Bus()) continue ;
        if (port->IsInout()) {
            Message::Msg(VERIFIC_NONE, 0, 0, "Inout port %s", port->Name()) ;
        }
        if (port->IsOutput()) {
            Message::Msg(VERIFIC_NONE, 0, 0, "Output port %s", port->Name()) ;
        }
        if (port->IsInput()) {
            Message::Msg(VERIFIC_NONE, 0, 0, "Input port %s", port->Name()) ;
        }
    }
    PortBus *port_bus ;
    FOREACH_PORTBUS_OF_NETLIST(netlist, mi, port_bus) {
        if (!port_bus) continue ;
        if (port_bus->IsInout()) {
            Message::Msg(VERIFIC_NONE, 0, 0, "Inout port_bus %s[%d:%d]", port_bus->Name(), port_bus->LeftIndex(), port_bus->RightIndex()) ;
        }
        if (port_bus->IsOutput()) {
            Message::Msg(VERIFIC_NONE, 0, 0, "Output port_bus %s[%d:%d]", port_bus->Name(), port_bus->LeftIndex(), port_bus->RightIndex()) ;
        }
        if (port_bus->IsInput()) {
            Message::Msg(VERIFIC_NONE, 0, 0, "Input port_bus %s[%d:%d]", port_bus->Name(), port_bus->LeftIndex(), port_bus->RightIndex()) ;
        }
    }
}