Resolve constant expressions, parameter values, and datatypes.
In the previous version of VL, we used to do a series of transforms that:
(We'll refer to these three kinds of transformations collectively as "elaboration;" commercial implementations use that term to mean something somewhat similar.)
The problem with this series of transformations is that there may be complicated relationships among functions, parameters, and datatypes -- a function, parameter, or datatype definition may use functions, parameters, and datatypes. Consider the following sequence of declarations:
function integer f1 (logic a); f1 = a ? 3 : 5; endfunction parameter p1 = f1(1); typedef logic [p1-1:0] t1; function t1 f2 (integer b); f2 = ~b; endfunction parameter t1 p2 = f2(p1);
From the example we can see that it won't suffice to use our three transformations once each in any order. One solution might be to try the tranformations repeatedly in a cycle. Our solution is instead to allow parameters, functions, and types to be resolved as needed while resolving other parameters, functions, and types. We use a lookup table to store previously resolved items as a form of memoization.
The lookup table in which we store these values is called an elabindex.
The elaboration algorithm calls subsidiary algorithms of vl-expr-svex-translation, which use the elabindex lookup tables in a read-only manner. Before translating an expression (or, similarly, function declaration) to svex, the elaboration algorithm walks over the expression and collects the information it needs to successfully resolve it to an svex expression: the types, svex translations, and port lists of functions that the expression calls, and types and values of parameters referenced in the expression. This information is stored in the elabindex before translating the expression.