How to insert/add a statement, or a module item, into a sequential block and a generate block

From Verific Design Automation FAQ
Jump to: navigation, search

This application shows how to insert a new statement into a sequential block and a generate block. It uses the Analyze* APIs that were described in the FAQ page: [1].

C++:

#include "veri_file.h"
#include "VeriModule.h"
#include "VeriId.h"
#include "VeriModuleItem.h"
#include "VeriStatement.h"
#include "VeriScope.h"
#include "VeriVisitor.h"

#include "Netlist.h"
#include "VeriWrite.h"

#include "Strings.h"

#include "Array.h"
#include "Map.h"
#include <iostream>
#include <sstream>

#ifdef VERIFIC_NAMESPACE
using namespace Verific ;
#endif
using namespace std ;

class MyVisitor : public VeriVisitor
{
public:
    MyVisitor() : VeriVisitor(), _parent_stack() { }
    virtual ~MyVisitor() { }

    virtual void VERI_VISIT(VeriSeqBlock, node)
    {
        // Don't stop at the first VeriSeqBlock
        VeriVisitor::VERI_VISIT_NODE(VeriSeqBlock, node) ;

        // Find the block to add the new statement
        char *pp_str = node.GetPrettyPrintedString() ;
        if(!Strings::compare(pp_str, "begin\n    test2 <=  ack ;\nend\n")) {
            Strings::free(pp_str) ;
            return ;
        }
        //  node.Info("Got VeriSeqBlock: %s", pp_str) ;
        Strings::free(pp_str) ;

        // Insert the statement
        unsigned st = 0;
        VeriScope *scope = node.GetScope() ;
        if (scope) {
            // Now analyze the string into VeriStatement:
            linefile_type dummy_lf = LineFile::EncodeLineFile("read-from-string", 1) ;
            VeriStatement *new_node = veri_file::AnalyzeStatement("A2:cover property (test2 == 1'b1) ;", veri_file::SYSTEM_VERILOG, dummy_lf /*could be 0, may use node.Linefile()*/, scope) ;
            if (new_node) { // Something went wrong
                st = node.AddStatement(new_node, 0 /*add at the end*/, 1 /*resolve*/);
            }
        }
        node.Info("Statement insertion into SeqBlock: %s", ((st)?"succeeded":"FAILED")) ;
    }

    virtual void VERI_VISIT(VeriGenerateConstruct, node)
    {
        // Don't stop at first node
        VeriVisitor::VERI_VISIT_NODE(VeriGenerateConstruct, node) ;

        // Find the block to add to
        // For now I assume there is only one so nothing to skip
        char *pp_str = node.GetPrettyPrintedString() ;
     //   node.Info("Got VeriGenerateConstruct: %s", pp_str) ;
        Strings::free(pp_str) ;

        // Insert the statement
        unsigned st = 0 ;
        VeriScope *scope = node.GetScope() ;

        // node doesn't have a scope get the parent scope.
        if (!scope) {
            VeriTreeNode *parent = GetParent() ;
            VERIFIC_ASSERT(parent) ;
            scope = parent->GetScope();
        }
        if (scope) {
            // Now analyze the string into ModuleItem:
            VeriModuleItem *new_node = veri_file::AnalyzeModuleItem("A1: cover property(@(posedge clk) test1 == 1'b1) ;", veri_file::SYSTEM_VERILOG, 0 /*may use node.Linefile()*/, scope) ;
            if (new_node) {
                // It is used as a module item - try adding it:
                st = node.AddModuleItem((VeriModuleItem *) new_node, 0 /*add at the end*/, 1 /*resolve*/) ;
            }
        }
        node.Info("Statement insertion into GenerateConstruct: %s", ((st)?"succeeded":"FAILED")) ;
    }


    // Maintain a parent pointer in the visitor:
    virtual void PreAction(VeriTreeNode &node)  { _parent_stack.Insert(&node) ; }
    virtual void PostAction(VeriTreeNode &node)
    {
        VeriTreeNode *n = (VeriTreeNode *)_parent_stack.RemoveLast() ;
        VERIFIC_ASSERT(n == &node) ;
    }
    VeriTreeNode *GetParent() const
    {
        VeriTreeNode *n = (VeriTreeNode *)_parent_stack.GetLast() ;
        VERIFIC_ASSERT(n) ;
        return n ;
    }

private:
    Array _parent_stack ;
} ; // class MyVisitor

int main(int argc, char **argv)
{
    Array files(1) ;
    files.Insert("test.v") ;
    if (!veri_file::AnalyzeMultipleFiles(&files, veri_file::SYSTEM_VERILOG)) return 1 ;

    veri_file::PrettyPrint("before.v.golden.new", 0) ;

    MyVisitor mv ;

    MapIter mi ;
    VeriModule *mod ;
    FOREACH_VERILOG_MODULE(mi, mod) if (mod) mod->Accept(mv) ;

    veri_file::PrettyPrint("after.v.golden.new", 0) ;

    // Elaborate the design:
    veri_file::ElaborateAll() ;

    VeriWrite vw ;
    vw.WriteFile("test.v.golden.new", Netlist::PresentDesign()) ;

    // Synthesize assertions in the parse tree:
    //veri_file::SynthesizeConcurrentAssertions() ;
    //veri_file::PrettyPrint("test_assert_synth.v.golden.new", 0) ;

    return 0 ;
}
 


The application is going to add the statements where the comments sit.

Testcase:

module top #(parameter HEADER = 1) (input clk, input rst, input ack) ;
    generate 
     reg test1 ;
     reg test2 ;
     if(HEADER) begin: HEADER_ADDR
        always @(posedge clk or posedge rst) begin
            if (rst) begin
                test1 <= 1'b0 ;
                test2 <= 1'b0 ;
            end else begin
                test2 <= ack ;
//              A2: cover property (test2 == 1'b1) ;
            end
        end
     end
//   A1: cover property(@(posedge clk) test1 == 1'b1) ;
    endgenerate
endmodule
 


Run:

[moh@awing0 240906]$ ./test-linux 
-- Analyzing Verilog file 'test.v' (VERI-1482)
-- Printing all libraries to file 'before.v.golden.new' (VERI-1492)
test.v(13): INFO: Statement insertion into SeqBlock: succeeded
test.v(17): INFO: Statement insertion into GenerateConstruct: succeeded
-- Printing all libraries to file 'after.v.golden.new' (VERI-1492)
test.v(1): INFO: compiling module 'top' (VERI-1018)
-- Writing netlist 'top' to Verilog file 'test.v.golden.new' (VDB-1030)
[moh@awing0 240906]$ cat after.v.golden.new 

module top #(parameter HEADER = 1) (
    input clk, 
    input rst, 
    input ack) ;
    generate
        reg test1 ; 
        reg test2 ; 
        if (HEADER) 
            begin : HEADER_ADDR
                always
                    @(posedge clk or posedge rst)
                    begin
                        if (rst) 
                            begin
                                test1 <=  1'b0 ;
                                test2 <=  1'b0 ;
                            end
                        else
                            begin
                                test2 <=  ack ;
                                A2 : cover property ((test2 == 1'b1)) ;
                            end
                    end
            end
        A1 : cover property (@(posedge clk) (test1 == 1'b1)) ;
    endgenerate
endmodule


[moh@awing0 240906]$