There are two ways to instantiate a module in VHDL: component instantiation and entity instantiation. Some people refer to the latter as direct instantiation.
Entity instantiation didn’t exist in the first revisions VHDL, but it has been available since VHDL’93. This is the method that I recommend unless you have specific reasons to use component instantiation.
To use the component instantiation method, you first have to declare the component in the declarative scope of where you want the module instance. That usually means in the VHDL file’s declarative region, but you can also define them in packages.
The listing below shows the syntax of the component declaration.
component_declaration ::= component identifier [ is ] [ local_generic_clause ] [ local_port_clause ] end component [ component_simple_name ] ;
While the component declaration resides in a declarative region, instantiations belong in the architecture. The Backus–Naur form notation below shows the combined instantiation syntax for all methods.
component_instantiation_statement ::= instantiation_label : instantiated_unit [ generic_map_aspect ] [ port_map_aspect ] ; instantiated_unit ::= [ component ] component_name | entity entity_name [ ( architecture_identifier ) ] | configuration configuration_name
Note that there is a third method of instantiation: configuration. That’s an advanced VHDL feature which I will cover in a separate article.
Entity instantiation example
The VHDL code below shows an example of direct instantiation of a multiplexer module.
architecture str of top_tb is constant n : positive := 5; signal sel : positive range 1 to n - 1; signal din : std_logic_vector(n - 1 downto 0); signal q : std_logic; begin MUX : entity work.mux(rtl) generic map (n => n) port map ( sel => sel, din => din, q => q ); end architecture;
First, we give the instance a name. If there’s just one instance, I usually use the same name as the module’s entity, MUX, in this case. That makes it easy to find it in the simulator hierarchy view.
Then we use the entity keyword to show that we want to use direct instantiation. After that, we identify the module by library, entity, and architecture name.
Specifying the architecture name is optional, but I recommend always to do it. It may help you avoid annoying errors due to multiple architectures. If you don’t explicitly specify one, you will get the latest compiled architecture.
The example module above has a generic declaration. If your module doesn’t use generics, omit the generic map section.
Component instantiation example
The code below is an equivalent example using component instantiation.
architecture str of top_tb is constant n : positive := 5; signal sel : positive range 1 to n - 1; signal din : std_logic_vector(n - 1 downto 0); signal q : std_logic; component mux generic (n : positive); port ( sel : in positive range 1 to n - 1; din : in std_logic_vector(n - 1 downto 0); q : out std_logic ); end component mux; begin MUX_1 : mux generic map (n => n) port map ( sel => sel, din => din, q => q ); end architecture;
The component declaration is equal to the entity of the module that you want to instantiate. If you change your module’s entity, you have to update three places: in the module’s entity, in the component declaration, and the instantiation.
Furthermore, there is no way to specify which architecture to use. If you have two or more architectures for your module, it’s the last compiled one that becomes active. That could be the one at the bottom of your VHDL file or determined by compile order if you have multiple files.
And finally, because you have to give a name to the component, you can’t use the same name as a label for your instance. If the module’s name is mux, and you name the component mux, you would have to call your instance MUX_1 or something like that, as shown in the example above.
For those reasons, I consider component instantiation to be inferior to entity instantiation.
When to use component instantiation
I would say always use entity instantiation if you can; it’s neater and safer. But there are some situations where the synthesis tools force you to use component instantiation. For example, when instantiating something that isn’t VHDL in a VHDL file.
That could be a netlist, a hard macro, or a Verilog module. Xilinx Vivado only supports the component instantiation method for including Verilog files into VHDL projects.
The image above is an excerpt from Xilinx UG901 (v2020.1).
Another reason is if you want to use configuration constructs. Because of how the implementation design flow works in VHDL, configurations only work with component instantiation.
All of the examples above use named association in the generic and port map. VHDL also supports positional association of entity to local signal names, as shown below.
MUX : entity work.mux(rtl) generic map (n) port map (sel, din, q);
Many style guides recommend only to use named association, and I have to agree with them. It’s easy to get into trouble if you make changes to the entity and forget to fix every single instance of the module. With named association, it will still work, or you get a compilation error.