How to evaluate a VHDL expression
From Verific Design Automation FAQ
Revision as of 14:13, 2 September 2025 by Hoa (Talk | contribs) (Created page with "'''>>> This page is under construction <<<''' Unlike in Verilog, expression evaluation in VHDL is fairly involved and needs all of the following: * Either static elaborated...")
>>> This page is under construction <<<
Unlike in Verilog, expression evaluation in VHDL is fairly involved and needs all of the following:
- Either static elaborated tree or context from correct HierTreeNode pushed into the parse tree.
- VhdlNode::_present_scope set to the container scope where the expression is defined or to be used.
- Expression evaluation method set to static elaboration with VhdlNode::SetStaticElab().
- Constant pwr/gnd/x/z nets set with VhdlNode::SetConstNets(). Constant nets also need to be deleted to avoid memory leaks, but should only be done after the evaluated value (that is using those nets) is deleted.
C++ example 1:
#include "vhdl_file.h"
#include "VhdlUnits.h"
#include "VhdlIdDef.h"
#include "VhdlExpression.h"
#include "VhdlValue_Elab.h"
#include "VhdlDataFlow_Elab.h"
#include "Strings.h"
#include "Map.h"
#ifdef VERIFIC_NAMESPACE
using namespace Verific ;
#endif
// Restore back to the previous setting:
#define RETURN(N) { \
if (!static_elab) VhdlNode::SetRtlElab() ; \
VhdlNode::_present_scope = save_scope ; \
VhdlNode::ResetConstNets() ; \
return N ; \
}
int main(int argc, const char **argv)
{
const char *file_name = (argc > 1) ? argv[1] : "test.vhd" ;
const char *entity_name = (argc > 2) ? argv[2] : "test_entity" ;
const char *arch_name = (argc > 2) ? argv[2] : "test_arch" ;
const char *expr_string = "a(b) + c" ;
const char *lib_name = "work" ;
if (!vhdl_file::SetDefaultLibraryPath("../vdbs")) return 1 ;
if (!vhdl_file::Analyze(file_name)) return 2 ;
// Step (0): Need to have the parse tree static elaborated already:
if (!vhdl_file::Elaborate(entity_name, lib_name, arch_name, 0 /* generics */, 1 /* static elab */)) return 3 ;
const VhdlLibrary *work = vhdl_file::GetLibrary(lib_name) ;
if (!work) return 4 ;
const VhdlPrimaryUnit *ent = work->GetPrimUnit(entity_name) ;
if (!ent) return 5 ;
const VhdlSecondaryUnit *arch = ent->GetSecondaryUnit(arch_name) ;
if (!arch) return 6 ;
VhdlScope *arch_scope = arch->LocalScope() ;
if (!arch_scope) return 7 ;
// Step (1): Need to set _present_scope:
VhdlScope *save_scope = VhdlNode::_present_scope ;
VhdlNode::_present_scope = arch_scope ;
// Step (2): Need to set constant _pwr, _gnd, _x, _z nets:
VhdlNode::SetConstNets() ;
// Step (3): Need to set evaluation flow to use static elaboration:
unsigned static_elab = VhdlNode::IsStaticElab() ;
if (!static_elab) VhdlNode::SetStaticElab() ;
// Apply following known values to evaluate "a(b) + c":
// a = (2, 3)
// b = 0
// c = 1
Map known_values(STRING_HASH) ;
(void) known_values.Insert("a", "(2, 3)") ;
(void) known_values.Insert("b", "0") ;
(void) known_values.Insert("c", "1") ;
// Create a data-flow and set it to be in the "initial" phase
// and in subprograms, so that static elab uses the values from there:
VhdlDataFlow df(0) ;
df.SetInInitial() ;
df.SetInSubprogramOrProcess() ;
// The known values need to be in the condition-id-value Map to be picked up:
Map *id_value_map = new Map(POINTER_HASH, known_values.Size()) ;
df.SetConditionIdValueMap(id_value_map) ;
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:
VhdlIdDef *id = arch->FindDeclared(id_name) ;
if (!id) RETURN(8) ;
// Create the expression:
VhdlExpression *expr = vhdl_file::AnalyzeExpr(val_str) ;
if (!expr) RETURN(9) ;
// Resolve the expression so that the id-refs are resolved:
(void) expr->TypeInfer(id->Type() /* expected type */, 0 /* return types */, 0 /* environment */, arch_scope) ;
// Evaluate the expression:
// If this is a literal expression, we do not need the value value or Resolve() call or else we need both:
VhdlConstraint *constraint = id->Constraint() ;
VhdlValue *val = expr->Evaluate(constraint, 0 /* DataFlow */, 0) ;
delete expr ;
if (!val) RETURN(10) ;
// Insert into the table to be used later:
//df.SetAssignValue(id, val) ; // This only works for variables and not for signals
(void) id_value_map->Insert(id, val) ;
}
// Now create the expression for to be evaluated:
VhdlExpression *expr = vhdl_file::AnalyzeExpr(expr_string) ;
if (!expr) RETURN(11) ;
// Resolve the expression (in self-context) so that the id-refs are resolved:
// NOTE: May need to have the context (target) type for resolving context dependent expressions:
VhdlIdDef *target_type = expr->TypeInfer(0 /* expected type */, 0 /* return types */, 0 /* environment */, arch_scope) ;
if (!target_type) RETURN(12) ;
// Evaluate the expression with the proper target type:
VhdlValue *val = expr->Evaluate(target_type->Constraint(), &df /* use this table with the known values */, 0) ;
delete expr ;
if (!val) RETURN(13) ; // Failed to evaluate
// Show the result:
char *image = val->Image() ;
verific_int64 result = val->Integer() ;
arch->Info("Evaluated value: %s (%d)", ((image)?image:""), result) ;
Strings::free(image) ;
// Can create constant expression node so that the value can be deleted and ResetConstNets() can safely be called:
expr = val->CreateConstantVhdlExpression(0, target_type, 0) ;
delete val ;
if (!expr) RETURN(14) ;
// Show the expression node:
image = expr->GetPrettyPrintedString() ;
arch->Info("Converted expression: %s", image) ;
Strings::free(image) ;
delete expr ;
RETURN(0) ;
}
VHDL testcase:
library ieee ;
use ieee.std_logic_1164.all ;
entity test_entity is
end ;
architecture test_arch of test_entity is
type int_array is array (1 downto 0) of integer ;
signal a : int_array ;
signal b : integer ;
signal c : integer ;
begin
end ;
Run:
$ test-linux INFO: default VHDL library search path is now "/mnt/awing5_customers/Verific/extra_tests/vdbs" (VHDL-1504) -- Analyzing VHDL file 'test.vhd' (VHDL-1481) -- Restoring VHDL unit 'ieee.std_logic_1164' from file '/mnt/awing5_customers/Verific/extra_tests/vdbs/ieee/std_logic_1164.vdb' (VHDL-1493) -- Restoring VHDL unit 'std.standard' from file '/mnt/awing5_customers/Verific/extra_tests/vdbs/std/standard.vdb' (VHDL-1493) test.vhd(3): INFO: analyzing entity 'test_entity' (VHDL-1012) test.vhd(6): INFO: analyzing architecture 'test_arch' (VHDL-1010) test.vhd(3): INFO: processing 'test_entity(test_arch)' (VHDL-1067) test.vhd(12): INFO: Evaluated value: 4 (4) test.vhd(12): INFO: Converted expression: 4 $