Prettyprint all modules in the design hierarchy
From Verific Design Automation FAQ
Revision as of 22:22, 28 July 2019 by Hoa (Talk | contribs) (Created page with "There is an API to prettyprint a module, and there is an API to prettyprint all modules in a library. But there is no single API to prettyprint all modules in the design hier...")
There is an API to prettyprint a module, and there is an API to prettyprint all modules in a library.
But there is no single API to prettyprint all modules in the design hierarchy.
To do so, you need to:
- Statically elaborate the top module. - Traverse the design hierarchy and save all the modules in the design in a Set. - Iterate over all items (modules) of the Set, and prettyprint each of them.
C++:
#include <iostream>
#include <fstream>
using namespace std;
// Verific utilities
#include "Array.h" // Make class Array available
#include "Set.h" // Make class Set available
#include "Message.h" // Make message handlers available
#include "Strings.h" // Definition of class to manipulate copy, concatenate, create etc...
// Verific command line interface
#include "Commands.h" // Make command line interface available
#include "ComRead.h" // Using Verific command 'analyze' as template for command line parsing
// Verific Verilog parser
#include "veri_file.h" // Make verilog reader available
#include "VeriModule.h" // Definition of a VeriModule and VeriPrimitive
#include "VeriExpression.h" // Definition of VeriName
#include "VeriId.h" // Definitions of all verilog identifier nodes
#include "VeriScope.h"
#ifdef VERIFIC_NAMESPACE
using namespace Verific ;
#endif
void Accumulate(VeriModule *module, Set &done);
int main(int argc, const char **argv)
{
// Set-up main line command line.
// This makes all options on the TCL command "analyze" available on this main command line.
Command *mainline = new ComAnalyze() ;
// Add the following options used in this application :
mainline->Add(new StringArg("top","name of top-level module",0/*not optional*/)) ;
// Default command line if no arguments given :
const char *default_argv[5] = {"parse_tree_hierarchy_traversal", "test.v", "-top", "top", 0} ;
if (argc==1) {
argc = 4 ;
argv = default_argv ;
}
// Now parse the command line
if (!mainline->ParseArgs(argc, argv)) {
mainline->Usage() ;
delete mainline ;
return 1 ; /* Command line failed */
}
// Same for SystemVerilog
// veri_file::SetDefaultLibraryPath(lib_path) ;
// Parse the 'analyze' command :
if (!mainline->Process(0/*no tcl interpreter needed*/)) {
mainline->Usage() ;
delete mainline ;
return 2 ; // failure in analysis
}
// Now get top design name :
const char *top_name = mainline->StringVal("top") ;
VERIFIC_ASSERT(top_name) ; // 'top' is not optional, so ParseArgs would already have failed.
// First get the library (from the 'analyze' command) :
const char *work_lib = mainline->StringVal("work") ;
if (!work_lib) work_lib = "work" ; // default library name
if (veri_file::GetModule(top_name)) {
// Top level unit is a Verilog module
// Statically elaborate all the Verilog modules. Return if any error shows up.
if (!veri_file::ElaborateStatic(top_name)) return 3 ; // statically elaborates all verilog modules in the "work" libarary
VeriModule *top_module = veri_file::GetModule(top_name) ; // Get the pointer to the top-level module
if (!top_module) {
delete mainline ;
return 4 ; // Exit from application if there is no top module by the given name in the given Verilog designs
}
// Prettyprint only top module
char *topfilename = Strings::save(top_module->Name(), "_pp.v");
veri_file::PrettyPrint(topfilename, top_module->Name(), work_lib);
Strings::free(topfilename);
top_module->Info("Start collecting modules in '%s' hierachy", top_module->Name()) ;
Set modules(POINTER_HASH);
Accumulate(top_module, modules);
top_module->Info("Prettyprint all modules in '%s' hierachy", top_module->Name()) ;
// Prettyprint all modules in the design hiearchy under top_module
char *tophierfilename = Strings::save(top_module->Name(), "_hier_pp.v");
std::ofstream f(tophierfilename, std::ios::out) ;
VeriModule *module ;
SetIter si ;
// FOREACH_SET_ITEM(&modules, si, &module) { // if you want to prettyprint top module last
FOREACH_SET_ITEM_BACK(&modules, si, &module) { // if you want to prettyprint top module first
if (module) {
Message::PrintLine("Prettyprinting module : ", module->Name()) ;
f << "// Printing module " << module->Name() << endl;
module->PrettyPrint(f, 0);
}
}
f.close();
Strings::free(tophierfilename);
}
delete mainline ;
return 0 ; // all good
}
// This function is recursive in nature, and collects all other
// modules that the incoming module depends on in a container.
void Accumulate(VeriModule *module, Set &done)
{
if (!module) return ; // Ignore NULL netlists
// Get the scope of the module:
VeriScope *scope = module->GetScope() ;
// Find all the declared ids in this scope:
Map *ids = scope ? scope->DeclArea() : 0 ;
MapIter mi ;
VeriIdDef *id ;
FOREACH_MAP_ITEM(ids, mi, 0, &id) { // Traverse declared ids
if (!id || !id->IsInst()) continue ; // Consider only the instance ids
VeriModuleInstantiation *mod_inst = id->GetModuleInstance() ; // Take the moduleinstance
VeriModule *mod = mod_inst ? mod_inst->GetInstantiatedModule() : 0 ; // The module instance is a module
if (mod) { // This is verilog module insatantiation: need to go into that module
Message::PrintLine("Processing instance : ", id->Name(), ", module: ", mod->Name()) ;
SetItem *item = done.GetItem(module) ;
if (item) {
return ; // We've already been here
}
Accumulate(mod, done) ; // Traverse the instantiated module
}
}
// Insert the traversed module
done.Insert(module) ;
}
input test.sv:
module top(a, b, c, d, e, f, out) ;
input a, b, c, d, e, f ;
output out ;
wire tmp1, tmp2 ;
mid1 i1(a, b, c, d, tmp1) ;
mid1 i2(a, d, e, f, tmp2) ;
mid1 i3(tmp1, tmp2, e, f, out) ;
endmodule
module mid1 (mid1_inp1, mid1_inp2, mid1_inp3, mid1_inp4, mid1_out) ;
input mid1_inp1, mid1_inp2, mid1_inp3, mid1_inp4 ;
output mid1_out ;
wire tmp1, tmp2 ;
mid2 m1(mid1_inp1, mid1_inp2, tmp1) ;
mid2 m2(mid1_inp3, mid1_inp4, tmp2) ;
mid2 m3(tmp1, tmp2, mid1_out) ;
endmodule
module mid2 (mid2_inp1, mid2_inp2, mid2_out) ;
input mid2_inp1, mid2_inp2 ;
output mid2_out ;
bot b(mid2_inp1, mid2_inp2, mid2_out) ;
endmodule
module bot (bot_inp1, bot_inp2, bot_out) ;
input bot_inp1, bot_inp2 ;
output bot_out ;
assign bot_out = bot_inp1 & bot_inp2 ;
endmodule
Output file top_hier_pp.v:
// Printing module top
module top (a, b, c, d, e, f, out) ;
input a, b, c, d, e, f ;
output out ;
wire tmp1, tmp2 ;
mid1 i1 (a, b, c, d, tmp1) ;
mid1 i2 (a, d, e, f, tmp2) ;
mid1 i3 (tmp1, tmp2, e, f, out) ;
endmodule
// Printing module mid1
module mid1 (mid1_inp1, mid1_inp2, mid1_inp3, mid1_inp4, mid1_out) ;
input mid1_inp1, mid1_inp2, mid1_inp3, mid1_inp4 ;
output mid1_out ;
wire tmp1, tmp2 ;
mid2 m1 (mid1_inp1, mid1_inp2, tmp1) ;
mid2 m2 (mid1_inp3, mid1_inp4, tmp2) ;
mid2 m3 (tmp1, tmp2, mid1_out) ;
endmodule
// Printing module mid2
module mid2 (mid2_inp1, mid2_inp2, mid2_out) ;
input mid2_inp1, mid2_inp2 ;
output mid2_out ;
bot b (mid2_inp1, mid2_inp2, mid2_out) ;
endmodule
// Printing module bot
module bot (bot_inp1, bot_inp2, bot_out) ;
input bot_inp1, bot_inp2 ;
output bot_out ;
assign bot_out = (bot_inp1 & bot_inp2) ;
endmodule