Prettyprint all modules in the design hierarchy

From Verific Design Automation FAQ
Revision as of 11:12, 19 July 2022 by Hoa (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
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 (this step is optional).
- 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 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()
{
    const char *file_name = "test.v" ;
    const char *top_name = "top" ;
    const char *work_lib = "work" ;

    if (!veri_file::Analyze(file_name, veri_file::VERILOG_2K /*Verilog 2000*/)) return 1 ;

    if (veri_file::GetModule(top_name)) {
        // Optional - statically elaborate all the top Verilog module. Return if any error shows up.
        if (!veri_file::ElaborateStatic(top_name)) return 2 ; // 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) {
            return 3 ; // 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);

    }

    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
    SetItem *item = done.GetItem(module) ;
    if (item) {
        // Message::PrintLine("Been in module ", module->Name(), " before. Returning....") ;
        return ; // We've already been here
    }

    // 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 module instance
        VeriModule *mod = mod_inst ? mod_inst->GetInstantiatedModule() : 0 ; // The module instance is a module
        if (mod) { // This is verilog module instantiation: need to go into that module
            // Message::PrintLine("In module ", module->Name()) ;
            // Message::PrintLine("Processing instance ", id->Name(), " of module ", mod->Name()); //, " in module ", module->Name()) ;
            Accumulate(mod, done) ; // Traverse the instantiated module
        }
    }

    // Insert the traversed module
    // Message::PrintLine("Inserting module ", module->Name()) ;
    done.Insert(module) ;
}
 

Input file test.v:

module top(a, b, c, d, e, f, out, m, n, o) ;
    input a, b, c, d, e, f, m, n ;
    output out, o ;

    wire tmp1, tmp2 ;

    mid1 i1(a, b, c, d, tmp1) ;
    mid1 i2(a, d, e, f, tmp2) ;
    mid1 i3(tmp1, tmp2, e, f, out) ;
    bot bi(o, m, n);

endmodule

module mid1 (mid1_inp1, mid1_inp2, mid1_inp3, mid1_inp4, mid1_out,
             mid1b_inp1, mid1b_inp2, mid1b_out) ;
    input mid1_inp1, mid1_inp2, mid1_inp3, mid1_inp4 ;
    output mid1_out ;
    input mid1b_inp1, mid1b_inp2 ;
    output mid1b_out ;
    
    wire tmp1, tmp2 ;

    mid2 m1(mid1_inp1, mid1_inp2, tmp1) ;
    mid2 m2(mid1_inp3, mid1_inp4, tmp2) ;
    mid2 m3(tmp1, tmp2, mid1_out) ;
    bot b(mid1b_inp1, mid1b_inp2, mid1b_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, m, n, o) ;
    input a, b, c, d, e, f, m, n ; 
    output out, o ; 
    wire tmp1, tmp2 ; 
    mid1 i1 (a, b, c, d, tmp1) ; 
    mid1 i2 (a, d, e, f, tmp2) ; 
    mid1 i3 (tmp1, tmp2, e, f, out) ; 
    bot bi (o, m, n) ; 
endmodule


// Printing module mid1

module mid1 (mid1_inp1, mid1_inp2, mid1_inp3, mid1_inp4, mid1_out, mid1b_inp1, mid1b_inp2, mid1b_out) ;
    input mid1_inp1, mid1_inp2, mid1_inp3, mid1_inp4 ; 
    output mid1_out ; 
    input mid1b_inp1, mid1b_inp2 ; 
    output mid1b_out ; 
    wire tmp1, tmp2 ; 
    mid2 m1 (mid1_inp1, mid1_inp2, tmp1) ; 
    mid2 m2 (mid1_inp3, mid1_inp4, tmp2) ; 
    mid2 m3 (tmp1, tmp2, mid1_out) ; 
    bot b (mid1b_inp1, mid1b_inp2, mid1b_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