5
\$\begingroup\$

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.

\$\endgroup\$
6
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ This is exactly what I have now, actually. And I have to edit multiple files when the data width changes. Guess there's no getting around that. I may be able to reorganize things and move the parallel->serial subcomponent instantiation inside the component that knows the width, then I can just pass a fixed-width serial interface up to the top-level. \$\endgroup\$ – Ben Voigt Jun 24 '11 at 19:15
  • \$\begingroup\$ @Ben Voigt If you did it right then you shouldn't have to edit multiple files when the data width changes. My rule for everything is: If you have to enter the information more than once then you're going to enter it wrong more than once. I've done lots of FPGA's where I only enter in a piece of info once and the rest of the code just figures it out. \$\endgroup\$ – user3624 Jun 24 '11 at 19:53
  • \$\begingroup\$ @David: I have one component providing the data, something like parallel_out <= some_data & some_more_data & even_more_data;. That really controls how wide the output port needs to be, when I add yet_more_data to the output, the array range has to increase. Then I need a constant in a package file, to make all the signals which route that data match the width, and the need to keep that in sync is what I'm trying to eliminate. \$\endgroup\$ – Ben Voigt Jun 24 '11 at 20:30
  • \$\begingroup\$ @Ben You can do math with the generics and constants. Just put that math into calculating your SLV sizes. Something like "signal parallel_out :slv (some_data_bits+some_more_data_bits+even_more_bits-1 downto 0)". Remember: enter info once, calculate everything else. \$\endgroup\$ – user3624 Jun 24 '11 at 20:39
  • \$\begingroup\$ @David: So now I need three constants instead of one? That's not an improvement. And there's no reason for any fpga component other than the data source to know the sizes of individual fields. (Obviously the microcontroller receiving the serial stream needs to know, but I don't expect to be able to share this information between C and VHDL) \$\endgroup\$ – Ben Voigt Jun 24 '11 at 20:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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