Electronic – Is it possible to have STD_LOGIC_VECTOR range constraint applied bottom-up

vhdl

I know that entities can use unconstrained array types (such as STD_LOGIC_VECTOR) in their port list, which will be automatically sized to match the signal connected in the port map when instantiated (and possibly different sizes for each instantiation). Within the entity attributes such as 'LENGTH and 'HIGH can be used to discover the actual instantiated range.

I have such an object, which is a parallel -> serial converter (accept any size input, wider inputs require more clock cycles to spit out).

Is it possible to make range inference work in reverse, that is, to have the range specified in a subcomponent, applied to an unconstrained signal in the parent component, and propagated from there to other components?

Further details:

My application has a number of data source subcomponents producing data streams of various width, arbitration logic to sample and serialize these sources round-robin, and parallel->serial converters doing the actual serialization and handshaking with the bus arbitration logic.

Right now I have the signal widths specified as constants in a package, but this means whenever any stream data format changes, I have to change both the source subcomponent and the package. I'd really like for the width to be specified in the source component only, since the downstream components adapt to any width.

Best Answer

The best thing is to use generics. Here's an example entity declaration for a shift register:

entity shift_register is
  generic (n_bits :integer := 8);
  port (clk  :std_logic;
        din  :std_logic_vector (n_bits-1 downto 0);
        dout :std_logic);
end entity shift_register;

When you instantiate this shift register you'd do it like this:

signal data :std_logic_vector (15 downto 0);
...
U0:  shift_register 
  generic map (n_bits => data'length)
  port map (clk, din, out);

In the entity, I defined the default value of n_bits to 8. When I instantiate it I could have left off the generic map stuff and then the default value of n_bits would be used.

EDIT: To better answer your question. Going in "reverse" doesn't really work that well, and I would avoid it if possible. But if you must, then you can always declare some constants in your package and use them farther up. It's not very clean, but it does work.