Process -f file and explore the Netlist Database (C++)

From Verific Design Automation FAQ
Jump to: navigation, search
#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()) ;
        }
    }
}