Prettyprint all modules in the design hierarchy

From Verific Design Automation FAQ
Revision as of 23:25, 28 July 2019 by Hoa (Talk | contribs)

Jump to: navigation, search

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 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 file test.v:

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