I have a question about writing scalable code in VHDL.
I have a structural VHDL project that contains a lot of components. I would like a method of changing the bit size of all components by just changing one value in my top level file.
For example I would like a integer constant called dataWidth that I can change in my top level file that will change the data size of all components used in this top level file.
I tried declaring the integer as a generic inside the entity of the top level file but it in the other components it doesn't compile saying the dataWidth hasn't been declared. What is a simple method of doing this?
I can provide code if you need to see it.
3 Answers 3
There is an alternative to passing generics through all levels of the hierarchy:
declare the relevant quantities in a package, and "use" that package in every unit that needs it.
You can do a little better than a constant data_width
.
package bus_types is
constant DATA_WIDTH: natural := 8;
subtype DATA_BUS is std_logic_vector(DATA_WIDTH - 1 downto 0);
end package bus_types;
Now, any unit that uses the bus_types package use work.bus_types.all;
can simply say
port
(
address : in ADDRESS_BUS,
data_in : in DATA_BUS,
data_out : out DATA_BUS
);
which is simpler and better documents the intent.
There are use cases for generics, and use cases for this. One is not universally better than the other.
Multiple memories, which may be different sizes, are best handled with a generic for memory size. Then the generic specialises the memory block for each usage.
But for a data bus width : the same width is likely to be used throughout the whole design. And then a package like this gets the job done with a lot less plumbing than a generic on every component ... especially if you find yourself passing generics through hierarchy levels, without using them, just to get to a lower level.
More on packages, may supply the additional info requested:
https://stackoverflow.com/questions/35234086/vhdl-standard-layout-syntax-for-header-file/35234901#35234901 https://stackoverflow.com/questions/31383481/vhdl-how-to-define-port-map-of-a-component-with-a-package-in-its-entity/31383565#31383565 https://stackoverflow.com/questions/16144135/avoid-duplicating-code-in-vhdl/16144861#16144861
And libraries https://stackoverflow.com/questions/13414682/how-to-to-create-include-files-in-vhdl/13415746#13415746 https://stackoverflow.com/questions/44222287/vhdl-library-doesnt-work/44226184#44226184
-
\$\begingroup\$ Ah looks good actually. Where are packages declared at in the top level file? \$\endgroup\$David777– David7772020年12月12日 16:33:10 +00:00Commented Dec 12, 2020 at 16:33
-
1\$\begingroup\$ Package is a separate file. Each file that needs to see
DATA_BUS
needs its own USE clause (so, one line overhead per file). But that's better than a generic map per component in each file, and the package can replace N generics. (Package can contain other things, like functions to pad 8 bits out to whatever size DATA_BUS is, etc. \$\endgroup\$user16324– user163242020年12月12日 16:35:53 +00:00Commented Dec 12, 2020 at 16:35 -
\$\begingroup\$ Sorry, I'm relatively new to VHDL. Is there any chance you could show this in a basic example? \$\endgroup\$David777– David7772020年12月12日 16:37:31 +00:00Commented Dec 12, 2020 at 16:37
-
\$\begingroup\$ So a package requires a separate design source file? \$\endgroup\$David777– David7772020年12月12日 18:03:02 +00:00Commented Dec 12, 2020 at 18:03
-
1\$\begingroup\$ You shouldn't need "library work;" - it's implicit in every unit. But the Use clause is correct. See stackoverflow.com/questions/44222287/vhdl-library-doesnt-work/… for a bit more. Note : not all tools get VHDL libraries right! (though most do nowadays). Might be worth mentioning what you're using. \$\endgroup\$user16324– user163242020年12月12日 20:38:15 +00:00Commented Dec 12, 2020 at 20:38
Declare data_width
as generic
in top module. Map this generic to corresponding generics in the submodules. For eg:
entity Top is
generic (data_width: integer := 32);
port (...);
end entity;
architecture Structure of Top is
component CompA
generic (data_width: integer := 8);
port (...);
end component;
begin
u1: CompA generic map (data_width => data_width)
port map (...);
u2: CompA generic map (data_width => data_width/2)
port map (...);
end Structure;
I can give default values to all generics in top modules and sub modules for individual synthesis/simulation. However it can be overridden while instantiating and generic mapping. For instance, here u1
's data_width
becomes 32, and u2
's data_width
becomes 16. Both were derived from Top
's data_width
.
-
1\$\begingroup\$ CompA has a generic as well (not necessarily same name). You simply map it to top module's generic. \$\endgroup\$Mitu Raj– Mitu Raj2020年12月12日 15:01:40 +00:00Commented Dec 12, 2020 at 15:01
-
1\$\begingroup\$ Its already there as 'component' declaration in the code. That's how compA looks like? Do you mean you want to see Top's port/generic declaration? \$\endgroup\$Mitu Raj– Mitu Raj2020年12月12日 15:15:46 +00:00Commented Dec 12, 2020 at 15:15
-
1\$\begingroup\$ Entity declaration of compA is same as the component declaration. However I have updated and put the entity declaration of top module for more clarity . \$\endgroup\$Mitu Raj– Mitu Raj2020年12月12日 15:25:37 +00:00Commented Dec 12, 2020 at 15:25
-
1\$\begingroup\$ Okay. I guess that's what this example was all about. So what's the confusion ? \$\endgroup\$Mitu Raj– Mitu Raj2020年12月12日 15:39:49 +00:00Commented Dec 12, 2020 at 15:39
-
1\$\begingroup\$ By default compA has generic that defaults the data width to some value say 8. It was overridden to 32 when instantiating it in the top module thru generic mapping. \$\endgroup\$Mitu Raj– Mitu Raj2020年12月12日 15:42:41 +00:00Commented Dec 12, 2020 at 15:42
The entity with a generic
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity MyGeneric is
generic
(
DATA_WIDTH: natural := 4 -- Default value of 4.
);
port
(
clock: in std_logic;
reset: in std_logic;
data : out std_logic_vector(DATA_WIDTH - 1 downto 0)
);
end entity;
architecture V1 of MyGeneric is
signal internal_data: std_logic_vector(DATA_WIDTH - 1 downto 0) := (others => '1');
begin
process(clock, reset)
begin
if reset then
data <= internal_data;
elsif rising_edge(clock) then
data <= std_logic_vector(to_unsigned(8, DATA_WIDTH));
end if;
end process;
end architecture;
Test bench
library ieee;
use ieee.std_logic_1164.all;
entity TestBench is
end entity;
architecture V1 of TestBench is
constant DATA_WIDTH: natural := 8;
signal clock: std_logic;
signal reset: std_logic;
signal data : std_logic_vector(DATA_WIDTH - 1 downto 0);
component MyGeneric is
generic
(
DATA_WIDTH: natural := 4 -- Default value of 4.
);
port
(
clock: in std_logic;
reset: in std_logic;
data : out std_logic_vector(DATA_WIDTH - 1 downto 0)
);
end component;
begin
MG: MyGeneric
generic map
(
DATA_WIDTH => DATA_WIDTH
)
port map
(
clock => clock,
reset => reset,
data => data
);
process
begin
clock <= '0';
reset <= '1';
wait for 10 ns;
clock <= '0';
reset <= '0';
wait for 10 ns;
clock <= '1';
wait for 10 ns;
clock <= '0';
wait for 10 ns;
wait;
end process;
end architecture;
generic
parameters in theentity
declaration, andgeneric map
in the instantiation to map those parameters to values in a higher level entity. \$\endgroup\$