Difference between revisions of "Process -f file and explore the Netlist Database (C++)"
From Verific Design Automation FAQ
(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...") |
|||
(One intermediate revision by the same user not shown) | |||
Line 1: | Line 1: | ||
<nowiki> | <nowiki> | ||
− | #include | + | #include "Map.h" // Make associated hash table class Map available |
− | #include | + | #include "Array.h" // Make associated hash table class Array available |
− | + | #include "Set.h" // Make associated hash table class Set available | |
− | #include " | + | #include "Message.h" // Make message handlers available |
− | #include " | + | #include "veri_file.h" // Make verilog reader available |
− | #include " | + | #include "DataBase.h" // Make (hierarchical netlist) database API available |
− | #include " | + | #include "RuntimeFlags.h" |
− | + | #include <string.h> | |
− | #include " | + | #include <stdio.h> |
− | + | ||
− | + | ||
#ifdef VERIFIC_NAMESPACE | #ifdef VERIFIC_NAMESPACE | ||
Line 16: | Line 14: | ||
#endif | #endif | ||
− | int main(int argc, | + | 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 ; | 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> |
Latest revision as of 17:17, 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()) ; } } }