Multiple VHDL packages with constant having same name, how to select the correct constant? - vhdl

I use a TCL script to generate a VHDL pkg for each submodule repository that stores the compilation date time and git hash of the submodule. The constant storing 32 bit git hash is called MAIN_GIT_HASH and is an std_logic_vector.
I now have multiple packages that all contain a constant called MAIN_GIT_HASH and I need to include them into the same source file using the VHDL "use" directive. Now the question is, what is the correct way to select the correct constant from each package since just writing "MAIN_GIT_HASH" will be ambigious?

Each of the packages either needs to have a unique name or needs to be analyzed into a separate library.
If you use separate libraries, you simply reference it using a package path:
library Submodule1 ;
use Submodule1.HashPkg.MAIN_GIT_HASH ; -- just get the relevant constant
Should a design need to reference more than one HashPkg (like your use case), then you can reference the constant with the same notation as above:
HashReg <= Submodule1.HashPkg.MAIN_GIT_HASH ;
If you use unique named packages, then they could all be put into the same library. Assuming that that library is the same as the one into which you are compiling the current design unit, then you can reference it as being in work:
use work.Submodule1HashPkg.MAIN_GIT_HASH ;
. . .
HashReg <= work.Submodule1HashPkg.MAIN_GIT_HASH ;

Use selected names.
The cause:
IEEE Std 1076-2008
12.4 Use clauses
In order to determine which declarations are made directly visible at a given place by use clauses, consider the set of declarations identified by all use clauses whose scopes enclose this place. Any declaration in this set is a potentially visible declaration. A potentially visible declaration is actually made directly visible except in the following three cases:
a) A potentially visible declaration is not made directly visible if the place considered is within the immediate scope of a homograph of the declaration.
b) If two potentially visible declarations are homographs and one is explicitly declared and the other is implicitly declared, then the implicit declaration is not made directly visible.
c) Potentially visible declarations that have the same designator and that are not covered by case b) are not made directly visible unless each of them is either an enumeration literal specification or the declaration of a subprogram.
12.3 Visibility
...Each of two declarations is said to be a homograph of the other if and only if both declarations have the same designator, and they denote different named entities, and either overloading is allowed for at most one of the two, or overloading is allowed for both declarations and they have the same parameter and result type profile (see 4.5.1).
12.5 The context of overload resolution
12.5 The context of overload resolution
Overloading is defined for names, subprograms, and enumeration literals.
Your constant declarations are not homographs, not enumeration literals nor declarations of subprograms. None of the multiple declarations of constants with the same name would be directly visible.
4.7 Package declarations
Items declared immediately within a simple or a generic-mapped package declaration become visible by selection within a given design unit wherever the name of that package is visible in the given unit. Such items may also be made directly visible by an appropriate use clause (see 12.4). Items declared immediately within an uninstantiated package declaration cannot be made visible outside of the package.
The cure:
back to 12.3:
Visibility is either by selection or direct. A declaration is visible by selection at places that are defined as follows:
...
f) For a declaration given in a package declaration, other than in a package declaration that defines an uninstantiated package: at the place of the suffix in a selected name whose prefix denotes the package.
...
8.3 Selected names
A selected name is used to denote a named entity whose declaration appears either within the declaration of another named entity or within a design library.
selected_name ::= prefix . suffix
suffix ::=
      simple_name
    | character_literal
    | operator_symbol
    | all
A selected name can denote an element of a record, an object designated by an access value, or a named entity whose declaration is contained within another named entity, particularly within a library, a package, or a protected type. Furthermore, a selected name can denote all named entities whose declarations are contained within a library or a package.
If we peruse 8. Names, 8.1 General we find that a prefix can be a name, including a selected name.
A code example:
library ieee;
use ieee.std_logic_1164.all;
package pkg1 is
constant MAIN_GIT_HASH: std_logic_vector := x"ffffffff";
end pkg1;
library ieee;
use ieee.std_logic_1164.all;
package pkg2 is
constant MAIN_GIT_HASH: std_logic_vector := x"00000000";
end pkg2;
library ieee;
use ieee.std_logic_1164.all;
use work.pkg1.all;
use work.pkg2.all;
entity foo is
end entity;
architecture fum of foo is
function to_string (inp: std_logic_vector) return string is -- before -2008
variable image_str: string (1 to inp'length);
alias input_str: std_logic_vector (1 to inp'length) is inp;
begin
for i in input_str'range loop
image_str(i) := character'VALUE(std_ulogic'IMAGE(input_str(i)));
end loop;
return image_str;
end function;
begin
process
begin
report LF & HT & " MAIN_GIT_HASH = " & to_string(work.MAIN_GIT_HASH);
report LF & HT & "pkg1 MAIN_GIT_HASH = "
& to_string(work.pkg1.MAIN_GIT_HASH);
report LF & HT & "pkg2 MAIN_GIT_HASH = "
& to_string(work.pkg2.MAIN_GIT_HASH);
wait;
end process;
end architecture;
where
ghdl:error: compilation error
%: ghdl -a multiple_packages.vhdl
multiple_packages.vhdl:37:63:error: unit "main_git_hash" not found in library "work"
report LF & HT & " MAIN_GIT_HASH = " & to_string(work.MAIN_GIT_HASH);
^
ghdl:error: compilation error
%:
ghdl isn't very descriptive (doesn't track visibility in it's name look up to tell us why it isn't visible) while Modelsim may be more expressive, something along the lines of:
Error (10621): VHDL Use Clause error at multiple_packages.vhdl(37): more than one Use Clause imports a declaration of simple name "MAIN_GIT_HASH"
This error shows up a lot where users provide use clauses for both IEEE package numeric_std and Synopsys package std_logic_arith.
Commenting out line 37 we can demonstrate the use of selected names where direct visibility is not available:
ghdl:error: compilation error
%: ghdl -a multiple_packages.vhdl
%: ghdl -e foo
%: ghdl -r foo
multiple_packages.vhdl:38:9:#0ms:(report note):
pkg1 MAIN_GIT_HASH = 11111111111111111111111111111111
multiple_packages.vhdl:40:9:#0ms:(report note):
pkg2 MAIN_GIT_HASH = 00000000000000000000000000000000
%:
Note with a use work.all; making the package names visible the selected name prefixes could be simple_names instead of themselves being selected names.

Related

How to create an VHDL-2008 alias to a signal in an hierarchy created by for-generate?

I have an hierarchy created by a for-generate like this:
INST: for ... generate
. . .
end generate;
It creates many instances, as expected, named as INST__0, INST__1, etc, which names have a double underscore on it.
When I try to create an alias to a signal A in this hierarchy I got an error like "Invalid literal" because the path to the signal has double underscores, which is indeed invalid in VHDL:
alias A is <<signal DUT.INST__0.COUNTER.A: std_logic>>;
Is there any way to solve this problem? Prevent for-generate using double underscores, maybe?
Thanks
You do not provide a reproducible or complete example nor demonstrate the syntax location of your alias declaration. Particular note the lack of a the loop parameter which your attempt alludes to include values 0 and 1.
See IEEE Std 1076-2008 8.7 External names
pathname_element ::=
      entity_simple_name
    | component_instantiation_label
    | block_label
    | generate_statement_label [ ( static_expression ) ]
    | package_simple_name
and the accompanying semantic description of the the static expression:
b)Second, for each package simple name in a package pathname, or for each pathname element in an absolute or relative pathname, in order, the previously identified declarative region is replaced as the identified declarative region by one of the following:
...
5)For a generate statement label, the declarative region of the equivalent block corresponding to the generate statement. If the generate statement is a for generate statement, the pathname element shall include a static expression, the type of the expression shall be the same as the type of the generate parameter, and the value of the expression shall belong to the discrete range specified for the generate parameter. The type of the expression shall be determined by applying the rules of 12.5 to the expression considered as a complete context, using the rule that the type shall be discrete. If the type of the expression is universal_integer and the type of the generate parameter is an integer type, an implicit conversion of the expression to the type of the generate parameter is assumed.
We see that the static expression included in parentheses following the generate statement label is a value of the loop parameter.
A -2008 example that can be analyzed, elaborated and simulated:
entity for_gen_label is
end entity;
architecture fum of for_gen_label is
begin
INST:
for i in 0 to 3 generate
COUNTER:
block
signal a: boolean;
begin
PROC_LABEL:
process
begin
report a'INSTANCE_NAME;
wait;
end process;
end block;
end generate;
end architecture;
where we also see that the -2008 predefined attribute 'INSTANCE_NAME can also demonstrate path name elements (GHDL):
for_gen_label.vhdl:16:17:#0ms:(report note): :for_gen_label(fum):inst(0):counter:a
for_gen_label.vhdl:16:17:#0ms:(report note): :for_gen_label(fum):inst(1):counter:a
for_gen_label.vhdl:16:17:#0ms:(report note): :for_gen_label(fum):inst(2):counter:a
for_gen_label.vhdl:16:17:#0ms:(report note): :for_gen_label(fum):inst(3):counter:a
The format of the 'INSTANCE_NAME predefined attribute value is given in 16.2.5 Predefined attributes of named entities.
The two underscores is a C(++) affectation for names which indicates you're probably getting information from the user interface of a simulator capable of supporting multiple hardware description languages. GHDL, a batch simulator supporting only VHDL produces output that adheres to VHDL path name elements:
ghdl -r for_gen_label --disp-signals-map
.for_gen_label(fum).inst(0).counter.a: 00007FBDBD504700 net: 0
.for_gen_label(fum).inst(1).counter.a: 00007FBDBD5047A0 net: 0
.for_gen_label(fum).inst(2).counter.a: 00007FBDBD504840 net: 0
.for_gen_label(fum).inst(3).counter.a: 00007FBDBD5048E0 net: 0
...
while incidentally demonstrating the entire path. VHDL unlike some other HDL's is not identifier case sensitive.
I would try an extended identifier. I would try both of the following, but I suspect the first one will get you there (and the second one not):
alias A is <<signal DUT.\INST__0\.COUNTER.A : std_logic>>;
and
alias A is <<signal \DUT.INST__0.COUNTER.A\ : std_logic>>;
I am concerned though the second one would be seen as a single identifier.

no function declarations for operator

I get this error message:
testbench.vhd:16:22: no function declarations for operator "+"
at this line:
Z <= unsigned(X) + resize(unsigned(Y),X'length);
with this code:
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity MCVE is
end entity MCVE;
architecture MCVE of MCVE is
signal X, Z : std_logic_vector(15 downto 0);
signal Y : std_logic_vector(7 downto 0);
begin
process
begin
Z <= unsigned(X) + resize(unsigned(Y),X'length);
end process;
end architecture MCVE;
https://www.edaplayground.com/x/2LBg
I don't understand why.
The error message is pretty clear. There is no function declarations for operator "+" which can add two unsigneds together and return a std_logic_vector. In the package numeric_std, there is however an opertor "+" which can add two unsigneds together and return an unsigned.
So, if you add another type conversion to convert the result of the addition back to a std_logic_vector the compiler can choose the version of the "+" operator that returns an unsigned.
Z <= std_logic_vector(unsigned(X) + unsigned(Y));
Overloading only works if there is exactly one fit for function, procedure or operator. If there is less than one, then there is no version for the compiler to choose; if there is more than one, the compiler doesn't know which one to choose and there is an ambiguity which needs to be sorted out.
Actually, you don't need to resize Y: the "+" operator is happy as long as one of the operands is the same width as the result.
https://www.edaplayground.com/x/4VJE
While Giwrgos Rizeakos original question was on resizing, there's a long history of questions and answers on operator and function overload visibility (there no function declaration visible here for operator "+").
After a search through those questions and answers this answer attempts to provide a question and answer pair that can be used to eliminated future duplicate questions based on providing authoritative references in an explanatory flow.
The problem starts with visibility:
12.3 Visibility
The meaning of the occurrence of an identifier at a given place in the text is defined by the visibility rules and also, in the case of overloaded declarations, by the overloading rules. The identifiers considered in this subclause include any identifier other than a reserved word or an attribute designator that denotes a predefined attribute. The places considered in this subclause are those where a lexical element (such as an identifier) occurs. The overloaded declarations considered in this subclause are those for subprograms and enumeration literals.
For each identifier and at each place in the text, the visibility rules determine a set of declarations (with this identifier) that define the possible meanings of an occurrence of the identifier. A declaration is said to be visible at a given place in the text when, according to the visibility rules, the declaration defines a possible meaning of this occurrence. The following two cases arise in determining the meaning of such a declaration:
— The visibility rules determine at most one possible meaning. In such a case, the visibility rules are sufficient to determine the declaration defining the meaning of the occurrence of the identifier, or in the absence of such a declaration, to determine that the occurrence is not legal at the given point.
— The visibility rules determine more than one possible meaning. In such a case, the occurrence of the identifier is legal at this point if and only if exactly one visible declaration is acceptable for the overloading rules in the given context or all visible declarations denote the same named entity.
It involves overloaded subprograms:
4.5.2 Operator overloading
The declaration of a function whose designator is an operator symbol is used to overload an operator. The sequence of characters of the operator symbol shall be one of the operators in the operator classes defined in 9.2.
The subprogram specification of a unary operator shall have a single parameter, unless the subprogram specification is a method (see 5.6.2) of a protected type. In this latter case, the subprogram specification shall have no parameters. The subprogram specification of a binary operator shall have two parameters, unless the subprogram specification is a method of a protected type, in which case, the subprogram specification shall have a single parameter. If the subprogram specification of a binary operator has two parameters, for each use of this operator, the first parameter is associated with the left operand, and the second parameter is associated with the right operand.
Operator overloads are defined as subprograms and use subprogram overloading rules:
4.5 Subprogram overloading
4.5.1 General
Two formal parameter lists are said to have the same parameter type profile if and only if they have the same number of parameters, and if at each parameter position the corresponding parameters have the same base type. Two subprograms are said to have the same parameter and result type profile if and only if both have the same parameter type profile, and if either both are functions with the same result base type or neither of the two is a function.
As a segue subprograms can be described in terms of signatures as a shorthand:
4.5.3 Signatures
A signature distinguishes between overloaded subprograms and overloaded enumeration literals based on their parameter and result type profiles. A signature can be used in a subprogram instantiation declaration, attribute name, entity designator, or alias declaration.
signature ::= [ [ type_mark { , type_mark } ] [ return type_mark ] ]
(Note that the initial and terminal brackets are part of the syntax of signatures and do not indicate that the entire right-hand side of the production is optional.) A signature is said to match the parameter and the result type profile of a given subprogram if, and only if, all of the following conditions hold:
— The number of type marks prior to the reserved word return, if any, matches the number of formal parameters of the subprogram.
— At each parameter position, the base type denoted by the type mark of the signature is the same as the base type of the corresponding formal parameter of the subprogram.
— If the reserved word return is present, the subprogram is a function and the base type of the type mark following the reserved word in the signature is the same as the base type of the return type of the function, or the reserved word return is absent and the subprogram is a procedure.
And here the example:
Z <= unsigned(X) + resize(unsigned(Y),X'length);
can be described in terms of a signature.
Z is declared as type std_logic_vector. The left operand to "+" is X which is subject type conversion to unsigned (rules given in 9.3.6, both array types, same element type). The right operand is the result of resize with a signature of [unsigned, natural, return unsigned] found in package numeric_std by overload resolution:
12.5 The context of overload resolution
Overloading is defined for names, subprograms, and enumeration literals.
...
When considering possible interpretations of a complete context, the only rules considered are the syntax rules, the scope and visibility rules, and the rules of the form as follows:
a) Any rule that requires a name or expression to have a certain type or to have the same type as another name or expression.
b) Any rule that requires the type of a name or expression to be a type of a certain class; similarly, any rule that requires a certain type to be a discrete, integer, floating-point, physical, universal, or character type.
...
e) The rules given for the resolution of overloaded subprogram calls; for the implicit conversions of universal expressions; for the interpretation of discrete ranges with bounds having a universal type; for the interpretation of an expanded name whose prefix denotes a subprogram; and for a subprogram named in a subprogram instantiation declaration to denote an uninstantiated subprogram.
...
And the function made visible through the use of use clause making the declarations in numeric_std visible:
12.4 Use clauses
A use clause achieves direct visibility of declarations that are visible by selection.
The same overload resolution is performed on the example where no function declaration is found. No function declaration is found for "+" [unsigned, unsigned return std_logic_vector] where the return value must match type std_logic_vector (the a) rule above).
And as Matthew Taylor points out you can alter the assignment right hand expression by type conversion to std_logic_vector:
Z <= std_logic_vector(unsigned(X) + resize(unsigned(Y),X'length));
And why the resize function call is not needed can authoritatively be shown by referencing the function declaration for "+" `[unsigned, unsigned return unsigned] found in IEEE package numeric_std, (found in numeric_std-body.vhdl, in the 1076-2008 downloads.zip which is part of the -2008 standard):
-- Id: A.3R
function "+" (L : UNRESOLVED_UNSIGNED; R : STD_ULOGIC)
return UNRESOLVED_UNSIGNED
is
variable XR : UNRESOLVED_UNSIGNED(L'length-1 downto 0) := (others => '0');
begin
XR(0) := R;
return (L + XR);
end function "+";
Interpreting that authoritatively requires the the declaration for unsigned in numeric_std.vhdl (also found in the same above zip file):
type UNRESOLVED_UNSIGNED is array (NATURAL range <>) of STD_ULOGIC;
subtype UNSIGNED is (resolved) UNRESOLVED_UNSIGNED;
which is a subtype of unresolved_unsigned providing an element resolution function name. Resolution functions are explained in the standard:
4.6 resolution functions
A resolution function is a function that defines how the values of multiple sources of a given signal are to be resolved into a single value for that signal. Resolution functions are associated with signals that require resolution by including the name of the resolution function in the declaration of the signal or in the declaration of the subtype of the signal. A signal with an associated resolution function is called a resolved signal (see 6.4.2.3).
and the subtype declaration syntax can require a resolution function be found:
6.3 Subtype declarations
subtype_declaration ::=
subtype identifier is subtype_indication ;
subtype_indication ::=
[ resolution_indication ] type_mark [ constraint ]
resolution_indication ::=
resolution_function_name | ( element_resolution )
element_resolution ::= array_element_resolution | record_resolution
and function resolved is found in the the std_logic_1164 package declaration (in the same above zip file, provided as part of the standard).
Resolution is a matter for simulation, see 14.7 Execution of a model, particularly 14.7.3 Propagation of signal values and it's sub-clauses where resolution is applied to signals.
(And about here you see why there can be a lot of incomplete answers that don't preclude future questions. Finding answers in the standard requires subject matter understanding and it's primary audiences are tool implementors and advanced users where VHDL syntax and semantics are defined concisely allowing it's use as a formal notation.)

Use a type before it's declared in VHDL (2008)

Is it possible in any version of VHDL, maybe in 2008, to use a type before it's declared?
E.g. I have this array declaration in the architecture of an entity:
type my_array is array (integer range <>) of my_type;
And still in the same architecture section, but later in the file I have this:
type my_type is record
my_field: signed(31 downto 0);
end record;
Now this gives the following error in Vivado:
[Synth 8-1031] my_type is not declared
The solution is of course to move the record declaration above the array declaration. However this gets very complicated and messy with the number of types increasing (since you basically have to topologically sort your types taking their dependencies into account).
Something like this is supported in every major programming language so I figured maybe it would also exist in VHDL. I also vaguely remember reading about this having been added to VHDL 2008 but can't find any resources about it and my quick test with VHDL 2008 was negative.
So is it possible to use a type in VHDL before its declared, given that the type is declared still in the same architecture, same file, but a few lines below?
Is it possible in any version of VHDL, maybe in 2008, to use a type before it's declared?
No.
IEEE Std 1076-2008 6. Declarations
6.1 General
The language defines several kinds of named entities that are declared explicitly or implicitly by declarations. Each entity’s name is defined by the declaration, either as an identifier or as an operator symbol or a character literal.
...
For each form of declaration, the language rules define a certain region of text called the scope of the declaration (see 12.2). ...
12.2 Scope of declarations
The scope of a declaration, except for an architecture body, extends from the beginning of the declaration to the end of the immediately closing declarative region; the scope of an architecture body extends from the beginning to the end of the architecture body. In either case, this part of the scope of a declaration is called the immediate scope.
12.3 Visibility
A declaration is visible only within a certain part of its scope; this part starts at the end of the declaration except in the declaration of a design unit other than a PSL verification unit, a package declaration, or a protected type declaration, in which case it starts immediately after the reserved word is occurring after the identifier of the design unit, a package declaration, or protected type declaration. This rule applies to both explicit and implicit declarations.
It's the visibility rules stopping you from referencing a type before it's declared.
Also VHDL does not support forward declaration of types other than interface type declarations (generic types), but does for subtypes as your example my_array shows.
The generic types Brian indicates usefulness is limited lacking synthesis vendor support as well as limitations on operations of a type (see 6.5.3 Interface type declarations) summarized in Peter Ashenden's book VHDL 2008 Just the New Stuff:
1.1 Generic Types
VHDL-2008 defines a number of rules covering formal generic types and the ways they can be used. The formal generic type name can potentially represent any constrained type, except a file type or a protected type. The entity can only assume that operations available for all such types are applicable, namely: assignment; allocation using new; type qualification and type conversion; and equality and inequality operations. The formal generic type cannot be used as the type of a file element or an attribute. Moreover, it can only be used as the type of an explicitly declared constant or a signal (including a port) if the actual type is not an access type and does not contain a subelement of an access type. For signals, the predefined equality operator of the actual type is used for driver update and event detection.
Note that for access types there is a special case, where an incomplete type declaration can be references, in order to allow types for linked lists, like:
type value_cell; -- Incomplete declaration
type value_ptr is access value_cell; -- value_cell only for access type
type value_cell is record -- Full declaration
value : bit_vector(0 to 3);
next_cell : value_ptr;
end record value_cell;
However, this is not using the type before declared, and the access type is neither synthesizable, but it is a useful technique for test bench code.

Can I access a constant inside a instantiated entity from outside?

I have a VHDL entity with a generic parameter list. The architecture to this entity calculates several constants, which are needed to create the intended functionality.
Is it possible to access one of these constants from outside?
Example 1:
Let's say there is a FIFO that decides based on DEPTH and OUTREG what the best implementation is (register based, SRL based or BlockRAM based). Depending on this the minimum delay through the FIFO can vary from 1 to 2 cycles.
Example 2:
Consider the same FIFO to be cross clock compatible. Now the min delay depends also on the choosen sync circuits and the frequency difference.
Example 3:
A division entity needs N cycles to calculate a div b. N depends on BITS, RADIX, OUTREG, IS_SIGNED, ...
Further let's say each entity has a MIN_DELAY constant of type NATURAL which is of interest for other instances.
E.g. the instantiating entity needs to know how long it must at least wait for a result.
I can think of 2 solutions, but I think neither is a nice one.
Solution 1:
I could store the algorithmn for the computation in a package so it's globally accessable. But this is against the encapsulation principle :). The outside world only needs to know the delay value not the algorithmn.
Solution 2:
I could use a valid bit. That's always a good solution in dynamic, adaptive or pipelined systems, but this bit can not be used at synthesis time for further choices or optimizations.
Possible solution 3:
VHDL has the ability to define new attributes, but can they be accessed?
Example entity: alu_div:
constant MIN_DELAY : NATURAL := BITS / log2(RADIX) + 2;
attribute DELAY : NATURAL;
attribute DELAY of alu_div : entity is MIN_DELAY;
Example top:
mydiv : entity work.alu_div
generic map (....)
port map (....);
blk : block
constant my : NATURAL := mydiv'delay;
begin
....
end block;
NEW: Possible solution 4:
I found this SE question, where Jim Lewis noted that hierarchical references should also work with constants.
alias MY_DELAY is <<constant mydiv.DELAY : NATURAL >>;
Get internal signals of vhdl design in ncvhdl (alternative to modelsim's signal spy)
This is a modification of Morten's first entity declaration, in which for the 'module' instantiating alu_div I expect there's a component declaration which provides the declaration for the name alu_div.
There is no attribute decorating that declaration so the instantiation found at label alu_div_0 has no attribute DELAY.
If you were to use direct entity instantiation it might work:
entity alu_div is
constant MIN_DELAY : NATURAL := 42;
attribute DELAY : NATURAL;
attribute DELAY of alu_div : entity is MIN_DELAY;
end entity;
architecture foo of alu_div is
begin
end architecture;
entity test is
end entity;
architecture foo of test is
begin
alu_div_0:
entity work.alu_div ;
MONITOR:
process
begin
wait for 1 ns;
report "alu_div'DELAY = " & natural'image(work.alu_div'DELAY);
wait;
end process;
end architecture;
Which gives:
ghdl -a alu_div.vhdl
ghdl -e test
ghdl -r test
alu_div.vhdl:25:9:#1ns:(report note): alu_div'DELAY = 42
>
The idea is that if you use a direct entity instantiation with a selected name (an expanded name) you're using the declaration in the library noted by the prefix (in this case WORK).
The following demonstrates accessing the value of alu_div'DELAY can be done at elaboration:
entity alu_div is
generic (pickone: natural := 1);
constant MIN_DELAY : NATURAL := 42;
constant TARG_DELAY: natural := MIN_DELAY + pickone;
attribute DELAY : NATURAL;
attribute DELAY of alu_div: entity is MIN_DELAY;
-- attribute DELAY of alu_div : entity is TARG_DELAY;
end entity;
architecture foo of alu_div is
begin
end architecture;
entity test is
end entity;
architecture fie of test is
constant fumble: natural := work.alu_div'DELAY;
component alu_div is
generic (pickone: natural := 1);
end component;
begin
alu_div_0:
alu_div
generic map(1);
MONITOR:
process
begin
report "constant fumble = " & natural'image(fumble);
report "alu_div'DELAY = " & natural'image(work.alu_div'DELAY);
wait;
end process;
end architecture;
And that works:
ghdl -a alu_div.vhdl
david_koontz#Macbook: ghdl -e test
david_koontz#Macbook: ghdl -r test
alu_div.vhdl:60:9:#0ms:(report note): constant fumble = 42
alu_div.vhdl:61:9:#0ms:(report note): alu_div'DELAY = 42
Also following Jonathan's comment that the question was attempting to loop information through the instantiated component supplied by generics I tried switching the entity attribute to depend on a generic (commenting out the one with MIN_DELAY, uncommenting the one with TARG_DELAY) and that results in a different error than Morten supplied:
ghdl -a alu_div.vhdl
alu_div.vhdl:36:13: attribute expression for entity must be locally static
ghdl: compilation error
And that error is singularly helpful and easy to find in the 2008 LRM and is quite specific:
7.2 Attribute specification (paragraph 8):
The expression specifies the value of this attribute for each of the named entities inheriting the attribute as a result of this attribute specification. The type of the expression in the attribute specification shall be the same as (or implicitly convertible to) the type mark in the corresponding attribute declaration. If the entity name list denotes an entity declaration, architecture body, configuration declaration, or an uninstantiated package that is declared as a design unit, then the expression is required to be locally static (see 9.4.1)....
This requirement was introduced in the '93 LRM (5.1 Attribute specification). And researching that we find there was a proposal for out-mode generics in the -1992 standardization effort (approved in -1993).
Also in the '87 Issue Report 40 (IR00040.txt) following the first ISAC rationale report of a discussion of the problem as relates to setting the attribute from within an architecture:
Such a capability would greatly (and negatively) affect at least some
implementations. A straightforward approach to the implementation of
specifications is to decorate the named entity with the information
contained in the specification. However, when the entity appears in
one design unit and the applicable specification appears in another,
many problems result. One cannot analyze the specification without
modifying the library unit containing the entity, which can lead to
potential circular chains of dependence. Moreover, multiple
architectures corresponding to a given entity interface cannot each
supply a different value to the attribute of some interface-resident
entity. Finally, there is no LRM requirement that, if one architecture
attributes some interface-resident entity, then all must, which seems
desirable.
You could note the undesired circular dependencies are also possible with an attribute dependent on a generic. Or similarly with out-mode generics the issue moves from circular dependencies in analysis order (locally static expressions in attribute declarations) to elaboration order (evaluating globally static expressions) which is likely quite a bit harder. out-mode generics show sporadic mention in available records, the last time on the vhdl-200x-mp (Modeling and Productivity) email reflector.
It's not likely the status of either of these will change without someone defining how to deal with late binding (linking loader time) order dependencies.
In the mean time as Brian says the accepted method is to use a package commonly shared, which uses locally static constant declarations (and are declaration order dependent). You could also manage the issue with configuration.
Good question. I have sometimes felt the need for "OUT mode generics" too, whose actual value is computed within the architecture, again to allow the higher levels in a hierarchy to know (and adjust to) the pipeline depth of a processing unit.
It might be worth writing a proposal to allow something of the sort in VHDL-201x and submit it to the standards group but meanwhile we have to live with what we have.
My normal solution is to use a package associated with the unit, holding both the initial constant (instead of a generic) and the dependent quantities. This limits the "encapsulation breakage" to those compilation units that use the package, making them at least readily identifiable.
Within the package the constants are deferred where possible, or parameterless (impure) functions, which amount to the same thing.
A possible approach I haven't explored is that an entity declaration, after the PORT list, also allows zero or more entity_delarative_items. If these may include function declarations, then we could potentially return such information that way.
EDIT : David points out an LRM rule (8.3) that prevents this approach with current VHDL versions : a limited relaxation of that rule might be an alternative to "OUT mode generics".
An entity declaration may also include begin and some passive constructs - such as asserts that a set of generics and port widths are consistent. That way you would have to input all the required values, but at least the build would fail reporting errors if e.g. width and depth were inconsistent.
Agree that it is sometimes very useful with information about implementation
details from the entity, even though it breaks the encapsulation principle, but
for white box verification it can be a great help.
Tried to use entity attribute based on entity like:
entity alu_div is
generic(
BITS : positive;
RADIX : positive);
port(
...);
constant MIN_DELAY : NATURAL := BITS / log2(RADIX) + 2;
attribute DELAY : NATURAL;
attribute DELAY of alu_div : entity is MIN_DELAY;
end entity;
But the module where the alu_div is instantiated is not able to access it
using e.g. alu_div_0'DELAY, since ModelSim gives error:
No attribute specification with designator "DELAY" decorates label "alu_div_0".
One method that is useful for white box verification, where the verification
depends on the implementation, is to make an output port with information from
the implementation, like:
entity alu_div is
...
port(
...
DELAY_O : out natural);
...
end entity;
architecture syn of alu_div is
begin
DELAY_O <= MIN_DELAY;
...
It won't be a true constant, since for simulation it will need a delta cycle
before getting the value, but it may be a sufficient solution in many cases.
Another approach I have used is to live with the restriction that all "generic" information flows into a module by specifying as another generic, the result I want from the derived parameter.
For example,
entity alu_div is
generic(
BITS : positive;
RADIX : positive;
DELAY : positive);
port(
...);
Within the architecture, an ACTUAL_DELAY constant is derived from the other generics (plus port bus-widths, etc) and compared with the given DELAY generic.
If the requested DELAY and ACTUAL_DELAY are identical, all is well.
If the requested DELAY exceeds ACTUAL_DELAY, the architecture can insert pipeline stages to meet the request. The overall design will function as intended, though it may consume more registers than strictly necessary.
Otherwise the requested delay cannot be met, and the architecture asserts with severity FAILURE.

Get internal signals of vhdl design in ncvhdl (alternative to modelsim's signal spy)

In ModelSim you can use something like
in modelsim we can use
init_signal_spy("../.../sig", mysignal);
to get deep hierarchy signals.
Is there a way to get such signals with Cadence's NCVhdl?
This should be flagged "SimVision", which is the name the tool, but that flag does not seem to exist.
If Cadence tools support VHDL-2008, you can access signals, shared variables, or constants in other levels of your design via external names.
Direct usage is as follows.
A <= <<signal .tb_top.u_comp1.my_sig : std_logic_vector >>;
Note that the object must be elaborated before the reference. Since VHDL designs are elaborated in order of instantiation later designs may reference into earlier ones.
Use an alias to create a local short hand name:
alias u1_my_sig is <<signal u1.my_sig : std_logic_vector >>;
Path starts with:
“.” = path starts at top level: “.tb_top.my_sig”
“u1” = path starts from current level: “u1.my_sig”
“^” = path starts from level above current: “^u2.my_sig”
As one can see here, the function is called nc_mirror.
nc_mirror (destination => "destination",
source => "source",
verbose => "verbose");
It takes a destination and a source and does just the same as init_signal_spy does for modelsim. The third parameter is optional. Additionally it supports mirroring arrays or records.
In this interesting answer a wrapper package is provided that converts the nc_mirror or init_spy_signal (and others) to a function "probe".

Resources