How to insert/add a statement, or a module item, into a sequential block and a generate block
From Verific Design Automation FAQ
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]$