7
\$\begingroup\$

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.

\$\endgroup\$
3
  • \$\begingroup\$ Use generic parameters in the entity declaration, and generic map in the instantiation to map those parameters to values in a higher level entity. \$\endgroup\$
    – tim
    Commented Dec 12, 2020 at 14:41
  • \$\begingroup\$ Are you familiar with generic map? \$\endgroup\$
    – Mitu Raj
    Commented Dec 12, 2020 at 14:42
  • \$\begingroup\$ Thanks guys! Yes I know about generic map but I am unsure how I should use them to avoid having to change the dataWidth in every component instead of just in the top level file \$\endgroup\$
    – David777
    Commented Dec 12, 2020 at 14:52

3 Answers 3

9
\$\begingroup\$

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

\$\endgroup\$
7
  • \$\begingroup\$ Ah looks good actually. Where are packages declared at in the top level file? \$\endgroup\$
    – David777
    Commented 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
    Commented 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
    Commented Dec 12, 2020 at 16:37
  • \$\begingroup\$ So a package requires a separate design source file? \$\endgroup\$
    – David777
    Commented 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
    Commented Dec 12, 2020 at 20:38
6
\$\begingroup\$

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.

\$\endgroup\$
11
  • 1
    \$\begingroup\$ CompA has a generic as well (not necessarily same name). You simply map it to top module's generic. \$\endgroup\$
    – Mitu Raj
    Commented 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
    Commented 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
    Commented 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
    Commented 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
    Commented Dec 12, 2020 at 15:42
3
\$\begingroup\$

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;

Try it out on EDA Playground

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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