0
\$\begingroup\$

I want to assign signals of a testbench to a component to which the port have infered constraints. I would like to introduce the problem with a working workbench before moving to a minimally reproducible example.

Example with constraint inference

Assume A and B

A.vhdl (the testbench)

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;

entity A is
end entity;

architecture A_arch of A is
    signal input, interm, output : std_logic_vector(10 downto 0);
begin
    B1: entity WORK.B port map (
        X => input, Y => interm
    );

    B2: entity WORK.B port map (
        X => interm, Y => output
    );

    process begin
        input <= (1 => '1', others => '0');
        wait;
    end process;
end architecture;

B.vhdl (component under test)

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;

entity B is
    port (
        X : in  std_logic_vector;
        Y : out std_logic_vector
    );
end entity;

architecture B_arch of B is
begin
    Y <= X;
end architecture;

As we can see, the size of B.X is inferred and everything compile just fine.

Example with different types

Again I would like to test B, except I would like to have X : signed and Y : unsigned instead. Their constraints are not (yet) inferred.

A.vhdl

…
    B1: entity WORK.B port map (
        X => unsigned(input), std_logic_vector(Y) => interm
    );

    B2: entity WORK.B port map (
        X => unsigned(interm), std_logic_vector(Y) => output
    );
…

B.vhdl

…
entity B is
    port (
        X : in  unsigned(10 downto 0);
        Y : out signed(10 downto 0)
    );
end entity;

architecture B_arch of B is
begin
    Y <= signed(X);
end architecture;
…

The minimally reproducible failing example

Again I would like to test B, except I would like to have X : signed and Y : unsigned instead with their constraints inferred.

B.vhdl

…
entity B is
    port (
        X : in  unsigned;
        Y : out signed
    );
end entity;

architecture B_arch of B is
begin
    Y <= signed(X);
end architecture;

B compile just fine but I can't seem to figure out how to handle the port mapping in A.

attempts

as is

Of course, it doesn't work because of the types differences.

with casting

from this post

…
architecture A_arch of A is
    signal input, interm, output : std_logic_vector(10 downto 0);
begin
    B1: entity WORK.B port map (
        X => unsigned(input), std_logic_vector(Y) => interm
    );

    B2: entity WORK.B port map (
        X => unsigned(interm), std_logic_vector(Y) => output
    );
…

** Warning: A.vhdl(12): (vcom-1191) Type conversion on actual associated with formal > "X" must be a constrained array subtype.

** Error: A.vhdl(12): (vcom-1189) Type conversion on formal "Y" must be a constrained > array subtype.

** Warning: A.vhdl(16): (vcom-1191) Type conversion on actual associated with formal > "X" must be a constrained array subtype.

** Error: A.vhdl(16): (vcom-1189) Type conversion on formal "Y" must be a constrained > array subtype.

\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

Per ieee-std-1076-1993, index ranges must be obtained from type conversion subtype ranges. Said subtype must be constrained (3.2.1.1 clause 415, p. 43):

For an interface object or member of an interface object whose mode is in, inout, or linkage, if the actual part includes a conversion function or a type conversion, then the result type of that function or the type mark of the type conversion must be a constrained array subtype, and the index ranges are obtained from this constrained subtype; otherwise, the index ranges are obtained from the object or value denoted by the actual designator(s).

(follows the same paragraph about out ports)

Here you type cast with std_logic vector or unsigned, which are unconstrained (i.e. array (... range <>) of ...).

This error is standard behavior.

You must add a constraint to the type conversion you use, like:

architecture a_arch of a is
  signal input, interm, output : std_logic_vector(10 downto 0);
  subtype u11 is unsigned(10 downto 0);
  subtype l11 is std_logic_vector(10 downto 0);
begin

  b1: entity work.b port map (
    x => u11(input), l11(y) => interm
    );

  b2: entity work.b port map (
    x => u11(interm), l11(y) => output
    );

  process
  begin
    input <= (1 => '1', others => '0');
    wait;
  end process;
end architecture;

This is rarely implemented correctly. For most vendor tools, expect to see crashes, strange error messages, or bad behavior.

\$\endgroup\$
2
  • \$\begingroup\$ Would you kindly tell me the reason, if any, of why this would not be correctly implemented nowadays ? What kind of bad behavior should I expect ? \$\endgroup\$
    – NRagot
    Apr 4, 2022 at 19:31
  • \$\begingroup\$ I’ve seen vivado, and ghdl crash, synplify tell it was not supported, etc. Some tools do not infer correct array constraints (range and direction) in instantiated module, which starts to be problematic when they are meaningful (e.g. sfixed/unfixed). Vivado chokes if there is a default assignment on unconstrained array port and associated signal is not the same size. Most tools do not accept port typecast mixed with structures. There are so many non portable things (despite being standard) around unconstrained ports and assignment casts that I learnt (the hard way) to avoid them. \$\endgroup\$
    – Nipo
    Apr 5, 2022 at 13:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.