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...")

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

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
$