Difference between revisions of "How to evaluate a Verilog expression"

From Verific Design Automation FAQ
Jump to: navigation, search
Line 110: Line 110:
 
  </nowiki>
 
  </nowiki>
  
If an element in the expression crosses module boundaries, elaboration needs to be run as in the example below:
+
If an element in the expression to be evaluated crosses module boundaries, elaboration needs to be run as in the Verilog testcase below ('my_int' is to be evaluated):
 
+
Verilog testcase:
+
  
 
  <nowiki>
 
  <nowiki>
Line 121: Line 119:
 
module test();
 
module test();
 
     ifc #(.N(13)) I();
 
     ifc #(.N(13)) I();
     int my_int = $bits(I.data);
+
     int my_int = $bits(I.data); // want to evaluated 'my_int' or '$bits(I.data)'
 
endmodule
 
endmodule
 
  </nowiki>
 
  </nowiki>
Line 189: Line 187:
 
Reference: https://www.verific.com/docs/index.php?title=Hierarchy_Tree
 
Reference: https://www.verific.com/docs/index.php?title=Hierarchy_Tree
  
The C++ example below uses hierarchy-tree elaboration:
+
The C++ example below uses hierarchy-tree elaboration instead of static elaboration:
  
 
C++:
 
C++:

Revision as of 13:44, 3 September 2025

Evaluating a Verilog expression requires 'Static Elaboration' or 'Hierarchy Tree' feature.

In the example below, a, b, and c are declared in the Verilog module. There is no need to run static elaboration on the whole module. But 'Static Elaboration' feature is still required because the API VeriExpression::StaticEvaluate() is available only with 'Static Elaboration' feature.

C++:

#include "veri_file.h"
#include "VeriExpression.h"
#include "VeriModule.h"
#include "VeriBaseValue_Stat.h"

#include "Strings.h"
#include "Array.h"
#include "Map.h"

#ifdef VERIFIC_NAMESPACE
using namespace Verific ;
#endif

int main(int argc, const char **argv)
{
    const char *file_name = (argc > 1) ? argv[1] : "test.v" ;
    const char *module_name = (argc > 2) ? argv[2] : "test_module" ;

    Array files(1) ;
    files.Insert(file_name) ;
    if (!veri_file::AnalyzeMultipleFiles(&files, veri_file::SYSTEM_VERILOG)) return 1 ; 

    const VeriModule *mod = veri_file::GetModule(module_name) ;
    if (!mod) return 2 ; 

    // Apply following known values to evaluate "a[b] + c": 
    //   a = {1'b1, 1'b1}
    //   b = 2'b00
    //   c = 2'b01  

    const char *expr_string = "a[b] + c" ;
    Map known_values(STRING_HASH) ;
    (void) known_values.Insert("a", "{1'b1, 1'b1}") ;
    (void) known_values.Insert("b", "2'b00") ;
    (void) known_values.Insert("c", "2'b01") ;

    ValueTable df ;

    MapIter mi ;
    const char *id_name ;
    const char *val_str ;
    FOREACH_MAP_ITEM(&known_values, mi, &id_name, &val_str) {
        if (!id_name || !val_str) continue ;

        // Find the identifier:
        VeriIdDef *id = mod->FindDeclared(id_name) ;
        if (!id) return 3 ; 

        // Create the expression:
        VeriExpression *expr = veri_file::AnalyzeExpr(val_str, veri_file::SYSTEM_VERILOG) ;
        if (!expr) return 4 ;

        // Evaluate the expression:
        // If this is a literal expression, we do not need the value value or Resolve() call or else we need both:
        VeriBaseValue *val = expr->StaticEvaluate(0 /* self context */, 0 /* value table */) ;
        delete expr ;
        if (!val) return 5 ; 

        // Insert into the table to be used later:
        if (!df.Insert(id, val)) {
            delete val ;
            return 6 ;
        }
    }

    // Now create the expression for to be evaluated:
    VeriExpression *expr = veri_file::AnalyzeExpr(expr_string, veri_file::SYSTEM_VERILOG) ;
    if (!expr) return 7 ;

    // Resolve the expression so that the id-refs are resolved:
    expr->Resolve(mod->GetScope(), VeriTreeNode::VERI_UNDEF_ENV) ;

    VeriBaseValue *val = expr->StaticEvaluate(0 /* self context */, &df /* use this table with the known values */) ;
    delete expr ;
    if (!val) return 8 ; // Failed to evaluate

    char *image = val->Image() ;
    int result = val->GetIntegerValue() ;
    mod->Info("Evaluated value: %s (%d)", ((image)?image:""), result) ;
    Strings::free(image) ;
    delete val ;

    return 0 ;
}
 

Verilog testcase:

module test_module;
    wire a [1:0];
    wire [1:0] b;
    wire [1:0] c;
endmodule
 

Run:

$ test-linux 
-- Analyzing Verilog file 'test.v' (VERI-1482)
test.v(5): INFO: Evaluated value: 2'b10 (2)
$ 
 

If an element in the expression to be evaluated crosses module boundaries, elaboration needs to be run as in the Verilog testcase below ('my_int' is to be evaluated):

interface ifc #(int N=10);
    logic [N-1:0] data;
endinterface
 
module test();
    ifc #(.N(13)) I();
    int my_int = $bits(I.data); // want to evaluated 'my_int' or '$bits(I.data)'
endmodule
 

The C++ example below calls static elaboration:

#include "veri_file.h"
#include "VeriModule.h"
#include "VeriVisitor.h"
#include "VeriExpression.h"

#ifdef VERIFIC_NAMESPACE
using namespace Verific ;
#endif

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

    virtual void VERI_VISIT(VeriExpression, node)
    {
        char *str = node.GetPrettyPrintedString() ;
        VeriExpression *new_exp = node.StaticEvaluateToExpr(0,0,0);
        if (new_exp) {
            char *str2 = new_exp->GetPrettyPrintedString() ;
            node.Info("    Expression: '%s', evaluated to '%s'", str, str2) ;
            Strings::free(str) ;
            Strings::free(str2) ;
        }
    }
} ;

int main (int argc, char **argv)
{
    const char *file_name = "test.sv" ; // defaulf input filename
    if (argc > 1) file_name = argv[1] ; // Set the file name as specified by the user
    if (!veri_file::Analyze(file_name, veri_file::SYSTEM_VERILOG)) return 1 ;

    if (!veri_file::ElaborateAllStatic()) return 1 ;

    MyVisitor mv ;

    VeriModule *mod = veri_file::GetModule("test") ;
    if (!mod) return 2 ;
    mod->Info("In module '%s'", mod->Name()) ;
    mod->Accept(mv) ;
    return 0 ;
}
 

Run:

$ test-linux 
-- Analyzing Verilog file 'test.sv' (VERI-1482)
test.sv(5): INFO: compiling module 'test' (VERI-1018)
test.sv(8): INFO: In module 'test'
test.sv(7): INFO:     Expression: 'int ', evaluated to 'int '
test.sv(7): INFO:     Expression: '$bits(I.data)', evaluated to '13'
$ 
 

If for some reason static elaboration is not desirable (it does take memory and CPU time), hierarchy-tree elaboration can be run instead. Hierarchy-tree elaboration takes much less memory anc CPU time than static elaborations does.

Reference: https://www.verific.com/docs/index.php?title=Hierarchy_Tree

The C++ example below uses hierarchy-tree elaboration instead of static elaboration:

C++:

#include "veri_file.h"
#include "VeriModule.h"
#include "VeriId.h"
#include "VeriExpression.h"
#include "VeriBaseValue_Stat.h"
#include "hier_tree.h"
#include "HierTreeNode.h"

#ifdef VERIFIC_NAMESPACE
using namespace Verific ;
#endif

int main(int argc, const char **argv)
{
    const char *file_name = "test.sv" ;
    const char *top_name = "test" ;
    const char *my_name = "my_int" ;

    if (!veri_file::Analyze(file_name, veri_file::SYSTEM_VERILOG)) return 1 ;

    VeriModule *top = veri_file::GetModule(top_name) ;
    if (!top) return 2 ;

    VeriIdDef *my_id = top->FindDeclared(my_name) ;
    if (!my_id) return 3 ;

    VeriExpression *init_val = my_id->GetInitialValue() ;
    if (!init_val) return 4 ;

    Array top_mods(1) ;
    top_mods.Insert(top) ;

    const Map *top_nodes = hier_tree::CreateHierarchicalTree(&top_mods, 0, 0, 0) ;
    if (!top_nodes) return 5 ;

    HierTreeNode *top_node = (HierTreeNode *)top_nodes->GetValue(top_name) ;
    if (!top_node) {
        hier_tree::DeleteHierarchicalTree() ;
        return 6 ;
    }

    InterfaceInfo *info = top_node->GetParamValue(my_id) ;
    VeriBaseValue *val = 0 ;
    VeriBaseValue *delete_val = 0 ;
    if (info) {
        // We already have the value evaluated, get from node:
        val = info->GetVeriEvaluatedValue() ;
    } else {
        // Need to evaluate the value, use the context from the node:
        Map *context = top_node->PushContext() ;
        hier_tree::PushNode(top_node) ;

        val = init_val->StaticEvaluate(0, 0, 0, 0) ;
        delete_val = val ;

        hier_tree::PopNode() ;
        top_node->PopContext(context) ;
    }

    char *val_img = (val) ? val->Image() : 0 ;
    init_val->Info("%s(%s) evaluated to %s", my_name, my_id->GetPrettyPrintedString(), ((val_img)?val_img:"<NULL>")) ;
    Strings::free(val_img) ;

    delete delete_val ;

    hier_tree::DeleteHierarchicalTree() ;

    return 0 ;
}
 

Run:

$ test-linux 
-- Analyzing Verilog file 'test.sv' (VERI-1482)
test.sv(7): INFO: my_int(my_int = $bits(I.data)) evaluated to 13
$