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

From Verific Design Automation FAQ
Jump to: navigation, search
(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...")
(No difference)

Revision as of 14:13, 2 September 2025

>>> 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
$