Difference between revisions of "How to evaluate a Verilog expression"
| (3 intermediate revisions by 2 users not shown) | |||
| Line 1: | Line 1: | ||
Evaluating a Verilog expression requires 'Static Elaboration' or 'Hierarchy Tree' feature. | Evaluating a Verilog expression requires 'Static Elaboration' or 'Hierarchy Tree' feature. | ||
| + | |||
| + | |||
| + | == Static evaluate an expression not in the design == | ||
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. | 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. | ||
| Line 9: | Line 12: | ||
#include "VeriModule.h" | #include "VeriModule.h" | ||
#include "VeriBaseValue_Stat.h" | #include "VeriBaseValue_Stat.h" | ||
| + | #include "VeriId.h" | ||
#include "Strings.h" | #include "Strings.h" | ||
| Line 42: | Line 46: | ||
ValueTable df ; | ValueTable df ; | ||
| + | Map old_param_val(POINTER_HASH) ; | ||
| + | |||
MapIter mi ; | MapIter mi ; | ||
| Line 56: | Line 62: | ||
VeriExpression *expr = veri_file::AnalyzeExpr(val_str, veri_file::SYSTEM_VERILOG) ; | VeriExpression *expr = veri_file::AnalyzeExpr(val_str, veri_file::SYSTEM_VERILOG) ; | ||
if (!expr) return 4 ; | if (!expr) return 4 ; | ||
| + | |||
| + | if (id->IsParam()) { | ||
| + | // Param values are NOT taken from value-table, initial value is used: | ||
| + | old_param_val.Insert(id, id->TakeInitialValue()) ; // Store current value | ||
| + | (void) id->SetInitialValue(expr) ; // Absorbed | ||
| + | continue ; | ||
| + | } | ||
// Evaluate the expression: | // Evaluate the expression: | ||
| Line 79: | Line 92: | ||
VeriBaseValue *val = expr->StaticEvaluate(0 /* self context */, &df /* use this table with the known values */) ; | VeriBaseValue *val = expr->StaticEvaluate(0 /* self context */, &df /* use this table with the known values */) ; | ||
delete expr ; | delete expr ; | ||
| + | |||
| + | VeriIdDef *id ; | ||
| + | FOREACH_MAP_ITEM(&old_param_val, mi, &id, &expr) { | ||
| + | // Restore back old initial value: | ||
| + | (void) id->SetInitialValue(expr) ; // Old value deleted | ||
| + | } | ||
if (!val) return 8 ; // Failed to evaluate | if (!val) return 8 ; // Failed to evaluate | ||
| Line 89: | Line 108: | ||
return 0 ; | return 0 ; | ||
} | } | ||
| + | |||
</nowiki> | </nowiki> | ||
| Line 110: | Line 130: | ||
</nowiki> | </nowiki> | ||
| − | + | ||
| + | |||
| + | == Static evaluate a function call in the design and generate variables (genvar)== | ||
| + | |||
| + | Function calls are similar to other expressions, and you can evaluate them using StaticEvaluate(). | ||
| + | |||
| + | Giving a value to a generate variable is a little different. 'genvar' is treated like a parameter; we try to use the initial value instead of looking into the passed-in VeriValueTable. But since 'genvar' doesn't have a single value, we need to set it to a desired value before evaluating the expression. | ||
| + | |||
| + | In the example below, you can see how this can be done: | ||
| + | |||
| + | C++: | ||
| + | <nowiki> | ||
| + | #include "veri_file.h" | ||
| + | #include "VeriModule.h" | ||
| + | #include "VeriVisitor.h" | ||
| + | #include "VeriExpression.h" | ||
| + | #include "VeriId.h" | ||
| + | #include "VeriBaseValue_Stat.h" | ||
| + | #include "Map.h" | ||
| + | #include "Strings.h" | ||
| + | |||
| + | #ifdef VERIFIC_NAMESPACE | ||
| + | using namespace Verific ; | ||
| + | #endif | ||
| + | |||
| + | class MyVisitor : public VeriVisitor | ||
| + | { | ||
| + | public: | ||
| + | MyVisitor() : VeriVisitor() { } | ||
| + | virtual ~MyVisitor() { } | ||
| + | |||
| + | virtual void VERI_VISIT(VeriFunctionCall, node) | ||
| + | { | ||
| + | char *str = node.GetPrettyPrintedString() ; | ||
| + | node.Info("Got function call: %s", str) ; | ||
| + | |||
| + | ValueTable df ; | ||
| + | Map old_param_val(POINTER_HASH) ; | ||
| + | |||
| + | if (Strings::compare(str, "A(i)")) { | ||
| + | |||
| + | // Apply following known values to evaluate: | ||
| + | // i = 2 (or 2'b10) | ||
| + | |||
| + | Map known_values(STRING_HASH) ; | ||
| + | (void) known_values.Insert("i", "2'b10") ; | ||
| + | |||
| + | unsigned i ; | ||
| + | VeriExpression *expr ; | ||
| + | // Going through arguments of the function call | ||
| + | FOREACH_ARRAY_ITEM(node.GetArgs(), i, expr) { | ||
| + | if (!expr) continue ; | ||
| + | if (!expr->IsIdRef()) continue ; | ||
| + | |||
| + | // Find the identifier: | ||
| + | VeriIdDef *id = expr->GetId() ; | ||
| + | if (!id) return ; | ||
| + | |||
| + | // Get the value that we want to set for this id | ||
| + | const char *val_str = (const char *) known_values.GetValue(expr->GetName()) ; | ||
| + | |||
| + | // Create the expression: | ||
| + | VeriExpression *expr = veri_file::AnalyzeExpr(val_str, veri_file::SYSTEM_VERILOG) ; | ||
| + | if (!expr) return ; | ||
| + | |||
| + | if (id->IsParam()) { | ||
| + | // Param values are NOT taken from value-table, initial value is used: | ||
| + | old_param_val.Insert(id, id->TakeInitialValue()) ; // Store current value | ||
| + | (void) id->SetInitialValue(expr) ; // Absorbed | ||
| + | continue ; | ||
| + | } | ||
| + | |||
| + | // 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 ; | ||
| + | |||
| + | // Insert into the table to be used later: | ||
| + | if (!df.Insert(id, val)) { | ||
| + | delete val ; | ||
| + | return ; | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | VeriBaseValue *val = node.StaticEvaluate(0 /* self context */, &df /* use this table with the known values */) ; | ||
| + | |||
| + | MapIter mi ; | ||
| + | VeriIdDef *id ; | ||
| + | VeriExpression *expr ; | ||
| + | FOREACH_MAP_ITEM(&old_param_val, mi, &id, &expr) { | ||
| + | // Restore back old initial value: | ||
| + | (void) id->SetInitialValue(expr) ; // Old value deleted | ||
| + | } | ||
| + | |||
| + | if (!val) { | ||
| + | node.Info("Couldn't evaluate the expression"); | ||
| + | return ; // Failed to evaluate | ||
| + | } | ||
| + | |||
| + | char *image = val->Image() ; | ||
| + | int result = val->GetIntegerValue() ; | ||
| + | node.Info("Evaluated value: %s (%d)", ((image)?image:""), result) ; | ||
| + | Strings::free(image) ; | ||
| + | delete val ; | ||
| + | Strings::free(str) ; | ||
| + | } | ||
| + | } ; | ||
| + | |||
| + | int main (int argc, char **argv) | ||
| + | { | ||
| + | const char *file_name = "test.v" ; // default input filename | ||
| + | if (argc > 1) file_name = argv[1] ; // Set the file name as specified by the user | ||
| + | |||
| + | // veri_file::Analyze(const char *file_name, unsigned verilog_mode=VERILOG_2K, const char *lib_name="work", unsigned cu_mode=NO_MODE) ; | ||
| + | if (!veri_file::Analyze(file_name, veri_file::SYSTEM_VERILOG)) return 1 ; | ||
| + | |||
| + | //if (!veri_file::ElaborateAllStatic()) return 1 ; | ||
| + | |||
| + | MyVisitor mv ; | ||
| + | |||
| + | MapIter mi ; | ||
| + | VeriModule *mod ; | ||
| + | FOREACH_VERILOG_MODULE(mi, mod) if (mod) mod->Accept(mv) ; | ||
| + | |||
| + | return 0 ; | ||
| + | } | ||
| + | </nowiki> | ||
Verilog testcase: | Verilog testcase: | ||
| + | |||
| + | <nowiki> | ||
| + | module test(); | ||
| + | parameter d = 0; | ||
| + | endmodule | ||
| + | |||
| + | module top(); | ||
| + | parameter PARAM = 5; | ||
| + | |||
| + | function[3:0] A(input [2:0] c); | ||
| + | return (2 + c); | ||
| + | endfunction | ||
| + | |||
| + | test#(A(PARAM)) test_e(); | ||
| + | |||
| + | genvar i; | ||
| + | for(i = 0; i < 10; i = i + 1) begin | ||
| + | test#(A(i)) test_i(); | ||
| + | end | ||
| + | endmodule | ||
| + | </nowiki> | ||
| + | |||
| + | Run: | ||
| + | |||
| + | <nowiki> | ||
| + | $ ./test-linux | ||
| + | -- Analyzing Verilog file 'test.v' (VERI-1482) | ||
| + | test.v(12): INFO: Got function call: A(PARAM) | ||
| + | test.v(12): INFO: Evaluated value: 4'b0111 (7) | ||
| + | test.v(16): INFO: Got function call: A(i) | ||
| + | test.v(16): INFO: Evaluated value: 4'b0100 (4) | ||
| + | $ | ||
| + | </nowiki> | ||
| + | |||
| + | == Static evaluate an expression that crosses module boundaries == | ||
| + | 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): | ||
<nowiki> | <nowiki> | ||
| Line 121: | Line 305: | ||
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 185: | Line 369: | ||
</nowiki> | </nowiki> | ||
| + | == Using Hierarchy Tree Elaboration to evaluate == | ||
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. | 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 | 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++: | ||
Latest revision as of 20:53, 18 November 2025
Evaluating a Verilog expression requires 'Static Elaboration' or 'Hierarchy Tree' feature.
Contents
Static evaluate an expression not in the design
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 "VeriId.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 ;
Map old_param_val(POINTER_HASH) ;
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 ;
if (id->IsParam()) {
// Param values are NOT taken from value-table, initial value is used:
old_param_val.Insert(id, id->TakeInitialValue()) ; // Store current value
(void) id->SetInitialValue(expr) ; // Absorbed
continue ;
}
// 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 ;
VeriIdDef *id ;
FOREACH_MAP_ITEM(&old_param_val, mi, &id, &expr) {
// Restore back old initial value:
(void) id->SetInitialValue(expr) ; // Old value deleted
}
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) $
Static evaluate a function call in the design and generate variables (genvar)
Function calls are similar to other expressions, and you can evaluate them using StaticEvaluate().
Giving a value to a generate variable is a little different. 'genvar' is treated like a parameter; we try to use the initial value instead of looking into the passed-in VeriValueTable. But since 'genvar' doesn't have a single value, we need to set it to a desired value before evaluating the expression.
In the example below, you can see how this can be done:
C++:
#include "veri_file.h"
#include "VeriModule.h"
#include "VeriVisitor.h"
#include "VeriExpression.h"
#include "VeriId.h"
#include "VeriBaseValue_Stat.h"
#include "Map.h"
#include "Strings.h"
#ifdef VERIFIC_NAMESPACE
using namespace Verific ;
#endif
class MyVisitor : public VeriVisitor
{
public:
MyVisitor() : VeriVisitor() { }
virtual ~MyVisitor() { }
virtual void VERI_VISIT(VeriFunctionCall, node)
{
char *str = node.GetPrettyPrintedString() ;
node.Info("Got function call: %s", str) ;
ValueTable df ;
Map old_param_val(POINTER_HASH) ;
if (Strings::compare(str, "A(i)")) {
// Apply following known values to evaluate:
// i = 2 (or 2'b10)
Map known_values(STRING_HASH) ;
(void) known_values.Insert("i", "2'b10") ;
unsigned i ;
VeriExpression *expr ;
// Going through arguments of the function call
FOREACH_ARRAY_ITEM(node.GetArgs(), i, expr) {
if (!expr) continue ;
if (!expr->IsIdRef()) continue ;
// Find the identifier:
VeriIdDef *id = expr->GetId() ;
if (!id) return ;
// Get the value that we want to set for this id
const char *val_str = (const char *) known_values.GetValue(expr->GetName()) ;
// Create the expression:
VeriExpression *expr = veri_file::AnalyzeExpr(val_str, veri_file::SYSTEM_VERILOG) ;
if (!expr) return ;
if (id->IsParam()) {
// Param values are NOT taken from value-table, initial value is used:
old_param_val.Insert(id, id->TakeInitialValue()) ; // Store current value
(void) id->SetInitialValue(expr) ; // Absorbed
continue ;
}
// 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 ;
// Insert into the table to be used later:
if (!df.Insert(id, val)) {
delete val ;
return ;
}
}
}
VeriBaseValue *val = node.StaticEvaluate(0 /* self context */, &df /* use this table with the known values */) ;
MapIter mi ;
VeriIdDef *id ;
VeriExpression *expr ;
FOREACH_MAP_ITEM(&old_param_val, mi, &id, &expr) {
// Restore back old initial value:
(void) id->SetInitialValue(expr) ; // Old value deleted
}
if (!val) {
node.Info("Couldn't evaluate the expression");
return ; // Failed to evaluate
}
char *image = val->Image() ;
int result = val->GetIntegerValue() ;
node.Info("Evaluated value: %s (%d)", ((image)?image:""), result) ;
Strings::free(image) ;
delete val ;
Strings::free(str) ;
}
} ;
int main (int argc, char **argv)
{
const char *file_name = "test.v" ; // default input filename
if (argc > 1) file_name = argv[1] ; // Set the file name as specified by the user
// veri_file::Analyze(const char *file_name, unsigned verilog_mode=VERILOG_2K, const char *lib_name="work", unsigned cu_mode=NO_MODE) ;
if (!veri_file::Analyze(file_name, veri_file::SYSTEM_VERILOG)) return 1 ;
//if (!veri_file::ElaborateAllStatic()) return 1 ;
MyVisitor mv ;
MapIter mi ;
VeriModule *mod ;
FOREACH_VERILOG_MODULE(mi, mod) if (mod) mod->Accept(mv) ;
return 0 ;
}
Verilog testcase:
module test();
parameter d = 0;
endmodule
module top();
parameter PARAM = 5;
function[3:0] A(input [2:0] c);
return (2 + c);
endfunction
test#(A(PARAM)) test_e();
genvar i;
for(i = 0; i < 10; i = i + 1) begin
test#(A(i)) test_i();
end
endmodule
Run:
$ ./test-linux -- Analyzing Verilog file 'test.v' (VERI-1482) test.v(12): INFO: Got function call: A(PARAM) test.v(12): INFO: Evaluated value: 4'b0111 (7) test.v(16): INFO: Got function call: A(i) test.v(16): INFO: Evaluated value: 4'b0100 (4) $
Static evaluate an expression that crosses module boundaries
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' $
Using Hierarchy Tree Elaboration to evaluate
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 $