An example would be a generic register file which I'm trying to implement like this:
entity register_file is
generic(reg_width: integer := 32; reg_num: integer := 16);
constant sel_num: integer := integer(CEIL(LOG(Real(reg_num))));
port (
data_in: in std_logic_vector(reg_width - 1 downto 0);
data_out: out std_logic_vector(reg_width - 1 downto 0);
rd_sel: in std_logic_vector(sel_num - 1 downto 0);
wr_sel: in std_logic_vector(sel_num - 1 downto 0);
rd_enable: in std_logic;
wr_enable: in std_logic;
clock: in std_logic;
);
end register_file;
This doesn't work because it seems generic and port have to be the first two declarations, followed by the others. If I move type and constant after the port declaration, they are not visible when the port declaration is being processed.
I'm new to VHDL and I think this should be a common problem, but I can't find the solution. Obviously, I would like to avoid the copy-paste solution.
If there is no other use of reg_num
, simply make sel_num
the generic.
Otherwise, write a function called sel
to convert reg_num
to another natural.
The question is, where to put the function?
In my designs I tend to put a lot of common datatypes, declarations, functions and the clock period (*) in a package called common
.
package common is
function sel(n : natural) return natural;
constant clock_period : time := 1 sec / 32000000;
constant num_regs : natural := 16;
subtype sel_word is std_logic_vector(sel(num_regs) downto 0);
end common; -- package body contains the function body
Then my entity looks like
use Work.common.all;
entity register_file is
generic(reg_width: integer := 32; reg_num: integer := 16);
port (
rd_sel: in std_logic_vector(sel(reg_num) downto 0); -- OK
wr_sel: in sel_word; -- better?
...
If different parts of a design need different values of "regnum" then the generic approach is to be preferred.
Otherwise, locating these details in "common" allows you to parameterise the whole design with a single file, and no risk of hard-coded (and possibly wrong) values for some of the generics.
(*) why the clock frequency? It's unbelievably useful to scale all the timing delays, baud rate parameters, memory wait states etc from one parameter, knowing they will all remain correct when I change the clock...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With