Evaluate 'for-generate' loop
From Verific Design Automation FAQ
Revision as of 14:32, 17 November 2022 by Hoa (Talk | contribs) (Created page with "C++ application: <nowiki> #include "veri_file.h" #include "VeriModule.h" #include "VeriBaseValue_Stat.h" #include "VeriVisitor.h" #include "VeriExpression.h" #include "VeriC...")
C++ application:
#include "veri_file.h" #include "VeriModule.h" #include "VeriBaseValue_Stat.h" #include "VeriVisitor.h" #include "VeriExpression.h" #include "VeriConstVal.h" #include "VeriId.h" #include "Map.h" #ifdef VERIFIC_NAMESPACE using namespace Verific ; #endif class MyVisitor : public VeriVisitor { public: MyVisitor() : VeriVisitor(), _value_table(0) { } virtual ~MyVisitor() { } private: MyVisitor(const MyVisitor &) ; MyVisitor& operator=(const MyVisitor &) ; public: virtual void VERI_VISIT(VeriGenerateFor, node) { Array genvars ; CheckForgenerate(node, genvars) ; // Accumulate genvars from this node // Visit my items via base: VeriVisitor::VERI_VISIT_NODE(VeriGenerateFor, node) ; // genvars can be used here RemoveGenVars(genvars) ; // Remove accumulated genvars from this node } private: void CheckForgenerate(VeriGenerateFor &node, Array &genvars) ; void RemoveGenVars(Array &genvars) ; private: ValueTable _value_table ; } ; // class MyVisitor void MyVisitor::CheckForgenerate(VeriGenerateFor &node, Array &genvars) { node.Info("Got a for-generate here") ; VeriModuleItem *initial = node.GetInitial() ; VeriExpression *cond = node.GetCondition() ; VeriModuleItem *rep = node.GetRepetition() ; // Elaborate the initial statement: if (initial) (void) initial->StaticElaborateStmt(&_value_table, 0) ; // Find the genvar id: VeriIdDef *gen_id = (initial) ? initial->GetId() : 0 ; if (!gen_id && initial && initial->IsGenVarDecl()) { // For SV: it can be a genvar declaration as well: Array *ids = initial->GetIds() ; gen_id = (ids && ids->Size()) ? (VeriIdDef*)ids->GetFirst() : 0 ; genvars.Append(ids) ; } else if (gen_id) { genvars.Insert(gen_id) ; } if (!gen_id) return ; // Must find a genvar here // Get the starting value of the genvar elaborated before: VeriBaseValue *gen_var_val = _value_table.FetchValue(gen_id) ; if (!gen_var_val) return ; // This should have a value int start_val = gen_var_val->GetIntegerValue() ; node.Info(" Starting at %s = %d", gen_id->Name(), start_val) ; unsigned loop_limit = veri_file::GetLoopLimit() ; // Loop limit int b_true = 0 ; unsigned loopcount = 0 ; for(;;) { loopcount++ ; b_true = 0 ; // Evaluate the condition: VeriBaseValue *final_value = cond->StaticEvaluate(0, &_value_table) ; b_true = (final_value) ? final_value->GetIntegerValue() : 0 ; delete final_value ; final_value = 0 ; if (b_true) { // Check limit only when progress is made if (loop_limit && (loopcount > loop_limit)) break ; VeriBaseValue *gen_var_val = _value_table.FetchValue(gen_id) ; if (!gen_var_val) break ; node.Info(" Genvar %s = %d", gen_id->Name(), gen_var_val->GetIntegerValue()) ; } else { // Condition is false: we are done: break ; } // Elaborate the repeat statement: if (rep) (void) rep->StaticElaborateStmt(&_value_table, 0) ; } int done_val = start_val + ((loopcount) ? (loopcount-1) : 0) ; node.Info(" Done at %s = %d", gen_id->Name(), done_val) ; } void MyVisitor::RemoveGenVars(Array &genvars) { unsigned i ; VeriIdDef *id ; FOREACH_ARRAY_ITEM(&genvars, i, id) { (void) _value_table.RemoveValue(id) ; } } int main() { if (!veri_file::Analyze("test.v", veri_file::VERILOG_2K)) return 1 ; MyVisitor mv ; // Set any parameter to a new value if required: begin: Map old_param_val(POINTER_HASH) ; VeriIdDef *id = 0 ; #if 0 // Set any parameter to a new value if required: begin: // If the for-generate loop depends on parameter, it will be evaluated with its default value. // Enable this block to set a specific overridden value for the parameter. VeriModule *test2 = veri_file::GetModule("test2") ; if (test2) { id = test2->FindDeclared("P") ; if (id) { old_param_val.Insert(id, id->TakeInitialValue()) ; VeriIntVal *val = new VeriIntVal(10) ; id->Info("Setting %s.%s = %d", test2->Name(), id->Name(), val->Integer()) ; id->SetInitialValue(val) ; } } // Set any parameter to a new value if required: end: #endif // Visit the for-generates and evaluate loop: begin: MapIter mi ; VeriModule *mod ; FOREACH_VERILOG_MODULE(mi, mod) { if (!mod) continue ; mod->Info("Checking module '%s'", mod->Name()) ; mod->Accept(mv) ; } // Visit the for-generates and evaluate loop: end: // Restore back to the old initial value: begin: VeriExpression *val ; FOREACH_MAP_ITEM(&old_param_val, mi, &id, &val) { if (!id || !val) continue ; delete id->TakeInitialValue() ; id->SetInitialValue(val) ; } // Restore back to the old initial value: end: return 0 ; }
Verilog testcase:
1 module top ; 2 test1 t1 () ; 3 test2 #(4) t2 () ; 4 endmodule 5 6 module test1 ; 7 genvar i, j ; 8 generate 9 for (i=0; i<4; i=i+1) begin: l1 10 for (j=0; j<4; j=j+1) begin: l2 11 end 12 end 13 endgenerate 14 endmodule 15 16 module test2 ; 17 parameter P = 0 ; 18 genvar i, j ; 19 generate 20 for (i=0; i<P; i=i+1) begin: l1 21 for (j=0; j<P; j=j+1) begin: l2 22 end 23 end 24 endgenerate 25 endmodule
Run:
$ test-linux -- Analyzing Verilog file 'test.v' (VERI-1482) test.v(4): INFO: Checking module 'top' test.v(14): INFO: Checking module 'test1' test.v(12): INFO: Got a for-generate here test.v(12): INFO: Starting at i = 0 test.v(12): INFO: Genvar i = 0 test.v(12): INFO: Genvar i = 1 test.v(12): INFO: Genvar i = 2 test.v(12): INFO: Genvar i = 3 test.v(12): INFO: Done at i = 4 test.v(11): INFO: Got a for-generate here test.v(11): INFO: Starting at j = 0 test.v(11): INFO: Genvar j = 0 test.v(11): INFO: Genvar j = 1 test.v(11): INFO: Genvar j = 2 test.v(11): INFO: Genvar j = 3 test.v(11): INFO: Done at j = 4 test.v(25): INFO: Checking module 'test2' test.v(23): INFO: Got a for-generate here test.v(23): INFO: Starting at i = 0 test.v(23): INFO: Done at i = 0 test.v(22): INFO: Got a for-generate here test.v(22): INFO: Starting at j = 0 test.v(22): INFO: Done at j = 0 $