Generic is a basic and very useful function of the VHDL. It allows creating more flexible and easy to modify components. Proper use of it will save your time and make your code clearer and more readable.
How do they work?
They allow easily changing structure and function of the component. To simplify, they can be treated as constants, but with one big advantage. They can be passed from one block to another. They are hardcoded, so their value can’t be changed after synthesis. Every data type can be used to create generic. Thanks to them, you can parameterize the component.
How can they be helpful?
During designing a block, where many vectors have the same size, instead of using numeric values for declaring width of every vector, you can use generic. This means that, if you need to change width of group of vectors in the future, you won’t have to change declaration of every vector separately, but only one generic parameter.
Another example is to use generics to pass timing parameters of the block. Imagine, you have to emulate in your project specific A/D Converter with its detailed parameters. In another project you have to do the same, but with different ADC. Instead of writing two emulators for every ADC (because they differ), you can write one, parameterized module, which can bahave in two different ways.
Another example is to control tests in testbench.
How to declare generic?
It can be set in entity declaration, configuration declaration or component instantiation:
generic_name : type [:= value];
Below is very simple example with two generics. First one specifies width of the counter, and the second specifies direction of the counter.
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity generics is generic ( GEN_N :integer := 8; GEN_DIR :string := "UP" ); port ( clk :in std_logic; rst :in std_logic; q :out std_logic_vector(GEN_N-1 downto 0) ); end generics; architecture generics_rtl of generics is signal main_cnt :unsigned(GEN_N-1 downto 0); begin counter: process(clk) begin if rising_edge(clk) then if rst = '1' then main_cnt <= (others => '0'); else if GEN_DIR = "UP" then main_cnt <= main_cnt + 1; elsif GEN_DIR = "DOWN" then main_cnt <= main_cnt - 1; else main_cnt <= main_cnt + 1; end if; end if; end if; end process; q <= std_logic_vector(main_cnt); end generics_rtl;
If you need to change width of the counter, you have to modify only one line. The same is with direction of the counter. Module is prepared to count up or down. You don’t have to keep two files for every counter. One file with generic parameter covers both functions.
*** *** ***
All source codes used in that post you can find on gitlab.com.
*** *** ***