Difference between revisions of "Evaluate 'for-generate' loop"
From Verific Design Automation FAQ
(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...") |
(No difference)
|
Latest revision as of 14:32, 17 November 2022
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 $