Matthew said:
That doesn't answer my question, as generics are still a better choice
in this case, because you can't even synthesize (or simulate for that
matter) unconstrained arrays.
Of course you can. The array becomes constrained as soon as you connect
a constrained signal to it. I use this quite often, actually, simulates
and synthesizes fine with every tool I've ever tried (ModelSim,
ActiveHDL, XST, Precision, Synplify).
Simple example:
I often do image-processing blocks. The bidtwidth of the pixels can be 8
in one case, 12 or 14 in another, the underlying operations remain the
same. Now I can solve this using a GENERIC, but then I'd have to drag
that GENERIC all through the hierarchy. Besides, the GENERIC clutters up
my entity declarations:
entity do_stuff is
generic (
BITWIDTH : positive := 8
);
port (
clk : in std_logic;
pix_in : in std_logic_vector(BITWIDTH-1 downto 0);
pix_out : out std_logic_vector(BITWIDTH-1 downto 0);
pix_mean : out std_logic_vector(BITWIDTH-1 downto 0);
pix_min : out std_logic_vector(BITWIDTH-1 downto 0);
pix_ax : out std_logic_vector(BITWIDTH-1 downto 0)
);
end entity do_stuff;
Looks ugly IMHO, only gets worse if you e.g. have separate RGB-values
and such. Now, I could instead use records or special types to make it
look nicer, but then I couldn't use a GENERIC, but would have to use
i.e. a constant defined in a package and the corresponding type
declarations. Then it would look better, but I'd have to drag a package
all through the hierarchy, and into every project I want to use that
specific module in.
So, what I do is use unconstrained arrays, and declare special types
inside the architecture:
entity do_stuff is
port (
clk : in std_logic;
pix_in : in std_logic_vector;
pix_out : out std_logic_vector;
);
end entity do_stuff;
architecture bla of do_stuff is
subtype t_pixdata is std_logic_vector(pix_in'length-1 downto 0);
-- I think std_logic_vector(pix_in'range) might work, too
signal pixel : t_pixdata;
begin
-- do stuff with pixels
end architecture bla;
This is "portable" (I can use it in every project without needing any
additional files), doesn't need any special constants or packages,
doesn't have a cluttered up port list and I don't have to drag a GENERIC
all through the hierarchy, which I might forget to hook up somewhere
along the line. I like to have only things configurable that need to be
configured. In this case, the width of the vectors can unmistakably be
deduced from the connected signals, so there's really no need to make it
configurable. My experience is that things that can be configured,
somebody will configure wrong, so it's better not to even give them the
chance
The only thing you have to take care of is that when you instantiate
do_stuff, the signals you connect to the unconstrained ports must be
constrained. But I think "constrainedness" even propagates down.
So, for me this works well, but I guess it's more of a personal
preference. BTW, I use GENERICs, too, but for other stuff, things that
can't be deducted from something else.
cu,
Sean